Configure backup encryption with GPG and rsync for secure automated backups

Intermediate 45 min Apr 04, 2026 198 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Set up automated encrypted backups using GPG 2.4 and rsync with systemd timers. This tutorial covers GPG key management, encrypted backup scripts, and restoration procedures for production environments.

Prerequisites

  • Root or sudo access
  • At least 2GB free disk space for backups
  • Network access for remote backup sync
  • Basic understanding of Linux file permissions

What this solves

Automated backups are essential, but storing sensitive data in plaintext creates security risks. This tutorial shows you how to implement GPG encryption with rsync for secure automated backups that protect your data both in transit and at rest. You'll create production-ready backup scripts with systemd timers that encrypt files before transfer and include verification procedures.

Step-by-step configuration

Update system packages

Start by updating your package manager to ensure you get the latest versions of GPG and related tools.

sudo apt update && sudo apt upgrade -y
sudo apt install -y gnupg2 rsync coreutils
sudo dnf update -y
sudo dnf install -y gnupg2 rsync coreutils

Verify GPG 2.4 installation

Check that GPG 2.4 or later is installed and working correctly.

gpg --version | head -1
gpg --list-keys

Generate GPG key pair for backups

Create a dedicated GPG key pair specifically for backup encryption. Use a strong passphrase and store it securely.

gpg --full-generate-key

Select the following options when prompted:

  • Key type: (1) RSA and RSA (default)
  • Key size: 4096
  • Valid for: 2y (2 years)
  • Real name: Backup System
  • Email: backups@example.com
  • Comment: Automated backup encryption

Export and backup the GPG keys

Export both public and private keys to secure locations. Store the private key backup in a safe location separate from your backup server.

gpg --list-secret-keys --keyid-format=long
export KEYID="your_key_id_here"
gpg --armor --export $KEYID > /root/backup-public-key.asc
gpg --armor --export-secret-keys $KEYID > /root/backup-private-key.asc
chmod 600 /root/backup-private-key.asc
Warning: Store the private key backup in a secure location separate from your backup server. If you lose this key, encrypted backups cannot be restored.

Create backup directory structure

Set up the directory structure for backup scripts, logs, and temporary files with proper permissions.

sudo mkdir -p /opt/backup-system/{scripts,logs,temp}
sudo chmod 755 /opt/backup-system
sudo chmod 750 /opt/backup-system/{scripts,logs,temp}
sudo chown root:root /opt/backup-system -R

Create GPG encryption wrapper script

Create a wrapper script that handles GPG encryption with proper error handling and logging.

#!/bin/bash

GPG Backup Encryption Wrapper

Usage: gpg-backup-wrapper.sh

set -euo pipefail

Configuration

GPG_RECIPIENT="backups@example.com" LOG_FILE="/opt/backup-system/logs/backup-$(date +%Y%m%d).log" TEMP_DIR="/opt/backup-system/temp" DATE=$(date +"%Y%m%d_%H%M%S")

Logging function

log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE" }

Check arguments

if [ $# -ne 3 ]; then log "ERROR: Usage: $0 " exit 1 fi SOURCE_DIR="$1" BACKUP_NAME="$2" DESTINATION="$3" ARCHIVE_NAME="${BACKUP_NAME}_${DATE}.tar.gz" ENCRYPTED_NAME="${ARCHIVE_NAME}.gpg" log "Starting backup: $BACKUP_NAME" log "Source: $SOURCE_DIR" log "Destination: $DESTINATION"

Verify source exists

if [ ! -d "$SOURCE_DIR" ]; then log "ERROR: Source directory does not exist: $SOURCE_DIR" exit 1 fi

Create destination if it doesn't exist

mkdir -p "$DESTINATION"

Create compressed archive

log "Creating compressed archive..." cd "$(dirname "$SOURCE_DIR")" tar czf "$TEMP_DIR/$ARCHIVE_NAME" "$(basename "$SOURCE_DIR")" 2>> "$LOG_FILE" if [ $? -eq 0 ]; then log "Archive created successfully: $ARCHIVE_NAME" else log "ERROR: Failed to create archive" exit 1 fi

Encrypt the archive

log "Encrypting archive..." gpg --trust-model always --cipher-algo AES256 --compress-algo 2 \ --recipient "$GPG_RECIPIENT" --encrypt \ "$TEMP_DIR/$ARCHIVE_NAME" if [ $? -eq 0 ]; then log "Archive encrypted successfully" else log "ERROR: Failed to encrypt archive" rm -f "$TEMP_DIR/$ARCHIVE_NAME" exit 1 fi

Move encrypted file to destination

log "Moving encrypted backup to destination..." mv "$TEMP_DIR/${ARCHIVE_NAME}.gpg" "$DESTINATION/$ENCRYPTED_NAME"

Clean up temporary files

rm -f "$TEMP_DIR/$ARCHIVE_NAME"

Calculate and log file sizes

ORIGINAL_SIZE=$(du -sh "$SOURCE_DIR" | cut -f1) ENCRYPTED_SIZE=$(du -sh "$DESTINATION/$ENCRYPTED_NAME" | cut -f1) log "Backup completed successfully" log "Original size: $ORIGINAL_SIZE, Encrypted size: $ENCRYPTED_SIZE" log "Backup file: $DESTINATION/$ENCRYPTED_NAME" exit 0

Make the wrapper script executable

Set proper permissions on the backup wrapper script.

sudo chmod 750 /opt/backup-system/scripts/gpg-backup-wrapper.sh
sudo chown root:root /opt/backup-system/scripts/gpg-backup-wrapper.sh

Create rsync encryption script

Create a script that combines encrypted local backups with secure rsync transfer to remote destinations.

#!/bin/bash

Encrypted Rsync Backup Script

Encrypts files locally, then syncs to remote destination

set -euo pipefail

Configuration

SOURCE_DIRS=( "/etc" "/home" "/var/log" "/opt/important-data" ) LOCAL_BACKUP_DIR="/backup/encrypted" REMOTE_USER="backup" REMOTE_HOST="backup.example.com" REMOTE_DIR="/backups/$(hostname)" SSH_KEY="/root/.ssh/backup_rsa" LOG_FILE="/opt/backup-system/logs/rsync-backup-$(date +%Y%m%d).log" RETENTION_DAYS=30

Logging function

log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE" } log "Starting encrypted rsync backup process"

Create local backup directory

mkdir -p "$LOCAL_BACKUP_DIR"

Encrypt each source directory

for SOURCE in "${SOURCE_DIRS[@]}"; do if [ -d "$SOURCE" ]; then BACKUP_NAME=$(echo "$SOURCE" | sed 's/\//_/g' | sed 's/^_//') log "Processing: $SOURCE -> $BACKUP_NAME" /opt/backup-system/scripts/gpg-backup-wrapper.sh \ "$SOURCE" "$BACKUP_NAME" "$LOCAL_BACKUP_DIR" if [ $? -ne 0 ]; then log "ERROR: Failed to backup $SOURCE" continue fi else log "WARNING: Source directory does not exist: $SOURCE" fi done

Sync encrypted backups to remote server

log "Syncing encrypted backups to remote server..." rsync -avz --delete-after --progress \ -e "ssh -i $SSH_KEY -o StrictHostKeyChecking=no" \ "$LOCAL_BACKUP_DIR/" \ "$REMOTE_USER@$REMOTE_HOST:$REMOTE_DIR/" \ 2>> "$LOG_FILE" if [ $? -eq 0 ]; then log "Remote sync completed successfully" else log "ERROR: Remote sync failed" exit 1 fi

Clean up old local backups

log "Cleaning up backups older than $RETENTION_DAYS days..." find "$LOCAL_BACKUP_DIR" -name "*.gpg" -mtime +$RETENTION_DAYS -delete log "Encrypted rsync backup process completed"

Generate backup report

BACKUP_COUNT=$(find "$LOCAL_BACKUP_DIR" -name "*.gpg" -mtime -1 | wc -l) TOTAL_SIZE=$(du -sh "$LOCAL_BACKUP_DIR" | cut -f1) log "Backup summary: $BACKUP_COUNT files created, total size: $TOTAL_SIZE"

Make rsync script executable

Set proper permissions on the rsync backup script.

sudo chmod 750 /opt/backup-system/scripts/encrypted-rsync-backup.sh
sudo chown root:root /opt/backup-system/scripts/encrypted-rsync-backup.sh

Create SSH key for backup authentication

Generate an SSH key pair for secure authentication to the remote backup server.

sudo ssh-keygen -t rsa -b 4096 -f /root/.ssh/backup_rsa -N ""
sudo chmod 600 /root/.ssh/backup_rsa
sudo chmod 644 /root/.ssh/backup_rsa.pub
Note: Copy the public key to your remote backup server and add it to the backup user's authorized_keys file.

Create systemd service and timer

Set up systemd service and timer files for automated backup execution.

[Unit]
Description=Encrypted Backup Service
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
User=root
ExecStart=/opt/backup-system/scripts/encrypted-rsync-backup.sh
StandardOutput=journal
StandardError=journal

Create systemd timer

Configure the timer to run encrypted backups daily at 2 AM.

[Unit]
Description=Run encrypted backup daily
Requires=encrypted-backup.service

[Timer]
OnCalendar=daily
Persistent=true
AccuracySec=1min

[Install]
WantedBy=timers.target

Enable and start the backup timer

Enable the systemd timer to run automatically and start it immediately.

sudo systemctl daemon-reload
sudo systemctl enable encrypted-backup.timer
sudo systemctl start encrypted-backup.timer
sudo systemctl status encrypted-backup.timer

Create backup verification script

Create a script to verify that encrypted backups can be successfully decrypted and restored.

#!/bin/bash

Backup Verification Script

Tests decryption and extraction of encrypted backups

set -euo pipefail

Configuration

BACKUP_DIR="/backup/encrypted" TEST_DIR="/tmp/backup-verification" LOG_FILE="/opt/backup-system/logs/verification-$(date +%Y%m%d).log"

Logging function

log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE" } log "Starting backup verification process"

Create test directory

rm -rf "$TEST_DIR" mkdir -p "$TEST_DIR"

Find most recent backup files

BACKUP_FILES=$(find "$BACKUP_DIR" -name "*.gpg" -mtime -1 -type f) if [ -z "$BACKUP_FILES" ]; then log "ERROR: No recent backup files found" exit 1 fi VERIFIED=0 FAILED=0 for BACKUP_FILE in $BACKUP_FILES; do FILENAME=$(basename "$BACKUP_FILE") log "Verifying: $FILENAME" # Attempt decryption if gpg --quiet --decrypt "$BACKUP_FILE" > "$TEST_DIR/test.tar.gz" 2>/dev/null; then log " Decryption: SUCCESS" # Attempt extraction test (first few files only) if tar -tzf "$TEST_DIR/test.tar.gz" | head -10 > /dev/null 2>&1; then log " Archive integrity: SUCCESS" ((VERIFIED++)) else log " Archive integrity: FAILED" ((FAILED++)) fi rm -f "$TEST_DIR/test.tar.gz" else log " Decryption: FAILED" ((FAILED++)) fi done

Cleanup

rm -rf "$TEST_DIR" log "Verification completed: $VERIFIED successful, $FAILED failed" if [ $FAILED -gt 0 ]; then exit 1 fi exit 0

Make verification script executable

Set proper permissions on the verification script.

sudo chmod 750 /opt/backup-system/scripts/verify-backup.sh
sudo chown root:root /opt/backup-system/scripts/verify-backup.sh

Create backup restoration script

Create a script to simplify the process of restoring encrypted backups when needed.

#!/bin/bash

Backup Restoration Script

Usage: restore-backup.sh

set -euo pipefail

Check arguments

if [ $# -ne 2 ]; then echo "Usage: $0 " echo "Example: $0 /backup/encrypted/etc_20241201_020000.tar.gz.gpg /tmp/restore" exit 1 fi ENCRYPTED_FILE="$1" DEST_DIR="$2" TEMP_DIR="/tmp/backup-restore-$$" echo "Starting restoration process..." echo "Source: $ENCRYPTED_FILE" echo "Destination: $DEST_DIR"

Verify source file exists

if [ ! -f "$ENCRYPTED_FILE" ]; then echo "ERROR: Encrypted backup file not found: $ENCRYPTED_FILE" exit 1 fi

Create temporary and destination directories

mkdir -p "$TEMP_DIR" "$DEST_DIR"

Decrypt the backup

echo "Decrypting backup..." if ! gpg --quiet --decrypt "$ENCRYPTED_FILE" > "$TEMP_DIR/backup.tar.gz"; then echo "ERROR: Failed to decrypt backup file" rm -rf "$TEMP_DIR" exit 1 fi echo "Decryption successful"

Extract the archive

echo "Extracting archive..." if tar -xzf "$TEMP_DIR/backup.tar.gz" -C "$DEST_DIR"; then echo "Extraction successful" else echo "ERROR: Failed to extract archive" rm -rf "$TEMP_DIR" exit 1 fi

Cleanup

rm -rf "$TEMP_DIR" echo "Backup restoration completed successfully" echo "Restored files are available in: $DEST_DIR" echo "Please verify the restored data before using it"

Make restoration script executable

Set proper permissions on the restoration script.

sudo chmod 750 /opt/backup-system/scripts/restore-backup.sh
sudo chown root:root /opt/backup-system/scripts/restore-backup.sh

Verify your setup

Test your encrypted backup system to ensure everything is working correctly.

# Check GPG key is available
gpg --list-keys "backups@example.com"

Test manual backup creation

sudo /opt/backup-system/scripts/gpg-backup-wrapper.sh /etc test-backup /tmp

Verify the encrypted file was created

ls -la /tmp/test-backup_*.tar.gz.gpg

Test backup verification

sudo /opt/backup-system/scripts/verify-backup.sh

Check systemd timer status

sudo systemctl list-timers encrypted-backup.timer

Check recent backup logs

sudo tail -20 /opt/backup-system/logs/backup-$(date +%Y%m%d).log
Note: The backup automation integrates well with Linux system backup automation for comprehensive data protection strategies.

Common issues

Symptom Cause Fix
GPG encryption fails with "public key not found" Wrong recipient email or key not imported gpg --list-keys and verify recipient matches exactly
Permission denied on backup scripts Incorrect file permissions chmod 750 /opt/backup-system/scripts/*.sh
Rsync fails with SSH connection error SSH key not configured or wrong permissions Verify SSH key exists and has chmod 600 permissions
Systemd timer not running Timer not enabled or service file error systemctl enable encrypted-backup.timer && systemctl start encrypted-backup.timer
Backup verification fails Corrupted backup or wrong GPG key Check log files and verify GPG key matches encryption key
Insufficient disk space for backups Large files or inadequate retention policy Adjust retention days or implement compression levels
Never use chmod 777. It gives every user on the system full access to your backup files and keys. Instead, use proper ownership with chown and minimal permissions like 750 for scripts and 600 for private keys.

Next steps

Automated install script

Run this to automate the entire setup

Need help?

Don't want to manage this yourself?

We handle infrastructure security hardening for businesses that depend on uptime. From initial setup to ongoing operations.