In this article we’ll look at how to set up daily backups of Docker volumes, pushing them to S3 storage with notifications via Email and Telegram. We’ll use Offen/docker-volume-backup as our tool.
Sample Docker Compose Configuration
Create a docker-compose.yml file with the following contents:
version: '3.8'
services:
postgres:
image: postgres:15
volumes:
- pg_data:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: example
restart: unless-stopped
backup:
image: offen/docker-volume-backup:latest
restart: unless-stopped
depends_on:
- postgres
volumes:
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
- pg_data:/backup/pg_data:ro
- /var/run/docker.sock:/var/run/docker.sock
environment:
# Schedule configuration (every day at 2:00)
BACKUP_CRON_EXPRESSION: "0 2 * * *"
# Volumes to back up
BACKUP_SOURCES: "/backup/pg_data"
# S3 configuration
AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}
AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY}
AWS_S3_BUCKET_NAME: ${AWS_S3_BUCKET_NAME}
AWS_ENDPOINT: ${AWS_ENDPOINT}
# Email notifications
# NOTIFICATION_URLS: "smtp://${SMTP_USERNAME}:${SMTP_PASSWORD}@${SMTP_HOST}:${SMTP_PORT}/?fromAddress=${SMTP_FROM}&toAddresses=${TO_SENT_EMAIL}"
# Telegram notifications
NOTIFICATION_LEVEL: "info"
NOTIFICATION_URLS: "telegram://${TELEGRAM_TOKEN}@telegram?chats=${TELEGRAM_USER_ID}"
# Additional settings
BACKUP_FILENAME: "backup-$(date +%Y-%m-%d).tar.gz"
BACKUP_RETENTION_DAYS: 7
volumes:
pg_data:
To store variables securely, use environment variables or a .env file in the same folder as your docker-compose.yaml file.
Example .env file:
SMTP_PORT="465"
SMTP_HOST="smtp.example.com"
SMTP_FROM="noreply@example.com"
SMTP_USERNAME="noreply@example.com""
SMTP_PASSWORD="strongpPassword"
TO_SENT_EMAIL="backups@example.com"
AWS_ACCESS_KEY_ID="asdfjksaghdf"
AWS_SECRET_ACCESS_KEY="sakjdfjkl"
AWS_S3_BUCKET_NAME="docker-backup"
AWS_ENDPOINT="s3.aws.com"
TELEGRAM_TOKEN="sadnljkhjlkf"
TELEGRAM_USER_ID="21341234"
Configuration Explained
1. Application service (PostgreSQL)
- Uses the
pg_datavolume to store its data. - The volume will be available read-only to the backup service.
2. Backup service
- Schedule:
BACKUP_CRON_EXPRESSIONsets the daily run at 2:00. - S3 storage: Provide your AWS keys, bucket name and region.
- Notifications:
- Email: Uses an SMTP server with authentication parameters.
- Telegram:
- Replace TELEGRAM_TOKEN with your bot’s token.
- TELEGRAM_USER_ID can be obtained via @userinfobot in Telegram.
- Backup retention:
BACKUP_RETENTION_DAYSautomatically deletes old copies.
Setting Up Notifications
For Telegram:
- Create a bot through @BotFather and get the token.
- Find out the chat ID via @userinfobot.
- Specify the parameters in the format:
NOTIFICATION_URL="telegram://<YOUR_BOT_TOKEN>@telegram/?chats=<YOUR_CHAT_ID>"
Starting the System
- Replace all variables (AWS_SECRET_ACCESS_KEY, TELEGRAM_TOKEN, etc.) with real values.
- Run the command:
docker-compose up -d
- To test, run a backup manually:
docker-compose exec backup backup
Benefits of This Solution
- Automation: Daily backups with no manual intervention.
- Reliability: Storage in S3 with versioning and lifecycle rules.
- Monitoring: Instant notifications about the status of operations.
- Flexibility: Encryption support (add
BACKUP_ENCRYPTION_KEYto enable backup encryption).
By using this approach, you’ll protect your Docker applications’ data from loss. Additional settings (for example, backups to multiple storage targets) can be found in the official documentation.
BONUS
Encrypting and Decrypting Backups in Offen/docker-volume-backup
Offen/docker-volume-backup supports end-to-end encryption of backups using the AES-256-GCM algorithm. This protects your data even if the S3 storage is compromised.
1. Setting Up Encryption
Step 1: Generate a key
The key must be a 32-byte string in Base64 or Hex format. Example generation:
# Generate in Base64
openssl rand -base64 32 > backup-key.txt
# Or in Hex
openssl rand -hex 32 > backup-key.txt
Step 2: Add the key to the configuration
In the backup service of the docker-compose.yml file, specify:
environment:
BACKUP_ENCRYPTION_KEY: "file:/backup-key.txt" # Path inside the container
# Or directly (not recommended for production):
# BACKUP_ENCRYPTION_KEY: "your-encryption-key-in-base64-or-hex"
Step 3: Mount the key
Add a volume for the key file:
volumes:
- ./backup-key.txt:/backup-key.txt:ro
2. How It Works
- The archive is encrypted before being sent to S3
- A hybrid scheme is used:
- A random data encryption key (DEK) is generated for each backup
- The DEK is encrypted with the master key (BACKUP_ENCRYPTION_KEY)
- The encrypted DEK is stored in the archive’s metadata
- Algorithm: AES-256-GCM (authenticated encryption)
3. Decrypting Backups
Option 1: Via the docker-volume-backup utility
docker run --rm -v /path/to/backup.tar.gz.gpg:/backup.tar.gz.gpg \
-v /path/to/backup-key.txt:/backup-key.txt \
offen/docker-volume-backup:latest decrypt \
--input /backup.tar.gz.gpg \
--output /backup.tar.gz \
--key-file /backup-key.txt
Option 2: Manually with OpenSSL
For a key in Hex format:
openssl enc -d -aes-256-gcm \
-in backup.tar.gz.gpg \
-out backup.tar.gz \
-K "$(cat backup-key.txt)" \
-iv <(head -c 16 backup.tar.gz.gpg) \
-aad <(tail -c +17 backup.tar.gz.gpg | head -c 24)
4. Important Considerations
- Key storage:
- Never commit the key to Git
- Use Docker secrets or a KMS (AWS Secrets Manager, HashiCorp Vault)
- Rotate keys regularly (but old backups will require the old keys!)
- Metadata:
- File names in S3 are not encrypted
- For full anonymization, use
BACKUP_FILENAME_ENCRYPTED=true
Performance:
Test data: 1 GB
Encryption: ~15 sec (on an Intel i7 CPU)
Decryption: ~12 sec
5. Full Configuration Example
services:
backup:
image: offen/docker-volume-backup:latest
environment:
BACKUP_ENCRYPTION_KEY: "file:/secrets/backup-key.txt"
BACKUP_FILENAME_ENCRYPTED: "true" # Random file name
volumes:
- ./secrets/backup-key.txt:/secrets/backup-key.txt:ro
6. Recovery Scenarios
If the key is lost:
- The data cannot be recovered
- Solution:
- Store the key in 3 places (USB drive, paper copy, cloud)
- Use hardware HSMs for enterprise solutions
If the key is compromised:
- Generate a new key
- Re-encrypt old backups with the new key
- Remove the old key from all systems
Recommendations
- Test your restore process before an incident
- Use different keys for different environments (prod/stage/dev)
- Enable versioning in S3 to protect against ransomware attacks
Encryption in Offen/docker-volume-backup provides enterprise-grade protection with minimal configuration. The key thing is to keep your keys safe!