Script 07 · Database Automation
7. Primary DB Auto Config & Backup
Initializes a primary PostgreSQL data directory, tunes database settings, and provides backup/restore migration flow.
Category: Database Automation
Risk: Destructive
Lines: calculating
Language: Bash / Linux
What this script does
- Create a dedicated primary DB cluster under /home/postgres.
- Tune PostgreSQL for Erupe workloads.
- Move data from a source DB to a target DB.
Prerequisites
- Root access
- PostgreSQL installed
- Known source/target credentials
- Reliable backup storage
Execution flow
- Detects PostgreSQL version
- Frees selected port
- Recreates primary data directory
- Writes postgresql.conf and pg_hba.conf
- Runs backup/restore
Validation checklist
- pg_isready -p <port>
- psql connection test
- pg_dump/pg_restore exit codes
- system logs
Operational cautions
- Deletes /home/postgres/primary_db if present.
- trust authentication is unsafe for public networks.
- Killing a port can stop unrelated services.
Original script notes
ℹ️ Script Info: Initializes the primary PostgreSQL database cluster, clears conflicting ports, applies advanced database performance tweaks, and includes built-in backup and restore functions.
cat << 'EOF' > setup_postgres_final.sh
#!/bin/bash
# ==========================================
# PostgreSQL Final Automation Script
# Auto Kill Port, Trust Auth, Full Backup
# ==========================================
# Check Root
if [ "$EUID" -ne 0 ]; then
echo "Run as root (sudo)."
exit 1
fi
# Error Handling Function
handle_error() {
echo "[ERROR] Occurred at stage: $1"
apt --fix-broken install -y
dpkg --configure -a
}
echo "=== 1. SYSTEM & USER PREP ==="
# Install extra tools for kill port (fuser) and locate
apt update
apt install plocate psmisc -y
# User Postgres
if id "postgres" >/dev/null; then
echo "User 'postgres' already exists."
else
echo "Creating user 'postgres'..."
useradd -m -s /bin/bash postgres
echo "Set password for Linux user 'postgres':"
passwd postgres
fi
echo -e "\n=== 2. DETECTION & POSTGRES PATH ==="
PG_VERSION=$(ls /usr/lib/postgresql/ | sort -V | tail -n 1)
if [ -z "$PG_VERSION" ]; then
echo "Installing PostgreSQL..."
apt install postgresql postgresql-contrib -y
PG_VERSION=$(ls /usr/lib/postgresql/ | sort -V | tail -n 1)
fi
PG_BIN_PATH="/usr/lib/postgresql/$PG_VERSION/bin"
echo "PostgreSQL Version: $PG_VERSION"
# Setup .bashrc
setup_path() {
local target_home=$2
if ! grep -q "$PG_BIN_PATH" $target_home/.bashrc; then
echo "export PATH=\$PATH:$PG_BIN_PATH" >> $target_home/.bashrc
fi
}
setup_path "postgres" "/home/postgres"
setup_path "root" "/root"
export PATH=$PATH:$PG_BIN_PATH
echo -e "\n=== 3. DATABASE INITIALIZATION ==="
echo "Define Port for Primary DB (This port will be cleared if currently in use)."
read -p "Enter PORT: " PG_PORT
# CLEANUP & KILL PORT LOGIC
echo ">> Checking availability of port and old directories..."
# 1. Check Directory
if [ -d "/home/postgres/primary_db" ]; then
echo "Old directory found. Attempting to stop related service..."
# Try graceful stop
sudo -u postgres $PG_BIN_PATH/pg_ctl -D /home/postgres/primary_db stop -m fast 2>/dev/null
fi
# 2. Kill Port Forcefully (Safety measure)
if fuser -n tcp $PG_PORT 2>/dev/null; then
echo "Port $PG_PORT is in use. Killing process forcefully..."
fuser -k -n tcp $PG_PORT
sleep 2
echo "Port $PG_PORT successfully freed."
fi
# 3. Delete Directory
if [ -d "/home/postgres/primary_db" ]; then
echo "Removing old directory /home/postgres/primary_db ..."
rm -rf /home/postgres/primary_db
fi
# Create New Directory
mkdir -p /home/postgres/primary_db
chown -R postgres:postgres /home/postgres
chmod -R 700 /home/postgres
echo ">> Performing InitDB..."
sudo -u postgres $PG_BIN_PATH/initdb -D /home/postgres/primary_db
CONF_FILE="/home/postgres/primary_db/postgresql.conf"
HBA_FILE="/home/postgres/primary_db/pg_hba.conf"
echo ">> Configuring postgresql.conf..."
sed -i "s/#listen_addresses = 'localhost'/listen_addresses = '*'/" $CONF_FILE
sed -i "s/#port = 5432/port = $PG_PORT/" $CONF_FILE
echo -e "\n=== INJECT CUSTOM CONFIGURATION ==="
echo "Select PostgreSQL Performance Profile:"
echo "1) Default Tweak Minimum (Recommended for smaller servers)"
echo "2) Advanced Tweak (High Performance / High RAM)"
read -p "Choice (1/2): " TWEAK_OPT
if [ "$TWEAK_OPT" == "2" ]; then
CONFIG_LIST="max_connections = 200
shared_buffers = 1024MB
effective_cache_size = 3072MB
maintenance_work_mem = 256MB
checkpoint_completion_target = 0.9
wal_buffers = 32MB
default_statistics_target = 100
random_page_cost = 1.1
effective_io_concurrency = 200
work_mem = 32MB
huge_pages = off
min_wal_size = 512MB
max_wal_size = 4GB
wal_writer_delay = 200ms
synchronous_commit = off
max_worker_processes = 8
max_parallel_maintenance_workers = 2
tcp_keepalives_idle = 60
tcp_keepalives_interval = 5
tcp_keepalives_count = 6
tcp_user_timeout = 0
client_connection_check_interval = 5000
dynamic_shared_memory_type = posix
autovacuum = on
autovacuum_vacuum_scale_factor = 0.1
autovacuum_analyze_scale_factor = 0.05
autovacuum_vacuum_cost_limit = 200
jit = off"
echo "Selected Advanced Tweak."
else
CONFIG_LIST="max_connections = 250
shared_buffers = 512MB
effective_cache_size = 1024MB
maintenance_work_mem = 64MB
checkpoint_completion_target = 0.9
wal_buffers = 4MB
default_statistics_target = 100
random_page_cost = 1.1
effective_io_concurrency = 250
work_mem = 4MB
huge_pages = off
min_wal_size = 128MB
max_wal_size = 1GB
wal_keep_size = 256MB
wal_level = replica
synchronous_commit = on
max_replication_slots = 10
max_wal_senders = 10
max_worker_processes = 2
max_parallel_workers_per_gather = 4
max_parallel_workers = 2
max_parallel_maintenance_workers = 4
tcp_keepalives_idle = 60
tcp_keepalives_interval = 5
tcp_keepalives_count = 4
tcp_user_timeout = 0
client_connection_check_interval = 0
dynamic_shared_memory_type = posix
autovacuum = on"
echo "Selected Default Tweak Minimum."
fi
echo "$CONFIG_LIST" | while IFS= read -r line; do
if [ ! -z "$line" ]; then
KEY=$(echo "$line" | cut -d'=' -f1 | sed 's/ //g')
sed -i "s/^$KEY\s*=/ #$KEY =/" $CONF_FILE
sed -i "s/^#$KEY\s*=/ #$KEY =/" $CONF_FILE
echo "$line" >> $CONF_FILE
fi
done
echo ">> Configuring pg_hba.conf (TRUST Method)..."
# Override for TRUST 0.0.0.0/0
echo "host all all 0.0.0.0/0 trust" >> $HBA_FILE
echo ">> Starting Database..."
sudo -u postgres $PG_BIN_PATH/pg_ctl -D /home/postgres/primary_db start
sleep 3
echo -e "\n=== 4. CREATE DATABASE & DB USER ==="
read -s -p "Enter password for DB user 'postgres' (Optional due to Trust, but recommended): " DB_PASS
echo ""
sudo -u postgres $PG_BIN_PATH/psql -p $PG_PORT -d postgres <<QueryEOF
ALTER USER postgres WITH ENCRYPTED PASSWORD '$DB_PASS';
CREATE DATABASE erupe;
GRANT ALL PRIVILEGES ON DATABASE erupe TO postgres;
QueryEOF
sudo -u postgres $PG_BIN_PATH/pg_ctl -D /home/postgres/primary_db restart
sleep 2
echo -e "\n=== 5. BACKUP PROCESS (FULL CONTENT) ==="
while true; do
echo ">> SETUP SOURCE SERVER:"
read -p "Source IP Address: " SRC_IP
read -p "Source Port: " SRC_PORT
read -p "Source DB User: " SRC_USER
read -s -p "Source DB Password: " SRC_PASS
echo ""
read -p "Name of Source Database to backup: " SRC_DB_NAME
# Check Connection
echo "Attempting connection to source..."
PGPASSWORD=$SRC_PASS $PG_BIN_PATH/psql -h $SRC_IP -p $SRC_PORT -U $SRC_USER -d $SRC_DB_NAME -c '\q' 2>/dev/null
if [ $? -eq 0 ]; then
echo "Connection Successful."
read -p "Backup Directory (e.g., /root/backup): " BACKUP_DIR
mkdir -p "$BACKUP_DIR"
read -p "Backup Filename (without extension): " BACKUP_NAME
FULL_PATH="$BACKUP_DIR/$BACKUP_NAME.sql"
echo ">> Running Full Backup (Schema + Data + Blobs)..."
# pg_dump -Fc includes blobs (-b) by default, but we flag it to be sure.
# No filter --schema-only or --data-only, so "everything" for that DB.
PGPASSWORD="$SRC_PASS" $PG_BIN_PATH/pg_dump -h "$SRC_IP" -p "$SRC_PORT" -U "$SRC_USER" -Fc -b -v -f "$FULL_PATH" -d "$SRC_DB_NAME"
if [ $? -eq 0 ]; then
echo "Backup Complete: $FULL_PATH"
BACKUP_SUCCESS=true
break
else
echo "Backup Failed during execution."
read -p "Try again? (y/n): " RETRY
if [[ "$RETRY" != "y" ]]; then BACKUP_SUCCESS=false; break; fi
fi
else
echo "Connection failed / Auth Incorrect."
read -p "Re-input data? (y/n): " RETRY
if [[ "$RETRY" != "y" ]]; then BACKUP_SUCCESS=false; break; fi
fi
done
echo -e "\n=== 6. RESTORE PROCESS ==="
if [ "$BACKUP_SUCCESS" = true ]; then
while true; do
echo ">> SETUP TARGET SERVER:"
read -p "Target IP Address: " TGT_IP
read -p "Target Port: " TGT_PORT
read -p "Target DB User: " TGT_USER
read -s -p "Target DB Password: " TGT_PASS
echo ""
read -p "Target Database Name for Restore: " TGT_DB_NAME
# Check Existing Database
DB_CHECK=$(PGPASSWORD=$TGT_PASS $PG_BIN_PATH/psql -h $TGT_IP -p $TGT_PORT -U $TGT_USER -d postgres -tAc "SELECT 1 FROM pg_database WHERE datname='$TGT_DB_NAME'" 2>/dev/null)
FINAL_DB_NAME="$TGT_DB_NAME"
DO_RESTORE=false
if [ "$DB_CHECK" == "1" ]; then
echo "Database '$TGT_DB_NAME' ALREADY EXISTS."
echo "1. Delete old DB & Re-Restore (Overwrite)."
echo "2. Restore to New DB (Rename)."
read -p "Choice (1/2): " OPT
if [ "$OPT" == "1" ]; then
echo "Terminating connections & Deleting old DB..."
PGPASSWORD=$TGT_PASS $PG_BIN_PATH/psql -h $TGT_IP -p $TGT_PORT -U $TGT_USER -d postgres -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '$TGT_DB_NAME';" >/dev/null
PGPASSWORD=$TGT_PASS $PG_BIN_PATH/psql -h $TGT_IP -p $TGT_PORT -U $TGT_USER -d postgres -c "DROP DATABASE \"$TGT_DB_NAME\";"
echo "Recreating DB..."
PGPASSWORD=$TGT_PASS $PG_BIN_PATH/psql -h $TGT_IP -p $TGT_PORT -U $TGT_USER -d postgres -c "CREATE DATABASE \"$TGT_DB_NAME\";"
PGPASSWORD=$TGT_PASS $PG_BIN_PATH/psql -h $TGT_IP -p $TGT_PORT -U $TGT_USER -d postgres -c "ALTER DATABASE \"$TGT_DB_NAME\" OWNER TO postgres;"
DO_RESTORE=true
elif [ "$OPT" == "2" ]; then
read -p "NEW Database Name: " NEW_DB_NAME
FINAL_DB_NAME="$NEW_DB_NAME"
echo "Creating DB '$FINAL_DB_NAME'..."
PGPASSWORD=$TGT_PASS $PG_BIN_PATH/psql -h $TGT_IP -p $TGT_PORT -U $TGT_USER -d postgres -c "CREATE DATABASE \"$FINAL_DB_NAME\";"
if [ $? -eq 0 ]; then
PGPASSWORD=$TGT_PASS $PG_BIN_PATH/psql -h $TGT_IP -p $TGT_PORT -U $TGT_USER -d postgres -c "ALTER DATABASE \"$FINAL_DB_NAME\" OWNER TO postgres;"
DO_RESTORE=true
else
echo "Failed to create new DB."
fi
fi
else
echo "Database does not exist. Creating new..."
PGPASSWORD=$TGT_PASS $PG_BIN_PATH/psql -h $TGT_IP -p $TGT_PORT -U $TGT_USER -d postgres -c "CREATE DATABASE \"$TGT_DB_NAME\";"
if [ $? -eq 0 ]; then
PGPASSWORD=$TGT_PASS $PG_BIN_PATH/psql -h $TGT_IP -p $TGT_PORT -U $TGT_USER -d postgres -c "ALTER DATABASE \"$TGT_DB_NAME\" OWNER TO postgres;"
DO_RESTORE=true
fi
fi
if [ "$DO_RESTORE" = true ]; then
echo ">> Starting Restore to '$FINAL_DB_NAME'..."
# Restore -v (verbose), -d (database)
PGPASSWORD="$TGT_PASS" $PG_BIN_PATH/pg_restore -h "$TGT_IP" -p "$TGT_PORT" -U "$TGT_USER" -d "$FINAL_DB_NAME" -v "$FULL_PATH"
if [ $? -eq 0 ]; then
echo "RESTORE SUCCESS!"
break
else
echo "Restore finished with Warning/Error."
read -p "Retry Restore? (y/n): " RETRY
if [[ "$RETRY" != "y" ]]; then break; fi
fi
else
read -p "Failed setup target DB. Retry input? (y/n): " RETRY
if [[ "$RETRY" != "y" ]]; then break; fi
fi
done
fi
echo "========================================="
echo "DONE. Script saved at: $(pwd)/setup_postgres_final.sh"
echo "========================================="
EOF
chmod +x setup_postgres_final.sh && ./setup_postgres_final.sh