Workload · Publishing with Ghost

Self-hosted Ghost for your blog, members and newsletter

To self-host Ghost you need an Ubuntu LTS server (22.04, 24.04 or 26.04) with 1 GB of memory or more, Node.js 22, MySQL 8 and NGINX, a domain already pointing at it, and a Mailgun account if you want to send newsletters. Ghost's own command-line installer does most of the work in one sitting. This page walks you through it, including the one moment where a stranger could beat you to your own admin screen.

The short version
  1. Ghost's tested setup: Ubuntu, Node 22, MySQL 8
  2. Your own login runs the installer, not root
  3. Claim the owner account while only you can see it
  4. Newsletters go out through Mailgun
  5. Firewall rules that cover IPv6 too

What your Ghost site runs on

Ghost is built and tested for one combination of software, and its documentation treats anything else as at your own risk. Here is that combination in plain terms:

  • Ubuntu in one of its long-term-support releases: 22.04, 24.04 or 26.04.
  • Node.js 22, the runtime Ghost is written for. Ghost marks versions 20, 21 and 23 onward as unsupported.
  • MySQL 8.0 or 8.4 as the database. Ghost supports no other database for a live site.
  • NGINX, the web server that sits in front of Ghost and handles HTTPS.
  • systemd, which keeps Ghost running and restarts it after a reboot.
  • 1 GB of memory at the very least.
  • A domain name whose A record already leads to your server's address before you install, because the certificate is issued during setup. A bare IP address as the site URL causes errors.

Will a small server keep up?

For most publications, yes. Ghost asks for 1 GB as a minimum, and the example machine in its Docker guide has 2 GB and one CPU. The docs give no larger figure, so treat anything above that as headroom for your traffic and the database.

Two facts from the docs shape the choice. Ghost cannot be clustered or sharded: one instance serves your site, and you scale it by putting a CDN and cache in front. And your newsletter is delivered by Mailgun, so a big list does not mean thousands of emails leaving your own machine.

The server that fits

A Ghost publication is one job, which is what our smallest dedicated servers are for: compact cartridges meant for one task, and single-processor everyday servers for sites, apps and their databases. Either way the whole machine is yours. Here is what that means for a publication:

  • Nobody else shares the processor, memory or disks, so your pages stay quick whatever other customers are doing.
  • The port is unmetered. If a post takes off and your images are fetched far more often than you planned, there is no allowance to run over.
  • You log in as root, and you can reinstall the operating system yourself whenever you like, right from the control panel.
  • If a firewall rule shuts you out, a rack server, a blade, or an m510 or m710x cartridge still gives you its console screen and power button; the remaining cartridges can only be switched off and on.
  • IPv6 comes at no charge, which is why the firewall steps below cover it.
  • A ready server is handed over within 30 minutes of the payment being approved. See what is racked right now on instant servers.

Avoid the ARM cartridge for this: its only systems are Ubuntu 16.04 and 18.04, both older than the 22.04 release Ghost asks for.

Up and running in an evening

Install Ubuntu, point your domain at the server, and log in over SSH. First, make yourself an everyday user and turn the firewall on. Pick any name except ghost, which the installer reserves for the account that runs your site.

# as root, once
adduser jane
usermod -aG sudo jane
su - jane

# firewall first: SSH only for now
grep IPV6 /etc/default/ufw   # should print IPV6=yes
sudo ufw allow OpenSSH
sudo ufw enable

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install nginx
sudo apt-get install mysql-server

IPV6=yes is Ubuntu's default, and it means every ufw rule you add covers both IPv4 and IPv6 traffic. Without it, an IPv6 address on the server would slip past your rules.

Next, give MySQL's root user a password (Ghost cannot log in with Ubuntu's default socket method), then install Node.js 22 and the Ghost installer, called Ghost-CLI:

sudo mysql
ALTER USER 'root'@'localhost' IDENTIFIED WITH 'caching_sha2_password' BY 'pick-a-long-password';
FLUSH PRIVILEGES;
exit

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
sudo npm install ghost-cli@latest -g

Claim your admin account first, privately

Here is the catch in Ghost's standard guide: once Ghost starts, the first person to open yoursite.com/ghost is invited to create the owner account. If a stranger or a bot gets there first, the site is theirs. Our way round it, which is not part of Ghost's guide: install without starting Ghost, let only your own internet address through while you sign up, then open the doors.

sudo ufw allow 'Nginx Full'   # Let's Encrypt has to reach port 80
sudo mkdir -p /var/www/mysite
sudo chown jane:jane /var/www/mysite
sudo chmod 775 /var/www/mysite
cd /var/www/mysite
ghost install --no-start
# add the mail section to config.production.json now

sudo ufw delete allow 'Nginx Full'
sudo ufw allow from 198.51.100.7 to any port 443 proto tcp
ghost start
# visit https://yoursite.com/ghost and create your account

sudo ufw delete allow from 198.51.100.7 to any port 443 proto tcp
sudo ufw allow 'Nginx Full'
  1. When the installer asks for the blog URL, type the full https:// address of your domain.
  2. For MySQL, enter root and the password you just set; say yes when it offers to create a separate MySQL user just for Ghost.
  3. Say yes to NGINX, SSL (it asks for an email for certificate notices) and systemd.
  4. Before you run ghost start, add the mail section to config.production.json, as the email section below explains.
  5. Swap 198.51.100.7 for your own public IPv4 address. If your computer connects over IPv6, add a second rule with your IPv6 address, or you will be locked out of your own sign-up page.
  6. Once your account exists, open the site to everyone with the last two lines, then run sudo mysql_secure_installation as Ghost's hosting guide recommends.

Getting your emails delivered

Ghost sends two very different kinds of email, and you set them up in two places.

  • Everyday account emails: sign-up confirmations, login links for members, staff invitations and password resets. These use the mail section of config.production.json with any SMTP service, Mailgun's SMTP included. If you change it later, run ghost restart.
  • Your newsletter: Ghost's docs say bulk newsletters can't be delivered with basic SMTP. Mailgun is the only bulk service it supports, and you paste its API keys into the newsletter settings in Ghost Admin.

Set up the everyday emails before you first run ghost start: after ghost install --no-start the config file is already in place, so add the mail section then. Out of the box, Ghost emails a code whenever a staff member logs in on a device it has not seen before, so if mail is broken you can lock yourself out of your own dashboard. Use a real sender address, add SPF, DKIM and DMARC to the DNS of the domain you send from, and remember that Mailgun's sandbox domain only reaches addresses you have approved. Put the SMTP password in the config file, not on the command line, where it would linger in shell history and show in ps.

Looking after it week to week

  1. Take a backup with ghost backup. It saves your posts as JSON, your members as a CSV, your themes, images and media, plus your routes and redirects. Copy the zip somewhere other than the server.
  2. Update with ghost update. New versions usually arrive every one to two weeks, and ghost update --rollback takes you back if something breaks.
  3. When Node.js needs a new major version, upgrade Node on its own, then reinstall your current Ghost version with ghost update [version] --force. Never change both at once.
  4. Sign in to SSH with keys only and switch off root login, as the docs suggest.
  5. Think about a separate admin domain for Ghost Admin; the docs say it reduces the ways in.

We keep the hardware and network running; Ghost itself, its updates and its backups are yours.

When another route suits you better

Ghost now also offers a Docker Compose setup, still marked as a preview, that runs Ghost with Caddy and MySQL. Choose it if you want Ghost's web analytics or to host the social web (ActivityPub) features yourself; the Ghost-CLI route relies on the ActivityPub service Ghost hosts and cannot run the analytics. Bear in mind that Docker opens its ports around ufw, so the owner-account trick above will not protect a Docker install as written.

And if keeping a server patched sounds like a chore you will skip, Ghost's documentation itself suggests a managed host. For a very light blog, a cloud VPS, a virtual machine on a server shared with other customers, can carry the same setup; send mail through your SMTP provider on port 587 or 465. Wherever you land, choose a city near your readers from our data centers.

Questions people ask

Do I need a domain before installing Ghost?
Yes. Point an A record at the server first, because Ghost-CLI asks for the site's address and sets up the HTTPS certificate during the install. Using an IP address as the site URL causes errors, according to the Ghost docs.
Why won't Ghost send my newsletter through ordinary SMTP?
Ghost's documentation rules out basic SMTP for bulk sending, so newsletters need a bulk provider, and Mailgun is the only one it supports. SMTP still handles the one-off emails, such as member login links and password resets.
What if a firewall rule locks me out of SSH?
On a rack server, a blade, or an m510 or m710x cartridge, the out-of-band console shows you the screen and lets you press the power button even when SSH is down, so you can undo the rule yourself. The remaining cartridges can only be switched off and on, so allow SSH before you enable ufw.
Should I use Docker instead of Ghost-CLI?
Use Ghost-CLI unless you need web analytics or a fully self-hosted ActivityPub service; those come with the Docker Compose tooling, which Ghost still calls a preview. Ghost-CLI is the route its Ubuntu guide is written around.
Which Ubuntu version should I choose?
Any of 22.04, 24.04 or 26.04, the releases Ghost lists; a newer one gives you longer support from Ubuntu. Which of them a server offers depends on its line, so check the order page. You pick the system when you order, and you can reinstall a different one from the control panel whenever you like.
Can I run the ghost commands as root?
No. Ghost's guide has you create a regular user, add it to the sudo group and run every ghost command from there. Ghost itself then runs as a low-privilege system user named ghost that the installer creates.

Give your publication a home of its own

Choose a server, install Ubuntu from the control panel, then work through this page from your first login.

Get a server for your Ghost site

Read next