Ghost
Open-source publishing platform for blogs and newsletters, with members, paid subscriptions, email newsletters and a built-in editor. The self-hosted stack is the Ghost Node.js app and MySQL; transactional mail needs an SMTP provider and newsletters need Mailgun.
Resources by load level
What the app itself needs at each level, next to what we recommend for a server that runs only this app.
| Level | What it means | App requirements | Recommended |
|---|---|---|---|
| LightEstimate | 1–2 staff users, ~100 posts with ~4 images each, ~8 new posts a month, ~1,000 page views a day, up to 500 members and a weekly newsletter. | 0.75 vCPU · 1.5 GiB RAM · 4.5 GiB disk | 1.02 vCPU · 3.3 GiB RAM · 14.605 GiB disk |
| MediumEstimate | Up to 5 staff users, ~1,000 posts, ~40 new posts a month, ~20,000 page views a day without a cache, ~5,000 members and a weekly newsletter. | 1.5 vCPU · 2 GiB RAM · 24 GiB disk | 1.92 vCPU · 3.9 GiB RAM · 37.03 GiB disk |
| HeavyEstimate | Up to 20 staff users, ~5,000 posts, ~150 new posts a month, ~200,000 page views a day behind a CDN or cache, ~50,000 members and weekly newsletters. | 2.5 vCPU · 3.5 GiB RAM · 108 GiB disk | 3.12 vCPU · 5.7 GiB RAM · 133.63 GiB disk |
Recommended = app requirements + system baseline + safety headroom, under sizing policy 2026.10.0. Options stay at their defaults. “Estimate” means the sources give no number for that case, so it is worked out from them by the method stated under Components. How the numbers are built
Ready-to-run files
Support level Supported
Compose template from the official sources; not yet verified by a run.
Components
What each component needs at each load level, before baseline and headroom.
| Component | Light | Medium | Heavy | Sources |
|---|---|---|---|---|
| Ghost (web, Admin and APIs) (app) | 0.5 / 0.75 / 3 | 1 / 1 / 21 | 1.5 / 1.5 / 100 | [5][6][7][21][22][24][32][41] |
| MySQL (database) | 0.25 / 0.75 / 1.5 | 0.5 / 1 / 3 | 1 / 2 / 8 | [6][42][43][44][45] |
How the estimates are worked out
- Ghost (web, Admin and APIs) · Light: Ghost asks for at least 1 GB of memory for Ghost, MySQL and the web server, and its Docker guide uses a 2 GB / 1 vCPU server for Ghost, MySQL and Caddy: 0.75 GiB and half a core for the single Node process here. Disk: 209,530,515 B compressed × 3 (0.585 GiB) rounded up to 0.75 GiB + 100 posts × 4 images × an assumed 5 MiB (original kept as _o plus resized copies) = 1.95 GiB, rounded up to 3 GiB.
- Ghost (web, Admin and APIs) · Medium: 20,000 views a day is ~0.23 a second on average and a few a second at peaks, all rendered by Ghost itself, plus image processing on upload and newsletter sends to 5,000 members: one core and 1 GiB. Disk: 0.75 GiB image + 1,000 posts × 4 images × an assumed 5 MiB (19.5 GiB), rounded up to 21 GiB.
- Ghost (web, Admin and APIs) · Heavy: Ghost runs as one process per site and says to scale with a cache or CDN in front, so most of the ~2.3 views a second never reach it. 1.5 vCPU / 1.5 GiB: the Node event loop plus image processing and rendering newsletters for 50,000 members (sent through Mailgun). Disk: 0.75 GiB image + 5,000 posts × 4 images × an assumed 5 MiB (97.7 GiB), rounded up to 100 GiB.
- MySQL · Light: MySQL's defaults are made to start on a ~512 MB VM with a 128 MB buffer pool; Ghost keeps a pool of 2 to 10 connections: 0.75 GiB. Disk: 238,271,431 B × 3 (0.666 GiB) rounded up to 0.75 GiB + an assumed 0.1 GiB of posts, members and newsletter recipient rows + 100 MB redo log + an assumed 0.5 GiB of binary logs (kept 30 days by default) = 1.45 GiB, rounded up to 1.5 GiB.
- MySQL · Medium: Data: 1,000 posts × an assumed 100 KB (content, HTML and revisions) + 5,000 members × 5 KB + 5,000 recipients × 4 newsletters × 12 months × 1 KB = 0.37 GB, ~0.5 GiB. 1 GiB leaves room to raise the 128 MB buffer pool to the whole database. Disk: 0.75 GiB image + 0.5 GiB data + 0.1 GiB redo + an assumed 1 GiB of binary logs = 2.35 GiB, rounded up to 3 GiB.
- MySQL · Heavy: Data: 5,000 posts × 100 KB + 50,000 members × 5 KB + 50,000 recipients × 4 × 12 months × 1 KB = 3.15 GB, ~4 GiB. 2 GiB fits a 1 GiB buffer pool (MySQL recommends 50 to 75% of memory), set with --innodb-buffer-pool-size. Disk: 0.75 GiB image + 4 GiB data + 0.1 GiB redo + an assumed 2 GiB of binary logs = 6.85 GiB, rounded up to 8 GiB.
Ports
Public ports are meant to be reached from outside the stack, usually through a reverse proxy; internal ones stay on the stack's own network.
User and permissions (UID/GID)
The user each container's process runs as, and the paths it writes to. A bind mount for one of these paths must be writable by that UID:GID.
| Component | UID:GID | User | Starts as root | Writes to | Sources |
|---|---|---|---|---|---|
| Ghost (web, Admin and APIs)Derived | 1000:1000 | node | Yes, prepares its directories, then drops to this user | /var/lib/ghost/content | [6][7][8][9] |
| MySQL | 999:999 | mysql | Yes, prepares its directories, then drops to this user | /var/lib/mysql/var/run/mysqld | [15][16] |
- Ghost (web, Admin and APIs): The image sets no USER: the entrypoint starts as root, chowns files in /var/lib/ghost/content to node and re-executes itself with gosu node (uid and gid 1000 in the node:22-alpine base). The content path holds Ghost's data, images, themes, logs and adapters folders.
Storage growth
How much each component's data grows per month at each load level, on top of the disk in the profile. A value marked Assumption is ANAROQ's stated assumption, not a figure from the sources; the notes say what it rests on.
| Component | Light | Medium | Heavy | Sources |
|---|---|---|---|---|
| Ghost (web, Admin and APIs)Assumption | 0.156 | 0.781 | 2.93 | [6][7] |
| MySQLAssumption | 0.003 | 0.022 | 0.2 | [6][45] |
What the growth figures rest on
- Ghost (web, Admin and APIs): New posts a month (8, 40, 150) × 4 images × an assumed 5 MiB: Ghost resizes uploads to 2,000 px and keeps the original with an _o suffix, and themes add smaller sizes. Nothing expires; Ghost's rotated log files (daily, 10 kept) also sit in this volume.
- MySQL: Members × 4 newsletters a month × an assumed 1 KB per recipient row, plus new posts × 100 KB (content, HTML and revisions). Binary logs add a steady window rather than growth: they expire after 30 days by default.
Upgrade and rollback
How to move to a new version safely, and how to go back if it fails.
Back up first
Take a mysqldump of the ghost database and an archive of the content volume first; database migrations cannot be undone by an older image. [28][29]
Upgrade steps
- Read the release notes and, before a new major, the breaking changes; Ghost advises moving to a new major after its first minor release. [26][27][28]
- Change the pinned ghost tag (keep the -alpine variant), then run docker compose pull and docker compose up -d. Ghost migrates its database at boot; follow docker compose logs -f ghost until it serves again. [5][36]
- Move MySQL only between 8.4.x patch tags: Ghost supports MySQL 8.0 and 8.4, not 9.x. [20][21]
Roll back
Stop Ghost, restore the database dump and the content archive from before the upgrade, pin the previous tag and start again. [29]
Known breaking changes
- In 6.0.0: Node.js 22 only (the image ships it). API requests return at most 100 items, ?limit=all included, so integrations must paginate. AMP and GET /ghost/api/admin/session/ were removed; extensionless files in a theme's root are no longer served. [25][27]
- In 5.0.0: MySQL 8 is the only supported database (MySQL 5 no longer works, MariaDB was never supported); API URLs lost their version and use the accept-version header; a url set to http no longer serves secure requests. [23][27]
Limits
- One Ghost instance per site: clustering, load balancing and multi-server setups are not supported. Scale by putting a cache or CDN in front. [21][24]
- Email newsletters need Mailgun's bulk API, set in Ghost Admin; SMTP (the smtp option) only carries transactional mail. Without Mailgun, members can still sign up but posts are not emailed. [6][32]
- Social Web (ActivityPub) and web analytics are off in this template. The first needs three routes to https://ap.ghost.org at your proxy (free hosted service, up to 2,000 followers and 100 interactions a day); the second needs Tinybird and upstream's analytics services. [4][5]
- MySQL keeps its defaults: a 128 MB buffer pool and 30 days of binary logs in the data volume. On the heavy level, raise the pool with --innodb-buffer-pool-size; Ghost-CLI's nginx allows 50 MB uploads, so set a similar body limit at your proxy. [30][43][44][45]
Security
- The first visitor to /ghost creates the owner account: setup stays open until it is done once. Complete it right after the first start, before the site is reachable from the internet. [5][34]
- Sign-in from a new device needs a code Ghost emails to the staff user, and fails if the email can't be sent. Turn on the smtp option before signing in from a second browser or inviting staff. [31][33][35]
- Serve Ghost over HTTPS (Admin must run over it) and have the proxy send X-Forwarded-Proto: https; without it Ghost redirects to https in a loop. [11][21][30]
- Every staff user is trusted and can publish scripts on the site. Ghost recommends a separate admin domain (admin__url, not set by the template) so such scripts can't reach the Admin session. [6][21][31]
Backup
- Back up the database with mysqldump --no-tablespaces as the ghost user, the content volume (images, media, files, themes) with tar, and the .env. Ghost Admin's export lacks comments, member activity and media. [29][39]
- To restore, stop Ghost, import the dump into the ghost database, unpack the content archive into the volume and start Ghost again. [29]
Latest release
- This profile was checked against
Ghost 6.70.0
This profile was checked against the newest release.
- Checked on
- 14 Oct 2026
- State
- Checked within the last 90 days
- Where releases are published
- GitHub Releases
Version
- Profile status
- Published
- Checked against release
- Ghost 6.70.0
- Profile version
- 1.0.0
- Figures verified
- 14 Oct 2026
- Catalog release
- 2026.10.10
- Sizing policy
- 2026.10.0
- Compose file
- Unverified
Project and alternatives
- Official site
- ghost.org
- Source code
- github.com/TryGhost/Ghost
- Alternatives
- WordPressWriteFreely
Sources
- TryGhost/ghost-docker compose.yml at 5109c70 (caddy on 80/443, ghost:${GHOST_VERSION:-6-alpine} with env_file .env, mysql:8.0.44 with mysqladmin ping healthcheck, analytics and activitypub profiles) (Official Compose · read 14 Oct 2026)
- TryGhost/ghost-docker .env.example at 5109c70 (DOMAIN, DATABASE_*PASSWORD; SMTP example smtp.example.com, 465, secure true; mail required for logins and invites) (Official Compose · read 14 Oct 2026)
- TryGhost/ghost-docker caddy/Caddyfile.example at 5109c70 (reverse_proxy ghost:2368, imports the ActivityPub, TrafficAnalytics and SecurityHeaders snippets) (Official Compose · read 14 Oct 2026)
- TryGhost/ghost-docker caddy/snippets/ActivityPub at 5109c70 (/.ghost/activitypub/*, /.well-known/webfinger and /.well-known/nodeinfo go to ACTIVITYPUB_TARGET, default https://ap.ghost.org) (Official Compose · read 14 Oct 2026)
- Ghost Docs: How to install Ghost with Docker (preview: Ghost, Caddy, MySQL; SMTP required; hosted ActivityPub, 2,000 followers and 100 interactions a day; pull and up -d) (Official docs · read 14 Oct 2026)
- Ghost Docs: Configuration (env vars with __ for nesting; url, database and mail required in production; pool 2 to 10; images resized to 2,000 px, original kept with _o) (Official docs · read 14 Oct 2026)
- TryGhost/docker-library-ghost 6/alpine3.23 Dockerfile at f3d7eab (node:22-alpine3.23, GHOST_VERSION 6.70.0, content in /var/lib/ghost/content, EXPOSE 2368, no HEALTHCHECK, no USER) (Official repository · read 14 Oct 2026)
- TryGhost/docker-library-ghost 6/alpine3.23 docker-entrypoint.sh at f3d7eab (as root: chown the content dir to node, then gosu node; seeds empty content from content.orig) (Official repository · read 14 Oct 2026)
- nodejs/docker-node 22/alpine3.23 Dockerfile (FROM alpine:3.23, so BusyBox wget; user node created with uid and gid 1000) (Official repository · read 14 Oct 2026)
- BusyBox command help: wget (--spider checks existence; --header 'header: value') (Official docs · read 14 Oct 2026)
- Ghost repository: url-redirects.js at v6.70.0 (an https url answers a non-secure request with a 301 to https) (Official repository · read 14 Oct 2026)
- Ghost repository: shared/express.js at v6.70.0 (trust proxy on, so req.secure follows X-Forwarded-Proto) (Official repository · read 14 Oct 2026)
- Ghost repository: Admin API routes.js at v6.70.0 (GET /site is a public Admin API endpoint) (Official repository · read 14 Oct 2026)
- Ghost repository: shared/config/loader.ts at v6.70.0 (nconf env with separator __ and parseValues true) (Official repository · read 14 Oct 2026)
- docker-library/mysql 8.4 Dockerfile.oracle at 01f90d8 (MYSQL_VERSION 8.4.11, mysql uid/gid 999, gosu, VOLUME /var/lib/mysql, EXPOSE 3306 33060, no HEALTHCHECK) (Official repository · read 14 Oct 2026)
- docker-library/mysql 8.4 docker-entrypoint.sh at 01f90d8 (init server with --skip-networking; MYSQL_DATABASE/USER/PASSWORD; MYSQL_RANDOM_ROOT_PASSWORD; chown to mysql, then gosu mysql) (Official repository · read 14 Oct 2026)
- Docker Official Image mysql: documentation (MYSQL_DATABASE, MYSQL_USER, MYSQL_PASSWORD, MYSQL_RANDOM_ROOT_PASSWORD, data in /var/lib/mysql) (Official docs · read 14 Oct 2026)
- MySQL 8.4 Reference Manual: mysqladmin (ping returns 0 when the server runs, even on Access denied) (Official docs · read 14 Oct 2026)
- MySQL: EOL notices (MySQL 8.0 in Oracle Sustaining Support since April 21, 2026; upgrade to 8.4 LTS or 9.7 LTS) (Official docs · read 14 Oct 2026)
- docker-library official-images: library/mysql (8.4.11, 9.7.2 lts and 26.7.0 innovation; no 8.0 tags are built any more) (Official repository · read 14 Oct 2026)
- Ghost Docs: Hosting Ghost (supported stack: Node.js 22, MySQL 8.0 or 8.4, at least 1 GB memory; admin must run over HTTPS; separate admin domain; scale with a cache, no clustering) (Official docs · read 14 Oct 2026)
- Ghost Docs: How to install Ghost (a server with at least 1 GB of memory recommended) (Official docs · read 14 Oct 2026)
- Ghost Docs: What databases are supported in production? (MySQL 8 only; MariaDB and SQLite3 not supported in production) (Official docs · read 14 Oct 2026)
- Ghost Docs: Clustering, sharding, HA and other multi-server setups (one Ghost instance per site; put a cache or CDN in front) (Official docs · read 14 Oct 2026)
- Ghost Docs: Supported Node versions (Ghost 6.0 and later require Node.js 22) (Official docs · read 14 Oct 2026)
- Ghost Docs: Major versions and long term support (5.x end of life January 2026; 6.x current; end-of-life versions are insecure) (Official docs · read 14 Oct 2026)
- Ghost Docs: Breaking changes (6.0: Node 22 only, max 100 results per API page, AMP removed; 5.0: MySQL 8 only, unversioned API URLs; update after the first minor) (Official docs · read 14 Oct 2026)
- Ghost Docs: How to update Ghost (weekly releases; back up first; check breaking changes before a major) (Official docs · read 14 Oct 2026)
- Ghost Docs: How can I backup my site data? (mysqldump of the database and a tar of the content volume for Docker; Admin export lacks comments, member activity and media) (Official docs · read 14 Oct 2026)
- Ghost Docs: Reverse proxying to Ghost (set X-Forwarded-Proto or get a redirect loop; Ghost-CLI's nginx allows 50 MB uploads) (Official docs · read 14 Oct 2026)
- Ghost Docs: Security (new-device sign-ins verified by emailed code; login attempts limited to 5 an hour per IP; all staff are trusted and can publish scripts) (Official docs · read 14 Oct 2026)
- Ghost Docs: Why do I have to set up Mailgun? (newsletters need a bulk mail API, Mailgun only; SMTP is for transactional mail) (Official docs · read 14 Oct 2026)
- Ghost repository: session-service.js at v6.70.0 (staffDeviceVerification: unverified sessions get an emailed code; a failed send ends in 'Failed to send email') (Official repository · read 14 Oct 2026)
- Ghost repository: services/auth/setup.js at v6.70.0 (the owner setup is open until it is completed once) (Official repository · read 14 Oct 2026)
- Ghost repository: shared/config/defaults.json at v6.70.0 (staffDeviceVerification true; log rotation daily, 10 files kept) (Official repository · read 14 Oct 2026)
- Ghost repository: database-state-manager.js at v6.70.0 (at boot: knex-migrator init on an empty database, migrate when needed) (Official repository · read 14 Oct 2026)
- Ghost repository: ghost/package.json at v6.70.0 (version 6.70.0, MIT, Node ^22.23.1 or ^24.20.0, mysql2) (Official repository · read 14 Oct 2026)
- Ghost repository: LICENSE at v6.70.0 (MIT, Ghost Foundation) (Official repository · read 14 Oct 2026)
- TryGhost/ghost-docker scripts/migrate.sh at 5109c70 (mysqldump --no-tablespaces with the Ghost database user) (Official repository · read 14 Oct 2026)
- docker-library official-images: library/ghost (6.70.0-alpine and 6.70.0 newest, from TryGhost/docker-library-ghost f3d7eab) (Official repository · read 14 Oct 2026)
- Docker Hub: ghost tag 6.70.0-alpine (linux/amd64 209,530,515 B compressed, pushed 2026-10-13) (Official repository · read 14 Oct 2026)
- Docker Hub: mysql tag 8.4.11 (linux/amd64 238,271,431 B compressed, pushed 2026-10-12) (Official repository · read 14 Oct 2026)
- MySQL 8.4 Reference Manual: How MySQL uses memory (defaults start on a ~512 MB VM; buffer pool 50 to 75% of memory recommended) (Official docs · read 14 Oct 2026)
- MySQL 8.4 Reference Manual: InnoDB startup options (innodb_buffer_pool_size default 128 MB; innodb_redo_log_capacity default 100 MB) (Official docs · read 14 Oct 2026)
- MySQL 8.4 Reference Manual: Binary logging options (on by default; binlog_expire_logs_seconds default 2,592,000 = 30 days) (Official docs · read 14 Oct 2026)
- Ghost: Ghost(Pro) plans and pricing (official managed hosting by the Ghost Foundation) (Official docs · read 14 Oct 2026)