Self-hosting Ghost
Run your own Ghost with Docker and one setup script.
Ghost runs as a handful of containers: the web app, the API, the docs, a delivery worker for webhooks and email, a code search node, Postgres, and S3 storage, plus an optional importer for GitHub repositories. One script asks a few questions, writes the configuration, and starts all of them.
What you need
- Docker with Compose v2 (Docker Desktop on macOS and Windows).
- About 4 GB of memory free while the images build for the first time.
- An SMTP server or an HTTP email relay. Ghost uses it for email verification, password resets and notifications.
- For a public instance: a domain, and ports 80 and 443 open. HTTPS certificates are issued automatically.
Install
git clone https://github.com/PhantomKnight287/ghost.git
cd ghost
./docker/setup.shThe script asks:
- Domain or IP. Enter a domain such as
git.example.comto serve Ghost over HTTPS. Enterlocalhostor an IP address to serve plain HTTP on ports 3000, 3001 and 3003. - SSH port. The port for
git clone ssh://…. The default is1031. - Email. Pick SMTP or an HTTP relay, then enter its details. One of them is required.
- Storage. Use the bundled S3 storage, or point Ghost at an existing bucket on Cloudflare R2, Tigris, MinIO or another S3-compatible service.
- GitHub imports. Optional, off by default. Say yes to let people import a GitHub repository with its code, releases, issues and pull requests, then enter the client ID and secret of a GitHub OAuth app. The script prints the callback URL the app needs. See GitHub imports.
- Secrets. Press enter at each one and the script generates it: the auth secret, the webhook encryption key, the SSH host key, the commit signing key, and the database and storage passwords.
The first build takes several minutes. When it is done, the script prints the addresses:
Web https://git.example.com
API https://api.git.example.com (git clone https://api.git.example.com/<user>/<repo>)
Docs https://docs.git.example.com
SSH ssh://git@git.example.com:1031/<user>/<repo>.gitOpen the web address and sign up. The first account is an ordinary account; there is no separate admin.
With a domain
Before you run the script, create DNS records that point three names at the server:
| Name | Serves |
|---|---|
git.example.com | The web app |
api.git.example.com | The API and git over HTTP |
docs.git.example.com | These docs |
The web app and the API share a sign-in cookie, so they have to be subdomains of one name. A Caddy container takes ports 80 and 443 and gets a certificate for each name on its first request.
Open the SSH port (default 1031) in your firewall as well. It does not go
through Caddy.
Upgrading
git pull
./docker/setup.sh # answer Y to start with the existing configurationOn Windows, run setup.ps1 the same way. The images are rebuilt, and database
migrations run before the API starts.
Back up
Everything that matters is in two places:
docker/.env: every secret. Without it, sign-ins, webhook secrets, the SSH host key and the commit signing key are lost.- The
ghost-server_postgresvolume, and the bucket (ghost-server_rustfswhen you use the bundled storage).
A database dump:
cd docker
docker compose exec postgres pg_dump -U ghost ghost > ghost.sqlNext: Self-hosting configuration covers every setting, running without the script, and troubleshooting.