If you run Docker containers on a Linux VPS and have not set up a real backup yet, this guide is for you. You will learn step by step how to back up Docker volumes to S3 or MinIO using Restic, an open-source backup tool that handles encryption, deduplication, and scheduling all in one place. Whether you push backups to AWS S3 or your own self-hosted MinIO server, the process is almost the same.
How to Back Up Docker Volumes to S3 or MinIO with Restic on a Linux VPS
Table of Contents
- What Is Restic and Why Use It for Docker?
- Prerequisites to Back Up Docker Volumes to S3 or MinIO
- Step 1. Install Restic on Your Linux VPS
- Step 2. Prepare Your S3 or MinIO Bucket
- Step 3. Set Up Your Environment Variables
- Step 4. Initialize the Restic Repository
- Step 5. Understand Named Volumes vs Bind Mounts
- Step 6. Turn Off Databases Before Backing Up
- Step 7. Write the Backup Script
- Step 8. Set a Retention Policy
- Step 9. Schedule with Systemd Timer
- Step 10. Test Your Restore
- Conclusion

What Is Restic and Why Use It for Docker?
Restic is a fast and modern backup program that works on Linux, stores backups as encrypted snapshots, and supports any S3-compatible object storage as a backend. It only uploads the parts of files that changed since the last backup, so after the first run, daily backups are very fast and use little extra storage.
For Docker, this matters because:
- Named volumes live under /var/lib/docker/volumes/ and are not backed up automatically.
- Bind mounts live on a host path you control, but those paths are still not protected unless you have a backup plan.
- Restic turns both types into encrypted, versioned snapshots you can restore in minutes.
Note: This guide focuses on backing up Docker volume data directly to an S3 or MinIO bucket. If your goal is backing up a whole server or multiple directories over SFTP to a Storage VPS, check the Restic Backup to Storage VPS guide instead, which covers a different target, including SFTP and Storage VPS.
Prerequisites to Back Up Docker Volumes to S3 or MinIO
Before you start, make sure you have:
A Linux VPS running Ubuntu, Debian, Rocky Linux, or AlmaLinux with Docker installed. You can easily get your server running from PerLod Linux VPS Hosting.
Root or sudo access to the server.
Either an AWS S3 bucket with an access key and secret key, or a self-hosted MinIO server with a bucket and credentials ready.
Step 1. Install Restic on Your Linux VPS
Restic is available in the default package repositories of most major Linux distributions.
On Ubuntu or Debian, you can install Restic with:
On Rocky Linux or AlmaLinux, you can use:
After installing, run the self-update command to make sure you have the latest version:
Confirm it works:
Step 2. Prepare Your S3 or MinIO Bucket
You need a bucket before Restic can initialize a repository. The steps have some differences depending on which backend you use.
Option A: AWS S3
- Log in to your AWS console and go to the S3 service.
- Create a new bucket, for example, my-docker-backups.
- Create an IAM user with the following permissions on that bucket:
s3:ListBuckets3:PutObjects3:GetObjects3:DeleteObject
- Save the Access Key ID and Secret Access Key for the next step.
Option B: Self-Hosted MinIO
Self-hosted MinIO is one of the best ways to back up Docker volumes to S3 or MinIO without relying on AWS. If you do not have MinIO set up yet, the Self-Hosting MinIO guide shows the full install process.
Also, you can put MinIO behind HTTPS with the Run MinIO Behind an HTTPS Reverse Proxy guide, which is strongly recommended for production use.
Once MinIO is running:
- Open the MinIO web console at
http://YOUR_SERVER_IP:9001. - Log in with your root credentials.
- Go to Buckets > Create Bucket and name it, for example, docker-backups.
- Go to Identity > Users > Create User, create a dedicated backup user.
- Create a policy that allows ListBucket, PutObject, GetObject, and DeleteObject on your bucket.
- Attach that policy to your backup user.
- Save the access key and secret key.
Also, you can do this from the command line with the mc client tool:
Step 3. Set Up Your Environment Variables
It is always recommended to store the credentials in a dedicated environment file that only root can read.
Create the file with your desired text editor:
For AWS S3, add:
For self-hosted MinIO, add:
Important Note: If MinIO is behind HTTPS, use https:// in the URL instead of http://. Restic uses path-style S3 URLs; the bucket name comes after the endpoint, not as a subdomain. This applies whether you back up Docker volumes to S3 or MinIO; the URL format is the only real difference.
Then, restrict the file permissions with:
Step 4. Initialize the Restic Repository
In this step, Restic creates the repository structure in your bucket and sets up the encryption keys. You can use the commands below to load your variables and run init:
In the output, you should see something similar to this:
Note: Do not lose your RESTIC_PASSWORD. If you lose it, your backups are permanently unreadable. Restic's encryption means nobody can recover data without the password.
Step 5. Understand Named Volumes vs Bind Mounts
Before writing your backup script, you need to know what kind of volumes your containers use.
Named Volumes
These are managed by Docker and stored at /var/lib/docker/volumes/ on the host. You can list them with:
To find the exact path of a specific volume:
To back up Docker volumes to S3 or MinIO, you can easily point Restic at the parent directory:
Bind Mounts
If your docker-compose.yml uses a path like ./data:/app/data or /opt/myapp:/app/data, that path on the host is your backup target. You can back up Docker volumes to S3 or MinIO for bind mounts just as easily:
Step 6. Turn Off Databases Before Backing Up
This is one of the most important things you must consider. Never back up database volume files while the database container is running. Copying live PostgreSQL or MySQL data files will produce a corrupted backup. This is true regardless of whether you back up Docker volumes to S3 or MinIO; this step is always required for databases.
For this purpose, you have two safe options:
Option A: Stop the Container First (Safest)
This guarantees a clean backup at the cost of a short downtime window.
Option B: Use a Database Dump (No Downtime)
For PostgreSQL, you can run a dump inside the container and back up the dump file:
For MySQL:
For MongoDB:
Option B is recommended for production because it keeps services running while still providing a consistent, restorable snapshot.
Step 7. Write the Backup Script
At this point, you can put all things together in one script. Create the script file with:
Paste the following content and adjust the paths and container names to match your setup:
Once you are done, save and close the file. Make it executable and restrict permissions:
Test it manually with the command below:
Step 8. Set a Retention Policy
The restic forget command removes old snapshots based on the rules you define. The --prune flag tells Restic to delete the actual data that those snapshots referenced.
The script above uses a solid default policy, including:
You can run restic forget --dry-run with the same flags to see what would be deleted before actually deleting anything.
Step 9. Schedule with Systemd Timer
Systemd timers are more reliable than plain cron because they log to the journal, handle missed runs, and give you clear status information.
Create the service unit file with:
Add:
Create the timer unit file:
Add:
Once you are done, enable and start the timer:
Check the timer status:
View the backup logs:
Step 10. Test Your Restore
A backup you have never tested is not a backup. You can run a restore test to confirm everything works.
First, list all snapshots with:
Restore the latest snapshot to a test directory:
Restore a specific snapshot by ID:
To actually restore a volume for a live app, you must:
Run a repository integrity check:
For deeper verification, you can run the command below to read all data blocks from the bucket:
For this setup to run consistently, you need a VPS with stable uptime and enough disk to handle staging database dumps before they are sent to the bucket. For larger setups with heavy Docker workloads, a high-performance dedicated server gives you more CPU, RAM, and storage space to run backup jobs without affecting your production containers.
Conclusion
Setting up a reliable way to back up Docker volumes to S3 or MinIO with Restic is one of the most useful things you can do for any self-hosted stack. Once the environment file is in place and the first restic init succeeds, everything else, including daily snapshots, retention cleanup, and restore testing, runs automatically with minimal overhead.
We hope you enjoy this guide. If you want to go deeper on S3 backend options and advanced repository settings, the Restic Official Documentation for Amazon S3 Backend is a good option.
Only for databases. For regular app data, you can back up Docker volumes to S3 or MinIO while containers are running without issue. For PostgreSQL, MySQL, or MongoDB, use a dump or stop the container first to get a consistent backup.
forget removes the snapshot record. prune removes the actual data blocks no longer referenced by any snapshot. Run them together using restic forget --prune to free up storage on your S3 or MinIO bucket.
Restic supports multiple hosts writing to the same repository. Each snapshot is tagged with a hostname, so they do not overwrite each other. However, for simplicity, separate repositories per server are usually easier to manage.