> ## Content Index
> Fetch the complete content index at: https://wealthlab.life/llms.txt
> Use this file to discover other available public pages before exploring further.

# Ghost Docker Backup and Restore: A Tested Recovery Guide
- URL: https://wealthlab.life/ghost-docker-backup-restore/
- Published: 2026-09-05T00:08:49.000Z
- Updated: 2026-09-11T12:07:14.000Z
- Description: Back up and restore Ghost on Docker with a consistent MySQL dump, complete content archive, protected configuration, checksums, and an isolated recovery drill.
- Author: WealthLab
- Tags: Ghost, Docker, Backup, VPS

*Disclosure: WealthLab.life may earn a commission when you register through some links on this page, at no additional cost to you.*

A reliable Ghost Docker backup contains a consistent MySQL dump, the complete Ghost content directory, deployment configuration, and a written record of the versions and external services needed to rebuild the site. The backup is not proven until you restore it into an isolated environment and verify posts, images, members, themes, redirects, and administration.

## Quick answer: what must be backed up?

- **MySQL:** posts, pages, members, settings, integrations, and other application state.
- **Ghost content:** images, files, media, themes, adapters, and custom route files stored under `/var/lib/ghost/content`.
- **Deployment configuration:** Compose and Caddy files plus a protected copy of required environment values.
- **External-service records:** DNS, SMTP, object storage, CDN, analytics, webhooks, and firewall configuration.
- **Recovery instructions:** image versions, restore order, validation checks, owners, and recovery targets.

A Ghost Admin JSON export is useful for content migration, but Ghost's documentation says it does not include some engagement data, email analytics, or comments. Do not treat that export alone as a disaster-recovery backup.

## Before running commands: identify your storage

Do not copy commands with guessed service, volume, database, or path names. Start in the actual Compose project and inspect its effective structure without printing secrets:

```bash
cd /opt/ghost
docker compose config --services
docker compose ps
docker compose volumes
docker inspect "$(docker compose ps -q ghost)"   --format '{{json .Mounts}}'
```

The official Ghost Docker project commonly uses Ghost, MySQL, and Caddy, but local filenames and mount choices can differ. A bind mount must be archived from its host path; a named volume is usually archived through a temporary container or a dedicated backup tool. Record the result in the recovery runbook.

Set a restrictive umask before creating local backup files. Store the backup outside the public web root and outside any directory synchronized to a public repository:

```bash
umask 077
backup_dir="$HOME/ghost-backups/$(date -u +%Y%m%dT%H%M%SZ)"
mkdir -p "$backup_dir"
```

## 1\. Create a consistent MySQL dump

For a standard Compose setup whose database service is named `db`, this pattern runs `mysqldump` inside the database container and writes the result on the host. The database credentials come from the container environment rather than being pasted into the host command:

```bash
docker compose exec -T db sh -c   'exec mysqldump --single-transaction --quick   -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE"'   > "$backup_dir/ghost.sql"
```

`--single-transaction` gives a transactionally consistent dump for InnoDB tables without a long global read lock. It does not make the content archive and database dump atomic with each other. For a busy publication or a strict recovery-point target, schedule a short write-maintenance window or use a database-aware backup system that coordinates the full set.

Check that the command succeeded and produced a non-empty SQL file. A size check is only a basic sanity check, not restore proof:

```bash
test -s "$backup_dir/ghost.sql"
wc -c "$backup_dir/ghost.sql"
```

## 2\. Archive the complete Ghost content directory

If Compose bind-mounts a host directory such as `./data/ghost` into `/var/lib/ghost/content`, archive that host directory using the path confirmed in the previous inspection:

```bash
tar --one-file-system -czf "$backup_dir/ghost-content.tar.gz"   -C /opt/ghost/data ghost
```

Change `/opt/ghost/data` and `ghost` to the real parent and directory names. The archive should include the full content tree, not only images. Themes, uploaded files, media, route files, and custom adapters may be needed for an accurate recovery.

For a named volume, follow Docker's volume backup pattern: mount the source volume read-only in a short-lived container and write the archive to a host backup directory. Confirm the exact volume name with `docker volume inspect` before running it:

```bash
docker run --rm   --mount source=YOUR_GHOST_VOLUME,target=/source,readonly   --mount type=bind,source="$backup_dir",target=/backup   alpine tar -czf /backup/ghost-content.tar.gz -C /source .
```

Pin or pre-approve the utility image in an automated job rather than silently pulling an unreviewed image during an emergency.

## 3\. Protect configuration without leaking secrets

Copy the Compose file, Caddy configuration, custom routes, and a note containing the deployed image references or Git commit. Environment files contain database, SMTP, analytics, and integration credentials, so encrypt them before they leave the host. Do not commit them, include them in a public support bundle, or print a rendered Compose configuration into logs.

```bash
cp compose.yml "$backup_dir/"
cp -a caddy "$backup_dir/caddy"
docker compose images > "$backup_dir/container-images.txt"
git rev-parse HEAD > "$backup_dir/deployment-commit.txt"
```

If the deployment is not tracked in Git, record file checksums and image digests. Keep a separate inventory of external dependencies: canonical domain, DNS records, TLS/reverse-proxy path, firewall rules, mail provider, From address, object-storage buckets, analytics, and webhooks. Database and content files cannot recreate an undocumented external service.

## 4\. Create checksums and move a copy off-server

Create checksums after all files are closed, then copy the directory to encrypted storage outside the VPS:

```bash
cd "$backup_dir"
sha256sum ghost.sql ghost-content.tar.gz compose.yml   > SHA256SUMS
sha256sum --check SHA256SUMS
```

Use at least one destination that survives loss of the server and hosting account. Limit access, encrypt sensitive configuration, enable retention or immutability where available, and alert when scheduled copies fail. A provider snapshot is useful as another recovery layer, but it should not be the only copy or the only restore format.

## 5\. Define retention from business requirements

Choose the schedule from the maximum acceptable data loss, not from a generic daily-backup rule. A low-change technical blog may accept a daily database and content backup; a membership or newsletter publication may need a shorter interval. Keep multiple generations so corruption or accidental deletion discovered late does not overwrite every usable copy.

- **Recovery point objective (RPO):** the maximum amount of recent data you can lose.
- **Recovery time objective (RTO):** how long the publication can remain unavailable.
- **Retention:** enough daily, weekly, and monthly generations to cover delayed discovery.
- **Verification:** automated checksum checks plus recurring full restore drills.

*Disclosure: WealthLab.life may earn a commission when you register through some links in this section, at no additional cost to you.*

## Restore safely into an isolated environment

Do not rehearse by overwriting production. Build a disposable VPS or private local environment with a temporary hostname, block public indexing, and prevent outbound newsletters or webhooks. Use compatible Ghost and MySQL versions first; perform application upgrades only after the recovered state works.

If you need a clean test server, [DigitalOcean](https://m.do.co/c/a3b3fb312857) and [Vultr](https://www.vultr.com/?ref=9919874-9J) are two self-managed VPS options. Confirm current specifications and charges before creating resources, and delete disposable infrastructure through the provider dashboard after the test.

## 1\. Prepare the destination without starting normal traffic

- Install Docker and the Compose plugin from official documentation.
- Restore the saved deployment files and protected environment values with restrictive permissions.
- Use a private hostname or hosts-file mapping; add `noindex` and access controls.
- Disable scheduled newsletters, transactional tests to real users, and external webhooks.
- Create empty persistent storage and start only the database when practical.

```bash
cd /opt/ghost-restore
docker compose config --quiet
docker compose up -d db
docker compose ps
```

## 2\. Restore MySQL

Verify the target database is empty or deliberately replaceable. The following pattern reads the saved SQL file into the database service using its configured credentials:

```bash
docker compose exec -T db sh -c   'exec mysql -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE"'   < /path/to/backup/ghost.sql
```

Check the exit status and database logs. Do not assume an import succeeded because the shell returned quickly. Authentication errors, insufficient disk space, incompatible SQL modes, or a truncated dump can stop or partially complete recovery.

## 3\. Restore Ghost content

For a bind mount, extract into the confirmed empty destination parent. Inspect archive paths before extraction and avoid unpacking an untrusted archive as root:

```bash
tar -tzf /path/to/backup/ghost-content.tar.gz | head
tar -xzf /path/to/backup/ghost-content.tar.gz   -C /opt/ghost-restore/data
```

For a named volume, use the inverse of the volume-backup pattern: mount the new target volume and backup directory into a temporary container, then extract into the empty target. Restore ownership and permissions expected by the Ghost image. Never extract over a working production content directory without a separate rollback copy.

## 4\. Start and verify the recovered site

```bash
docker compose up -d
docker compose ps
docker compose logs --tail=100 ghost db caddy
```

Complete a reader and administrator verification pass:

- Homepage, representative posts, pages, tags, and pagination load.
- Old and recent images, downloadable files, and media render.
- The expected theme, routes, redirects, navigation, canonical URL, and metadata are present.
- Members, staff roles, settings, integrations, and scheduled posts match the recovery point.
- Ghost Admin opens, but no real email or webhook fires from the isolated test.
- `robots.txt` and the sitemap are correct for production only after cutover.
- Database, content, configuration, DNS, mail, and analytics dependencies are documented.

Record the restore duration and any manual fixes. Update the runbook immediately; undocumented improvisation will be forgotten before the real incident.

## Cutover and rollback

For an actual migration, lower DNS TTL in advance when appropriate, take a final backup during a controlled write freeze, restore and verify the destination, then change routing. Keep the old server intact and inaccessible to writers until the rollback window closes. After cutover, verify HTTPS, canonical tags, Admin, mail, images, redirects, robots, sitemap, analytics, and monitoring from outside the destination network.

Use the [Docker VPS production checklist](https://wealthlab.life/docker-vps-checklist/) to review the new host. The [Ghost Docker installation guide](https://wealthlab.life/install-ghost-docker-vps/) covers the wider deployment path.

## Common backup failures

### Only the container image was saved

Container images do not contain data stored in MySQL or mounted Ghost content. Back up persistent application data and configuration separately.

### Only Ghost Admin JSON was exported

The export is valuable for migration and selective recovery, but it is not a full copy of database-only engagement data, uploaded assets, themes, or every integration secret.

### The archive stayed on the VPS

A disk failure, account suspension, compromise, or accidental deletion can remove both production and its local backup. Maintain protected off-server generations.

### The backup job succeeded but restore failed

Exit code zero, a non-empty file, and a valid checksum show limited properties. Only an isolated full restoration tests credentials, archive layout, permissions, version compatibility, external dependencies, and the runbook.

### The test site sent mail or exposed duplicate content

Use a private hostname, authentication, indexing controls, and disabled outbound integrations. Never point the production domain at the rehearsal until validation and cutover are intentional.

## FAQ

### How often should I back up Ghost?

Set the interval from your RPO. Daily may fit a low-change publication, while active memberships, comments, or frequent publishing can require more frequent database copies. Always retain multiple generations and test restores.

### Are VPS snapshots enough?

No. Snapshots are useful for host-level rollback, but portable MySQL dumps, Ghost content archives, protected configuration, and an off-provider copy provide different recovery paths.

### Can I restore to another hosting provider?

Yes. A portable database dump, complete content archive, compatible deployment files, and documented external services support migration between providers. Test on the destination before changing DNS.

### Should I stop Ghost during every backup?

A transactionally consistent MySQL dump can be taken while the site runs, but the database and content archive are not automatically one atomic snapshot. Use a short maintenance window or a coordinated backup system when your consistency and recovery-point requirements demand it.

### What should be encrypted?

Encrypt environment files, database dumps, member data, integration credentials, and any archive that can expose private publication data. Manage encryption keys separately from the backup destination and test that authorized operators can recover them.

## Related WealthLab guides

- [Install Ghost with Docker on a VPS](https://wealthlab.life/install-ghost-docker-vps/)
- [Ghost VPS requirements and sizing](https://wealthlab.life/ghost-vps-sizing/)
- [Best VPS for Ghost hosting](https://wealthlab.life/best-vps-ghost-hosting/)
- [Deploy Ghost on DigitalOcean with Docker](https://wealthlab.life/deploy-ghost-digitalocean-docker/)
- [Deploy Ghost on Vultr with Docker](https://wealthlab.life/deploy-ghost-vultr-docker/)
- [Docker VPS production checklist](https://wealthlab.life/docker-vps-checklist/)

## Sources checked

- [Ghost manual backup and restore documentation](https://docs.ghost.org/faq/manual-backup)
- [Ghost-to-Ghost migration documentation](https://docs.ghost.org/migration/ghost)
- [Ghost Docker installation documentation](https://docs.ghost.org/install/docker)
- [Docker volume backup, restore, and migration documentation](https://docs.docker.com/engine/storage/volumes/#back-up-restore-or-migrate-data-volumes)
- [MySQL 8.0 mysqldump documentation](https://dev.mysql.com/doc/refman/8.0/en/mysqldump.html)

*Official sources reviewed September 5, 2026\. Commands are patterns that must be adapted to the actual Compose project, service names, storage mounts, versions, and recovery policy.*