Set up automated GitLab backups with GPG encryption, remote storage, and systemd timers. This tutorial covers backup script creation, encryption setup, and monitoring for production GitLab instances.
Prerequisites
- GitLab CE or EE installed and running
- Root or sudo access
- Remote backup server with SSH access
- At least 10GB free disk space for temporary backup files
What this solves
GitLab contains critical data including repositories, issues, merge requests, and user accounts that need reliable backup protection. This tutorial sets up automated GitLab backups with GPG encryption, remote storage, and systemd scheduling to ensure your GitLab data is secure and recoverable.
Step-by-step configuration
Install required packages
Install GPG for encryption, rsync for remote transfers, and backup utilities.
sudo apt update
sudo apt install -y gnupg2 rsync gzip pigz
Create backup user and directories
Create a dedicated user for backup operations with restricted permissions for security.
sudo useradd -r -s /bin/bash -d /opt/gitlab-backup gitlab-backup
sudo mkdir -p /opt/gitlab-backup/{scripts,logs,tmp}
sudo mkdir -p /var/backups/gitlab
sudo chown -R gitlab-backup:gitlab-backup /opt/gitlab-backup
sudo chown gitlab-backup:gitlab-backup /var/backups/gitlab
sudo chmod 750 /opt/gitlab-backup /var/backups/gitlab
Generate GPG encryption key
Create a dedicated GPG key for backup encryption. Use a strong passphrase and store it securely.
sudo -u gitlab-backup gpg --full-generate-key
When prompted, select:
- Key type: RSA and RSA (default)
- Key size: 4096
- Validity: 0 (key does not expire)
- Real name: GitLab Backup
- Email: backup@example.com
List the key to get the key ID:
sudo -u gitlab-backup gpg --list-secret-keys --keyid-format LONG
Configure GitLab backup settings
Modify GitLab configuration to optimize backup creation and set the backup path.
gitlab_rails['backup_path'] = "/var/backups/gitlab"
gitlab_rails['backup_archive_permissions'] = 0640
gitlab_rails['backup_pg_schema'] = 'public'
gitlab_rails['backup_keep_time'] = 604800
gitlab_rails['backup_upload_connection'] = {
'provider' => 'Local'
}
Reconfigure GitLab to apply the changes:
sudo gitlab-ctl reconfigure
Create backup encryption script
Create the main backup script that handles GitLab backup creation, encryption, and cleanup.
#!/bin/bash
GitLab Backup Script with GPG Encryption
set -euo pipefail
Configuration
BACKUP_DIR="/var/backups/gitlab"
LOG_DIR="/opt/gitlab-backup/logs"
TMP_DIR="/opt/gitlab-backup/tmp"
REMOTE_HOST="backup-server.example.com"
REMOTE_PATH="/backup/gitlab"
REMOTE_USER="backup"
GPG_RECIPIENT="backup@example.com"
RETENTION_DAYS=30
LOG_FILE="$LOG_DIR/backup-$(date +%Y%m%d).log"
Logging function
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}
Error handling
error_exit() {
log "ERROR: $1"
exit 1
}
Start backup process
log "Starting GitLab backup process"
Create GitLab backup
log "Creating GitLab backup"
gitlab-backup create BACKUP=gitlab_backup_$(date +%s_%Y_%m_%d_%H_%M_%S) || error_exit "GitLab backup creation failed"
Find the latest backup file
LATEST_BACKUP=$(ls -t "$BACKUP_DIR"/*.tar 2>/dev/null | head -1)
if [[ -z "$LATEST_BACKUP" ]]; then
error_exit "No backup file found"
fi
log "Latest backup: $LATEST_BACKUP"
Compress and encrypt backup
BACKUP_NAME=$(basename "$LATEST_BACKUP" .tar)
ENCRYPTED_FILE="$TMP_DIR/${BACKUP_NAME}.tar.gz.gpg"
log "Compressing and encrypting backup"
pigz -c "$LATEST_BACKUP" | gpg --trust-model always --encrypt -r "$GPG_RECIPIENT" --cipher-algo AES256 --compress-algo 1 --output "$ENCRYPTED_FILE" || error_exit "Encryption failed"
Verify encrypted file
if [[ ! -f "$ENCRYPTED_FILE" ]] || [[ ! -s "$ENCRYPTED_FILE" ]]; then
error_exit "Encrypted backup file is missing or empty"
fi
log "Encrypted backup size: $(du -h $ENCRYPTED_FILE | cut -f1)"
Upload to remote storage
log "Uploading backup to remote storage"
rsync -avz --progress "$ENCRYPTED_FILE" "${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_PATH}/" || error_exit "Remote upload failed"
Cleanup local files
log "Cleaning up local backup files"
rm -f "$LATEST_BACKUP"
rm -f "$ENCRYPTED_FILE"
Remove old backups from remote storage
log "Cleaning old backups on remote storage"
ssh "${REMOTE_USER}@${REMOTE_HOST}" "find ${REMOTE_PATH} -name '*.tar.gz.gpg' -type f -mtime +${RETENTION_DAYS} -delete" || log "WARNING: Could not clean old remote backups"
Remove old local log files
find "$LOG_DIR" -name "backup-*.log" -type f -mtime +7 -delete || log "WARNING: Could not clean old log files"
log "GitLab backup completed successfully"
Send completion notification
echo "GitLab backup completed at $(date)" | logger -t gitlab-backup
Make the script executable:
sudo chmod 750 /opt/gitlab-backup/scripts/gitlab-backup.sh
sudo chown gitlab-backup:gitlab-backup /opt/gitlab-backup/scripts/gitlab-backup.sh
Create backup restore script
Create a script to decrypt and restore GitLab backups when needed.
#!/bin/bash
GitLab Restore Script
set -euo pipefail
Configuration
BACKUP_DIR="/var/backups/gitlab"
TMP_DIR="/opt/gitlab-backup/tmp"
LOG_DIR="/opt/gitlab-backup/logs"
LOG_FILE="$LOG_DIR/restore-$(date +%Y%m%d-%H%M%S).log"
Logging function
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}
Error handling
error_exit() {
log "ERROR: $1"
exit 1
}
Check if backup file provided
if [[ $# -ne 1 ]]; then
echo "Usage: $0 "
exit 1
fi
ENCRYPTED_FILE="$1"
if [[ ! -f "$ENCRYPTED_FILE" ]]; then
error_exit "Backup file not found: $ENCRYPTED_FILE"
fi
log "Starting GitLab restore process"
log "Backup file: $ENCRYPTED_FILE"
Extract backup name
BACKUP_NAME=$(basename "$ENCRYPTED_FILE" .tar.gz.gpg)
DECRYPTED_FILE="$TMP_DIR/${BACKUP_NAME}.tar"
Decrypt backup
log "Decrypting backup file"
gpg --decrypt "$ENCRYPTED_FILE" | pigz -d > "$DECRYPTED_FILE" || error_exit "Decryption failed"
Move to GitLab backup directory
mv "$DECRYPTED_FILE" "$BACKUP_DIR/"
DECRYPTED_FILE="$BACKUP_DIR/${BACKUP_NAME}.tar"
Stop GitLab services
log "Stopping GitLab services"
gitlab-ctl stop unicorn
gitlab-ctl stop puma
gitlab-ctl stop sidekiq
Restore GitLab backup
log "Restoring GitLab from backup"
gitlab-backup restore BACKUP="$BACKUP_NAME" || error_exit "GitLab restore failed"
Start GitLab services
log "Starting GitLab services"
gitlab-ctl start
Cleanup
rm -f "$DECRYPTED_FILE"
log "GitLab restore completed successfully"
log "Please run: gitlab-rake gitlab:check SANITIZE=true"
Make the restore script executable:
sudo chmod 750 /opt/gitlab-backup/scripts/gitlab-restore.sh
sudo chown gitlab-backup:gitlab-backup /opt/gitlab-backup/scripts/gitlab-restore.sh
Set up SSH key authentication for remote storage
Configure passwordless SSH for secure remote backup transfers.
sudo -u gitlab-backup ssh-keygen -t ed25519 -f /opt/gitlab-backup/.ssh/id_ed25519 -N ""
sudo -u gitlab-backup ssh-copy-id backup@backup-server.example.com
Test the SSH connection:
sudo -u gitlab-backup ssh backup@backup-server.example.com "mkdir -p /backup/gitlab"
Create systemd service and timer
Configure systemd to run backups automatically on a schedule.
[Unit]
Description=GitLab Backup Service
Wants=network-online.target
After=network-online.target
[Service]
Type=oneshot
User=gitlab-backup
Group=gitlab-backup
ExecStart=/opt/gitlab-backup/scripts/gitlab-backup.sh
PrivateTmp=true
ProtectHome=true
ProtectSystem=strict
ReadWritePaths=/var/backups/gitlab /opt/gitlab-backup
NoNewPrivileges=true
[Unit]
Description=Run GitLab backup daily
Requires=gitlab-backup.service
[Timer]
OnCalendar=daily
RandomizedDelaySec=3600
Persistent=true
[Install]
WantedBy=timers.target
Enable and start the timer:
sudo systemctl daemon-reload
sudo systemctl enable gitlab-backup.timer
sudo systemctl start gitlab-backup.timer
Create backup monitoring script
Set up monitoring to alert when backups fail or are missing.
#!/bin/bash
GitLab Backup Monitor
set -euo pipefail
REMOTE_HOST="backup-server.example.com"
REMOTE_PATH="/backup/gitlab"
REMOTE_USER="backup"
ALERT_EMAIL="admin@example.com"
MAX_AGE_HOURS=25
Check if latest backup exists and is recent
LATEST_BACKUP=$(ssh "${REMOTE_USER}@${REMOTE_HOST}" "find ${REMOTE_PATH} -name '*.tar.gz.gpg' -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -d' ' -f2" || echo "")
if [[ -z "$LATEST_BACKUP" ]]; then
echo "CRITICAL: No GitLab backups found on remote storage" | mail -s "GitLab Backup Alert" "$ALERT_EMAIL"
exit 1
fi
Check backup age
BACKUP_TIME=$(ssh "${REMOTE_USER}@${REMOTE_HOST}" "stat -c %Y '$LATEST_BACKUP'")
CURRENT_TIME=$(date +%s)
AGE_HOURS=$(( (CURRENT_TIME - BACKUP_TIME) / 3600 ))
if [[ $AGE_HOURS -gt $MAX_AGE_HOURS ]]; then
echo "WARNING: Latest GitLab backup is $AGE_HOURS hours old (file: $LATEST_BACKUP)" | mail -s "GitLab Backup Age Warning" "$ALERT_EMAIL"
exit 1
fi
echo "GitLab backup check passed: Latest backup is $AGE_HOURS hours old"
exit 0
Make the monitor script executable and create a timer:
sudo chmod 750 /opt/gitlab-backup/scripts/backup-monitor.sh
sudo chown gitlab-backup:gitlab-backup /opt/gitlab-backup/scripts/backup-monitor.sh
Configure backup verification
Create a script to periodically verify backup integrity.
#!/bin/bash
GitLab Backup Verification
set -euo pipefail
REMOTE_HOST="backup-server.example.com"
REMOTE_PATH="/backup/gitlab"
REMOTE_USER="backup"
TMP_DIR="/opt/gitlab-backup/tmp"
LOG_FILE="/opt/gitlab-backup/logs/verify-$(date +%Y%m%d).log"
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}
Download latest backup for verification
log "Starting backup verification"
LATEST_BACKUP=$(ssh "${REMOTE_USER}@${REMOTE_HOST}" "find ${REMOTE_PATH} -name '*.tar.gz.gpg' -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -d' ' -f2")
if [[ -z "$LATEST_BACKUP" ]]; then
log "ERROR: No backup found for verification"
exit 1
fi
BACKUP_NAME=$(basename "$LATEST_BACKUP")
LOCAL_FILE="$TMP_DIR/$BACKUP_NAME"
log "Downloading backup: $BACKUP_NAME"
rsync -avz "${REMOTE_USER}@${REMOTE_HOST}:$LATEST_BACKUP" "$LOCAL_FILE"
Verify GPG signature and decrypt headers only
log "Verifying GPG encryption"
if gpg --list-packets "$LOCAL_FILE" > /dev/null 2>&1; then
log "SUCCESS: Backup GPG encryption verified"
else
log "ERROR: Backup GPG verification failed"
rm -f "$LOCAL_FILE"
exit 1
fi
Test partial decryption
log "Testing backup decryption"
if gpg --decrypt "$LOCAL_FILE" 2>/dev/null | pigz -t; then
log "SUCCESS: Backup can be decrypted and decompressed"
else
log "ERROR: Backup decryption or decompression failed"
rm -f "$LOCAL_FILE"
exit 1
fi
Cleanup
rm -f "$LOCAL_FILE"
log "Backup verification completed successfully"
Report to monitoring system if using one
echo "GitLab backup verification passed" | logger -t gitlab-backup-verify
Make the script executable:
sudo chmod 750 /opt/gitlab-backup/scripts/backup-verify.sh
sudo chown gitlab-backup:gitlab-backup /opt/gitlab-backup/scripts/backup-verify.sh
Add GitLab backup user to required groups
Grant necessary permissions for the backup user to access GitLab data.
sudo usermod -a -G git gitlab-backup
sudo usermod -a -G gitlab-redis gitlab-backup
Verify your setup
Test the backup system to ensure everything works correctly.
# Test backup creation
sudo systemctl start gitlab-backup.service
sudo systemctl status gitlab-backup.service
Check backup logs
sudo tail -f /opt/gitlab-backup/logs/backup-$(date +%Y%m%d).log
Verify timer schedule
sudo systemctl list-timers gitlab-backup.timer
Test GPG functionality
sudo -u gitlab-backup gpg --list-keys
Test remote connectivity
sudo -u gitlab-backup ssh backup@backup-server.example.com "ls -la /backup/gitlab/"
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Permission denied accessing GitLab files | Backup user not in git group | sudo usermod -a -G git gitlab-backup |
| GPG encryption fails | GPG key not found or expired | sudo -u gitlab-backup gpg --list-keys and regenerate if needed |
| Remote upload fails | SSH authentication or network issue | Test SSH: sudo -u gitlab-backup ssh backup@backup-server.example.com |
| Backup service fails to start | Missing directories or permissions | Check sudo journalctl -u gitlab-backup.service and verify paths |
| Out of disk space during backup | Insufficient space in backup directory | Increase disk space or adjust retention policy in script |
| GitLab backup command not found | GitLab not properly installed | Verify with which gitlab-backup and check GitLab installation |
Next steps
With your GitLab backup automation configured, consider these additional enhancements:
- Implement backup rotation policies with automated cleanup for more sophisticated retention management
- Setup backup monitoring with Prometheus and Grafana for comprehensive oversight
- Configure GitLab SAML authentication with Keycloak for enterprise user management
- Setup GitLab CI/CD with automated testing and deployment for complete DevOps workflows
- Configure GitLab disaster recovery with Geo replication for multi-site redundancy
Running this in production?
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# GitLab Backup Automation Setup Script
# Configures automated GitLab backups with GPG encryption
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Default values
BACKUP_EMAIL="${1:-backup@example.com}"
REMOTE_HOST="${2:-}"
REMOTE_USER="${3:-backup}"
usage() {
echo "Usage: $0 [backup-email] [remote-host] [remote-user]"
echo "Example: $0 backup@mycompany.com backup.example.com backupuser"
exit 1
}
log() {
echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')] $1${NC}"
}
warn() {
echo -e "${YELLOW}[WARNING] $1${NC}"
}
error() {
echo -e "${RED}[ERROR] $1${NC}"
exit 1
}
cleanup() {
if [[ -n "${TMP_SCRIPT:-}" && -f "$TMP_SCRIPT" ]]; then
rm -f "$TMP_SCRIPT"
fi
}
trap cleanup ERR EXIT
check_root() {
if [[ $EUID -ne 0 ]]; then
error "This script must be run as root"
fi
}
detect_distro() {
if [[ ! -f /etc/os-release ]]; then
error "Cannot detect distribution. /etc/os-release not found."
fi
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_UPDATE="apt update"
PKG_INSTALL="apt install -y"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_UPDATE="dnf makecache"
PKG_INSTALL="dnf install -y"
if ! command -v dnf &> /dev/null; then
PKG_MGR="yum"
PKG_UPDATE="yum makecache"
PKG_INSTALL="yum install -y"
fi
;;
amzn)
PKG_MGR="yum"
PKG_UPDATE="yum makecache"
PKG_INSTALL="yum install -y"
;;
*)
error "Unsupported distribution: $ID"
;;
esac
}
install_packages() {
log "[2/8] Installing required packages..."
$PKG_UPDATE
$PKG_INSTALL gnupg2 rsync gzip
# Install pigz if available, fallback to gzip
if ! $PKG_INSTALL pigz 2>/dev/null; then
warn "pigz not available, will use gzip for compression"
fi
}
create_backup_user() {
log "[3/8] Creating backup user and directories..."
if ! id "gitlab-backup" &>/dev/null; then
useradd -r -s /bin/bash -d /opt/gitlab-backup gitlab-backup
fi
mkdir -p /opt/gitlab-backup/{scripts,logs,tmp}
mkdir -p /var/backups/gitlab
chown -R gitlab-backup:gitlab-backup /opt/gitlab-backup
chown gitlab-backup:gitlab-backup /var/backups/gitlab
chmod 750 /opt/gitlab-backup /var/backups/gitlab
chmod 755 /opt/gitlab-backup/scripts
chmod 755 /opt/gitlab-backup/logs
chmod 700 /opt/gitlab-backup/tmp
}
generate_gpg_key() {
log "[4/8] Generating GPG key for backup encryption..."
# Check if key already exists
if sudo -u gitlab-backup gpg --list-secret-keys | grep -q "$BACKUP_EMAIL"; then
log "GPG key for $BACKUP_EMAIL already exists, skipping generation"
return
fi
# Create GPG key configuration
cat > /tmp/gpg-key-config << EOF
Key-Type: RSA
Key-Length: 4096
Subkey-Type: RSA
Subkey-Length: 4096
Name-Real: GitLab Backup
Name-Email: $BACKUP_EMAIL
Expire-Date: 0
Passphrase:
%commit
EOF
chown gitlab-backup:gitlab-backup /tmp/gpg-key-config
sudo -u gitlab-backup gpg --batch --generate-key /tmp/gpg-key-config
rm -f /tmp/gpg-key-config
log "GPG key generated successfully"
sudo -u gitlab-backup gpg --list-secret-keys --keyid-format LONG
}
configure_gitlab() {
log "[5/8] Configuring GitLab backup settings..."
if [[ ! -f /etc/gitlab/gitlab.rb ]]; then
error "GitLab configuration file not found. Please install GitLab first."
fi
# Backup original config
cp /etc/gitlab/gitlab.rb /etc/gitlab/gitlab.rb.backup.$(date +%s)
# Add backup configuration
cat >> /etc/gitlab/gitlab.rb << 'EOF'
# GitLab Backup Configuration
gitlab_rails['backup_path'] = "/var/backups/gitlab"
gitlab_rails['backup_archive_permissions'] = 0640
gitlab_rails['backup_pg_schema'] = 'public'
gitlab_rails['backup_keep_time'] = 604800
gitlab_rails['backup_upload_connection'] = {
'provider' => 'Local'
}
EOF
gitlab-ctl reconfigure
}
create_backup_script() {
log "[6/8] Creating backup encryption script..."
TMP_SCRIPT="/tmp/gitlab-backup.sh"
cat > "$TMP_SCRIPT" << 'EOF'
#!/usr/bin/env bash
set -euo pipefail
# Configuration
BACKUP_DIR="/var/backups/gitlab"
LOG_DIR="/opt/gitlab-backup/logs"
TMP_DIR="/opt/gitlab-backup/tmp"
REMOTE_HOST="REPLACE_REMOTE_HOST"
REMOTE_PATH="/backup/gitlab"
REMOTE_USER="REPLACE_REMOTE_USER"
GPG_RECIPIENT="REPLACE_BACKUP_EMAIL"
RETENTION_DAYS=30
LOG_FILE="$LOG_DIR/backup-$(date +%Y%m%d).log"
# Logging function
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}
# Error handling
error_exit() {
log "ERROR: $1"
exit 1
}
# Start backup process
log "Starting GitLab backup process"
# Create GitLab backup
log "Creating GitLab backup"
gitlab-backup create BACKUP=gitlab_backup_$(date +%s_%Y_%m_%d_%H_%M_%S) || error_exit "GitLab backup creation failed"
# Find the latest backup file
LATEST_BACKUP=$(ls -t "$BACKUP_DIR"/*.tar 2>/dev/null | head -1)
if [[ -z "$LATEST_BACKUP" ]]; then
error_exit "No backup file found"
fi
log "Latest backup: $LATEST_BACKUP"
# Compress and encrypt backup
BACKUP_NAME=$(basename "$LATEST_BACKUP" .tar)
ENCRYPTED_FILE="$TMP_DIR/${BACKUP_NAME}.tar.gz.gpg"
log "Compressing and encrypting backup"
if command -v pigz &> /dev/null; then
COMPRESSOR="pigz"
else
COMPRESSOR="gzip"
fi
$COMPRESSOR -c "$LATEST_BACKUP" | gpg --trust-model always --encrypt -r "$GPG_RECIPIENT" --cipher-algo AES256 --compress-algo 1 --output "$ENCRYPTED_FILE" || error_exit "Encryption failed"
# Verify encrypted file
if [[ ! -f "$ENCRYPTED_FILE" ]] || [[ ! -s "$ENCRYPTED_FILE" ]]; then
error_exit "Encrypted backup file is missing or empty"
fi
log "Encrypted backup size: $(du -h "$ENCRYPTED_FILE" | cut -f1)"
# Upload to remote storage (if configured)
if [[ -n "$REMOTE_HOST" ]]; then
log "Uploading backup to remote storage"
rsync -avz --progress "$ENCRYPTED_FILE" "${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_PATH}/" || error_exit "Remote upload failed"
# Remove old backups from remote storage
log "Cleaning old backups on remote storage"
ssh "${REMOTE_USER}@${REMOTE_HOST}" "find ${REMOTE_PATH} -name '*.gpg' -mtime +${RETENTION_DAYS} -delete" || warn "Could not clean remote backups"
else
log "No remote host configured, keeping backup locally"
fi
# Cleanup local files
log "Cleaning up local backup files"
rm -f "$LATEST_BACKUP"
if [[ -n "$REMOTE_HOST" ]]; then
rm -f "$ENCRYPTED_FILE"
fi
# Remove old local encrypted backups
find "$TMP_DIR" -name "*.gpg" -mtime +7 -delete 2>/dev/null || true
log "Backup process completed successfully"
EOF
# Replace placeholders
sed -i "s/REPLACE_BACKUP_EMAIL/$BACKUP_EMAIL/g" "$TMP_SCRIPT"
sed -i "s/REPLACE_REMOTE_HOST/$REMOTE_HOST/g" "$TMP_SCRIPT"
sed -i "s/REPLACE_REMOTE_USER/$REMOTE_USER/g" "$TMP_SCRIPT"
# Install script
mv "$TMP_SCRIPT" /opt/gitlab-backup/scripts/gitlab-backup.sh
chown gitlab-backup:gitlab-backup /opt/gitlab-backup/scripts/gitlab-backup.sh
chmod 750 /opt/gitlab-backup/scripts/gitlab-backup.sh
}
create_systemd_service() {
log "[7/8] Creating systemd service and timer..."
# Create service file
cat > /etc/systemd/system/gitlab-backup.service << EOF
[Unit]
Description=GitLab Backup with GPG Encryption
After=gitlab-runsvdir.service
[Service]
Type=oneshot
User=gitlab-backup
Group=gitlab-backup
ExecStart=/opt/gitlab-backup/scripts/gitlab-backup.sh
StandardOutput=journal
StandardError=journal
EOF
# Create timer file
cat > /etc/systemd/system/gitlab-backup.timer << EOF
[Unit]
Description=Run GitLab backup daily
Requires=gitlab-backup.service
[Timer]
OnCalendar=daily
RandomizedDelaySec=30m
Persistent=true
[Install]
WantedBy=timers.target
EOF
systemctl daemon-reload
systemctl enable gitlab-backup.timer
systemctl start gitlab-backup.timer
}
verify_installation() {
log "[8/8] Verifying installation..."
# Check backup user
if ! id gitlab-backup &>/dev/null; then
error "Backup user not created properly"
fi
# Check directories
for dir in /opt/gitlab-backup /var/backups/gitlab; do
if [[ ! -d "$dir" ]]; then
error "Directory $dir not created"
fi
done
# Check GPG key
if ! sudo -u gitlab-backup gpg --list-secret-keys | grep -q "$BACKUP_EMAIL"; then
error "GPG key not generated properly"
fi
# Check script
if [[ ! -f /opt/gitlab-backup/scripts/gitlab-backup.sh ]]; then
error "Backup script not created"
fi
# Check systemd timer
if ! systemctl is-enabled gitlab-backup.timer &>/dev/null; then
error "Systemd timer not enabled"
fi
log "Installation verification completed successfully!"
log "Backup timer status:"
systemctl status gitlab-backup.timer --no-pager
if [[ -n "$REMOTE_HOST" ]]; then
warn "Remember to set up SSH key authentication for $REMOTE_USER@$REMOTE_HOST"
fi
}
main() {
log "[1/8] Starting GitLab backup automation setup..."
check_root
detect_distro
install_packages
create_backup_user
generate_gpg_key
configure_gitlab
create_backup_script
create_systemd_service
verify_installation
log "GitLab backup automation setup completed successfully!"
log "Daily backups will run automatically via systemd timer"
log "Manual backup: sudo -u gitlab-backup /opt/gitlab-backup/scripts/gitlab-backup.sh"
}
main "$@"
Review the script before running. Execute with: bash install.sh