Configure Redis backup encryption with GPG for secure automated backups

Intermediate 45 min Apr 15, 2026 765 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Set up encrypted Redis backups using GPG keys with automated scheduling through systemd timers. This tutorial covers GPG key management, backup script creation, and secure restoration procedures for production Redis environments.

Prerequisites

  • Redis server installed and running
  • Root or sudo access
  • Basic understanding of Linux systemd services
  • Familiarity with GPG encryption concepts

What this solves

Redis databases contain sensitive application data that needs secure backup strategies in production environments. Standard Redis backup files (RDB and AOF) are stored in plain text, making them vulnerable if backup storage is compromised. This tutorial implements GPG encryption for Redis backups with automated scheduling, ensuring your database snapshots remain secure during storage and transmission.

Prerequisites and preparation

Install required packages

Install GPG, Redis tools, and backup utilities needed for encrypted backup operations.

sudo apt update
sudo apt install -y gnupg2 redis-tools gzip rsync
sudo dnf update -y
sudo dnf install -y gnupg2 redis gzip rsync

Create dedicated backup user

Create a system user specifically for Redis backup operations to maintain security isolation.

sudo useradd -r -s /bin/bash -d /var/lib/redis-backup -m redis-backup
sudo mkdir -p /var/lib/redis-backup/{scripts,backups,keys}
sudo chown -R redis-backup:redis-backup /var/lib/redis-backup
sudo chmod 750 /var/lib/redis-backup

GPG key generation and management

Generate GPG key pair for backups

Create a dedicated GPG key pair for Redis backup encryption using the backup user account.

sudo -u redis-backup gpg --batch --full-generate-key <

Export and secure GPG keys

Export the GPG keys and store them securely for backup recovery scenarios.

`sudo -u redis-backup bash -c '
GPG_KEY_ID=$(gpg --list-secret-keys --keyid-format=long | grep sec | awk "{print \$2}" | cut -d"/" -f2)
echo "GPG Key ID: $GPG_KEY_ID" > /var/lib/redis-backup/keys/key-info.txt
gpg --armor --export $GPG_KEY_ID > /var/lib/redis-backup/keys/public-key.asc
gpg --armor --export-secret-keys $GPG_KEY_ID > /var/lib/redis-backup/keys/private-key.asc
chmod 600 /var/lib/redis-backup/keys/private-key.asc
chmod 644 /var/lib/redis-backup/keys/public-key.asc
'`

Configure GPG trust and passphrase

Set up GPG trust relationships and configure passphrase handling for automated operations.

`sudo -u redis-backup bash -c '
GPG_KEY_ID=$(gpg --list-secret-keys --keyid-format=long | grep sec | awk "{print \$2}" | cut -d"/" -f2)
echo "$GPG_KEY_ID:6:" | gpg --import-ownertrust
echo "your-secure-passphrase-here" > /var/lib/redis-backup/keys/passphrase
chmod 600 /var/lib/redis-backup/keys/passphrase
'`

Redis backup script with GPG encryption

Create encrypted backup script

Develop a comprehensive backup script that handles Redis data export, compression, and GPG encryption.

`#!/bin/bash

# Redis Backup Script with GPG Encryption
# Configuration
REDIS_HOST="127.0.0.1"
REDIS_PORT="6379"
REDIS_PASSWORD=""
BACKUP_DIR="/var/lib/redis-backup/backups"
LOG_FILE="/var/lib/redis-backup/backup.log"
GPG_PASSPHRASE_FILE="/var/lib/redis-backup/keys/passphrase"
RETENTION_DAYS="30"

# Get GPG key ID
GPG_KEY_ID=$(gpg --list-secret-keys --keyid-format=long | grep sec | awk '{print $2}' | cut -d"/" -f2)

# Function to log messages
log_message() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE"
}

# Function to create RDB backup
create_rdb_backup() {
    local backup_file="$1"
    
    if [ -n "$REDIS_PASSWORD" ]; then
        redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" -a "$REDIS_PASSWORD" --rdb "$backup_file"
    else
        redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" --rdb "$backup_file"
    fi
    
    return $?
}

# Function to backup Redis using BGSAVE
create_bgsave_backup() {
    local redis_data_dir="$1"
    local backup_file="$2"
    
    # Trigger BGSAVE
    if [ -n "$REDIS_PASSWORD" ]; then
        redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" -a "$REDIS_PASSWORD" BGSAVE
    else
        redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" BGSAVE
    fi
    
    # Wait for BGSAVE to complete
    while true; do
        if [ -n "$REDIS_PASSWORD" ]; then
            BGSAVE_STATUS=$(redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" -a "$REDIS_PASSWORD" LASTSAVE)
        else
            BGSAVE_STATUS=$(redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" LASTSAVE)
        fi
        
        sleep 2
        
        if [ -n "$REDIS_PASSWORD" ]; then
            CURRENT_STATUS=$(redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" -a "$REDIS_PASSWORD" LASTSAVE)
        else
            CURRENT_STATUS=$(redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" LASTSAVE)
        fi
        
        if [ "$BGSAVE_STATUS" != "$CURRENT_STATUS" ]; then
            break
        fi
    done
    
    # Copy the RDB file
    cp "$redis_data_dir/dump.rdb" "$backup_file"
    return $?
}

# Main backup function
perform_backup() {
    local timestamp=$(date +"%Y%m%d_%H%M%S")
    local backup_name="redis_backup_${timestamp}"
    local temp_backup="${BACKUP_DIR}/${backup_name}.rdb"
    local compressed_backup="${BACKUP_DIR}/${backup_name}.rdb.gz"
    local encrypted_backup="${BACKUP_DIR}/${backup_name}.rdb.gz.gpg"
    
    log_message "Starting Redis backup: $backup_name"
    
    # Create backup directory if it doesn't exist
    mkdir -p "$BACKUP_DIR"
    
    # Create Redis backup
    if create_rdb_backup "$temp_backup"; then
        log_message "Redis RDB backup created successfully"
    else
        log_message "ERROR: Failed to create Redis backup"
        return 1
    fi
    
    # Compress the backup
    if gzip -c "$temp_backup" > "$compressed_backup"; then
        log_message "Backup compressed successfully"
        rm "$temp_backup"
    else
        log_message "ERROR: Failed to compress backup"
        rm "$temp_backup"
        return 1
    fi
    
    # Encrypt the backup
    if gpg --batch --yes --passphrase-file "$GPG_PASSPHRASE_FILE" --cipher-algo AES256 --compress-algo 1 --symmetric --output "$encrypted_backup" "$compressed_backup"; then
        log_message "Backup encrypted successfully: $encrypted_backup"
        rm "$compressed_backup"
    else
        log_message "ERROR: Failed to encrypt backup"
        rm "$compressed_backup"
        return 1
    fi
    
    # Verify encrypted backup
    if gpg --batch --yes --passphrase-file "$GPG_PASSPHRASE_FILE" --list-packets "$encrypted_backup" > /dev/null 2>&1; then
        log_message "Backup verification successful"
    else
        log_message "ERROR: Backup verification failed"
        return 1
    fi
    
    # Calculate and log file sizes
    local file_size=$(du -h "$encrypted_backup" | cut -f1)
    log_message "Encrypted backup size: $file_size"
    
    return 0
}

# Function to clean old backups
cleanup_old_backups() {
    log_message "Starting cleanup of backups older than $RETENTION_DAYS days"
    
    find "$BACKUP_DIR" -name "redis_backup_*.rdb.gz.gpg" -mtime +"$RETENTION_DAYS" -delete
    
    local deleted_count=$(find "$BACKUP_DIR" -name "redis_backup_*.rdb.gz.gpg" -mtime +"$RETENTION_DAYS" | wc -l)
    log_message "Cleanup completed. Deleted $deleted_count old backup files"
}

# Function to check Redis connectivity
check_redis_connection() {
    if [ -n "$REDIS_PASSWORD" ]; then
        redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" -a "$REDIS_PASSWORD" ping > /dev/null 2>&1
    else
        redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" ping > /dev/null 2>&1
    fi
    
    return $?
}

# Main execution
main() {
    log_message "Redis backup script started"
    
    # Check Redis connection
    if ! check_redis_connection; then
        log_message "ERROR: Cannot connect to Redis server at $REDIS_HOST:$REDIS_PORT"
        exit 1
    fi
    
    # Check GPG key
    if [ -z "$GPG_KEY_ID" ]; then
        log_message "ERROR: No GPG key found for encryption"
        exit 1
    fi
    
    # Perform backup
    if perform_backup; then
        log_message "Backup completed successfully"
        
        # Cleanup old backups
        cleanup_old_backups
        
        log_message "Redis backup script completed successfully"
        exit 0
    else
        log_message "ERROR: Backup failed"
        exit 1
    fi
}

# Run main function
main "$@"`

Set script permissions and ownership

Configure appropriate permissions for the backup script to ensure security and functionality.

`sudo chown redis-backup:redis-backup /var/lib/redis-backup/scripts/redis-backup.sh
sudo chmod 750 /var/lib/redis-backup/scripts/redis-backup.sh`

Create backup verification script

Develop a script to verify and test encrypted backup integrity and restoration capabilities.

`#!/bin/bash

# Redis Backup Verification Script
BACKUP_DIR="/var/lib/redis-backup/backups"
GPG_PASSPHRASE_FILE="/var/lib/redis-backup/keys/passphrase"
TEMP_DIR="/tmp/redis-backup-verify"

# Function to verify backup integrity
verify_backup() {
    local backup_file="$1"
    
    echo "Verifying backup: $(basename $backup_file)"
    
    # Create temporary directory
    mkdir -p "$TEMP_DIR"
    
    # Decrypt backup
    if gpg --batch --yes --passphrase-file "$GPG_PASSPHRASE_FILE" --decrypt "$backup_file" > "$TEMP_DIR/backup.rdb.gz" 2>/dev/null; then
        echo "✓ Decryption successful"
    else
        echo "✗ Decryption failed"
        return 1
    fi
    
    # Decompress backup
    if gunzip -c "$TEMP_DIR/backup.rdb.gz" > "$TEMP_DIR/backup.rdb" 2>/dev/null; then
        echo "✓ Decompression successful"
    else
        echo "✗ Decompression failed"
        rm -rf "$TEMP_DIR"
        return 1
    fi
    
    # Verify RDB file format
    if file "$TEMP_DIR/backup.rdb" | grep -q "Redis RDB"; then
        echo "✓ RDB format verification successful"
    else
        echo "✗ RDB format verification failed"
        rm -rf "$TEMP_DIR"
        return 1
    fi
    
    # Get file size
    local size=$(du -h "$backup_file" | cut -f1)
    echo "✓ Backup size: $size"
    
    # Cleanup
    rm -rf "$TEMP_DIR"
    
    echo "✓ Backup verification completed successfully"
    return 0
}

# Main function
if [ $# -eq 0 ]; then
    echo "Usage: $0 `

Set verification script permissions

Configure permissions for the backup verification script.

`sudo chown redis-backup:redis-backup /var/lib/redis-backup/scripts/verify-backup.sh
sudo chmod 750 /var/lib/redis-backup/scripts/verify-backup.sh`

Automated backup scheduling with systemd

Create systemd service unit

Create a systemd service unit for the Redis backup process to ensure proper execution environment.

`[Unit]
Description=Redis Encrypted Backup Service
After=redis.service network.target
Requires=redis.service

[Service]
Type=oneshot
User=redis-backup
Group=redis-backup
WorkingDirectory=/var/lib/redis-backup
ExecStart=/var/lib/redis-backup/scripts/redis-backup.sh
Environment=HOME=/var/lib/redis-backup
Environment=GNUPGHOME=/var/lib/redis-backup/.gnupg
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/redis-backup
NoNewPrivileges=true
CapabilityBoundingSet=
SystemCallFilter=@system-service
SystemCallErrorNumber=EPERM`

Create systemd timer unit

Configure a systemd timer to schedule automated backup execution at regular intervals.

`[Unit]
Description=Redis Encrypted Backup Timer
Requires=redis-backup.service

[Timer]
# Run daily at 2:30 AM
OnCalendar=*-*-* 02:30:00
# Run 5 minutes after boot if missed
OnBootSec=5min
# Randomize execution time by up to 10 minutes
RandomizedDelaySec=600
Persistent=true

[Install]
WantedBy=timers.target`

Enable and start systemd timer

Activate the systemd timer and verify its configuration for automated backup scheduling.

`sudo systemctl daemon-reload
sudo systemctl enable redis-backup.timer
sudo systemctl start redis-backup.timer
sudo systemctl status redis-backup.timer`

Test backup service manually

Execute the backup service manually to verify proper operation before relying on automated scheduling.

`sudo systemctl start redis-backup.service
sudo systemctl status redis-backup.service
sudo -u redis-backup cat /var/lib/redis-backup/backup.log`

Backup verification and restoration procedures

Verify latest backup

Test the integrity and accessibility of the most recent encrypted backup file.

`sudo -u redis-backup /var/lib/redis-backup/scripts/verify-backup.sh latest`

Create restoration script

Develop a comprehensive script for restoring Redis data from encrypted backups.

`#!/bin/bash

# Redis Backup Restoration Script
BACKUP_DIR="/var/lib/redis-backup/backups"
GPG_PASSPHRASE_FILE="/var/lib/redis-backup/keys/passphrase"
REDIS_DATA_DIR="/var/lib/redis"
TEMP_DIR="/tmp/redis-restore"
LOG_FILE="/var/lib/redis-backup/restore.log"

# Function to log messages
log_message() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE"
    echo "$1"
}

# Function to restore backup
restore_backup() {
    local backup_file="$1"
    
    if [ ! -f "$backup_file" ]; then
        log_message "ERROR: Backup file not found: $backup_file"
        return 1
    fi
    
    log_message "Starting restoration from: $(basename $backup_file)"
    
    # Create temporary directory
    mkdir -p "$TEMP_DIR"
    
    # Stop Redis service
    log_message "Stopping Redis service"
    sudo systemctl stop redis-server 2>/dev/null || sudo systemctl stop redis 2>/dev/null
    
    # Wait for Redis to stop
    sleep 3
    
    # Backup current Redis data
    if [ -f "$REDIS_DATA_DIR/dump.rdb" ]; then
        log_message "Backing up current Redis data"
        sudo cp "$REDIS_DATA_DIR/dump.rdb" "$REDIS_DATA_DIR/dump.rdb.backup.$(date +%Y%m%d_%H%M%S)"
    fi
    
    # Decrypt backup
    log_message "Decrypting backup file"
    if gpg --batch --yes --passphrase-file "$GPG_PASSPHRASE_FILE" --decrypt "$backup_file" > "$TEMP_DIR/backup.rdb.gz" 2>/dev/null; then
        log_message "Decryption successful"
    else
        log_message "ERROR: Decryption failed"
        rm -rf "$TEMP_DIR"
        sudo systemctl start redis-server 2>/dev/null || sudo systemctl start redis 2>/dev/null
        return 1
    fi
    
    # Decompress backup
    log_message "Decompressing backup file"
    if gunzip -c "$TEMP_DIR/backup.rdb.gz" > "$TEMP_DIR/dump.rdb" 2>/dev/null; then
        log_message "Decompression successful"
    else
        log_message "ERROR: Decompression failed"
        rm -rf "$TEMP_DIR"
        sudo systemctl start redis-server 2>/dev/null || sudo systemctl start redis 2>/dev/null
        return 1
    fi
    
    # Copy restored file to Redis data directory
    log_message "Installing restored Redis data"
    sudo cp "$TEMP_DIR/dump.rdb" "$REDIS_DATA_DIR/dump.rdb"
    sudo chown redis:redis "$REDIS_DATA_DIR/dump.rdb"
    sudo chmod 644 "$REDIS_DATA_DIR/dump.rdb"
    
    # Start Redis service
    log_message "Starting Redis service"
    sudo systemctl start redis-server 2>/dev/null || sudo systemctl start redis 2>/dev/null
    
    # Wait for Redis to start
    sleep 5
    
    # Verify Redis is running
    if redis-cli ping > /dev/null 2>&1; then
        log_message "Redis restoration completed successfully"
        
        # Get database info
        local db_size=$(redis-cli dbsize)
        log_message "Restored database contains $db_size keys"
        
        # Cleanup
        rm -rf "$TEMP_DIR"
        
        return 0
    else
        log_message "ERROR: Redis failed to start after restoration"
        rm -rf "$TEMP_DIR"
        return 1
    fi
}

# Main function
if [ $# -eq 0 ]; then
    echo "Usage: $0 `

Set restoration script permissions

Configure appropriate permissions for the restoration script with elevated privileges for Redis service management.

`sudo chown redis-backup:redis-backup /var/lib/redis-backup/scripts/restore-backup.sh
sudo chmod 750 /var/lib/redis-backup/scripts/restore-backup.sh`

Configure sudo permissions for Redis service management

Allow the backup user to manage Redis service for restoration procedures.

`# Allow redis-backup user to manage Redis service
redis-backup ALL=(ALL) NOPASSWD: /bin/systemctl start redis-server, /bin/systemctl stop redis-server, /bin/systemctl start redis, /bin/systemctl stop redis, /bin/cp, /bin/chown`

Monitoring and maintenance

Create backup monitoring script

Develop a monitoring script to

Automated install script

Run this to automate the entire setup

Non vuoi gestirlo da solo?

Gestiamo l'infrastruttura di aziende che dipendono dall'uptime. Completamente gestita, con un referente fisso che conosce il tuo ambiente.

Avete un referente fisso che conosce il vostro ambiente

Rotterdam 08:39 · raggiungibile con un messaggio, senza modulo ticket