A Docker image that performs scheduled, encrypted, deduplicated backups of Docker volumes using BorgBackup.
It is designed to run alongside your existing containers (Docker Compose or Docker Swarm) and periodically back up application data to a remote Borg repository over SSH.
- Incremental, encrypted backups with Borg
- Automated backups via cron
- Optional database dumps:
- MySQL
- MongoDB
- Elasticsearch snapshot support
- Email notification on backup failure
- Supports Docker secrets for sensitive data
- Can be run manually (one-shot backup)
By default, backups are executed via cron inside the container.
- The crontab process is the container main process. Its job runs automatically when the container is started.
- The default schedule is every day at 1AM (UTC). Set your own schedule by setting the
BACKUP_CRON_SCHEDULEenv var (examples below). - You can also run the cron job directly by overriding the command with value
/var/backup_script.sh.
git clone https://github.com/Ovski4/docker-borgbackup-cron.git
cd docker-borgbackup-cron
docker build -t ovski/borgbackup-cron:latest .
- Ensure borg is installed on your remote server.
- Add the public SSH key to
~/.ssh/authorized_keyson your remote server. - Run the container with the required environment variables.
docker run \
-d \
-v /path/to/folder_to_backup:/var/folder_to_backup \
-v /path/to/backup_user_private_key:/var/backup_user_private_key \
-e SSH_KNOWN_HOSTS=my-server.com,27.189.111.145 \
-e SSH_CONNECTION=backup_user@my-server.com \
-e PRIVATE_KEY_PATH=/var/backup_user_private_key \
-e BORG_REPO_PATH=/home/backup_user/borg_repositories \
-e BORG_REPO_NAME=folder_to_backup \
-e BORG_PASSPHRASE=youyouthatsnotgood \
-e LOCAL_FOLDER=/var/folder_to_backup \
-e BACKUP_CRON_SCHEDULE="0 1 * */1 *"
ovski/borgbackup-cronYou can use use https://crontab.guru/ and copy the crontab value in
BACKUP_CRON_SCHEDULE.
-e MYSQL_USER=myuser \
-e MYSQL_DATABASE=mydbname \
-e MYSQL_PASSWORD=mypass \
-e MYSQL_HOST=mysql-e PG_USER=myuser \
-e PG_DATABASE=mydbname \
-e PG_PASSWORD=mypass \
-e PG_HOST=db-e MONGO_PORT=27017 \
-e MONGO_DATABASE=my_mongo_dbname \
-e MONGO_HOST=mongo-e ELASTICSEARCH_PORT=9200 \
-e ELASTICSEARCH_HOST=elasticsearch \
-e ELASTICSEARCH_REPOSITORY=backup-e SMTP_USER=smtpuser@gmail.com \
-e SMTP_PASSWORD=smtppassword \
-e SMTP_PORT=587 \
-e SMTP_HOST=smtp.mailgun.org \
-e MAIL_TO=Test User <user@domain.com> \
-e MAIL_BODY="Backup failed" \
-e MAIL_SUBJECT="Backup job failed. Check container logs for details." \For better security, sensitive values can be provided using Docker secrets instead of environment variables.
Create the following files in /run/secrets (default location):
| Secret file | Environment variable |
|---|---|
| borg_passphrase | BORG_PASSPHRASE |
| mysql_password | MYSQL_PASSWORD |
| pg_password | POSTGRES_PASSWORD |
| smtp_password | SMTP_PASSWORD |
Taking a nextcloud app as an example, here is an excerpt of a docker compose configuration that will backup nextcloud data and create a MySQL dump.
volumes:
mysql:
data:
services:
mysql:
image: mysql
environment:
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/mysql_root_password
MYSQL_USER: nextcloud
MYSQL_DATABASE: nextcloud
MYSQL_PASSWORD_FILE: /run/secrets/mysql_password
volumes:
- mysql:/var/lib/mysql
secrets:
- mysql_root_password
- mysql_password
php:
image: nextcloud
volumes:
- data:/var/www/html
depends_on:
- mysql
nginx:
image: nginx:1.15.8-alpine
...
volumes:
- data:/var/www/html
...
backup_cron:
image: ovski/borgbackup-cron:latest
volumes:
- data:/var/docker_volumes/nextcloud/app/data
environment:
SSH_CONNECTION: backup_user@your.server.net
PRIVATE_KEY_PATH: /run/secrets/backup_server_user_private_key
BORG_REPO_PATH: /home/backup_user/borg_repositories
BORG_REPO_NAME: nextcloud
BACKUP_CRON_SCHEDULE: 30 0 * * * # At 00:30 every day
LOCAL_FOLDER: /var/docker_volumes/nextcloud
MYSQL_USER: nextcloud
MYSQL_DATABASE: nextcloud
MYSQL_PASSWORD_FILE: /run/secrets/mysql_password
SMTP_USER: smtpuser@gmail.com
SMTP_PORT: 587
SMTP_HOST: smtp.mailgun.org
MAIL_TO: Test User <user@domain.com> \
MAIL_SUBJECT: Backup failed
MAIL_BODY: |
Backup for nextcloud app failed.
Run "docker compose logs -f backup_cron" for more information
SSH_KNOWN_HOSTS: your.server.net,38.26.55.241
secrets:
- backup_server_user_private_key
- borg_passphrase
- mysql_password
- smtp_password
secrets:
...
backup_server_user_private_key:
file: secret_backup_server_user_private_key.txt
borg_passphrase:
file: secret_borg_passphrase.txt
mysql_root_password:
file: secret_mysql_root_password.txt
mysql_password:
file: secret_mysql_password.txt
smtp_password:
file: secret_smtp_password.txtTo restore data:
- Connect to the backup server
- Use standard Borg commands:
borg list /path/to/repo
borg extract /path/to/repo::archive_nameRefer to the Borg documentation: https://borgbackup.readthedocs.io/
If the script fails at borg repository initalization with an error such as Load key "/run/secrets/backup_user_private_key": error in libcrypto, Permission denied, please try again., try adding a newline (\n) at the end of the private key file secret.
This image relies on the following Ansible playbooks:
- Borg backup tasks: https://github.com/Ovski4/ansible-playbook-borg-backup.git
- MySQL dump creation: https://github.com/Ovski4/ansible-playbook-mysql-dump.git
- MongoDB dump creation: https://github.com/Ovski4/ansible-playbook-mongo-dump.git
- Elasticsearch snapshot creation: https://github.com/Ovski4/ansible-playbook-elasticsearch-snapshot.git
- SMTP email sending: https://github.com/Ovski4/ansible-playbook-smtp-email.git
Ansible docker base image: https://github.com/Ovski4/docker-ansible