Skip to main content

Backup and Monitoring System Setup Guide


Table of Contents

  1. Overview
  2. Prerequisites
  3. Installation
  4. Configuration
  5. Usage
  6. Troubleshooting
  7. Maintenance
  8. Security

Overview

This system provides automated backups for PostgreSQL and MongoDB databases with optional monitoring via:

  • AWS CloudWatch (for cloud environments)
  • Prometheus + Grafana (for on-premises visualization)

Key Features:

  • Daily compressed backups with retention policy
  • One-click restore functionality
  • Interactive setup script
  • Log rotation and monitoring

Prerequisites

For All Systems

  • Linux server (Ubuntu/CentOS recommended)
  • sudo privileges
  • Docker installed
  • docker-compose (for Prometheus/Grafana)

For CloudWatch

  • AWS account with IAM permissions
  • AWS CLI configured (aws configure)

For Prometheus/Grafana

  • Open ports: 9090 (Prometheus), 3000 (Grafana), 8080 (cAdvisor)

Installation

1. Copy the Script

#!/bin/bash

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

log "Starting interactive setup for Backup and Monitoring System."

# Initialize configuration variables
BASE_DIR=""
POSTGRES_CONTAINER=""
MONGO_CONTAINER=""
RETENTION_DAYS=""
POSTGRES_USER=""
POSTGRES_PASSWORD=""
MONGO_BACKUP_HOUR=""
POSTGRES_BACKUP_HOUR=""
SETUP_BACKUP=false
SETUP_MONITORING=false
MONITOR_TYPE=""
CLOUDWATCH_CONFIG=""
PROMETHEUS_PORT=""
GRAFANA_PORT=""
CADVISOR_PORT=""
GRAFANA_PASSWORD=""

# Function to validate directory path
validate_directory() {
local dir=$1
if [[ ! -d "$dir" ]]; then
read -p "Directory $dir does not exist. Create it? (yes/no): " create_dir
if [[ "$create_dir" =~ ^(yes|y)$ ]]; then
mkdir -p "$dir" || {
log "Failed to create directory $dir"
return 1
}
return 0
else
return 1
fi
fi
return 0
}

# Function to validate container name
validate_container() {
local container=$1
if ! docker ps --format '{{.Names}}' | grep -q "^${container}\$"; then
log "Warning: Container '$container' not found in running Docker containers."
read -p "Continue anyway? (yes/no): " continue_anyway
if [[ ! "$continue_anyway" =~ ^(yes|y)$ ]]; then
return 1
fi
fi
return 0
}

# Function to validate port
validate_port() {
local port=$1
if ! [[ "$port" =~ ^[0-9]+$ ]] || [ "$port" -lt 1 ] || [ "$port" -gt 65535 ]; then
log "Invalid port number: $port. Must be between 1-65535."
return 1
fi

if ss -tuln | grep -q ":${port} "; then
log "Warning: Port $port is already in use."
read -p "Continue anyway? (yes/no): " continue_anyway
if [[ ! "$continue_anyway" =~ ^(yes|y)$ ]]; then
return 1
fi
fi
return 0
}

# Function to collect backup configuration
collect_backup_config() {
log "Collecting backup system configuration..."

# Get base directory
while true; do
read -p "Enter base directory for scripts (default: /opt/backup-monitoring): " BASE_DIR
BASE_DIR=${BASE_DIR:-/opt/backup-monitoring}
if validate_directory "$BASE_DIR"; then
break
fi
done

# Get container names
while true; do
read -p "Enter PostgreSQL Docker container name: " POSTGRES_CONTAINER
if validate_container "$POSTGRES_CONTAINER"; then
break
fi
done

while true; do
read -p "Enter MongoDB Docker container name: " MONGO_CONTAINER
if validate_container "$MONGO_CONTAINER"; then
break
fi
done

# Get retention policy
while true; do
read -p "Enter backup retention period in days (default: 7): " RETENTION_DAYS
RETENTION_DAYS=${RETENTION_DAYS:-7}
if [[ "$RETENTION_DAYS" =~ ^[0-9]+$ ]] && [ "$RETENTION_DAYS" -gt 0 ]; then
break
else
log "Invalid retention period. Please enter a positive number."
fi
done

# Get PostgreSQL credentials
read -p "Enter PostgreSQL username (default: postgres): " POSTGRES_USER
POSTGRES_USER=${POSTGRES_USER:-postgres}
read -s -p "Enter PostgreSQL password (leave empty if none): " POSTGRES_PASSWORD
echo ""

# Get backup schedule
while true; do
read -p "Enter hour for MongoDB backup (0-23, default 2): " MONGO_BACKUP_HOUR
MONGO_BACKUP_HOUR=${MONGO_BACKUP_HOUR:-2}
if [[ "$MONGO_BACKUP_HOUR" =~ ^[0-9]+$ ]] && [ "$MONGO_BACKUP_HOUR" -ge 0 ] && [ "$MONGO_BACKUP_HOUR" -le 23 ]; then
break
else
log "Invalid hour. Please enter between 0-23."
fi
done

while true; do
read -p "Enter hour for PostgreSQL backup (0-23, default 3): " POSTGRES_BACKUP_HOUR
POSTGRES_BACKUP_HOUR=${POSTGRES_BACKUP_HOUR:-3}
if [[ "$POSTGRES_BACKUP_HOUR" =~ ^[0-9]+$ ]] && [ "$POSTGRES_BACKUP_HOUR" -ge 0 ] && [ "$POSTGRES_BACKUP_HOUR" -le 23 ]; then
break
else
log "Invalid hour. Please enter between 0-23."
fi
done

SETUP_BACKUP=true
}

# Function to collect CloudWatch configuration
collect_cloudwatch_config() {
log "Collecting CloudWatch configuration..."

read -p "Enter metrics collection interval in seconds (default: 60): " COLLECTION_INTERVAL
COLLECTION_INTERVAL=${COLLECTION_INTERVAL:-60}

read -p "Monitor disk usage? (yes/no, default: yes): " MONITOR_DISK
MONITOR_DISK=${MONITOR_DISK:-yes}

read -p "Monitor memory usage? (yes/no, default: yes): " MONITOR_MEM
MONITOR_MEM=${MONITOR_MEM:-yes}

# Build metrics_collected object
METRICS_COLLECTED="{"
if [[ "$MONITOR_DISK" =~ ^(yes|y)$ ]]; then
METRICS_COLLECTED+="\"disk\":{\"measurement\":[\"used_percent\"],\"metrics_collection_interval\":$COLLECTION_INTERVAL,\"resources\":[\"*\"]},"
fi
if [[ "$MONITOR_MEM" =~ ^(yes|y)$ ]]; then
METRICS_COLLECTED+="\"mem\":{\"measurement\":[\"mem_used_percent\"],\"metrics_collection_interval\":$COLLECTION_INTERVAL},"
fi
METRICS_COLLECTED=${METRICS_COLLECTED%,}
METRICS_COLLECTED+="}"

CLOUDWATCH_CONFIG="$BASE_DIR/cloudwatch-config.json"
cat <<EOF >"$CLOUDWATCH_CONFIG"
{
"agent": {
"metrics_collection_interval": $COLLECTION_INTERVAL,
"run_as_user": "root"
},
"metrics": {
"aggregation_dimensions": [["InstanceId"]],
"append_dimensions": {
"InstanceId": "\${aws:InstanceId}"
},
"metrics_collected": $METRICS_COLLECTED
}
}
EOF

MONITOR_TYPE="cloudwatch"
SETUP_MONITORING=true
}

# Function to collect Prometheus/Grafana configuration
collect_prometheus_config() {
log "Collecting Prometheus & Grafana configuration..."

# Get server IP
SERVER_IP=$(hostname -I | awk '{print $1}')

# Get configuration options
while true; do
read -p "Enter Prometheus port (default: 9090): " PROMETHEUS_PORT
PROMETHEUS_PORT=${PROMETHEUS_PORT:-9090}
if validate_port "$PROMETHEUS_PORT"; then
break
fi
done

while true; do
read -p "Enter Grafana port (default: 3000): " GRAFANA_PORT
GRAFANA_PORT=${GRAFANA_PORT:-3000}
if validate_port "$GRAFANA_PORT"; then
break
fi
done

while true; do
read -p "Enter cAdvisor port (default: 8080): " CADVISOR_PORT
CADVISOR_PORT=${CADVISOR_PORT:-8080}
if validate_port "$CADVISOR_PORT"; then
break
fi
done

read -p "Enter Grafana admin password (default: admin): " GRAFANA_PASSWORD
GRAFANA_PASSWORD=${GRAFANA_PASSWORD:-admin}

MONITOR_TYPE="prometheus"
SETUP_MONITORING=true
}

# Function to show configuration summary
show_config_summary() {
echo ""
echo "========================================"
echo " Configuration Summary"
echo "========================================"

if [ "$SETUP_BACKUP" = true ]; then
echo "Backup System:"
echo " Base Directory: $BASE_DIR"
echo " PostgreSQL Container: $POSTGRES_CONTAINER"
echo " MongoDB Container: $MONGO_CONTAINER"
echo " Retention Period: $RETENTION_DAYS days"
echo " PostgreSQL User: $POSTGRES_USER"
echo " MongoDB Backup Hour: $MONGO_BACKUP_HOUR:00"
echo " PostgreSQL Backup Hour: $POSTGRES_BACKUP_HOUR:00"
echo ""
fi

if [ "$SETUP_MONITORING" = true ]; then
echo "Monitoring System:"
if [ "$MONITOR_TYPE" = "cloudwatch" ]; then
echo " Type: AWS CloudWatch"
echo " Config File: $CLOUDWATCH_CONFIG"
echo " Collection Interval: $COLLECTION_INTERVAL seconds"
elif [ "$MONITOR_TYPE" = "prometheus" ]; then
echo " Type: Prometheus & Grafana"
echo " Prometheus Port: $PROMETHEUS_PORT"
echo " Grafana Port: $GRAFANA_PORT"
echo " cAdvisor Port: $CADVISOR_PORT"
echo " Grafana Admin Password: $GRAFANA_PASSWORD"
fi
echo ""
fi

read -p "Proceed with this configuration? (yes/no): " CONFIRM
if [[ ! "$CONFIRM" =~ ^(yes|y)$ ]]; then
log "Configuration aborted by user."
exit 0
fi
}

# Function to setup backup scripts
setup_backup_scripts() {
log "Setting up backup system..."

# Subdirectories
LOG_DIR="$BASE_DIR/logs"
POSTGRES_BACKUP_DIR="$BASE_DIR/postgres-backup"
MONGO_BACKUP_DIR="$BASE_DIR/mongo-backup"

mkdir -p "$LOG_DIR" "$POSTGRES_BACKUP_DIR" "$MONGO_BACKUP_DIR"

# Create postgres_backup.sh with all variables expanded
cat <<EOF >"$BASE_DIR/postgres_backup.sh"
#!/bin/bash

# Configurations
DOCKER_CONTAINER_NAME="$POSTGRES_CONTAINER"
BACKUP_DIR="$POSTGRES_BACKUP_DIR"
RETENTION_DAYS=$RETENTION_DAYS
POSTGRES_USER="$POSTGRES_USER"
POSTGRES_PASSWORD="$POSTGRES_PASSWORD"
DATE=\$(date +%F)

# Ensure backup directory exists
mkdir -p "\$BACKUP_DIR"

# Create today's backup directory
TODAYS_BACKUP_DIR="\$BACKUP_DIR/\$DATE"
mkdir -p "\$TODAYS_BACKUP_DIR"

# Function to log messages
log() {
echo "\$(date +'%Y-%m-%d %H:%M:%S') - \$1" >> "$LOG_DIR/postgres_backup.log"
}

log "Starting PostgreSQL backup process."

# Set password if provided
if [ -n "\$POSTGRES_PASSWORD" ]; then
export PGPASSWORD="\$POSTGRES_PASSWORD"
fi

# Step 1: List all databases
log "Fetching database list from container: \$DOCKER_CONTAINER_NAME"
DATABASES=\$(docker exec -i "\$DOCKER_CONTAINER_NAME" psql -U "\$POSTGRES_USER" -t -c "SELECT datname FROM pg_database WHERE datistemplate = false;")
if [ -z "\$DATABASES" ]; then
log "No databases found or an error occurred. Exiting."
exit 1
fi

log "Databases found: \$DATABASES"

# Step 2: Backup each database
for DB in \$DATABASES; do
DB=\${DB// /} # Remove whitespace
if [ -n "\$DB" ]; then
DUMP_FILE="\$TODAYS_BACKUP_DIR/\$DB.sql"
log "Backing up database: \$DB to \$DUMP_FILE"
docker exec -i "\$DOCKER_CONTAINER_NAME" pg_dump -U "\$POSTGRES_USER" "\$DB" > "\$DUMP_FILE"
fi
done

# Step 3: Compress the backups into a zip file
ZIP_FILE="\$BACKUP_DIR/\$DATE.zip"
log "Compressing backup files into: \$ZIP_FILE"
cd "\$BACKUP_DIR" || exit 1
zip -r "\$DATE.zip" "\$DATE" > /dev/null 2>&1
rm -rf "\$TODAYS_BACKUP_DIR" # Remove uncompressed backup folder
log "Backup completed and stored at \$ZIP_FILE"

# Step 4: Retention policy - Delete backups older than retention period
log "Applying retention policy: Keeping last \$RETENTION_DAYS days of backups."
find "\$BACKUP_DIR" -type f -name "*.zip" -mtime +\$RETENTION_DAYS -exec rm -f {} \;
log "Old backups removed."

log "PostgreSQL backup process completed successfully."
EOF
chmod +x "$BASE_DIR/postgres_backup.sh"
log "Created and set permissions for postgres_backup.sh."

# Create postgres_restore.sh with all variables expanded
cat <<EOF >"$BASE_DIR/postgres_restore.sh"
#!/bin/bash

# Configurations
DOCKER_CONTAINER_NAME="$POSTGRES_CONTAINER"
BACKUP_DIR="$POSTGRES_BACKUP_DIR"
POSTGRES_USER="$POSTGRES_USER"
POSTGRES_PASSWORD="$POSTGRES_PASSWORD"

# Function to log messages
log() {
echo "\$(date +'%Y-%m-%d %H:%M:%S') - \$1" >> "$LOG_DIR/postgres_restore.log"
}

# Set password if provided
if [ -n "\$POSTGRES_PASSWORD" ]; then
export PGPASSWORD="\$POSTGRES_PASSWORD"
fi

# Step 1: Ask for the date to restore
read -p "Enter the backup date to restore (YYYY-MM-DD): " RESTORE_DATE

# Validate the date format
if ! [[ \$RESTORE_DATE =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}\$ ]]; then
log "Invalid date format. Use YYYY-MM-DD."
exit 1
fi

ZIP_FILE="\$BACKUP_DIR/\$RESTORE_DATE.zip"

# Step 2: Check if the backup file exists
if [ ! -f "\$ZIP_FILE" ]; then
log "Backup file \$ZIP_FILE not found. Exiting."
exit 1
fi

log "Backup file found: \$ZIP_FILE"

# Step 3: Unzip the file
TEMP_RESTORE_DIR="\$BACKUP_DIR/\$RESTORE_DATE"
mkdir -p "\$TEMP_RESTORE_DIR"
log "Extracting \$ZIP_FILE to \$TEMP_RESTORE_DIR"
unzip -o "\$ZIP_FILE" -d "\$TEMP_RESTORE_DIR" > /dev/null 2>&1

# Step 4: Create databases and restore
log "Restoring databases from backup files."
for DUMP_FILE in "\$TEMP_RESTORE_DIR"/*.sql; do
if [ -f "\$DUMP_FILE" ]; then
DB_NAME=\$(basename "\$DUMP_FILE" .sql)

log "Ensuring database '\$DB_NAME' exists."
docker exec -i "\$DOCKER_CONTAINER_NAME" psql -U "\$POSTGRES_USER" -c "CREATE DATABASE \"\$DB_NAME\";" > /dev/null 2>&1

log "Restoring dump file \$DUMP_FILE into database \$DB_NAME."
docker exec -i "\$DOCKER_CONTAINER_NAME" psql -U "\$POSTGRES_USER" -d "\$DB_NAME" < "\$DUMP_FILE"
fi
done

# Step 5: Cleanup temporary restore directory
log "Cleaning up temporary files."
rm -rf "\$TEMP_RESTORE_DIR"

log "Database restore process completed successfully."
EOF
chmod +x "$BASE_DIR/postgres_restore.sh"
log "Created and set permissions for postgres_restore.sh."

# Create mongo_backup.sh with all variables expanded
cat <<EOF >"$BASE_DIR/mongo_backup.sh"
#!/bin/bash

# Configuration variables
CONTAINER_NAME="$MONGO_CONTAINER"
BACKUP_DIR="$MONGO_BACKUP_DIR"
RETENTION_DAYS=$RETENTION_DAYS
EXCLUDE_DBS=("admin" "config" "local") # Databases to exclude

# Function to log messages
log() {
echo "\$(date +'%Y-%m-%d %H:%M:%S') - \$1" >> "$LOG_DIR/mongo_backup.log"
}

# Create backup directory for today
TODAY=\$(date +"%Y-%m-%d")
TODAY_DIR="\$BACKUP_DIR/tmp_\$TODAY"
mkdir -p "\$TODAY_DIR"

# Step 1: List databases
DATABASES=\$(docker exec "\$CONTAINER_NAME" mongo --quiet --eval "db.adminCommand('listDatabases').databases.map(db => db.name).join(' ')" | tr -d '\r')

# Step 2: Filter databases to exclude specified ones
DBS_TO_BACKUP=()
for DB in \$DATABASES; do
if [[ ! " \${EXCLUDE_DBS[@]} " =~ " \${DB} " ]]; then
DBS_TO_BACKUP+=("\$DB")
fi
done

# Step 3: Dump each database
for DB in "\${DBS_TO_BACKUP[@]}"; do
log "Backing up database: \$DB"
docker exec "\$CONTAINER_NAME" mongodump --db="\$DB" --archive > "\$TODAY_DIR/\$DB.archive"
done

# Step 4: Compress the backup
ZIP_FILE="\$BACKUP_DIR/\${TODAY}.zip"
(cd "\$TODAY_DIR" && zip -r "\$ZIP_FILE" .)
rm -rf "\$TODAY_DIR" # Remove the temporary uncompressed files

# Step 5: Retain only the last \$RETENTION_DAYS days of backups
find "\$BACKUP_DIR" -type f -name "*.zip" -mtime +\$RETENTION_DAYS -exec rm {} \;

log "Backup completed and stored in: \$ZIP_FILE"
EOF
chmod +x "$BASE_DIR/mongo_backup.sh"
log "Created and set permissions for mongo_backup.sh."

# Create mongo_restore.sh with all variables expanded
cat <<EOF >"$BASE_DIR/mongo_restore.sh"
#!/bin/bash

# Configuration variables
CONTAINER_NAME="$MONGO_CONTAINER"
BACKUP_DIR="$MONGO_BACKUP_DIR"

# Function to log messages
log() {
echo "\$(date +'%Y-%m-%d %H:%M:%S') - \$1" >> "$LOG_DIR/mongo_restore.log"
}

# Step 1: Ask for the date
read -p "Enter the backup date to restore (YYYY-MM-DD): " RESTORE_DATE
ZIP_FILE="\$BACKUP_DIR/\${RESTORE_DATE}.zip"
RESTORE_DIR="\$BACKUP_DIR/tmp_restore_\$RESTORE_DATE"

if [[ ! -f "\$ZIP_FILE" ]]; then
log "Error: Backup file for \$RESTORE_DATE not found."
exit 1
fi

# Step 2: Unzip the backup file
mkdir -p "\$RESTORE_DIR"
unzip "\$ZIP_FILE" -d "\$RESTORE_DIR"

# Step 3: List the databases in the backup
DBS_IN_BACKUP=()
for FILE in "\$RESTORE_DIR"/*.archive; do
BASENAME=\$(basename "\$FILE" .archive)
DBS_IN_BACKUP+=("\$BASENAME")
done

# Step 4: Check existing databases in the container
EXISTING_DBS=\$(docker exec "\$CONTAINER_NAME" mongo --quiet --eval "db.adminCommand('listDatabases').databases.map(db => db.name).join(' ')" | tr -d '\r')

# Step 5: Restore each database
for DB in "\${DBS_IN_BACKUP[@]}"; do
log "Restoring database: \$DB"

# Check if the database exists
if [[ ! " \${EXISTING_DBS[@]} " =~ " \${DB} " ]]; then
log "Database \$DB does not exist. It will be created."
fi

# Restore the database
cat "\$RESTORE_DIR/\$DB.archive" | docker exec -i "\$CONTAINER_NAME" mongorestore --archive --nsInclude="\$DB.*"
done

# Cleanup
rm -rf "\$RESTORE_DIR"

log "Restore completed successfully."
EOF
chmod +x "$BASE_DIR/mongo_restore.sh"
log "Created and set permissions for mongo_restore.sh."

# Configure cronjobs
log "Configuring cronjobs for backup scripts."
(crontab -l 2>/dev/null; echo "0 $MONGO_BACKUP_HOUR * * * $BASE_DIR/mongo_backup.sh >> $LOG_DIR/mongo_backup.log 2>&1") | crontab -
(crontab -l 2>/dev/null; echo "0 $POSTGRES_BACKUP_HOUR * * * $BASE_DIR/postgres_backup.sh >> $LOG_DIR/postgres_backup.log 2>&1") | crontab -

# Configure logrotate
log "Setting up logrotate for backup logs."
sudo tee /etc/logrotate.d/backup_logs << EOF
$LOG_DIR/*.log {
daily
rotate 7
compress
missingok
notifempty
create 644 $(whoami) $(whoami)
dateext
}
EOF
sudo chmod 644 /etc/logrotate.d/backup_logs
sudo chown root:root /etc/logrotate.d/backup_logs

log "Backup system setup completed successfully."
}

# Function to setup CloudWatch monitoring
setup_cloudwatch() {
log "Setting up CloudWatch monitoring..."

# Check if AWS CLI is installed
if ! command -v aws &> /dev/null; then
log "AWS CLI not found. Installing..."
sudo apt-get update
sudo apt-get install -y awscli
fi

# Configure AWS CLI if not already configured
if [ ! -f ~/.aws/config ]; then
log "AWS CLI not configured. Running setup..."
aws configure
fi

# Install CloudWatch agent
if ! command -v amazon-cloudwatch-agent &> /dev/null; then
log "Installing CloudWatch agent..."
sudo apt-get update
sudo apt-get install -y amazon-cloudwatch-agent
fi

# Start CloudWatch agent
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -c file:$CLOUDWATCH_CONFIG -s
log "CloudWatch agent started with configuration at $CLOUDWATCH_CONFIG"
}

# Function to setup Prometheus/Grafana monitoring
setup_prometheus_grafana() {
log "Setting up Prometheus & Grafana monitoring..."

SERVER_IP=$(hostname -I | awk '{print $1}')
SERVER_IP_PUB=$(curl -s ifconfig.me)

# Define paths for docker-compose and Prometheus configuration
COMPOSE_FILE="$BASE_DIR/docker-compose.yml"
PROMETHEUS_CONFIG="$BASE_DIR/prometheus.yml"

# Create docker-compose.yml
cat <<EOF >"$COMPOSE_FILE"
version: '3.3'
services:
prometheus:
image: prom/prometheus:latest
container_name: prometheus
ports:
- "$PROMETHEUS_PORT:9090"
volumes:
- $BASE_DIR/prometheus.yml:/etc/prometheus/prometheus.yml
- $BASE_DIR/prometheus-data:/prometheus
restart: unless-stopped

grafana:
image: grafana/grafana-oss:latest
container_name: grafana
ports:
- "$GRAFANA_PORT:3000"
volumes:
- $BASE_DIR/grafana-data:/var/lib/grafana
environment:
- GF_SERVER_ROOT_URL=http://$SERVER_IP_PUB/grafana
- GF_SECURITY_ADMIN_PASSWORD=$GRAFANA_PASSWORD
restart: unless-stopped

node_exporter:
image: quay.io/prometheus/node-exporter:latest
container_name: node_exporter
command:
- '--path.rootfs=/host'
network_mode: host
pid: host
restart: unless-stopped
volumes:
- /:/host:ro,rslave

cadvisor:
image: google/cadvisor
container_name: cadvisor
volumes:
- /:/rootfs:ro
- /var/run:/var/run:rw
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
ports:
- "$CADVISOR_PORT:8080"
EOF

# Create prometheus.yml
cat <<EOF >"$PROMETHEUS_CONFIG"
global:
scrape_interval: 15s
evaluation_interval: 15s

scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['$SERVER_IP:9090']

- job_name: 'node_exporter'
static_configs:
- targets: ['$SERVER_IP:9100']

- job_name: 'cadvisor'
static_configs:
- targets: ['$SERVER_IP:$CADVISOR_PORT']

- job_name: 'docker'
static_configs:
- targets: ['$SERVER_IP:9323']
EOF

# Start containers
log "Starting monitoring containers with docker-compose."
docker-compose -f "$COMPOSE_FILE" up -d

# Add firewall rules if needed
if command -v ufw &> /dev/null; then
sudo ufw allow "$PROMETHEUS_PORT/tcp"
sudo ufw allow "$GRAFANA_PORT/tcp"
sudo ufw allow 9100/tcp # node_exporter
sudo ufw allow "$CADVISOR_PORT/tcp"
log "Firewall rules added for monitoring ports."
fi

log "Prometheus is available at http://$SERVER_IP:$PROMETHEUS_PORT"
log "Grafana is available at http://$SERVER_IP:$GRAFANA_PORT (username: admin, password: $GRAFANA_PASSWORD)"
}

# Main interactive menu
while true; do
echo ""
echo "========================================"
echo " Backup and Monitoring Setup Menu"
echo "========================================"
echo "1. Configure Backup System"
echo "2. Configure Monitoring System"
echo "3. Review Configuration and Install"
echo "4. Exit"
echo ""
read -p "Enter your choice (1-4): " MAIN_CHOICE

case "$MAIN_CHOICE" in
1)
collect_backup_config
;;
2)
echo ""
echo "Select Monitoring Option:"
echo "1. AWS CloudWatch"
echo "2. Prometheus & Grafana"
read -p "Enter your choice (1-2): " MONITOR_OPTION

case "$MONITOR_OPTION" in
1)
collect_cloudwatch_config
;;
2)
collect_prometheus_config
;;
*)
log "Invalid monitoring option selected."
;;
esac
;;
3)
if [ "$SETUP_BACKUP" = false ] && [ "$SETUP_MONITORING" = false ]; then
log "Nothing to install. Please configure at least one system first."
continue
fi

show_config_summary

if [ "$SETUP_BACKUP" = true ]; then
setup_backup_scripts
fi

if [ "$SETUP_MONITORING" = true ]; then
if [ "$MONITOR_TYPE" = "cloudwatch" ]; then
setup_cloudwatch
elif [ "$MONITOR_TYPE" = "prometheus" ]; then
setup_prometheus_grafana
fi
fi

log "Setup completed successfully."
exit 0
;;
4)
log "Exiting setup script."
exit 0
;;
*)
echo "Invalid option. Please try again."
;;
esac
done

Create a file

nano setup_backup_monitoring.sh

Give the executable permission

chmod +x setup_backup_monitoring.sh

2. Run Interactive Setup

./setup_backup_monitoring.sh

3. Follow Prompts

The script will guide you through:

  • Backup system configuration
  • Monitoring system selection
  • Final confirmation

Configuration

Backup System Defaults

ParameterDefault Value
Base Directory/opt/backup-monitoring
Retention Period7 days
PostgreSQL Userpostgres
Backup ScheduleMongoDB: 2 AM, PostgreSQL: 3 AM

Monitoring Options

CloudWatch

  • Metrics: Disk/Memory usage
  • Config: cloudwatch-config.json

Prometheus/Grafana

ServicePortCredentials
Prometheus9090None
Grafana3000admin / [your-password]
cAdvisor8080None

Usage

Manual Backups

/opt/backup-monitoring/postgres_backup.sh
/opt/backup-monitoring/mongo_backup.sh

Restore Databases

/opt/backup-monitoring/postgres_restore.sh  # Follow date prompt
/opt/backup-monitoring/mongo_restore.sh # Follow date prompt

Access Monitoring

  • Prometheus: http://<server-ip>:9090
  • Grafana: http://<server-ip>:3000

Troubleshooting

Common Issues

SymptomSolution
Backup failsCheck container names in logs
Grafana inaccessibleVerify port 3000 is open
CloudWatch metrics missingCheck IAM permissions

Log Locations

  • Backup logs: /opt/backup-monitoring/logs/
  • Docker logs: docker logs [container-name]

Maintenance

Update Retention

nano /opt/backup-monitoring/postgres_backup.sh  # Edit RETENTION_DAYS
nano /opt/backup-monitoring/mongo_backup.sh

Rotate Logs

logrotate -f /etc/logrotate.d/backup_logs

Security

  • 🔒 Change default Grafana password
  • 🔐 Restrict access to monitoring ports
  • 🛡️ Update Docker images regularly:
docker-compose -f /opt/backup-monitoring/docker-compose.yml pull