# How to deploy Ghost on Ownkube

> Deploy the official Ghost image on Ownkube with a managed MySQL database, persistent content storage, and a custom domain, in about ten minutes.

- **Published:** 2026-08-27
- **Author:** Ownkube team
- **Category:** How-To
- **Tags:** ghost, self-hosting, cms, deploy, tutorial
- **Canonical URL:** https://ownkube.io/blog/deploy-ghost
- **Cover:** https://ownkube.io/blog/deploy-ghost.png

---
Ghost is a fast, open source publishing platform, and the official [Docker image](https://docs.docker.com/) is the simplest way to self-host it if you would rather own the writing than rent a Ghost(Pro) seat. This walks through deploying that image on Ownkube with a real database behind it, from an empty project to a working blog on your own domain.

**TL;DR**

- Ghost's production database is MySQL (its SQLite mode is meant for local development, not a live site), so you need a managed database next to the app.
- Deploy the official `ghost:5` image on Ownkube Compute, point it at a managed MySQL database, and give it a persistent volume for `/var/lib/ghost/content` so themes, images, and uploads survive restarts.
- Set `url` to your final domain before first boot. Ghost bakes the URL into generated links and changing it later needs a config update and restart.
- Ownkube issues TLS automatically once you attach a [custom domain](/blog/automatic-https-custom-domain), so `https://` works without a certificate step.
- A database box starts at $4/month plus storage, and the app itself can run metered so an idle blog barely draws your wallet down.

## What you need before you start

- A Docker Hub image reference: `ghost:5` (or pin a specific version tag; avoid `latest` for anything you plan to keep running).
- A domain or subdomain you can point at Ownkube, if you want something other than the auto-allocated `*.ownkube.app` hostname.
- An email provider if you want Ghost's built-in newsletter and staff invite emails to send (Mailgun is the one Ghost documents best, but any SMTP provider works).

Ghost does not run on SQLite in production. The image supports it for quick local testing, but the maintainers are explicit that a live site needs MySQL, so budget for a small database from the start rather than migrating later.

## 1. Create a managed MySQL database

[Ghost's own docs](https://ghost.org/docs/) specify MySQL 8, so that is the database box to provision. From the Ownkube dashboard, create a database box (from $4/month plus storage at $0.15/GB/month) and note the connection details: host, port, database name, user, and password. Ownkube databases are single-instance and private within the region today, which is the right shape for a single Ghost site; multi-instance and public access are on the roadmap.

## 2. Deploy the Ghost image

Create a new app from the `ghost:5` image (image deploys skip the build step entirely, so there is nothing to compile). If you would rather deploy from a Dockerfile so you can bake in a custom theme, this is enough to start from:

```dockerfile
FROM ghost:5

# Optional: copy a custom theme into the default themes directory
# COPY ./themes/my-theme /var/lib/ghost/content/themes/my-theme
```

Either path, point the app at port `2368`, which is what the Ghost image listens on by default.

## 3. Set the environment variables

Ghost reads configuration from [environment variables](/blog/manage-secrets-env-vars) using double-underscore nesting for its [config object](https://ghost.org/docs/config/). Set these on the app:

```bash
# Core
url=https://blog.example.com
database__client=mysql
database__connection__host=<your-mysql-host>
database__connection__port=3306
database__connection__user=<your-mysql-user>
database__connection__password=<your-mysql-password>
database__connection__database=ghost

# Mail (optional but recommended so staff invites and newsletters work)
mail__transport=SMTP
mail__options__service=Mailgun
mail__options__host=smtp.mailgun.org
mail__options__port=587
mail__options__auth__user=<smtp-user>
mail__options__auth__pass=<smtp-password>

NODE_ENV=production
```

Set `url` to the real domain before you first boot the app. Ghost uses it to generate absolute links in posts, sitemaps, and RSS, and changing it after content exists means editing the config and restarting rather than a quick dashboard tweak.

## 4. Attach persistent storage for content

Everything Ghost writes that matters, themes, images, member data exports, custom integrations, lives under `/var/lib/ghost/content` inside the container. Mount a persistent volume at that path so uploads and theme changes survive redeploys and restarts. Without it, a redeploy resets the container to the image's baked-in content and any uploaded images or theme edits are gone.

## 5. Attach your domain and go live

Point your domain's DNS at the hostname Ownkube gives the app, then attach the custom domain in the dashboard. TLS is issued automatically once the domain resolves, so there is no separate certificate step. Visit the domain, and Ghost's setup wizard walks you through creating the first admin user.

```bash
# Verify the app is listening once DNS has propagated
curl -I https://blog.example.com
```

## Keeping the site running

Ghost's admin panel handles most day-to-day work: publishing, member management, theme uploads. The two things worth watching from the infrastructure side are the database box's storage (grows with post history and member data) and whether the app is metered or reserved. A personal blog with modest traffic is a good fit for [metered pricing](/blog/prepaid-wallet-no-surprise-bill), since CPU usage tracks actual visits and an idle blog barely registers. A newsletter-heavy site with a large member list sending regularly is a better fit for a flat Spark box, since the load is more constant.

If you later want to move this same Ghost deployment into your own AWS account, for example once traffic or compliance needs outgrow a shared platform, the app and its Dockerfile do not need to change. Ownkube's own-cloud option runs the identical container on your AWS instance with the same logs, metrics, and health checks attached, so the migration is a redeploy target, not a rewrite. If you are comparing that path against other platforms first, our [Railway, Render, and Northflank comparison](/blog/railway-vs-render-vs-northflank-2026) is a reasonable place to start.

## FAQ

### Can Ghost run on SQLite instead of MySQL?

The Ghost image supports SQLite for local development, but the Ghost team documents MySQL 8 as the production database. Use a managed MySQL database box for anything you plan to keep running.

### Do I need a separate volume for themes?

Yes. Themes, uploaded images, and member exports all live under `/var/lib/ghost/content`. Mount a persistent volume there or a redeploy wipes them back to the image defaults.

### How do I change my site's URL after launch?

Update the `url` environment variable and restart the app. Ghost regenerates links going forward, but content published before the change may still reference the old URL in cached pages until you republish or purge a CDN cache if you use one.

### Does Ghost need a build step on Ownkube?

No, if you deploy the official image directly. A build step only applies if you extend the image with a custom Dockerfile, for example to bake in a theme.

### What does this cost to run?

A database box starts at $4/month plus storage, and the app itself can run on Ownkube's metered pricing, where CPU and memory bill on actual per-minute use. A low-traffic blog typically costs a few dollars a month beyond the database.

## Where Ownkube fits

Ghost's official image is straightforward to run anywhere that gives it a MySQL database and a place to persist content, and Ownkube Compute covers both without a cloud account or a Kubernetes manifest to write. Deploy the image, point it at a managed database, mount the content volume, and attach your domain. [Deploy your first app](https://app.ownkube.io/login).