Intro
Running a Docker Registry in production means you are responsible for the integrity and availability of the images your team depends on. A lost registry can halt CI/CD pipelines, block deployments, and leave you scrambling to rebuild artifacts that may no longer exist elsewhere. Backup and restore are not optional add-ons; they are core operational tasks.
This guide walks through Docker Registry backup and restore using the official registry:2 image and filesystem-based storage. You will learn how to inspect your environment, safely back up data, verify backups, restore after failure, and automate the process. Every command is explained with expected output and recovery decisions, so you can apply these steps with confidence.
We focus on practical, version-scoped procedures that minimize risk. Before changing anything, observe the current state. Use placeholders instead of secrets. After any change, verify the result. This is operational safety in action.
Version and Environment Inventory
Begin by knowing exactly what you have. The official Docker Registry image is registry:2, and its data lives in /var/lib/registry inside the container. Most production setups run it with Docker Compose or Kubernetes, but the core concepts apply broadly.
First, confirm the container is running and note its configuration:
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
Expected output might look like:
NAMES STATUS PORTS
registry Up 3 hours 0.0.0.0:5000->5000/tcp
Next, inspect the container to see its mounts, environment variables, and health status:
docker inspect registry
Look for the Mounts section. If you see a named volume or bind mount for /var/lib/registry, your data is already persistent. If not, your registry is writing to the container filesystem and will lose everything when the container is removed.
Check recent logs for any errors or warnings:
docker logs registry --tail 100
If using Docker Compose, the equivalent commands are:
docker compose ps
docker compose logs -f registry
docker compose exec registry sh
The last command gives you a shell inside the container to inspect the filesystem directly. Run df -h /var/lib/registry to see disk usage and ensure the volume has enough space for backups.
Confirming Data Persistence
At this point, you must confirm where registry data is stored. A named volume like registry_data:/var/lib/registry is managed by Docker and survives container recreation. A bind mount like ./data:/var/lib/registry maps directly to a host directory, which is easier to inspect and back up but can cause permission issues on different machines.
To test persistence, perform a restart test:
- Stop the container:
docker stop registry - Start it again:
docker start registry - Pull an image list from the registry:
curl -s http://localhost:5000/v2/_catalog
If the list still shows your images, the data persisted. If it is empty, your volume isn't mounted correctly. Fix the mount before proceeding.
Safe Configuration Path
The safest way to back up a Docker Registry is to avoid interfering with running write operations. For a filesystem-backed registry, the recommended approach is to place the registry in read-only mode before copying data. This prevents corruption from concurrent writes.
Step 1: Put Registry in Read-Only Mode
You can enable read-only mode by setting the REGISTRY_STORAGE_MAINTENANCE_READONLY environment variable to enabled and recreating the container. With Docker Compose, add to your service:
services:
registry:
image: registry:2
environment:
REGISTRY_STORAGE_MAINTENANCE_READONLY: enabled
volumes:
- registry_data:/var/lib/registry
Then run:
docker compose up -d
Verify the registry is read-only by attempting to push an image. It should fail with a 405 error. For example:
docker push localhost:5000/test:latest
Expected output includes:
The push refers to repository [localhost:5000/test]
...
error: failed to push image: received unexpected HTTP status: 405 Method Not Allowed
Step 2: Back Up the Data Directory
Now that the registry is stable, copy the data. If using a named volume, you can use a temporary container to export the data:
docker run --rm -v registry_data:/data -v $(pwd):/backup alpine tar czf /backup/registry-backup-$(date +%Y%m%d%H%M).tar.gz -C /data .
This command creates a compressed archive in your current directory with a timestamp. If using a bind mount, you can simply tar the host directory:
tar czf registry-backup-$(date +%Y%m%d%H%M).tar.gz -C ./data .
Check the archive size and list its contents to confirm it includes data:
ls -lh registry-backup-*.tar.gz
tar tzf registry-backup-*.tar.gz | head
You should see files like docker/registry/v2/repositories/....
Step 3: Return Registry to Read-Write Mode
After the backup completes, revert the read-only setting and restart the registry:
environment:
REGISTRY_STORAGE_MAINTENANCE_READONLY: disabled
Then run docker compose up -d again. Confirm normal operation by pushing a test image.
Verification and Diagnostics
A backup is only useful if it can be restored. Verification reduces the chance that your backup is incomplete or corrupt.
Verify Backup Integrity
One quick check is to compare file counts and sizes between the original and backup. While the registry is read-only, run:
find /var/lib/registry -type f | wc -l
(If using a named volume, you may need to exec into a container with that volume mounted.) Then compare with the backup:
tar tzf registry-backup-*.tar.gz | wc -l
The numbers should match exactly. A mismatch suggests files changed during backup or an incomplete archive.
List Repositories After Restore
After restoring to a separate test registry, query the catalog:
curl -s http://localhost:5000/v2/_catalog
Expected output:
{"repositories":["myapp","nginx","redis"]}
Compare this with the original registry's catalog. If any repository is missing, the backup may have been taken from the wrong directory or ignored hidden files.
Diagnose Common Issues
If the registry fails to start after restore, check logs:
docker logs registry
Common errors include permission denials (fix ownership: chown -R 1000:1000 /path/to/data on host, because the registry container runs as UID 1000) and corrupted storage (indicated by level=error msg="error resolving image"). In such cases, restore from an earlier backup.
Failure Modes and Recovery
Registries fail in predictable ways. Knowing these modes helps you respond quickly and accurately.
Failure Mode 1: Container Deleted Accidentally
If you have a volume mount, the data survives. Simply recreate the container with the same volume:
docker run -d -p 5000:5000 --name registry -v registry_data:/var/lib/registry registry:2
The registry will serve the same images. If you had no volume, you must restore from backup.
Failure Mode 2: Host Disk Failure
If the host disk containing the registry data fails, you need to restore the backup to a new disk on a new or repaired host. After provisioning the host:
- Recreate the directory structure and set permissions.
- Extract the backup:
tar xzf registry-backup-*.tar.gz -C /new/data/path - Mount that directory into a new registry container and start it.
Failure Mode 3: Corrupted Storage
Storage corruption can happen due to abrupt power loss or disk errors. Symptoms include 500 errors on pulls and log messages like filesystem: file has vanished. To recover, stop the registry, replace the data directory with the latest backup, and restart. If corruption recurs, investigate disk health immediately.
Failure Mode 4: Incomplete Backup
If a backup was taken while the registry was writable, some blobs may be missing. You can detect this by comparing the backup size with the live data size. Restore may fail partially; in that case, use an older backup and re-push any images that were added after that backup.
Recovery Drill
Run a recovery drill quarterly. Simulate a failure by moving the live data directory aside, restoring from backup, and verifying that docker pull localhost:5000/myapp:latest works. Document the exact steps and time required. This ensures your team can execute recovery under pressure.
Operations Checklist
Use this checklist to maintain a robust backup strategy. Assign a single owner, and review the checklist monthly.
| Step | Action | Owner | Frequency | Expected Success Signal |
|---|---|---|---|---|
| 1 | Verify volume mount is correct | Priya Shah, DevOps Lead | Monthly | docker inspect shows mount at /var/lib/registry |
| 2 | Run backup script | Marcus Chen, SysAdmin | Daily | Archive file created with timestamp, size > 1 MB |
| 3 | Verify backup integrity (file counts match) | Marcus Chen | Weekly | Counts match exactly |
| 4 | Test restore to staging registry | Priya Shah | Monthly | Catalog matches production, pulls succeed |
| 5 | Rotate old backups | Marcus Chen | Monthly | Only last 6 daily and 4 weekly backups retained |
| 6 | Monitor disk space | Automated alert | Continuous | Alert if volume > 80% full |
| 7 | Update documentation with any changes | Priya Shah | As needed | Document reflects current setup |
Each step must have a clear owner, not a team. If Marcus is unavailable, Priya is his backup, but accountability remains with the named owner.
Common Pitfalls and How to Avoid Them
Pitfall 1: Assuming Default Storage is Persistent
Many first-time users run docker run -d -p 5000:5000 registry:2 without a volume. The registry stores data on the container's ephemeral filesystem. When the container is removed, all images are lost.
How to avoid: Always define a volume in your docker run or compose file. Check with docker inspect that the mount is present.
Pitfall 2: Taking Backups While Registry Is Writable
Backing up a live filesystem can result in inconsistent state: an image manifest is saved but its blobs are not, or vice versa. This leads to restore failures.
How to avoid: Enable read-only mode before backup, as described above. If you cannot afford downtime, use filesystem snapshots (e.g., LVM, ZFS) for atomic backups, then copy from the snapshot.
Pitfall 3: Ignoring Permissions on Restore
The registry container runs as UID 1000. If you restore files on the host and they are owned by root, the registry cannot read them, resulting in permission errors.
How to avoid: After extraction, run chown -R 1000:1000 /path/to/registry/data before starting the container.
Pitfall 4: Not Testing Restores
A backup that has never been restored is a hope, not a backup. Corrupt archives, missing files, or changed configurations may only surface during an actual emergency.
How to avoid: Automate a restore test to a staging registry on a schedule. Compare catalogs and pull a set of representative images.
Pitfall 5: Backing Up Only the Data Directory, Forgetting Configuration
If you customize the registry configuration (e.g., authentication, storage backends), those settings are not in the data directory. Losing them means your restored registry may behave differently.
How to avoid: Store your config.yml and compose files in version control. Include them in the backup archive or ensure they are recoverable from Git.
Pitfall 6: Relying on a Single Backup Copy
If the backup resides on the same disk as the registry, a disk failure destroys both. If it is only on one external drive, that drive could fail.
How to avoid: Follow the 3-2-1 rule: three copies, two different media, one offsite. Use cloud object storage for offsite copies.
Conclusion
Docker Registry backup and restore is a critical discipline that protects your software supply chain. By understanding your environment, implementing read-only backups, verifying integrity, and rehearsing recovery, you can prevent data loss and minimize downtime.
Start with a low-risk action: inspect your current registry setup. Is the data on a persistent volume? If not, fix that today. Then implement the backup script in this guide, test a restore, and set up monitoring. These steps move you from reactive panic to proactive resilience.
A reliable workflow makes failure visible, protects sensitive values, limits changes to the intended resource, and defines recovery verification before an incident forces the decision. Assign clear owners, review the checklist monthly, and keep your team prepared for the day you need to use that backup.