This project is currently a work in progress. Contributions are welcome! Feel free to open a Pull Request.
Services Backup is a tool designed to automate the backup of various services. Currently, it supports the following sources:
- Pterodactyl: A game server management panel.
- MySQL/MariaDB: Popular relational database management systems.
- PostgreSQL: A powerful open-source relational database.
- Rsync: Mirror remote folders over SSH using rsync.
- Local Files: Backup local files and folders with support for exclusion patterns.
And the following storage classes:
- Local Storage: Store backups directly on the local filesystem.
- FTP: A standard network protocol used to transfer files from one host to another over a TCP-based network.
- SFTP: SSH File Transfer Protocol, a secure file transfer protocol that runs over SSH, supporting password and SSH key authentication.
The application also supports alert notifications through:
- Discord: Real-time notifications via Discord webhooks for backup status and errors.
To deploy the application, you can use the provided docker-compose.yaml. The entire deployment can be done directly from the docker-compose file.
- Copy the content of the
docker-compose.yamlfile. - Modify the environment variables directly in the file to match your configuration.
- Run the application using the following command:
docker-compose up -d --buildTo set up a local development environment, you can use the development docker-compose file which includes local FTP and MySQL servers for testing. The entire development environment can be deployed directly from the docker-compose:
- Create a
.envfile based on.env.exampleand fill in your configuration. For the local development environment, the default values should work. - Start the entire development environment (including local FTP, MySQL, and PostgreSQL servers):
docker-compose -f docker-compose-dev.yaml up -d --build
This will start:
- A local FTP server for testing storage functionality
- A local MySQL server with sample databases for testing backup functionality
- A local PostgreSQL server with sample databases for testing backup functionality
- A local rsync target exposed over SSH for testing rsync-based backups
- The application in development mode with hot-reloading
Alternatively, if you prefer to run the application locally while using containerized services:
- Start only the local services:
docker-compose -f docker-compose-dev.yaml up -d --build ftp mysql postgres
2. Install the project dependencies:bash
npm install
3. Run the application in development mode:bash
npm run dev
```
For MySQL/MariaDB and PostgreSQL backup functionality in non-Docker deployments, the system requires:
mysqldumputility (usually included with MySQL/MariaDB client packages)pg_dumputility (usually included with PostgreSQL client packages)rsyncutility available in the runtime environment for rsync-based backups.
Note: Docker deployments already include this dependency in the container.
Here is the list of environment variables you can configure:
| Variable | Description | Default |
|---|---|---|
LOG_LEVEL |
Log level (error, warn, info, http, verbose, debug, silly). | info |
TMP_DIR |
Temporary directory to store backups before uploading. | /tmp |
MAX_BACKUP_PER_ELEMENT |
Maximum number of backups to keep per server/database. | 5 |
MAX_BACKUP_RETENTION_DAYS |
Maximum retention duration in days for backups. | 30 |
PERIODIC_BACKUP_RETENTION_ENABLED |
Enable periodic backup retention to keep specific backups at defined intervals (true or false). |
false |
PERIODIC_BACKUP_RETENTION |
Comma-separated list of time intervals (in minutes) and amounts to keep. Format: interval1:amount1,interval2:amount2. |
(empty) |
The PERIODIC_BACKUP_RETENTION setting allows you to define custom retention policies to keep specific backups at defined time intervals, even if they exceed the normal retention limits.
Format: interval_in_minutes:amount_to_keep
Examples:
-
Keep 1 backup every hour for the last 4 hours:
PERIODIC_BACKUP_RETENTION=60:4 -
Keep 1 backup every day for the last 7 days:
PERIODIC_BACKUP_RETENTION=1440:7 -
Keep 1 backup every week for the last 4 weeks:
PERIODIC_BACKUP_RETENTION=10080:4 -
Complex retention policy (hourly, daily, weekly, monthly):
PERIODIC_BACKUP_RETENTION=60:24,1440:7,10080:4,43800:3This example keeps:
- 24 backups: one for each of the last 24 hour periods
- 7 backups: one for each of the last 7 day periods
- 4 backups: one for each of the last 4 week periods
- 3 backups: one for each of the last 3 month periods
-
Long-term archival policy:
PERIODIC_BACKUP_RETENTION=525600:2,262800:4,43800:6,10080:8,1440:14This example keeps:
- 2 backups: one for each of the last 2 year periods
- 4 backups: one for each of the last 4 six-month periods
- 6 backups: one for each of the last 6 month periods
- 8 backups: one for each of the last 8 week periods
- 14 backups: one for each of the last 14 day periods
Note: When PERIODIC_BACKUP_RETENTION_ENABLED=true, backups that match these retention criteria will be preserved even if they exceed the MAX_BACKUP_PER_ELEMENT or MAX_BACKUP_RETENTION_DAYS limits. The system will keep the most recent backup within each time period defined.
| Variable | Description | Default |
|---|---|---|
BACKUP_PTERODACTYL |
Enable backup for Pterodactyl (true or false). |
true |
PTERODACTYL_URL |
The URL of your Pterodactyl panel. | https://panel.example.com |
PTERODACTYL_API_KEY |
Your Pterodactyl client API key. | ptlc_XXXXXX |
PTERODACTYL_FETCH_AS_ADMIN |
Fetch servers as an administrator (true or false). |
true |
PTERODACTYL_FOLDER_PATH |
Base path to store Pterodactyl backups on the remote storage. | pterodactyl/servers |
| Variable | Description | Default |
|---|---|---|
BACKUP_MYSQL |
Enable backup for MySQL/MariaDB (true or false). |
true |
MYSQL_HOST |
Your MySQL/MariaDB server host. | localhost |
MYSQL_PORT |
Your MySQL/MariaDB server port. | 3306 |
MYSQL_USER |
The username for the MySQL/MariaDB connection. | myuser |
MYSQL_PASSWORD |
The password for the MySQL/MariaDB connection. | mypassword |
MYSQL_POOL_SIZE |
Connection pool size for MySQL/MariaDB. | 5 |
MYSQL_IGNORE_DATABASES |
Comma-separated list of databases to ignore during backup. | information_schema,performance_schema,mysql,sys |
MYSQL_FOLDER_PATH |
Base path to store MySQL backups on the remote storage. | mysql |
MYSQL_SSL_ENABLED |
Enable SSL for MySQL connection (true or false). |
false |
| Variable | Description | Default |
|---|---|---|
BACKUP_POSTGRESQL |
Enable backup for PostgreSQL (true or false). |
false |
POSTGRES_HOST |
Your PostgreSQL server host. | localhost |
POSTGRES_PORT |
Your PostgreSQL server port. | 5432 |
POSTGRES_USER |
The username for the PostgreSQL connection. | myuser |
POSTGRES_PASSWORD |
The password for the PostgreSQL connection. | mypassword |
POSTGRES_DB |
Default database used for the initial connection. | postgres |
POSTGRES_IGNORE_DATABASES |
Comma-separated list of databases to ignore during backup. | template0,template1 |
POSTGRES_FOLDER_PATH |
Base path to store PostgreSQL backups on the remote storage. | postgresql |
POSTGRES_SSL_ENABLED |
Enable SSL for PostgreSQL connection (true or false). |
false |
POSTGRES_SSL_REJECT_UNAUTHORIZED |
Reject self-signed certificates when SSL is enabled (true). |
true |
| Variable | Description | Default |
|---|---|---|
BACKUP_RSYNC |
Enable rsync-based backups (true or false). |
false |
RSYNC_FOLDER_PATH |
Base path to store rsync archives on the remote storage. | rsync |
RSYNC_TARGET_NAME |
Friendly name for the rsync target (defaults to host when empty). | remote-server |
RSYNC_TARGET_HOST |
Remote host to sync from. Supports IPv4 and IPv6. | (empty) |
RSYNC_TARGET_USER |
SSH user for the remote host. | (empty) |
RSYNC_TARGET_PORT |
SSH port for the remote host. | 22 |
RSYNC_TARGET_PATH |
Remote directory to mirror. | (empty) |
RSYNC_SSH_KEY_PATH |
Optional path to the private SSH key used by rsync. | (empty) |
RSYNC_EXCLUDES |
Comma-separated list of patterns ignored during sync (e.g. node_modules,tmp). |
(empty) |
RSYNC_SSH_OPTIONS |
Additional SSH options appended to the rsync SSH command. Useful for disabling host key checks during testing. | (empty) |
RSYNC_EXTRA_ARGS |
Additional rsync arguments (space separated, double quotes supported for paths or arguments that contain spaces) | (empty) |
The rsync backup service supports two different backup modes depending on the path configuration:
Single Backup Mode (without /*):
When RSYNC_TARGET_PATH does not end with /*, the entire directory content is backed up as a single archive with a timestamp. A new backup is created at each execution.
RSYNC_TARGET_PATH=/var/www/mysiteResult:
- Creates:
mysite-2026-02-16-14-30-00.tar.gz - Behavior: New backup at each execution
- Storage:
rsync/mysite/mysite-2026-02-16-14-30-00.tar.gz
Multi-Backup Mode (with /*):
When RSYNC_TARGET_PATH ends with /*, each file and subdirectory is backed up individually without timestamp. This prevents duplicate backups: if a backup already exists for an item, it is skipped.
RSYNC_TARGET_PATH=/var/www/*Result (assuming /var/www/ contains site1, site2, site3):
- Creates:
site1.tar.gz,site2.tar.gz,site3.tar.gz - Behavior: Backup only created if file doesn't exist
- Storage:
rsync/target-name/site1/site1.tar.gz,rsync/target-name/site2/site2.tar.gz, etc.
Use Cases:
- Single mode: For backing up a complete application with versioning (database backups, complete application snapshots)
- Multi mode: For backing up multiple independent sites/projects where you only want to backup once and skip duplicates (web hosting directories, user folders)
The default development .env values point RSYNC_TARGET_HOST to this container (rsync) and mount the generated SSH private key at /app/docker_keys/id_ed25519. The files served over rsync live in docker/rsync/data.
To generate the development key pair, run the helper script and recreate the container:
bash docker/rsync/generate-keys.sh
docker compose -f docker-compose-dev.yaml build rsync
docker compose -f docker-compose-dev.yaml up -d rsync| Variable | Description | Default |
|---|---|---|
BACKUP_LOCAL_FILES |
Enable backup for local files and folders (true or false). |
false |
LOCAL_FILES_PATH |
Absolute path to the file or folder to backup. | (empty) |
LOCAL_FILES_IGNORE |
Comma-separated list of patterns to exclude from the archive (e.g., *.log,cache/*). |
(empty) |
LOCAL_FILES_FOLDER_PATH |
Base path to store local files backups on the remote storage. | local-files |
LOCAL_FILES_TMP_DIR |
Temporary directory to create archives before uploading. | /tmp/local-files-backups |
The local files backup service allows you to backup a single file or directory with optional exclusion patterns.
Example 1: Backup a single folder
BACKUP_LOCAL_FILES=true
LOCAL_FILES_PATH=/etc/myappExample 2: Backup with exclusions
BACKUP_LOCAL_FILES=true
LOCAL_FILES_PATH=/home/user/Documents
LOCAL_FILES_IGNORE=*.log,*.tmp,cache/*,node_modulesExample 3: Docker configuration
services:
services-backup:
environment:
- BACKUP_LOCAL_FILES=true
- LOCAL_FILES_PATH=/data
- LOCAL_FILES_IGNORE=*.log,temp/*
volumes:
- /path/to/backup:/data:ro| Variable | Description | Default |
|---|---|---|
STORAGE_TYPE |
The storage type to use. Supported: ftp, sftp, local. |
local |
LOCAL_STORAGE_PATH |
Path to store backups when using local storage. | backups |
FTP_HOST |
Your FTP server host. | localhost |
FTP_PORT |
Your FTP server port. | 21 |
FTP_USER |
The username for the FTP connection. | myuser |
FTP_PASSWORD |
The password for the FTP connection. | mypassword |
SFTP_HOST |
Your SFTP server host. | localhost |
SFTP_PORT |
Your SFTP server port. | 22 |
SFTP_USER |
The username for the SFTP connection. | myuser |
SFTP_PASSWORD |
The password for the SFTP connection (if not using SSH key). | (empty) |
SFTP_PRIVATE_KEY_PATH |
Path to the SSH private key file for SFTP authentication. | (empty) |
SFTP_PASSPHRASE |
Optional passphrase for the SSH private key. | (empty) |
You must also set LOCAL_STORAGE_PATH to the directory where backups will be stored.
When using Docker, mount a volume to persist your backups:
services:
services-backup:
...
environment:
- STORAGE_TYPE=local
- LOCAL_STORAGE_PATH=/backups
volumes:
- ./backups:/backupsBackups will be saved in the ./backups directory on the host machine.
You must set the FTP connection details:
services:
services-backup:
...
environment:
- STORAGE_TYPE=ftp
- FTP_HOST=ftp.example.com
- FTP_PORT=21
- FTP_USER=myuser
- FTP_PASSWORD=mypasswordSFTP storage supports two authentication methods:
1. Password authentication:
services:
services-backup:
...
environment:
- STORAGE_TYPE=sftp
- SFTP_HOST=sftp.example.com
- SFTP_PORT=22
- SFTP_USER=myuser
- SFTP_PASSWORD=mypassword2. SSH Key authentication (recommended):
services:
services-backup:
...
environment:
- STORAGE_TYPE=sftp
- SFTP_HOST=sftp.example.com
- SFTP_PORT=22
- SFTP_USER=myuser
- SFTP_PRIVATE_KEY_PATH=/app/ssh/id_rsa
- SFTP_PASSPHRASE=optional_key_passphrase # Only if your key is encrypted
volumes:
- ./ssh-keys:/app/ssh:roNote: SSH key authentication is preferred over password authentication for better security. The SSH key file should be mounted as read-only (:ro) and have appropriate permissions (600).
| Variable | Description | Default |
|---|---|---|
ALERT_SERVICE_ENABLED |
Enable alert notifications (true or false). |
false |
ALERT_AFTER_PROCESS |
Send alerts after each backup process (true or false). |
false |
ALERT_DISCORD_ENABLED |
Enable Discord alerts (true or false). |
false |
DISCORD_ALERT_WEBHOOK_URL |
Discord webhook URL for sending alert notifications. | (empty) |
DISCORD_ALERT_EVERYONE_ON_ERROR |
Mention everyone in Discord on error alerts (true or false). |
false |
| Variable | Description | Default |
|---|---|---|
ENCRYPTION_ENABLED |
Enable GPG encryption for backup files (true or false). |
false |
ENCRYPTION_PUBLIC_KEY_PATH |
Path to the GPG public key file for encrypting backups. | /app/public.asc |
Services Backup supports GPG encryption for all backup files. When enabled, all backup files are automatically encrypted using GPG before being stored.
To use encryption, you need to generate a GPG key pair. Here are the commands to create, export, and manage your GPG keys:
# Generate a new key pair interactively
gpg --full-generate-key
# Or use batch mode for automation
gpg --batch --generate-key <<EOF
%echo Generating GPG key for Services Backup
Key-Type: RSA
Key-Length: 4096
Subkey-Type: RSA
Subkey-Length: 4096
Name-Real: Services Backups
Name-Comment: Backups
Name-Email: backup@test.com
Expire-Date: 0
Passphrase: your_secure_passphrase_here
%commit
%echo Done
EOF# List all keys
gpg --list-keys
# List secret keys
gpg --list-secret-keysExport public key (replace with your key ID or email)
gpg --armor --export backup@test.com > public.ascExport private key (replace with your key ID or email)
gpg --armor --export-secret-keys backup@test.com > private.ascWhen using Docker, you need to mount the GPG key files and configure the environment variables:
services:
services-backup:
image: ghcr.io/hugoheml/services-backup:latest
environment:
# Encryption settings
- ENCRYPTION_ENABLED=true
- ENCRYPTION_PUBLIC_KEY_PATH=/app/keys/public.asc
# Other environment variables...
- STORAGE_TYPE=local
- LOCAL_STORAGE_PATH=/backups
volumes:
# Mount your GPG keys
- ./keys:/app/keys:ro
# Mount backup storage
- ./backups:/backupsDirectory structure:
.
├── docker-compose.yaml
├── keys/
│ ├── public.asc # Your GPG public key
│ └── private.asc # Your GPG private key
└── backups/ # Backup storage directory
Note: The keys directory is mounted as read-only (:ro) for security. Make sure the key files have appropriate permissions (readable by the container user).
To decrypt your backup files, you can use the following methods:
Decrypt a single backup file
gpg --decrypt backup-file.gz.asc > backup-file.gzDecrypt with specific private key
gpg --decrypt --secret-keyring ./private.asc backup-file.gz.asc > backup-file.gzFor batch decryption with passphrase
echo "your_passphrase" | gpg --batch --yes --passphrase-fd 0 --decrypt backup-file.gz.asc > backup-file.gzWarn: This method expose your passphrase in your bash history.
Here are the features planned for future releases:
- Add more detailed error messages, especially for misconfigured environment variables.
- Add a maximum storage threshold to avoid filling up the storage space.
- Add more alert systems for backup failures.
- Add support for more services and storage classes.
- Make some tutorials for backuping some services
- Rework the files organization (especially in
services/folder).