Development 9 min read

How to Set Up Ghost CMS From Scratch

Ghost Theme
Ghost Theme June 30, 2026
How to Set Up Ghost CMS From Scratch

There's a moment in every Ghost setup where you have to be honest with yourself about how much server you actually want to babysit. That's the real question hiding inside "how do I set up Ghost," and the answer changes everything that follows. So before we touch a single command, let's get that sorted, because the wrong choice here is how people end up either overpaying or stranded in a terminal at 2am wondering why Nginx hates them.

Ghost runs three ways that matter. You can let Ghost host it for you (Ghost(Pro)), you can run it on your own laptop for tinkering (local install), or you can stand it up properly on your own server (self-hosted production). Most "from scratch" guides quietly mean the third one, and that's the one with actual teeth, so that's where most of this post lives. But let's give the other two their due first, because for a lot of people they're the right call.

The honest fork in the road

If you want Ghost and you do not want to think about Linux, MySQL, SSL certificates, or the words "reverse proxy" ever, use Ghost(Pro). You sign up at ghost.org, you pick a plan, you get a working publication in about the time it takes to make coffee. They patch it, back it up, and keep it online. You pay a monthly fee and, not incidentally, you fund the open-source project everyone else is self-hosting for free. There's no shame in this. Your time is worth money, and server maintenance is a hobby that bills you whether or not you enjoy it.

If you just want to kick the tyres — try the editor, build a theme, see what the fuss is about — install it locally. It's one command and it uses a throwaable SQLite database, no server required:

npm install ghost-cli@latest -g
mkdir ghost-local && cd ghost-local
ghost install local

That spins up Ghost in development mode at http://localhost:2368, with the admin panel at http://localhost:2368/ghost. It's perfect for poking around and genuinely the best way to learn the theme layer. Useful commands while you're in there: ghost start, ghost stop, ghost ls. When you're bored, delete the folder and nobody gets hurt.

Everything from here on is the real thing: Ghost on your own VPS, in production, on your own domain. This is more work, it's cheaper at scale, and it hands you total control along with total responsibility. Worth it if you've got basic command-line comfort and a reason to own your stack. Let's build it.

What you actually need before you start

Ghost is opinionated about its stack, and fighting those opinions is a losing game. As of right now, the officially supported production setup is:

  • Ubuntu 22.04 or 24.04. Not Debian, not CentOS, not whatever your host defaults to. The official tooling is tested against these, and "it probably works on X" is how you lose a Saturday.
  • MySQL 8. Specifically MySQL — not MariaDB, not Postgres, and not SQLite (that's for local only). This trips up people who assume MariaDB is a drop-in. It isn't, for Ghost.
  • Node.js — the supported version, currently Node 22 LTS. This is the single most common reason installs fail. Ghost only supports specific Node versions, and the one it wants moves over time. Before you install anything, glance at Ghost's "supported Node versions" page and use that number. Do not use whatever Node ships in Ubuntu's default repos — it's usually too old.
  • Nginx, which Ghost's installer configures for you as a reverse proxy.
  • systemd, so Ghost restarts itself on reboot or crash.
  • A server with at least 1GB RAM. That's the floor. Give it 2GB for any real traffic, and 4GB if you're sending newsletters to thousands of people — email blasts are hungry.
  • A registered domain with a DNS A-record already pointing at your server's IP. Set this up first. SSL gets configured during install, and that can't happen if your domain doesn't resolve to the box yet. DNS propagation takes time, so do it early and let it settle.

A cheap VPS from Hetzner, DigitalOcean, Linode, or similar with 2 vCPU and 2GB RAM runs a comfortable Ghost site for a long while. You don't need anything fancy to start.

Step 1: Get onto the server and make a proper user

SSH in as root to set things up:

ssh root@your_server_ip

Now, the first real gotcha, and it's a sneaky one. Ghost's installer refuses to run as root — that's deliberate, root installs are a security mess. So you make a normal user with sudo rights. But here's the trap: do not name that user ghost. The name ghost collides with the system user the installer creates for itself, and you'll get baffling errors. Call it literally anything else.

# Create a user (use any name EXCEPT "ghost")
adduser myuser

# Give it sudo powers
usermod -aG sudo myuser

# Switch to it
su - myuser

From now on you're this user, not root.

Step 2: Update the box and install Nginx

Always start with fresh package lists:

sudo apt-get update
sudo apt-get upgrade

Then Nginx, which will sit in front of Ghost and handle the public-facing web traffic and SSL:

sudo apt-get install nginx

If you've got the ufw firewall on (and you should), let web traffic through:

sudo ufw allow 'Nginx Full'

That opens both HTTP and HTTPS. You don't need to write any Nginx config by hand — Ghost's installer generates it for you later. This step just gets the software on the box.

Step 3: Install and de-booby-trap MySQL

sudo apt-get install mysql-server

Here's the part that quietly breaks installs on newer Ubuntu. By default, modern MySQL sets up its root user with socket authentication, meaning only the Unix root user can log in and there's no password. Ghost doesn't support that. So you have to give the MySQL root user an actual password:

sudo mysql

Then inside the MySQL shell:

ALTER USER 'root'@'localhost' IDENTIFIED WITH 'mysql_native_password' BY 'your-strong-password';
FLUSH PRIVILEGES;
exit

Pick a real password and remember it — you'll hand it to the Ghost installer in a minute so it can create your database. (If you'd rather, you can pre-create a dedicated database and restricted user yourself, but letting Ghost-CLI do it with your root credentials is the simpler, well-trodden path, and it'll offer to lock down a Ghost-only user for you anyway.)

Step 4: Install the right version of Node

This is where you earn your keep. Use NodeSource's repository, not Ubuntu's, and pin the major version Ghost currently supports (Node 22 at time of writing — check the docs and change the number if it's moved):

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  # use the version Ghost currently supports
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

Confirm it took with node -v. If that doesn't say v22-something, stop and fix it now, because every later step assumes a supported Node and the errors you'll get otherwise are deeply unhelpful.

Step 5: Install Ghost-CLI

Ghost-CLI is the tool that does all the heavy lifting — installs Ghost, wires up Nginx, fetches your SSL cert, sets up the systemd service. Install it globally:

sudo npm install ghost-cli@latest -g

You can always run ghost help later to see everything it can do.

Step 6: Make Ghost a home and install it

Ghost wants its own directory with the right owner and permissions. Pick a name for the folder (your site name is fine):

sudo mkdir -p /var/www/sitename
sudo chown myuser:myuser /var/www/sitename
sudo chmod 775 /var/www/sitename
cd /var/www/sitename

Then the moment of truth — a single command:

ghost install

This kicks off an interactive setup that asks you a handful of questions. None of them are scary, but here's what they're really asking:

  • Blog URL — the full public address with the protocol, e.g. https://example.com. Use https here and the installer will offer to set up SSL for you. Don't use a bare IP; it'll cause errors.
  • MySQL hostname — if MySQL is on the same server (it is, you just installed it), press Enter for localhost.
  • MySQL username / password — enter root and the password you set back in Step 3.
  • Ghost database name — make something up; Ghost creates it for you.
  • Set up a ghost MySQL user? — say yes. This makes a locked-down database user that can only touch your Ghost database and nothing else. Good hygiene.
  • Set up Nginx? — yes. This is the part where setting it up by hand would be a miserable afternoon, so let the tool do it.
  • Set up SSL? — yes, assuming your domain already points at the server (remember that A-record from earlier?). Ghost grabs a free Let's Encrypt certificate and you get HTTPS automatically. It'll ask for an email so you get renewal warnings.
  • Set up systemd? — yes. This keeps Ghost running and restarts it on reboot.
  • Start Ghost? — yes. This is the part where your site actually comes alive.

If your DNS is propagated and nothing went sideways, your Ghost site is now live on your domain.

Step 7: Create your account and you're publishing

Go to https://example.com/ghost in a browser. You'll be greeted by Ghost's setup wizard, where you create the owner account — site title, your name, email, password. Finish that and you're standing in the Ghost admin panel, which, after the terminal gauntlet you just ran, is going to feel like stepping into a clean, quiet room.

From here you're in normal-human territory: write a post, set your publication details under Settings, build your nav menu under Settings → Navigation, pick a theme. The default theme (Source) is genuinely good and a perfectly respectable place to start.

The thing the install wizard won't do for you: email

Here's a sharp edge worth knowing before you celebrate. A self-hosted Ghost can't send email on its own, and Ghost is built around email — newsletters, member signups, password resets. There are two separate kinds to configure:

Transactional email (password resets, login links, system messages) goes through any standard SMTP provider on port 587 — Mailgun, Postmark, SendGrid, Amazon SES, take your pick. You set this in your config.production.json (in your Ghost directory) or via environment variables.

Bulk email (the actual newsletter to your list) is more particular: Ghost's built-in newsletter feature integrates with Mailgun specifically. If sending newsletters to your audience is a core reason you're here, you'll want a Mailgun account. Most people just use Mailgun for both and call it done, since transactional volume is tiny next to newsletter sends.

If you don't set email up, Ghost still runs fine as a website — you just can't send anything until you do. Plan for it rather than discovering it the day you try to email 500 people.

Keeping it alive (the part you signed up for)

You chose self-hosting, so maintenance is now your job. The good news is Ghost-CLI makes it about as painless as this gets. The commands you'll actually use:

  • ghost update — pulls the latest Ghost, runs database migrations, restarts everything. Run it regularly; it's how you get security patches.
  • ghost ls — shows your running Ghost instances.
  • ghost doctor — diagnoses common configuration and version problems. Run this first when something's wrong.
  • ghost restart / ghost stop / ghost start — exactly what they say.

And please, back up. That means two things together: the Ghost directory (your themes, images, and config) and a mysqldump of your database. A simple cron job that tars the content folder and dumps the database to an offsite location, daily or weekly, is the difference between "annoying afternoon" and "catastrophe" when a server eventually misbehaves. It will eventually misbehave. They all do.

Your Let's Encrypt SSL certificate auto-renews, but it's worth knowing it exists and expires every 90 days, so if your site ever throws certificate warnings, that renewal is the first thing to check.

A note on the newer Docker path

You may run across mentions of a Docker Compose install method, and it's real — but as things stand it's still a preview, recommended mainly if you specifically want to self-host Ghost's web analytics or run the full social-web (ActivityPub) features yourself rather than through Ghost's hosted service. For a standard "I want a fast blog with a newsletter" setup, the Ghost-CLI route above is still the stable, well-supported, boring-in-a-good-way choice. Boring is what you want from infrastructure. Keep an eye on it though — Docker is expected to become the default eventually, so the ground may shift under this advice.

So which path was yours?

If you got this far and the terminal made you twitchy the whole way, that's useful information — it might mean Ghost(Pro) was your answer all along, and there's no defeat in that. If instead you found a quiet satisfaction in watching ghost install wire the whole thing together, congratulations: you now own a fast, clean, genuinely lovely publishing platform, and you owe no plugin author a single update ever again.

Set up email before you need it. Back up before you don't think you need it. And then do the thing the whole setup was for — go write something.


Ghost Theme

Written by

Ghost Theme

View all posts →

Build something beautiful

Your dream publication, today.

Join 5,000+ creators who trust our themes. Get every theme — plus all future releases — for one simple price.

30-day money back guarantee · Cancel anytime