# 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.

Difficulty: Intermediate\
Tested on: Ubuntu 24.04 LTS, Ubuntu 26.04 LTS

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.

> **Note**
>
> Ghost also offers official Docker Compose tooling, which its documentation still labels as a **preview**. It runs Ghost, MySQL and Caddy in containers and adds optional self-hosted ActivityPub and Tinybird-based web analytics, which do not work with Ghost-CLI installs. A section near the end of this guide explains it briefly.

## 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](/guides/ssh-keys). The basics in [Secure a new Linux server](/guides/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:

| 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:

```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();"`.

> **Tip**
>
> You can keep socket authentication for root instead: create a database and a dedicated MySQL user for Ghost yourself, grant that user all privileges on the database, and enter these credentials when Ghost-CLI asks for the MySQL user. Ghost's documentation notes that the database must already exist in that case.

## 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`.

> **Note**
>
> Outbound port 25 is closed by default on HyperDC VPS. For services bought for a term of 3 months or longer, it is opened on request: [open a support ticket](/guides/support-tickets). Until then, send mail through an SMTP relay on port 587.

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' <noreply@example.com>",
    "transport": "SMTP",
    "options": {
      "host": "smtp.example.com",
      "port": 587,
      "secure": false,
      "auth": {
        "user": "postmaster@example.com",
        "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

- Compare Ghost with WordPress in [WordPress with Nginx, PHP-FPM and MariaDB](/guides/install-wordpress-lemp) or [WordPress with Docker](/guides/install-wordpress-docker).
- Learn more about Nginx and Let's Encrypt in [Nginx reverse proxy with Certbot](/guides/nginx-reverse-proxy-certbot).
- Find servers for your publication on the [Ghost hosting](/ghost-hosting) page.
- Read the official [Ghost-CLI documentation](https://docs.ghost.org/ghost-cli/) 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.

---

Source: <https://hyperdc.com/guides/tutorials/install-ghost>\
Updated: 2026-10-09
