Back to Blog
Tutorial10 min read2026-07-02

How to Deploy a Ghost Blog with MySQL

Run the self-hosted Ghost publishing platform backed by MySQL 8: the config that matters, persistent storage for uploaded images, mail for member emails, and going live with SSL.

Ajay Kumar
Ajay Kumar
Founder & DevOps, PandaStack

Ghost is a focused, fast publishing platform — a clean alternative to WordPress for blogs, newsletters, and membership sites. The self-hosted version is a Node.js application that, for production, runs on MySQL. Getting Ghost right comes down to three things: the database, persistent storage for content, and mail.

Ghost wants MySQL 8 in production

Ghost supports SQLite for local development but officially recommends MySQL 8 for production. SQLite on a container is ephemeral and unsuitable for a real site. Provision a managed MySQL 8.x and connect Ghost to it.

Ghost reads either a config.production.json file or environment variables in the database__* form. Environment variables are the cleanest fit for a container platform:

NODE_ENV=production
database__client=mysql
database__connection__host=your-managed-mysql-host
database__connection__port=3306
database__connection__user=ghost
database__connection__password=...
database__connection__database=ghost
url=https://blog.yourdomain.com

On PandaStack, attach a managed MySQL (8.x) and map its connection details into these variables. The url must be your public HTTPS address — Ghost bakes it into links, RSS feeds, and emails, so getting it wrong breaks navigation and SEO.

Persistent storage for images

By default Ghost stores uploaded images and themes on local disk under content/. In a container — especially one that can restart or scale — local disk is ephemeral, so uploaded images vanish. You have two good options:

  1. 1Mount a persistent volume at /var/lib/ghost/content so content survives restarts.
  2. 2Use an S3-compatible storage adapter so images live in object storage independent of the container.

For a single-instance blog, a persistent volume is the simplest correct choice. If you ever scale to multiple replicas, switch to the S3 adapter — multiple containers can't share a local volume safely.

Mail is not optional

Ghost sends two kinds of email: transactional (staff invites, password resets) via any SMTP provider, and bulk newsletter email which Ghost specifically integrates with Mailgun. If you run a membership/newsletter site, configure Mailgun:

mail__transport=SMTP
mail__options__service=Mailgun
mail__options__auth__user=...
mail__options__auth__pass=...

Without working mail, member signups and magic-link logins silently fail — a frustrating bug to diagnose after launch.

Deploying

  1. 1Provision managed MySQL 8.x.
  2. 2Deploy the official ghost image (port 2368) as a container service with the env vars above.
  3. 3Mount a persistent volume at the content path.
  4. 4Add your custom domain; SSL is issued automatically.
  5. 5Visit /ghost to complete setup and create the owner account.
ConcernSetting
Databasemanaged MySQL 8.x via database__*
Public URLurl=https://... (HTTPS)
Imagespersistent volume or S3 adapter
MailSMTP + Mailgun for newsletters
Port2368

Upgrades and backups

Ghost runs database migrations automatically on startup, so pin a version tag and upgrade deliberately. Back up two things: the MySQL database (managed MySQL gives you scheduled backups) and the content directory (snapshot the volume or rely on S3 versioning). Both are required for a full restore — the database alone won't bring back your images.

Go-live checklist

  • MySQL 8.x configured, not SQLite
  • url set to the public HTTPS domain
  • Content on a persistent volume or S3 adapter
  • Mail configured (transactional + newsletter)
  • Pinned Ghost version
  • Database + content backups

References

  • [Ghost configuration reference](https://ghost.org/docs/config/)
  • [Ghost Docker image](https://hub.docker.com/_/ghost)
  • [Ghost MySQL requirement](https://ghost.org/docs/install/ubuntu/)
  • [Ghost storage adapters](https://ghost.org/integrations/custom-storage-adapters/)

Ghost runs as a PandaStack container service with managed MySQL attached and persistent storage for your media — plus automatic SSL on your custom domain. Launch your blog on the free tier at [dashboard.pandastack.io](https://dashboard.pandastack.io).

Ready to deploy?

Start free on PandaStack.

Start free on PandaStack

More in Tutorial

Browse all Tutorial articles →

See also