Ghost Self-Hosting: VPS, Docker & Real Costs

Self-host Ghost with confidence: Ghost(Pro) vs DigitalOcean, Docker, Railway, and Pikapods with real monthly costs and step-by-step setup for each option.

Luxe Themes Updated 17 min read

Self-hosting Ghost means running it on a server you control instead of paying for Ghost(Pro). It can cost as little as $3–4/month, against $15–199/month for Ghost(Pro), and it gives you full control. In return, you handle updates, backups, and email deliverability yourself.

This guide covers the decision itself and what each hosting option really costs. It then walks through server sizing, a Docker setup we’d use, the managed middle ground, email, and backups. Our short recommendation: pick a managed host such as Pikapods or Railway if you want the least work, or a DigitalOcean or Docker VPS if you want the most control.

Should You Self-Host Ghost?

The first decision is whether to self-host at all. If you’re still weighing where to run Ghost, managed or self-hosted, our Ghost hosting options comparison covers that choice first. Here is how we’d think about it.

Self-host if you:

  • Want to minimize monthly costs (as low as $3–4/month vs $15–199/month for Ghost(Pro))
  • Need full control over your server, database, and backups
  • Want to run custom Node.js code or integrations
  • Are comfortable with Linux command line and Docker
  • Plan to run ActivityPub with self-hosted containers

Use Ghost(Pro) if you:

  • Want zero server maintenance
  • Don’t want to manage email deliverability (SPF, DKIM, DMARC)
  • Need included CDN, SSL, and automatic updates
  • Value your time more than the monthly cost difference
  • Are starting out and want to focus on content, not infrastructure

Self-hosting Ghost saves money but costs time. You become your own system administrator. Updates, backups, security patches, email configuration, and uptime monitoring are all your responsibility. For most solo publishers, Ghost(Pro) Publisher at $29/month is the simpler path.

If you only want to get Ghost running and don’t need to weigh hosting options, our Ghost installation guide has the step-by-step procedures.

Ghost Hosting Options Compared

Real monthly costs as of February 2026:

ProviderTypeMonthly CostIncludedSetup Difficulty
Ghost(Pro) StarterManaged$15/mo (annual)CDN, SSL, backups, email, updatesEasy
Ghost(Pro) PublisherManaged$29/moEverything + paid memberships, custom sending domainEasy
Ghost(Pro) BusinessManaged$199/moEverything + 10K members, priority supportEasy
DigitalOcean DropletVPS$6/mo (1 GB)Raw server — you manage everythingAdvanced
Hetzner CloudVPS€5.99/mo (CX23, 4 GB; often sold out)Same as DO, more RAM per euro when availableAdvanced
PikapodsManaged containerfrom $3.30/moGhost + MySQL, managed updatesEasy
RailwayPaaS~$5-10/moGhost + database, auto-deploys from GitHubIntermediate
MagicPagesManaged Ghost$15/moManaged Ghost, unlimited members, custom themes, email includedEasy

Cost Breakdown: Self-Hosted vs Ghost(Pro)

For a newsletter with 500 paid subscribers at $7/month:

Ghost(Pro) Publisher:

  • Hosting: $29/month
  • Email: Included
  • Total: $29/month

DigitalOcean + Mailgun (500 subscribers, weekly sends = ~2,000 emails/month):

  • VPS: $6/month (1 GB Droplet)
  • Mailgun Basic: $15/month (10,000 emails included)
  • Total: $21/month, a little cheaper than Ghost(Pro) Publisher, with more work

DigitalOcean + Mailgun (2,000 subscribers, 2x/week = ~16,000 emails/month):

  • VPS: $6/month
  • Mailgun Foundation: $35/month (50,000 emails included)
  • Total: $41/month, more expensive than Ghost(Pro) Publisher

The crossover point is email volume. Self-hosting is cheaper while your sends stay low. Once you’re sending more than ~14,000 emails/month, Ghost(Pro) Publisher at $29/month, with unlimited sends included, becomes the better deal.

Ghost VPS Hosting: Requirements and Providers

A VPS (virtual private server) is a server you rent by the month and administer yourself. For Ghost, the official minimum is a server with 1 GB of RAM, running MySQL 8.0 and Node.js 22 LTS. In practice we recommend 2 GB. The server sizing section below explains why 1 GB servers crash, and how to make one survivable with swap if that’s your budget.

The VPS providers that work well for Ghost:

  • DigitalOcean ($6/mo, 1 GB) — the most-documented path, with a long-standing 1-Click Ghost image; DigitalOcean calls its servers Droplets. The setup walkthrough is below.
  • Hetzner Cloud (€5.99/mo, 4 GB on CX23) — the most RAM per euro here when available, with European data centers. The CX23 plan is frequently out of stock; the Regular Performance line starts at €11.99.
  • Vultr ($5-6/mo) — comparable specs, more global regions.

A raw VPS means you handle the operating system, the NGINX web server, SSL, MySQL, backups, and updates yourself. The Docker setup below is the cleanest way to manage all of it. If you want VPS pricing without the sysadmin work, the managed alternatives (Pikapods, Railway, MagicPages) run Ghost containers for $4–10/month. And if you’re still deciding between self-hosting and managed hosting at all, our Ghost hosting page compares every option side by side.

One hardware caveat. Ghost’s ActivityPub containers (the part that connects your site to the fediverse) only run on AMD64 processors. Skip ARM-based VPS plans, including Hetzner’s CAX line, if the fediverse matters to you.

Realistic Server Sizing: Why 1 GB Droplets Struggle

Ghost’s official prerequisite is “a server with at least 1GB memory”, and technically that’s true. But 1 GB behaves differently in production than that line suggests, and many self-hosters hit the same wall. The pattern repeats: a fresh install with two posts and almost no traffic sits at 90–100% RAM. Then it crashes, or starts returning 502 errors, the first time anything asks for more memory.

The usual cause isn’t Ghost itself. It’s MySQL 8, the database Ghost runs on. On a 1 GB server, MySQL’s default configuration uses several hundred MB before Ghost’s own process even starts. Add Ghost’s Node.js footprint and the operating system, and there’s nothing left. For the technical reader: the InnoDB buffer pool and the performance schema account for most of MySQL’s share. Three failure modes follow:

  1. Random crashes under load. When memory runs out, the operating system kills MySQL or Ghost to free it (the kernel’s “OOM killer”). The result is the familiar cycle of a site being down until you reboot the server.
  2. Updates fail. Ghost’s update command (ghost update) checks for ~150 MB of free memory first. If it isn’t there, the update aborts with the message “Ghost recommends you have at least 150 MB of memory available”. There is a flag that skips the check (--no-check-mem), but running an update with no free memory is exactly how half-finished upgrades happen.
  3. MySQL dies quietly. If your site starts showing database connection errors (ECONNREFUSED) after a few days of uptime, MySQL was usually killed in the background for the same reason.

The fix: swap now, 2 GB when you can

Swap is disk space the operating system uses as overflow when RAM runs out. If you’re on a 1 GB server, add swap now. Cloud images from DigitalOcean and Hetzner ship without it:

Terminal window
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

Swap won’t make the server fast, but it turns hard crashes into slowdowns. That is the difference between a 502 error and a page that loads in two seconds. A second lever many self-hosters use is trimming MySQL’s memory. Turning off MySQL’s performance schema frees a meaningful chunk of RAM on small servers. For the technical reader: add performance_schema = 0 under [mysqld] in your MySQL config.

Our recommendation is to treat 2 GB as the real baseline. The $6/month 1 GB droplet works with swap and tuning. But the $12–14/month 2 GB tier (or Hetzner’s CX23, which gives you 4 GB for less) removes an entire category of late-night problems for a few dollars more.

Ghost Docker Setup

Docker Compose is the official primary install method for Ghost 6. It describes your whole stack (Ghost, its database, and the web server in front of it) in one file, and runs each piece as an isolated container. Ghost-CLI, the older installer, is becoming legacy because Docker provides better reproducibility and simpler updates.

Production Docker Compose

This is a complete, production-ready stack: Ghost 6, Caddy (a web server that handles SSL automatically), and MySQL 8:

services:
ghost:
image: ghost:6-alpine
restart: always
environment:
NODE_ENV: production
database__client: mysql
database__connection__host: mysql
database__connection__user: ghost
database__connection__password: ${MYSQL_PASSWORD}
database__connection__database: ghost
url: https://yourdomain.com
volumes:
- ghost-content:/var/lib/ghost/content
depends_on:
mysql:
condition: service_healthy
networks:
- ghost-internal
- caddy-public
caddy:
image: caddy:2-alpine
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy-data:/data
- caddy-config:/config
networks:
- caddy-public
mysql:
image: mysql:8.0
restart: always
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ghost
MYSQL_USER: ghost
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
volumes:
- mysql-data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
networks:
- ghost-internal
networks:
ghost-internal:
caddy-public:
volumes:
ghost-content:
mysql-data:
caddy-data:
caddy-config:

Create a Caddyfile in the same directory:

yourdomain.com {
reverse_proxy ghost:2368
}

Create a .env file (never commit this):

MYSQL_PASSWORD=generate-a-strong-password
MYSQL_ROOT_PASSWORD=generate-another-strong-password

Security notes:

  • MySQL has no exposed ports; it is only reachable on the ghost-internal network
  • Credentials come from environment variables, never hardcoded
  • Named volumes keep your data across container restarts
  • Caddy handles SSL certificate provisioning and renewal automatically

Start Ghost

Terminal window
docker compose up -d

Ghost is running at https://yourdomain.com. Set up your admin account at https://yourdomain.com/ghost.

Docker Compose Configuration Details

Why Caddy instead of NGINX? Caddy obtains and renews HTTPS certificates from Let’s Encrypt on its own, with no SSL configuration. With NGINX, you’d need to install Certbot, set up renewal cron jobs, and manage certificate files by hand. Ghost’s official documentation has also shifted to recommending Caddy for new deployments.

Why ghost:6-alpine? The Alpine-based image is ~180 MB vs ~350 MB for the Debian-based image. Same functionality, smaller attack surface.

Why MySQL 8.0, not MariaDB? Ghost officially supports MySQL 8.0+ only. MariaDB may work but is not tested or supported. If you hit edge cases, you’re on your own.

ARM64 Caveat

ARM64 and AMD64 are two different processor architectures, and not every container is built for both. If you’re running on ARM64 hardware (Oracle Cloud’s free tier, a Raspberry Pi, or Apple Silicon for local development), the main Ghost image works fine. Ghost’s ActivityPub and Traffic Analyzer containers, however, are AMD64-only. Running them on ARM64 means building multi-architecture images yourself or using QEMU emulation, and emulation significantly hurts performance.

If ActivityPub integration is important to you, choose an AMD64 VPS. See our ActivityPub guide for details.

Ghost on DigitalOcean

The traditional Ghost-CLI installation on a DigitalOcean Droplet remains popular, though Docker is now the recommended path.

Step 1: Create a Droplet

  1. Choose Ubuntu 24.04, Basic plan
  2. Select $6/month (1 GB RAM) or $12/month (2 GB, recommended if you’re using ActivityPub)
  3. Add your SSH key
  4. Create the Droplet

Step 2: Install Ghost

SSH into your server and follow the Ubuntu installation steps in our Ghost installation guide. The Ghost-CLI handles NGINX, SSL (Let’s Encrypt), and systemd service configuration.

When DigitalOcean Makes Sense

DigitalOcean is a good choice if:

  • You’re already familiar with their platform
  • You want the $6/month price point
  • You prefer Ghost-CLI’s opinionated setup over Docker

For new deployments, we recommend Docker Compose instead. It’s more portable, easier to back up, and simpler to update.

Managed Alternatives

If you want self-hosting benefits without managing servers, these managed options sit between Ghost(Pro) and raw VPS hosting:

Pikapods (from $3.30/month)

Pikapods runs Ghost in a managed container. You get your own Ghost instance with MySQL, managed updates, best-effort daily backups, and a $5 welcome credit. Off-site backups to your own S3 storage are optional. It is the cheapest way to run Ghost without managing infrastructure.

Limitations: No SSH access, limited customization of server-level settings, and email delivery still requires Mailgun configuration.

Railway (~$5-10/month)

Railway deploys Ghost from a GitHub repository with automatic builds. You pay for what you use, compute plus database. It suits developers who want Git-based deployments.

Limitations: No persistent file storage by default, so you need to configure S3 for image uploads, and pricing can spike with traffic.

MagicPages ($15/month)

MagicPages is managed hosting built specifically for Ghost. For $15/month (or $150/year) you get unlimited members and staff, custom themes, 10,000 emails a month included, and daily backups. It is run by a long-time Ghost community member.

Limitations: Smaller company, less infrastructure redundancy than Ghost(Pro) or major cloud providers.

Email Setup: The Mailgun Problem

Email is the part of self-hosting that surprises people most, so it’s worth being precise. Every self-hosted Ghost installation sends two kinds of email, and they work differently:

  1. Transactional email: the small one-to-one messages, such as signup confirmations, magic login links, and password resets. These can go through any SMTP provider, meaning any ordinary email-sending service (Postmark, Brevo, Amazon SES, or even a Gmail app password for tiny sites). You set this up in Ghost’s config file, config.production.json.
  2. Bulk newsletter email: the newsletter itself, sent to your whole subscriber list at once. Here Ghost is opinionated. The built-in newsletter feature only supports Mailgun’s bulk API. Not SMTP, not SES, not your favorite provider.

Ghost’s own docs explain the reasoning. Sending bulk email to many recipients over basic SMTP is a fast route to getting your IP blacklisted. So Ghost requires a bulk-mail API, and Mailgun is the only one it integrates with. The practical consequence trips up almost every new self-hoster. It usually shows up in one of two ways. Transactional emails work but the newsletter never sends, or test emails from a draft arrive but the published post fails to go out. Both are the same confusion. Test emails and magic links use your SMTP transport, so they work. The actual newsletter send goes through the Mailgun bulk path, so it silently fails until Mailgun is configured correctly.

If you don’t want Mailgun, you have three realistic options today. You can keep newsletters off and use Ghost purely as a site. You can sync members to an external newsletter service (Mailchimp, Kit, and others) via Zapier or the API. Or you can run one of the community-built Mailgun-compatible proxies, which accept Ghost’s Mailgun API calls and pass them to another backend such as Amazon SES. That last one is a more advanced setup, and we’ll cover it in a dedicated SMTP-alternatives article.

Mailgun Configuration

  1. Create a Mailgun account
  2. Add a sending domain: mg.yourdomain.com (use a subdomain)
  3. Add DNS records: SPF, DKIM, and DMARC
  4. In Ghost Admin: Settings → Email newsletter → enter Mailgun region, domain, and API key
  5. For transactional email, add SMTP configuration to config.production.json

For detailed step-by-step instructions, see the Mailgun section in our Ghost newsletter guide.

Mailgun Pricing Reality (2026)

Mailgun discontinued its legacy Flex (pay-as-you-go) plan for new accounts in late 2025. These are the plans available to a new self-hoster in August 2026:

PlanPriceVolume
Free$0100 emails/day (testing only)
Basic$15/mo10,000/mo included
Foundation$35/mo50,000/mo included
Scale$90/mo100,000/mo included

For context: a weekly newsletter to 1,000 subscribers uses ~4,000 emails/month, which fits Mailgun Basic at $15/month. Add your VPS at $6-12/month on top. Ghost(Pro) Publisher at $29/month includes unlimited sends and zero configuration. The cost advantage of self-hosting shrinks fast once you factor in Mailgun.

Backups and Maintenance

Self-hosting means you own your backups. If your server dies and you have no backup, your publication is gone.

What to Back Up

  • Ghost content: /var/lib/ghost/content/ (or the Docker volume ghost-content)
  • MySQL database: Use mysqldump or Docker’s docker exec mysql mysqldump
  • Configuration files: docker-compose.yml, .env, Caddyfile

Backup Strategy

Daily database backups:

Terminal window
# Add to cron (crontab -e)
0 3 * * * docker exec mysql mysqldump -u root -p${MYSQL_ROOT_PASSWORD} ghost > /backups/ghost-$(date +\%Y\%m\%d).sql

Weekly full backups: Snapshot your entire server via DigitalOcean/Hetzner’s snapshot feature ($1-2/month for weekly snapshots).

Test your backups. A backup you’ve never restored is not a backup. It’s a hope.

Updating Ghost Safely

Updates are where self-hosters lose sites. The failures follow a pattern: no backup taken, the update half-completes, and the rollback fails too. A safe update routine has three parts.

1. Snapshot before every update. A snapshot is a complete copy of your server, taken and stored by your provider. DigitalOcean and Hetzner both do it in one click, for cents. Take one before running any update. Updates run database migrations, which change the structure of your database as they go. A snapshot restores everything, including a database caught mid-migration, which a content export can’t. A failed migration on a live database is the worst place to be without one.

2. Check your Node version first. Node.js is the runtime Ghost runs on. Ghost 6 requires Node 22 LTS (^22.13.1), and it’s the only supported version. If your server is still on an older Node, the update fails with “Unsupported version of Node”. On Ghost-CLI installs, upgrade Node first, following Ghost’s supported-versions doc, then update Ghost. This is the single most common cause of failed major-version upgrades.

3. Then update. With Docker Compose it’s:

Terminal window
# Pull the latest Ghost image
docker compose pull
# Restart with the new image
docker compose up -d
# Ghost handles database migrations automatically on startup

On a Ghost-CLI install, run ghost update from your install directory. Two things are worth knowing. First, there is a rollback flag (ghost update --rollback) that reverts to the previously installed version if an upgrade goes wrong. It’s not a substitute for a snapshot once database migrations have run. Second, the memory pre-check will abort the update on a starved 1 GB server. Fix the memory (see the server sizing section) rather than skipping the check with --no-check-mem. Ghost-CLI also ships a backup command (ghost backup) that zips your content, member export, themes, and config files. It’s cheap insurance to run before the snapshot.

Major version upgrades (5→6) occasionally require manual intervention. Read the release notes before jumping, and never skip the snapshot on a major.

Monitoring

At minimum, set up uptime monitoring. Free options:

  • UptimeRobot — 50 monitors free, 5-minute check intervals
  • Betterstack — 10 monitors free, 3-minute intervals

Get notified when your site goes down so you can restart Docker or investigate before readers notice.

Common Questions

Can I run Ghost on a Raspberry Pi?

Yes, but with caveats. The main Ghost image supports ARM64. However, ActivityPub and Traffic Analyzer containers are AMD64-only. Performance on a Pi 4 with 4 GB RAM is adequate for small sites with low traffic, but MySQL can be memory-hungry.

How do I migrate from Ghost(Pro) to self-hosted?

  1. Export your content from Ghost(Pro): Settings → Import/Export → Export
  2. Download your theme: Settings → Design → Download current theme
  3. Set up self-hosted Ghost (Docker or CLI)
  4. Import your content and upload your theme
  5. Update your DNS to point to the new server
  6. Configure Mailgun for email delivery

Paid subscribers will need to re-subscribe through your new Stripe connection.

How much RAM do I need?

  • 1 GB: The official minimum. Workable for a small site with swap configured, but expect MySQL to use most of it and updates to be tight
  • 2 GB: Our recommended baseline. Ghost and MySQL run comfortably, and updates don’t fight for memory
  • 4 GB: Comfortable for high-traffic sites, ActivityPub, or multiple staff users

See the server sizing section for the full picture.

Is it worth self-hosting in 2026?

It depends on your situation. If you enjoy server management, want the lowest possible cost for a small site, or need custom server-level configuration, self-hosting works well. If you’d rather spend your time writing, Ghost(Pro) Publisher at $29/month is excellent value.

A sensible strategy is to start with Ghost(Pro) to validate your publication, then migrate to self-hosted if and when the cost savings justify the maintenance.

After Setup: Install a Theme

Once Ghost is running, the default Casper theme is active. You upload a custom theme under Settings → Design → Change theme → Upload theme. Ghost themes are .zip files, and they work identically on Ghost(Pro) and self-hosted installations. There are no configuration differences.

If you’d like a starting point, our Ghost themes include membership pages, dark mode, and ready-made layouts.

Frequently Asked Questions

How much does it cost to self-host Ghost?
Self-hosting Ghost can start around 3 to 4 dollars per month with a managed container like Pikapods, versus 15 to 199 dollars for Ghost(Pro). A DigitalOcean VPS runs 6 dollars per month, but adding Mailgun email and snapshots raises the real total, so savings shrink as your newsletter volume grows.
What VPS specs do I need to run Ghost?
Ghost's official minimum is 1 GB of RAM, but in practice 1 GB is tight: MySQL 8 alone consumes most of it, and updates frequently fail without swap. We recommend 2 GB as the realistic baseline, with swap configured either way. Choose 4 GB for high-traffic sites or ActivityPub. Ghost officially supports MySQL 8.0/8.4, and ActivityPub containers require AMD64 rather than ARM64 hardware.
Should I use Docker or Ghost-CLI to install Ghost?
Docker Compose is the official primary install method for Ghost 6, offering better reproducibility, easier backups, and simpler updates, so it is recommended for new deployments. Ghost-CLI on a DigitalOcean Droplet still works and remains popular, especially if you prefer its opinionated NGINX and Let's Encrypt setup, but it is becoming legacy.
Is self-hosting Ghost worth it versus Ghost(Pro)?
It depends on your situation. Self-hosting saves money for small, low-email sites and gives full server control, but you handle updates, backups, security, and email deliverability yourself. If you would rather write than manage servers, Ghost(Pro) Publisher at 29 dollars per month is excellent value. A good strategy is starting on Ghost(Pro), then migrating later.

Keep reading