Skip to content

TutorialsCMS & websites

How to install Ghost on Ubuntu with Ghost-CLI, Nginx and MySQL

Install Ghost 6 on Ubuntu 24.04 or 26.04 with Ghost-CLI, Nginx, MySQL and Node.js 22, add HTTPS, configure mail and newsletters, and back up and update safely.

  • Intermediate
  • 40 min read
  • Updated

Tested on: Ubuntu 24.04 LTS, Ubuntu 26.04 LTS

This guide is not available in your language yet, so it is shown in English.

On this page
  1. Prerequisites
  2. Step 1 — Create a non-root user
  3. Step 2 — Install Nginx and open the firewall
  4. Step 3 — Install MySQL and set a root password
  5. Step 4 — Install Node.js 22
  6. Step 5 — Install Ghost-CLI
  7. Step 6 — Install Ghost
  8. Step 7 — Create the owner account
  9. Step 8 — Configure transactional email
  10. Alternative: Ghost's Docker setup (preview)
  11. Back up and restore
  12. Update Ghost
  13. Troubleshooting
  14. Ghost-CLI refuses to run as root or reports permission errors
  15. Access denied for user 'root'@'localhost' during ghost install
  16. ghost start fails or the site shows 502 Bad Gateway
  17. The installer stops because of an unsupported Node.js version
  18. Emails are not delivered
  19. Next steps

Ghost is an open-source publishing platform for blogs, magazines and newsletters. It combines a fast editor, membership and subscription features and built-in email newsletters, and it is built on Node.js with a MySQL database.

Ghost's documentation lists several ways to self-host. This guide follows the Ubuntu installation with Ghost-CLI, the standard method in the official docs: you prepare a non-root user, Nginx, MySQL and Node.js 22, and Ghost-CLI then installs Ghost, creates a dedicated database user, writes the Nginx configuration, obtains a Let's Encrypt certificate and registers a systemd service. Afterwards you configure transactional email and newsletters, and set up backups and updates.

Prerequisites

  • A server running Ubuntu 24.04 LTS or Ubuntu 26.04 LTS. Ghost also supports Ubuntu 22.04; Debian is not on Ghost's list of supported systems, so use Ubuntu for this method.
  • Root or sudo access to create a non-root user in Step 1, and SSH key login as described in Set up SSH keys. The basics in Secure a new Linux server apply here too.
  • A domain such as example.com with an A record (and AAAA for IPv6) pointing at the server before you start, because Ghost-CLI requests the TLS certificate during installation.
  • An SMTP account from a transactional email provider for login links and invitations, and a Mailgun account if you want to send newsletters.

Ghost strongly recommends at least 1 GB of memory and publishes no CPU or disk figures, so the suggestions below are a conservative starting point for one publication:

ResourceMinimum (official)Suggested starting point
CPUNot published1 vCPU
RAM1 GB2 GB
DiskNot published20 GB SSD plus your images and media

Step 1 — Create a non-root user

Ghost-CLI refuses to run as root, and it creates its own system user named ghost to run the site. Log in as root and create an admin user with any name except ghost, for example webadmin, then give it sudo rights and switch to it. Skip this step if you already have such a user:

Bash
adduser webadmin
usermod -aG sudo webadmin
su - webadmin

Run all following commands as this user.

Step 2 — Install Nginx and open the firewall

Update the system and install Nginx. Ghost-CLI writes its own Nginx site configuration later:

Bash
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install nginx
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable

The Nginx Full profile opens ports 80 and 443. Check that Nginx answers with curl -I http://localhost.

Step 3 — Install MySQL and set a root password

Install the MySQL server from Ubuntu's archive. Ubuntu 24.04 provides MySQL 8.0 and Ubuntu 26.04 provides MySQL 8.4, both supported by Ghost:

Bash
sudo apt-get install mysql-server
mysql --version

On Ubuntu the MySQL root account authenticates through the Unix socket, which Ghost-CLI cannot use. Ghost's documentation therefore gives root a password. Generate a strong one with openssl rand -hex 24, then open the MySQL shell with sudo mysql and run:

SQL
ALTER USER 'root'@'localhost' IDENTIFIED WITH 'caching_sha2_password' BY 'change-me';
FLUSH PRIVILEGES;
EXIT;

Replace change-me with the generated password and store it in your password manager. Test it with mysql -u root -p -e "SELECT VERSION();".

Step 4 — Install Node.js 22

Ghost 6 requires Node.js 22 LTS; Node 20, 21 and 23 or newer are not supported. Ghost's documentation installs it from the NodeSource repository and warns that other installation methods can cause problems:

Bash
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
NODE_MAJOR=22
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list
sudo apt-get update
sudo apt-get install nodejs -y
node -v

node -v must print a version that starts with v22.

Step 5 — Install Ghost-CLI

Ghost-CLI is the command-line tool that installs, configures and updates Ghost. Install it globally with npm:

Bash
sudo npm install ghost-cli@latest -g
ghost help

ghost help lists the available commands, such as install, update, backup and doctor.

Step 6 — Install Ghost

Create the install directory, give it to your user with the permissions Ghost-CLI expects, and run the installer from inside it. Use an empty directory:

Bash
sudo mkdir -p /var/www/ghost
sudo chown $USER:$USER /var/www/ghost
sudo chmod 775 /var/www/ghost
cd /var/www/ghost
ghost install

Ghost-CLI checks the system, downloads the current Ghost release and asks a series of questions:

  • Blog URL: the full address with protocol, such as https://example.com. Use HTTPS so that the SSL step is offered; IP addresses cause errors.
  • MySQL hostname: press Enter to accept localhost.
  • MySQL username and password: root and the password from Step 3, or the dedicated user from the tip.
  • Ghost database name: accept the suggestion; with root, Ghost-CLI creates the database.
  • Set up a ghost MySQL user?: answer yes. Ghost-CLI creates a MySQL user that can only access the Ghost database and writes its credentials to the config file, so root is not used at runtime.
  • Set up Nginx?: yes. Ghost-CLI writes a site configuration that proxies your domain to Ghost.
  • Set up SSL?: yes. Enter an email address for Let's Encrypt; Ghost-CLI obtains the certificate with acme.sh and configures HTTPS on port 443.
  • Set up systemd? and Start Ghost?: yes to both, so that Ghost runs as a service and starts at boot.

When the installer finishes, check the result:

Bash
ghost ls
ghost doctor
curl -I https://example.com

ghost ls shows the site with status running, ghost doctor reports no errors, and curl returns HTTP/2 200 with a valid certificate.

Step 7 — Create the owner account

Open https://example.com/ghost right away and create the owner account with your name, email address and a strong password. Until this is done, anyone who finds the URL could claim the site. Then work through the setup wizard: site title, design and the first staff invitations.

Step 8 — Configure transactional email

Ghost needs a working mail configuration in production for staff invitations, password resets, member sign-ups and member login links. Configure an SMTP provider in /var/www/ghost/config.production.json.

Open the file with nano config.production.json and replace the existing mail block with your provider's details. With port 587 and secure set to false, the connection is upgraded with STARTTLS:

JSON
  "mail": {
    "from": "'Example Blog' <[email protected]>",
    "transport": "SMTP",
    "options": {
      "host": "smtp.example.com",
      "port": 587,
      "secure": false,
      "auth": {
        "user": "[email protected]",
        "pass": "change-me"
      }
    }
  },

Use a real sender address on your own domain to help deliverability. The file must remain valid JSON, so check commas and quotes. Apply the change:

Bash
cd /var/www/ghost
ghost restart

Test it by inviting a staff user or signing up as a member with another address. If no email arrives, ghost log -e shows the error.

Newsletters are a separate path. Ghost's documentation states that bulk newsletters cannot be sent through basic SMTP and that Mailgun is currently the only supported bulk email provider. Enter your Mailgun domain and API key in the Email newsletter settings in Ghost Admin. Member login emails keep using the SMTP configuration above.

Alternative: Ghost's Docker setup (preview)

Ghost's Docker tooling lives in the official TryGhost/ghost-docker repository. You clone it to /opt/ghost, copy .env.example and caddy/Caddyfile.example, set your domain, database passwords and SMTP details, then run docker compose pull and docker compose up -d. Caddy handles TLS, and optional profiles add self-hosted ActivityPub and web analytics. Updates are git pull, docker compose pull and docker compose up -d. The repository includes scripts/migrate.sh, which moves an existing Ghost-CLI site into containers. Because Ghost still labels this setup a preview, check the current status in Ghost's install documentation before you use it in production.

Back up and restore

Ghost's state lives in the MySQL database, the content folder (images, media, files, themes and logs) and config.production.json. Start with Ghost-CLI's own backup, which Ghost recommends before every update. It creates a zip file with a JSON content export, a members CSV, your themes, images, files and media, and the routes and redirects files. Check the command's output for the location of the zip file:

Bash
cd /var/www/ghost
ghost backup

For disaster recovery or an exact copy, also dump the database and archive the content folder, as Ghost's manual backup guide describes. Look up the database name, user and password in the database.connection block of config.production.json, then replace ghost_user and ghost_production below with your values:

Bash
sudo mkdir -p /opt/backups
sudo chown $USER:$USER /opt/backups
cd /var/www/ghost
mysqldump --single-transaction --no-tablespaces -u ghost_user -p ghost_production > /opt/backups/ghost-db-$(date +%F).sql
sudo tar czf /opt/backups/ghost-content-$(date +%F).tar.gz -C /var/www/ghost content config.production.json
sudo chmod 600 /opt/backups/ghost-*

--no-tablespaces avoids an error that MySQL 8 raises when a user without the PROCESS privilege dumps tablespace information. Copy the backups to another machine, for example with rsync; a backup that only lives on the server is lost together with it.

To restore on a new server, complete Steps 1 to 7 with the same Ghost version that the backup came from (ghost ls on the old server shows it; ghost install 6.69.0 installs a specific version), then import the database with the credentials from the new config.production.json and put the content back:

Bash
cd /var/www/ghost
ghost stop
mysql -u ghost_user -p ghost_production < /opt/backups/ghost-db-2026-10-09.sql
sudo tar xzf /opt/backups/ghost-content-2026-10-09.tar.gz -C /var/www/ghost content
sudo chown -R ghost:ghost /var/www/ghost/content
ghost start

Replace the version, dates, user and database name with your own values, then run ghost update to move to the latest release. To move only posts, pages, tags and members to a fresh site, you can also use Settings → Advanced → Import/Export in Ghost Admin; the JSON export does not include comments, member activity or media files, which is why the full backup above is the safer default.

Update Ghost

Ghost releases updates weekly. Keep Ghost-CLI current, back up, check for an update and apply it:

Bash
cd /var/www/ghost
sudo npm install -g ghost-cli@latest
ghost backup
ghost check-update
ghost update

ghost update downloads the new version, runs the database migrations, restarts Ghost and rolls back automatically if the update fails. To return to the previous version manually, run ghost update --rollback. Major Ghost versions arrive every 12 to 18 months and need more care: read the release notes and breaking changes, make sure your theme supports the new version, and check whether the required Node.js version changed. If it did, change NODE_MAJOR in Step 4 to the new version, run the NodeSource commands again, and then update Ghost. Keep Nginx, MySQL and the rest of the system patched with sudo apt-get update && sudo apt-get upgrade.

Troubleshooting

Ghost-CLI refuses to run as root or reports permission errors

Since Ghost-CLI 1.5.0, running Ghost commands as root is not allowed. Create a sudo user as in Step 1. If you already installed as root, Ghost's root user fix moves /root/.ghost/config to the new user's home and changes the ownership of root-owned files in /var/www/ghost with find . -group root -user root -exec chown webadmin:webadmin {} \;. Do not set setuid or setgid bits on the install directory; Ghost-CLI does not support them.

Access denied for user 'root'@'localhost' during ghost install

MySQL root still uses socket authentication or the password is wrong. Repeat the ALTER USER command from Step 3 with sudo mysql, test the password with mysql -u root -p, then run ghost setup to continue the installation.

ghost start fails or the site shows 502 Bad Gateway

Nginx is running but Ghost is not. Run ghost ls to see the status, ghost doctor to check the configuration and ghost run to start Ghost in the foreground, where startup errors appear directly in your terminal. The log files are in /var/www/ghost/content/logs/, and ghost log -e shows the latest errors.

The installer stops because of an unsupported Node.js version

Ghost 6 requires Node.js 22. Check with node -v; if another version is installed, for example from Ubuntu's archive or nvm, remove it and repeat Step 4 so that the NodeSource package provides Node.js 22.

Emails are not delivered

Check the mail block in config.production.json for typos, a port other than 587, or secure set to true with port 587, and remember to run ghost restart after every change. ghost log -e shows SMTP errors such as rejected credentials. Newsletters additionally need the Mailgun settings in Ghost Admin.

Next steps

Frequently asked questions

Should I install Ghost with Ghost-CLI or Docker?

Ghost's documentation lists the Ubuntu install with Ghost-CLI as its standard self-hosting method and labels its Docker Compose tooling as a preview. Ghost-CLI is the mature path today; the Docker preview adds features such as self-hosted web analytics and includes a migration script for Ghost-CLI sites.

Why must the Linux user not be called ghost?

Ghost-CLI creates its own system user named ghost to run the Ghost process with minimal rights. If your login user has the same name, the two collide and the install fails, so Ghost's documentation tells you to choose any other name.

Which Node.js and MySQL versions does Ghost 6 need?

Ghost 6 requires Node.js 22 LTS; Node 20, 21 and 23 or newer are not supported. For the database Ghost supports MySQL 8.0 or 8.4. Ubuntu 24.04 ships MySQL 8.0 and Ubuntu 26.04 ships MySQL 8.4.

Can Ghost send newsletters with my SMTP server?

No. SMTP covers transactional mail such as login links, invitations and password resets. Bulk newsletters need a bulk email provider, and Mailgun is currently the only one Ghost supports for that.

Can I run Ghost on a HyperDC server?

Yes. The guide works on a HyperDC Linux VPS, VDS or dedicated server with root access running Ubuntu 24.04 or 26.04 and at least the 1 GB of memory that Ghost recommends.

Sources

ایجاد گذرواژه

Please confirm