Setting up BorgBackup on a VPS for Encrypted and Deduplicated Backups
TL;DR
In this detailed guide, we will set up the BorgBackup backup system on your VPS server step-by-step. You will learn how to create secure, encrypted, and deduplicated backups of important data, as well as automate the process and ensure their reliable storage. This solution is ideal for protecting configurations, databases, user files, and other critically important data with minimal disk space and bandwidth consumption.
Setting up BorgBackup for creating encrypted and deduplicated backups.
Using SSH for secure access to a remote Borg repository.
Automating the backup process using cron scripts.
Implementing backup retention policies (pruning) to save space.
Verifying integrity and restoring data from backups.
Ensuring server and data security at all stages.
What We Are Setting Up and Why
Diagram: What We Are Setting Up and Why
Setting up a reliable backup system is the cornerstone of any infrastructure, be it a small personal project or a complex SaaS service. In this tutorial, we will focus on BorgBackup — a powerful tool for creating encrypted and deduplicated backups. It allows for efficient storage of multiple data versions, occupying significantly less space than traditional methods, thanks to smart block-level deduplication.
Ultimately, you will get a fully automated system that regularly creates backups of your data (files, databases, configurations), stores them in an encrypted form, and allows for easy restoration in case of unforeseen situations. This is critically important for protecting against data loss due to errors, hardware failures, cyberattacks, or accidental deletion.
There are alternatives, such as cloud services (e.g., AWS Backup, Google Cloud Backup) or managed solutions from hosting providers. However, a self-hosted solution on a VPS gives you full control over your data, its encryption, storage location, and cost. For many developers, startups, and crypto enthusiasts who value privacy and control, this is the preferred choice. You are not dependent on third-party service pricing plans, you can configure any retention policies, and you can be confident in the security of your data, as the encryption keys are solely in your possession.
What VPS Configuration is Needed for This Task
Diagram: What VPS Configuration is Needed for This Task
The VPS requirements for BorgBackup are relatively low if it is used as a backup source (client) or as storage for small data volumes. However, if you plan to store significant data volumes on it or use it as a central repository for multiple servers, the requirements increase.
Minimum Requirements for a BorgBackup Client (the server from which backups are made):
CPU: 1 core (any modern x86-64 processor). The backup creation process can be CPU-intensive due to encryption and deduplication, but these are usually short-term peaks.
RAM: 1 GB. BorgBackup can consume up to several hundred megabytes of RAM during backup creation and verification operations, especially when processing very large files or repositories.
Disk: 20-40 GB NVMe/SSD. Sufficient for the operating system, BorgBackup itself, and temporary files. The main data will be stored in a remote repository.
Network: 100 Mbps. For data transfer to a remote repository. Speed can be important if a large volume of data is being backed up.
Minimum Requirements for a BorgBackup Repository Server (the server where backups are stored):
CPU: 1-2 cores. For processing client requests, deduplication, and encryption/decryption.
RAM: 2-4 GB. Borg actively uses RAM for caching indexes when working with a repository. The larger the repository, the more RAM may be required. For multi-terabyte repositories, 8 GB or more may be needed.
Disk: From 100 GB to several TB NVMe/SSD/HDD. Disk space entirely depends on the volume of data you plan to back up and its retention period. For optimal performance, SSD is preferable for Borg indexes, but the data itself can be stored on HDD. For most tasks related to backing up web servers or small databases, 200-500 GB will be sufficient.
Network: 100 Mbps - 1 Gbps. High network bandwidth is critical for fast backup creation and restoration, especially if you have many clients or large data volumes.
For a typical task of encrypted and deduplicated backup of one or two VPS with a total data volume of up to 500 GB, you can choose a VPS with 2 vCPU, 4 GB RAM, 200 GB NVMe SSD, and a 1 Gbps channel. This will provide sufficient performance for Borg operations and comfortable work with the repository.
When a dedicated server is needed instead of a VPS: If you plan to store tens of terabytes of data, serve dozens of clients, or need maximum disk subsystem performance (e.g., for backing up very large databases with intensive I/O), then it's better to consider a dedicated server. It offers guaranteed resources (CPU, RAM, disk) without "neighboring" other users, which is critical for stable performance under high loads.
Location: what it affects: The location of the VPS server for backups matters. It is desirable that it be in a different data center or even region compared to the main server you are backing up. This will protect you from regional failures (e.g., power outage in one data center). At the same time, you should consider the network latency (ping) between your servers – the lower it is, the faster backup operations will be performed.
Server Preparation
Diagram: Server Preparation
Before installing BorgBackup, basic server preparation is required. We assume you are using a clean Ubuntu Server 24.04 LTS distribution (current version for 2026). All commands are executed as the root user or using sudo.
1. System Update
First, let's update all packages to their latest versions. This will ensure stability and security.
sudo apt update && sudo apt upgrade -y # Update package list and upgrade them
sudo apt autoremove -y # Remove unnecessary packages
2. Creating a New User and Configuring SSH Keys
Working as root is insecure. Let's create a new user with limited privileges and configure SSH key-based login.
sudo adduser sysadmin # Create a new user "sysadmin"
sudo usermod -aG sudo sysadmin # Add user to the sudo group
sudo mkdir /home/sysadmin/.ssh # Create directory for SSH keys
sudo chmod 700 /home/sysadmin/.ssh # Set correct permissions
sudo cp ~/.ssh/authorized_keys /home/sysadmin/.ssh/ # Copy your public SSH key
sudo chown -R sysadmin:sysadmin /home/sysadmin/.ssh # Set owner for the directory and keys
After this, log out of root and log in as the new user sysadmin. After successful login, disable password login for root and password login in general in /etc/ssh/sshd_config.
sudo nano /etc/ssh/sshd_config # Open the SSH configuration file
Find and change the following lines:
PermitRootLogin no # Forbid root login
PasswordAuthentication no # Forbid password login
ChallengeResponseAuthentication no # Disable challenge-response authentication
UsePAM no # Disable PAM for SSH
Save changes (Ctrl+X, Y, Enter) and restart the SSH service:
sudo systemctl restart sshd # Restart SSH service
3. Firewall Configuration (UFW)
Let's enable a simple but effective UFW firewall to restrict access to ports.
If BorgBackup is to be used for a remote repository, you might need to open other ports, but by default, it works over SSH, so OpenSSH will be sufficient.
4. Installing Fail2ban (Bruteforce Protection)
Fail2ban will block IP addresses that attempt to guess passwords to your server.
sudo apt install fail2ban -y # Install Fail2ban
sudo systemctl enable fail2ban # Enable service autostart
sudo systemctl start fail2ban # Start service
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local # Create local copy of config
sudo nano /etc/fail2ban/jail.local # Edit config for settings
In the jail.local file, ensure that the [sshd] section is active (enabled = true) and configure parameters as desired (e.g., bantime, findtime, maxretry). Default settings are quite adequate.
sudo systemctl restart fail2ban # Restart Fail2ban to apply changes
sudo fail2ban-client status sshd # Check Fail2ban status for SSH
Now your server is ready for BorgBackup installation.
Software Installation — Step-by-Step
Diagram: Software Installation — Step-by-Step
We will install BorgBackup on two servers: the "client" (the server from which backups will be made) and the "repository" (the server where backups will be stored). The installation process is almost identical.
1. Installing BorgBackup
BorgBackup is available in the official Ubuntu repositories. We assume the use of BorgBackup version 1.2.x or 1.3.x, which will be current and stable in 2026.
# Install BorgBackup on both servers (client and repository)
sudo apt update # Update package list
sudo apt install borgbackup -y # Install BorgBackup package
Let's check the installed BorgBackup version:
borg --version # Output BorgBackup version
The expected output will be similar to: borg 1.2.x or borg 1.3.x.
2. Creating a dedicated Borg user on the repository server
To enhance security, we will create a special user borguser on the repository server, who will only have access to the Borg repository and will not be able to execute other commands. This is an important step to minimize risks if an attacker gains access to the client's SSH keys.
# On the repository server
sudo adduser borguser --shell /usr/bin/borg-shell # Create user with restricted Borg shell
sudo mkdir /home/borguser/backups # Create directory for storing repositories
sudo chown borguser:borguser /home/borguser/backups # Set owner for the directory
The borg-shell (or borg-serve) shell allows the user to execute only Borg commands, which significantly enhances security. Ensure that /usr/bin/borg-shell exists. If not, BorgBackup usually provides borg-serve, which can be used with the SSH command= option.
3. Configuring SSH access for Borg on the repository server
We will need to configure SSH keys for the borguser on the repository server. The client will use its private key for authentication.
# On the repository server, as sysadmin (or root) user
sudo mkdir /home/borguser/.ssh # Create directory for SSH keys
sudo chmod 700 /home/borguser/.ssh # Set correct permissions
sudo touch /home/borguser/.ssh/authorized_keys # Create authorized_keys file
sudo chown borguser:borguser /home/borguser/.ssh/authorized_keys # Set owner
sudo nano /home/borguser/.ssh/authorized_keys # Edit file
In the /home/borguser/.ssh/authorized_keys file, add your client's public SSH key. It is important to add the command= option to restrict the commands the client can execute. Replace ваш_публичный_ключ with the actual client key.
This line ensures that the borguser can only execute the borg serve command and only within the /home/borguser/backups directory. Options like no-port-forwarding and others further enhance security.
4. Initializing the Borg repository on the repository server
Now that everything is set up, you can initialize the Borg repository itself. This can be done from the client server or directly on the repository server using SSH access.
# On the client server, as sysadmin user
# Initialize repository (replace repository_IP/domain with yours)
borg init --encryption=repokey-blake2 --make-parent-dirs ssh://borguser@your_repository_ip_or_domain:22/home/borguser/backups/my_server_repo # Initialize repository with repokey-blake2 encryption
You will be prompted to enter and confirm a passphrase for the repository. This passphrase is the master key to your encrypted backups. Make sure to store it in a safe place! Without it, you will not be able to recover your data.
--encryption=repokey-blake2: Recommended encryption method. The encryption key is stored in the repository, but it is itself encrypted with a passphrase.
--make-parent-dirs: Creates parent directories if they do not exist.
ssh://borguser@ваш_ip_или_домен_репозитория:22/home/borguser/backups/my_server_repo: Path to the remote repository.
BorgBackup is now installed and the repository initialized. You can proceed to configuration and creating your first backups.
Configuration
Diagram: Configuration
BorgBackup configuration primarily involves creating scripts for backup creation and maintenance. It is important to correctly define what to back up, where, and how to manage encryption keys. We will use environment variables to store sensitive data, such as the repository passphrase.
1. Setting up environment variables for Borg passphrase
To avoid entering the passphrase every time the script runs, Borg can retrieve it from the BORG_PASSPHRASE environment variable. This is convenient for automation but requires careful storage.
# On the client server
# Create file for storing environment variables
sudo nano /etc/profile.d/borg_env.sh
Insert the following content, replacing ВАШ_ПАРОЛЬ_К_РЕПОЗИТОРИЮ with your actual passphrase:
#!/bin/bash
export BORG_PASSPHRASE="YOUR_REPOSITORY_PASSPHRASE"
export BORG_REPO="ssh://borguser@your_repository_ip_or_domain:22/home/borguser/backups/my_server_repo"
export BORG_CACHE_DIR="/var/cache/borg" # Directory for Borg cache
Save the file and make it executable:
sudo chmod 600 /etc/profile.d/borg_env.sh # Set permissions
sudo chown root:root /etc/profile.d/borg_env.sh # Set owner
# To make variables available in the current session (for testing)
source /etc/profile.d/borg_env.sh
Important: Ensure that the file permissions are restricted so that only root can read it. For cron jobs, environment variables will be loaded automatically if the script is run with appropriate permissions.
2. Creating a backup script
Let's create the main script that will perform the backup. This script will include archive creation, verification, and old backup cleanup.
# On the client server
sudo mkdir -p /opt/backup_scripts # Create directory for scripts
sudo nano /opt/backup_scripts/create_backup.sh
Script content:
#!/bin/bash
# Load environment variables
source /etc/profile.d/borg_env.sh
# Directories to back up
BACKUP_DIRS="/etc /var/www /home /var/lib/mysql_dumps" # Example: /var/lib/mysql_dumps should be pre-created with DB dumps
# Archive name (with timestamp)
ARCHIVE_NAME="{hostname}-$(date +%Y-%m-%d_%H-%M-%S)"
echo "--- Starting backup to ${BORG_REPO}::${ARCHIVE_NAME} ---"
# Create backup
borg create --stats --progress \
--compression zstd,5 \
--exclude '/home//.cache' \
--exclude '/var/cache/' \
--exclude '/var/tmp/' \
--exclude '/var/log/' \
--exclude '/var/lib/mysql/.sock' \
--exclude '/var/lib/mysql/mysql.sock' \
--exclude '.log' \
"${BORG_REPO}::${ARCHIVE_NAME}" ${BACKUP_DIRS} \
2>&1 | tee /var/log/borg_backup.log # Redirect output to log file
EXIT_STATUS=$?
if [ ${EXIT_STATUS} -eq 0 ]; then
echo "--- Backup completed successfully ---"
elif [ ${EXIT_STATUS} -eq 1 ]; then
echo "--- Backup completed with warnings (see log) ---"
else
echo "--- Backup completed with error (code ${EXIT_STATUS}, see log) ---"
fi
echo "--- Running repository check ---"
borg check --last 1 "${BORG_REPO}" # Check last archive
echo "--- Running old backup cleanup ---"
# Retention policy:
# 7 latest daily backups
# 4 latest weekly backups
# 6 latest monthly backups
borg prune --list --stats --show-rc \
--keep-daily 7 --keep-weekly 4 --keep-monthly 6 "${BORG_REPO}" \
2>&1 | tee -a /var/log/borg_backup.log # Append output to the same log file
PRUNE_EXIT_STATUS=$?
if [ ${PRUNE_EXIT_STATUS} -eq 0 ]; then
echo "--- Cleanup completed successfully ---"
else
echo "--- Cleanup completed with error (code ${PRUNE_EXIT_STATUS}, see log) ---"
fi
echo "--- Listing archives ---"
borg list "${BORG_REPO}"
echo "--- Backup script finished ---"
Make the script executable:
sudo chmod +x /opt/backup_scripts/create_backup.sh # Make script executable
Script explanations:
source /etc/profile.d/borg_env.sh: Loads BORG_PASSPHRASE and BORG_REPO variables.
BACKUP_DIRS: Defines which directories will be backed up. It's important that database dumps (e.g., /var/lib/mysql_dumps) are pre-created.
--compression zstd,5: Uses the Zstandard compression algorithm with level 5 (a good balance between speed and compression ratio).
--exclude: Excludes temporary files, caches, and logs that are not needed in backups.
borg check: Verifies the integrity of the repository. This is a critically important step to ensure recoverability.
borg prune: Deletes old archives according to the specified policy (7 daily, 4 weekly, 6 monthly). This helps save space and maintain order.
3. Database Dumps (MySQL/PostgreSQL)
Before running BorgBackup, if you are using databases, you need to create their dumps. For example, for MySQL:
# On the client server
sudo mkdir -p /var/lib/mysql_dumps # Create directory for dumps
sudo chown mysql:mysql /var/lib/mysql_dumps # Set owner (or your user if the dump will be made by them)
# Create dump of all databases
sudo mysqldump --all-databases --single-transaction --flush-logs --master-data \
-u root -p'YOUR_MYSQL_PASSWORD' > /var/lib/mysql_dumps/all_databases_$(date +%Y%m%d%H%M%S).sql # Dump all DBs
# Or for a specific database
# sudo mysqldump -u root -p'YOUR_MYSQL_PASSWORD' YOUR_DATABASE > /var/lib/mysql_dumps/your_database_$(date +%Y%m%d%H%M%S).sql
This step should be added to your create_backup.sh script before the borg create command, so that Borg backs up the already prepared dumps. Alternatively, create a separate dump script that will run before the main backup.
4. Verifying functionality
Run the script manually to ensure everything is working:
sudo /opt/backup_scripts/create_backup.sh # Run script
Check the console output and the log file /var/log/borg_backup.log for errors. After successful execution, you can check the list of archives on the repository:
borg list "${BORG_REPO}" # Check list of archives
You should see the archive name you generated.
Backups and Maintenance
Diagram: Backups and Maintenance
After BorgBackup is configured and tested, it is necessary to automate the process and define a maintenance strategy.
1. What to back up
The choice of data for backup depends on your service, but usually includes:
Web server data:/var/www/ or /opt/www/ (site files, static content, media).
User home directories:/home/ (if users store important data there).
Databases: Database dumps (MySQL, PostgreSQL, MongoDB, etc.), which should be created before running Borg. For example, in /var/lib/mysql_dumps/.
Applications: If you installed anything outside of a package manager (e.g., in /opt/), include it.
What not to back up: Temporary files (/tmp, /var/tmp), caches (/var/cache), logs (/var/log), OS system files (except /etc) that can be easily restored by reinstalling packages.
2. Automating backups with cron
To regularly execute the backup script, use cron.
# On the client server
sudo crontab -e # Open crontab file for root (or sudo crontab -e -u sysadmin for user sysadmin)
Add the following line for a daily backup at 03:00 AM:
0 3 /opt/backup_scripts/create_backup.sh > /dev/null 2>&1 # Daily backup at 03:00 AM
If you want to receive email notifications in case of errors, you can remove > /dev/null 2>&1 and configure an email client on the server.
Important: Make sure that environment variables, including BORG_PASSPHRASE, are available to cron. If you use /etc/profile.d/borg_env.sh, cron might not load it. A more reliable way is to explicitly define variables in the crontab file itself or at the beginning of the script.
3. Where to store backups (external S3 / separate VPS)
In our case, backups are stored on a separate VPS, which acts as a Borg repository. This is already much better than storing backups on the same server as the source data.
For maximum reliability, consider:
External S3-compatible object storage: BorgBackup does not directly support S3, but you can use rclone to synchronize the Borg repository with S3-compatible storage after creating backups. This adds another layer of redundancy and geographical distribution.
Second remote VPS: Create a second Borg repository on another VPS (possibly in a different data center or region) and send backups there as well.
Remember the 3-2-1 rule: 3 copies of data, on 2 different media, 1 of which is off-site.
4. Data recovery
Data recovery is the most important aspect of any backup system. BorgBackup makes it relatively simple.
List archives:
borg list "${BORG_REPO}" # Show all archives in the repository
View archive contents:
borg list "${BORG_REPO}::ARCHIVE_NAME" # Show contents of a specific archive (replace ARCHIVE_NAME)
Restore entire archive:
borg extract "${BORG_REPO}::ARCHIVE_NAME" --paths /path/to/restore/to # Restore entire archive to specified directory
Restore specific files/directories:
borg extract "${BORG_REPO}::ARCHIVE_NAME" path/to/file_or_dir --paths /path/to/restore/to # Restore specific file or directory
Always restore data to a new or temporary directory to avoid overwriting existing files and to ensure correct recovery.
5. Updates: rolling vs maintenance window
Updating BorgBackup and the operating system should be performed regularly.
Rolling updates: For non-critical components and minor OS patches, updates can be applied regularly without service interruption.
Maintenance window: For major BorgBackup or OS updates, as well as kernel updates, it is recommended to schedule a "maintenance window". This is a time when you can stop services, take a VPS snapshot (if your provider offers this option), perform the update, and thoroughly test the system.
Always check BorgBackup version compatibility when updating. Although Borg is usually very stable, major releases may have changes that require attention.
After updating the OS and BorgBackup, always check the functionality of the backup script and the ability to restore data.
Troubleshooting + FAQ
What to do if BorgBackup returns "Remote: Host key verification failed"?
This error means that the SSH client cannot verify the authenticity of the remote server. Most often, this happens when connecting to a new server for the first time if you have not confirmed the key fingerprint, or if the server's IP address has changed and the old key remains in ~/.ssh/known_hosts. To resolve the issue, remove the corresponding line from the ~/.ssh/known_hosts file on the client server (or from /root/.ssh/known_hosts if the script is run as root) and try connecting again, confirming the new fingerprint.
How to solve the problem of insufficient disk space on the repository?
If the repository server is running out of space, first check how the borg prune command works. Perhaps the retention policy is too liberal, and you are storing too many old archives. Reduce the number of daily, weekly, or monthly backups kept. Also, check if there are other large files on the disk that are not related to Borg. If the problem persists, it may be time to increase the disk size on the VPS repository or consider switching to a dedicated server with larger storage.
What is the minimum VPS configuration suitable for a BorgBackup repository?
For a small project with data volumes up to 100-200 GB and one or two clients, a VPS with 1 vCPU, 2 GB RAM, and 200 GB SSD/NVMe disk will be minimally suitable. It is important that the disk is fast enough for Borg operations (SSD/NVMe is preferred). If the amount of data or clients grows, resources should be scaled, especially RAM and disk space.
What to choose — VPS or dedicated for this task?
The choice between a VPS and a dedicated server depends on the scale of your needs. A VPS is ideal for most small to medium-sized projects, offering flexibility and cost-effectiveness. It is suitable if you are backing up a few hundred gigabytes of data with moderate frequency. A dedicated server is necessary if the data volume is measured in terabytes, maximum disk subsystem performance is required, or you act as a backup provider for multiple clients. A dedicated server provides guaranteed resources and a complete absence of "neighbors," which is critical for performance under high load.
What to do if I forgot the Borg repository password?
If you forget the Borg repository password, unfortunately, it will be impossible to recover data from it. Borg's encryption is very strong, and without the password, access to the data is impossible. This emphasizes the critical importance of securely storing the password. Always use a password manager or another secure storage for such critical data.
How to check the integrity of backups?
Regular integrity checking of backups is an essential part of maintenance. The borg check command is used for this. You can add it to your backup script, as we did, or run it separately. The command borg check --repository-only checks only the repository, while borg check --archives-only checks the archives. A full borg check can take a long time for large repositories, but it ensures that the data is not corrupted.
Can multiple servers be backed up to a single repository?
Yes, BorgBackup is excellent for backing up multiple servers to a single central repository. For each client server, it is sufficient to create its own set of SSH keys and configure them in the authorized_keys of the borguser user on the repository server, using the option command="borg serve --restrict-to-path /home/borguser/backups/SERVER_NAME" to isolate each client in its own repository subdirectory. This enhances security and allows for easy management of backups from different sources.
Conclusions and Next Steps
Diagram: Conclusions and Next Steps
We have successfully configured BorgBackup on your VPS to create encrypted and deduplicated backups. Now your critical data is protected from loss, and the backup process is fully automated. You have full control over your data, its security, and storage costs.
Next steps for further improving your backup system may include:
Monitoring setup: Integrate BorgBackup logs with a monitoring system (e.g., Prometheus, Grafana, ELK stack) to track backup success and error alerts.
Additional redundancy: Consider creating copies of your Borg repository on another remote storage (e.g., S3-compatible or a second VPS) to implement the 3-2-1 rule.
Regular recovery testing: Periodically test the data recovery process to ensure that backups are current and functional. This will give you confidence in a critical situation.
Was this guide helpful?
Your feedback helps us improve our guides.
Share this post:
Send this guide to someone who may find it useful.