Mahbubur Riad
Back to blog
DevOps 5 min read

Automating Multi-Container Backup and Restore with Docker Compose and Restic on a Low-Cost VPS

Jun 25, 2026 · Mahbubur Riad

Stop risking your data. Learn how to set up encrypted, automated backups for Docker Compose services using Restic on a budget VPS.

On this page

If you are running a few self-hosted services on a budget VPS—think Nextcloud, Ghost, or a custom API with a PostgreSQL database—you know the anxiety of the "what if" scenario. What if the provider has a catastrophic failure? What if you run a docker-compose down -v by mistake?

Traditional tar backups or simple rsync scripts are fine for a single file, but they fall apart when you have multiple containers, database locks, and the need for encryption.

That is where Restic comes in. It is a fast, secure, and efficient backup program that supports deduplication and encryption by default. In this guide, I'll show you how to orchestrate a backup system that handles multiple Docker Compose services and ships the data off-site.

Why Restic instead of simple scripts?

When managing a VPS, you have limited CPU and RAM. You can't afford a backup solution that eats 2GB of RAM just to compress a folder. Restic is written in Go and is incredibly lightweight.

Feature Tar/Rsync Restic
Deduplication None (unless using hard links) Native (saves massive space)
Encryption Manual (GPG/OpenSSL) Built-in (AES-256)
Snapshots Full copies every time Incremental snapshots
Off-site Support SSH/FTP S3, B2, Azure, SFTP, Local
Integrity Check Manual checksums Built-in check command

The Architecture

We aren't going to install Restic inside every single container. That would be a nightmare to maintain. Instead, we will run Restic on the host machine. Since Docker Compose usually maps volumes to the host filesystem (e.g., ./data:/var/lib/mysql), Restic can simply back up those host directories.

For the storage backend, I recommend Backblaze B2 or an S3-compatible bucket. They are dirt cheap and keep your backups physically separate from your VPS.

Step 1: Installing Restic on the Host

First, let's get Restic installed on your Ubuntu/Debian VPS.

Bash
sudo apt update
sudo apt install restic -y

Verify the installation:

Bash
restic version

Step 2: Configuring the Remote Storage

For this tutorial, I'll use an S3-compatible backend, but the process is similar for B2 or SFTP. You need to set environment variables so Restic knows where to push the data.

Create a backup environment file to keep things clean:

Bash
sudo nano /etc/restic/env.conf

Add the following (replace with your actual credentials):

Bash
# The location of your backup repository
export RESTIC_REPOSITORY="s3:http://your-s3-endpoint/backup-bucket"
# Your S3 Access Key
export AWS_ACCESS_KEY_ID="your-access-key"
# Your S3 Secret Key
export AWS_SECRET_ACCESS_KEY="your-secret-key"
# Encryption password (KEEP THIS SAFE!)
export RESTIC_PASSWORD="a-very-strong-random-password"

Now, initialize the repository. This creates the structure on your remote storage:

Bash
source /etc/restic/env.conf
restic init

Step 3: Handling Database Consistency

This is the most critical part. You cannot simply copy a running database file (like MySQL or Postgres) because the data might be in flux, leading to a corrupted backup.

The "Correct" way is to trigger a dump before the backup. We can do this using a small bash script that tells Docker to execute a dump command inside the container.

Create a script called /opt/backup-prep.sh:

Bash
#!/bin/bash

# Backup PostgreSQL
docker exec postgres_container_name pg_dumpall -U postgres > /tmp/postgres_dump.sql

# Backup MariaDB/MySQL
docker exec mysql_container_name mysqldump -u root -p'password' --all-databases > /tmp/mysql_dump.sql

# Add any other services that need a dump here

Make it executable:

Bash
sudo chmod +x /opt/backup-prep.sh

Step 4: The Automation Script

Now we create the main backup wrapper. This script will:

  1. Load the Restic credentials.
  2. Run the database dump script.
  3. Back up the Docker volume directories.
  4. Prune old backups to save space.

Create /opt/docker-backup.sh:

Bash
#!/bin/bash

# Load Restic environment variables
source /etc/restic/env.conf

# 1. Prepare database dumps
/opt/backup-prep.sh

# 2. Run the backup
# We back up the folder where your docker-compose.yml and data folders live
restic backup /home/user/docker-stacks/ \
             /tmp/postgres_dump.sql \
             /tmp/mysql_dump.sql

# 3. Cleanup: Keep the last 7 daily, 4 weekly, and 6 monthly backups
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune

# 4. Optional: Check for corruption
restic check

Make it executable:

Bash
sudo chmod +x /opt/docker-backup.sh

Step 5: Scheduling with Cron

We want this to run automatically every night at 3 AM.

Open the crontab editor:

Bash
sudo crontab -e

Add this line to the bottom:

CRON
0 3 * * * /opt/docker-backup.sh >> /var/log/docker-backup.log 2>&1

Step 6: The Restore Procedure (The "Panic" Guide)

Backing up is useless if you don't know how to restore. There are two types of restores: full and selective.

Full Restore

To restore everything to the original location:

Bash
source /etc/restic/env.conf
restic restore latest --target /

Selective Restore

If you only need a specific folder or a specific database dump from three days ago:

  1. List snapshots to find the ID:
    Bash
    restic snapshots
    
  2. Restore a specific path from a specific snapshot:
    Bash
    restic restore snapshot_id:/home/user/docker-stacks/app1 --target /tmp/restore-app1
    

Practical Checklist for Sysadmins

Before you consider your backup system "done," run through this checklist:

  • Test the Restore: Have you actually tried restoring a file to a temporary folder?
  • Verify Encryption: Do you have the RESTIC_PASSWORD stored in a password manager (Bitwarden/KeePass)? If you lose this, your backups are useless.
  • Monitor Logs: Check /var/log/docker-backup.log after the first 24 hours to ensure the cron job fired correctly.
  • Off-site Check: Log into your S3/B2 console and verify that files are actually appearing in the bucket.
  • Permission Check: Ensure the user running the cron job has read access to the Docker volume folders.

FAQ

Q: Does Restic slow down my VPS during the backup? A: Restic is very efficient, but the initial backup (the "full" one) can be CPU intensive. Subsequent backups only upload changed blocks (deduplication), which is very light on resources.

Q: Should I run Restic inside a Docker container? A: You can, but for a low-cost VPS, running it on the host is simpler. It avoids the "Docker-in-Docker" complexity and gives the tool direct access to the mapped volumes.

Q: How do I handle very large files (like 50GB media libraries)? A: Restic handles large files well via chunking. However, if you have terabytes of data, consider using a dedicated backup server or increasing your S3 upload bandwidth.

Q: Is it safe to store the password in /etc/restic/env.conf? A: It is acceptable if the file permissions are locked down (chmod 600). For higher security, you can use a secret management tool or pass the password via a pipe.

Q: What happens if the VPS crashes mid-backup? A: Restic is designed to be atomic. If a backup is interrupted, it simply won't create a new snapshot. The previous snapshots remain intact and usable.

Final Thoughts

Setting up a robust backup system doesn't require an enterprise budget. By combining the orchestration of Docker Compose, the efficiency of Restic, and the affordability of S3 storage, you can sleep soundly knowing your data is encrypted and safe.

If you found this guide helpful, I share more practical DevOps and system administration tips over at mahbuburriad.com. Keep your data safe and your uptime high.

Related

Related posts