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
- Prerequisites
- Step 1 — Create a non-root user
- Step 2 — Install Nginx and open the firewall
- Step 3 — Install MySQL and set a root password
- Step 4 — Install Node.js 22
- Step 5 — Install Ghost-CLI
- Step 6 — Install Ghost
- Step 7 — Create the owner account
- Step 8 — Configure transactional email
- Alternative: Ghost's Docker setup (preview)
- Back up and restore
- Update Ghost
- Troubleshooting
- Ghost-CLI refuses to run as root or reports permission errors
- Access denied for user 'root'@'localhost' during ghost install
- ghost start fails or the site shows 502 Bad Gateway
- The installer stops because of an unsupported Node.js version
- Emails are not delivered
- 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.comwith 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:
| Resource | Minimum (official) | Suggested starting point |
|---|---|---|
| CPU | Not published | 1 vCPU |
| RAM | 1 GB | 2 GB |
| Disk | Not published | 20 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:
adduser webadmin
usermod -aG sudo webadmin
su - webadminRun 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:
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install nginx
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enableThe 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:
sudo apt-get install mysql-server
mysql --versionOn 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:
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:
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 -vnode -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:
sudo npm install ghost-cli@latest -g
ghost helpghost 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:
sudo mkdir -p /var/www/ghost
sudo chown $USER:$USER /var/www/ghost
sudo chmod 775 /var/www/ghost
cd /var/www/ghost
ghost installGhost-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:
rootand 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:
ghost ls
ghost doctor
curl -I https://example.comghost 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:
"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:
cd /var/www/ghost
ghost restartTest 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:
cd /var/www/ghost
ghost backupFor 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:
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:
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 startReplace 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:
cd /var/www/ghost
sudo npm install -g ghost-cli@latest
ghost backup
ghost check-update
ghost updateghost 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
- Compare Ghost with WordPress in WordPress with Nginx, PHP-FPM and MariaDB or WordPress with Docker.
- Learn more about Nginx and Let's Encrypt in Nginx reverse proxy with Certbot.
- Find servers for your publication on the Ghost hosting page.
- Read the official Ghost-CLI documentation for all commands and options.
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
- docs.ghost.org/install
- docs.ghost.org/install/ubuntu
- docs.ghost.org/install/docker
- docs.ghost.org/faq/node-versions
- docs.ghost.org/config
- docs.ghost.org/newsletters
- docs.ghost.org/ghost-cli
- docs.ghost.org/update
- docs.ghost.org/faq/manual-backup
- docs.ghost.org/faq/root-user-fix
- docs.ghost.org/faq/troubleshooting-mysql-database
- docs.ghost.org/faq/errors-running-ghost-start