204 lines
8.1 KiB
Bash
Executable File
204 lines
8.1 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# C-Relay-PG PostgreSQL Deployment Script
|
|
# Deploys static relay binary and configures PostgreSQL 18 + systemd service on remote server.
|
|
|
|
set -euo pipefail
|
|
|
|
# Configuration
|
|
REMOTE_HOST="ubuntu@laantungir.net"
|
|
LOCAL_BINARY="build/c_relay_pg_static_x86_64"
|
|
LOCAL_CACHING_BINARY="build/caching_relay"
|
|
REMOTE_BINARY_DIR="/usr/local/bin/c_relay_pg"
|
|
REMOTE_BINARY_PATH="/usr/local/bin/c_relay_pg/c_relay_pg"
|
|
REMOTE_CACHING_BINARY_PATH="/opt/c-relay-pg/caching_relay"
|
|
SERVICE_NAME="c-relay-pg"
|
|
|
|
LOCAL_SERVICE_FILE="systemd/c-relay.service"
|
|
LOCAL_PG_SETUP_SCRIPT="systemd/setup_postgres_18.sh"
|
|
|
|
if [ ! -f "$LOCAL_BINARY" ]; then
|
|
echo "ERROR: Binary not found: $LOCAL_BINARY"
|
|
echo "Build it first (e.g. ./make_and_restart_relay.sh)"
|
|
exit 1
|
|
fi
|
|
|
|
if [ ! -f "$LOCAL_SERVICE_FILE" ]; then
|
|
echo "ERROR: Service file not found: $LOCAL_SERVICE_FILE"
|
|
exit 1
|
|
fi
|
|
|
|
if [ ! -f "$LOCAL_PG_SETUP_SCRIPT" ]; then
|
|
echo "ERROR: PostgreSQL setup script not found: $LOCAL_PG_SETUP_SCRIPT"
|
|
exit 1
|
|
fi
|
|
|
|
echo "==> Uploading artifacts to $REMOTE_HOST"
|
|
scp "$LOCAL_BINARY" "$REMOTE_HOST:/tmp/c_relay_pg.tmp"
|
|
scp "$LOCAL_SERVICE_FILE" "$REMOTE_HOST:/tmp/c-relay-pg.service"
|
|
scp "$LOCAL_PG_SETUP_SCRIPT" "$REMOTE_HOST:/tmp/setup_postgres_18.sh"
|
|
# Upload the caching_relay binary if it was built locally. The caching
|
|
# service is NOT started by this deploy (the systemd unit does not pass
|
|
# --start-caching), but the binary is placed in the relay's WorkingDirectory
|
|
# so it is ready for when caching is enabled via event-based config.
|
|
if [ -f "$LOCAL_CACHING_BINARY" ]; then
|
|
scp "$LOCAL_CACHING_BINARY" "$REMOTE_HOST:/tmp/caching_relay.tmp"
|
|
else
|
|
echo "WARNING: caching_relay binary not found locally ($LOCAL_CACHING_BINARY) — skipping caching binary upload"
|
|
fi
|
|
|
|
# Upload admin PHP files (tar to preserve directory structure, exclude
|
|
# cache logs and the dev-only serve.sh / php_server.log).
|
|
echo "==> Packaging admin files"
|
|
tar czf /tmp/admin_deploy.tar.gz \
|
|
--exclude='admin/serve.sh' \
|
|
--exclude='admin/php_server.log' \
|
|
--exclude='admin/cache' \
|
|
-C . admin/
|
|
scp /tmp/admin_deploy.tar.gz "$REMOTE_HOST:/tmp/admin_deploy.tar.gz"
|
|
|
|
echo "==> Running remote install/configuration"
|
|
ssh "$REMOTE_HOST" 'bash -s' <<'EOF'
|
|
set -euo pipefail
|
|
|
|
SERVICE_NAME="c-relay-pg"
|
|
RELAY_USER="c-relay-pg"
|
|
REMOTE_BINARY_DIR="/usr/local/bin/c_relay_pg"
|
|
REMOTE_BINARY_PATH="/usr/local/bin/c_relay_pg/c_relay_pg"
|
|
REMOTE_CACHING_BINARY_PATH="/opt/c-relay-pg/caching_relay"
|
|
|
|
echo "[remote] Ensuring service user exists"
|
|
if ! id "$RELAY_USER" >/dev/null 2>&1; then
|
|
sudo useradd --system --home-dir /opt/c-relay-pg --shell /usr/sbin/nologin "$RELAY_USER"
|
|
fi
|
|
|
|
echo "[remote] Ensuring required directories exist"
|
|
sudo mkdir -p "$REMOTE_BINARY_DIR" /opt/c-relay-pg /etc/c-relay-pg
|
|
sudo chown "$RELAY_USER:$RELAY_USER" /opt/c-relay-pg
|
|
|
|
echo "[remote] Installing PostgreSQL 18 (PGDG) if missing"
|
|
if ! dpkg -s postgresql-18 >/dev/null 2>&1; then
|
|
sudo apt-get update
|
|
sudo apt-get install -y curl ca-certificates lsb-release gnupg
|
|
sudo install -d /usr/share/postgresql-common/pgdg
|
|
sudo curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc
|
|
echo "deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" | sudo tee /etc/apt/sources.list.d/pgdg.list >/dev/null
|
|
sudo apt-get update
|
|
sudo apt-get install -y postgresql-18
|
|
fi
|
|
|
|
sudo systemctl enable postgresql
|
|
sudo systemctl restart postgresql
|
|
|
|
echo "[remote] Configuring PostgreSQL role/database"
|
|
sudo chmod +x /tmp/setup_postgres_18.sh
|
|
sudo /tmp/setup_postgres_18.sh
|
|
|
|
echo "[remote] Installing relay binary"
|
|
if [ -f "$REMOTE_BINARY_PATH" ]; then
|
|
sudo cp "$REMOTE_BINARY_PATH" "${REMOTE_BINARY_PATH}.backup.$(date +%Y%m%d_%H%M%S)"
|
|
fi
|
|
sudo mv /tmp/c_relay_pg.tmp "$REMOTE_BINARY_PATH"
|
|
sudo chown "$RELAY_USER:$RELAY_USER" "$REMOTE_BINARY_PATH"
|
|
sudo chmod +x "$REMOTE_BINARY_PATH"
|
|
|
|
echo "[remote] Installing caching_relay binary (if uploaded)"
|
|
if [ -f /tmp/caching_relay.tmp ]; then
|
|
sudo mv /tmp/caching_relay.tmp "$REMOTE_CACHING_BINARY_PATH"
|
|
sudo chown "$RELAY_USER:$RELAY_USER" "$REMOTE_CACHING_BINARY_PATH"
|
|
sudo chmod +x "$REMOTE_CACHING_BINARY_PATH"
|
|
echo " -> caching_relay installed at $REMOTE_CACHING_BINARY_PATH (not started; enable via config when ready)"
|
|
else
|
|
echo " -> no caching_relay binary uploaded, skipping"
|
|
fi
|
|
|
|
echo "[remote] Installing admin PHP files"
|
|
# Back up existing config.php and .htpasswd so we don't lose production
|
|
# credentials (DB password, basic-auth) across deploys.
|
|
if [ -f /opt/c-relay-pg/admin/lib/config.php ]; then
|
|
sudo cp /opt/c-relay-pg/admin/lib/config.php /tmp/admin_config_backup
|
|
echo " -> backed up config.php"
|
|
fi
|
|
if [ -f /opt/c-relay-pg/admin/.htpasswd ]; then
|
|
sudo cp /opt/c-relay-pg/admin/.htpasswd /tmp/admin_htpasswd_backup
|
|
echo " -> backed up .htpasswd"
|
|
fi
|
|
# Extract the new admin files (overwrites old admin at /opt/c-relay-pg/admin/).
|
|
sudo mkdir -p /opt/c-relay-pg/admin
|
|
sudo tar xzf /tmp/admin_deploy.tar.gz -C /opt/c-relay-pg/
|
|
# Restore config.php and .htpasswd if they were backed up.
|
|
if [ -f /tmp/admin_config_backup ]; then
|
|
sudo cp /tmp/admin_config_backup /opt/c-relay-pg/admin/lib/config.php
|
|
echo " -> restored config.php"
|
|
fi
|
|
if [ -f /tmp/admin_htpasswd_backup ]; then
|
|
sudo cp /tmp/admin_htpasswd_backup /opt/c-relay-pg/admin/.htpasswd
|
|
echo " -> restored .htpasswd"
|
|
fi
|
|
# Set ownership: www-data (nginx/php-fpm) for web-served files,
|
|
# but keep .htpasswd readable by nginx.
|
|
sudo chown -R www-data:www-data /opt/c-relay-pg/admin/
|
|
sudo chmod 640 /opt/c-relay-pg/admin/.htpasswd 2>/dev/null || true
|
|
# Ensure the cache directory exists (for chart text files).
|
|
sudo mkdir -p /opt/c-relay-pg/admin/cache
|
|
sudo chown www-data:www-data /opt/c-relay-pg/admin/cache
|
|
echo " -> admin files installed at /opt/c-relay-pg/admin/"
|
|
|
|
# Also update admin2 if it exists (symlink or copy to keep it in sync).
|
|
if [ -d /opt/c-relay-pg/admin2 ]; then
|
|
sudo rm -rf /opt/c-relay-pg/admin2
|
|
sudo cp -a /opt/c-relay-pg/admin /opt/c-relay-pg/admin2
|
|
sudo chown -R www-data:www-data /opt/c-relay-pg/admin2/
|
|
echo " -> admin2 synced at /opt/c-relay-pg/admin2/"
|
|
fi
|
|
|
|
echo "[remote] Installing systemd unit"
|
|
sudo mv /tmp/c-relay-pg.service /etc/systemd/system/c-relay-pg.service
|
|
sudo chown root:root /etc/systemd/system/c-relay-pg.service
|
|
sudo chmod 644 /etc/systemd/system/c-relay-pg.service
|
|
|
|
echo "[remote] Killing stale caching_relay processes (safety)"
|
|
# The caching service is forked by the relay with setsid(), so it detaches
|
|
# from the relay's process group and survives when the relay is killed.
|
|
# Without this, every restart orphans the previous caching_relay child and
|
|
# a new relay forks another, leading to many stale processes with dead PG
|
|
# connections spamming errors. Kill them here so the new relay starts clean.
|
|
CACHING_PIDS=$(pgrep -f "caching_relay" || echo "")
|
|
if [ -n "$CACHING_PIDS" ]; then
|
|
echo " -> killing stale caching_relay PIDs: $CACHING_PIDS"
|
|
kill -9 $CACHING_PIDS 2>/dev/null || true
|
|
sleep 1
|
|
else
|
|
echo " -> no stale caching_relay processes found"
|
|
fi
|
|
|
|
echo "[remote] Reloading and restarting service"
|
|
sudo systemctl daemon-reload
|
|
sudo systemctl enable "$SERVICE_NAME"
|
|
sudo systemctl restart "$SERVICE_NAME"
|
|
|
|
echo "[remote] Health checks"
|
|
sudo systemctl --no-pager --full status "$SERVICE_NAME" | sed -n '1,25p'
|
|
sudo -u "$RELAY_USER" psql -d crelay -c "SELECT current_user, current_database();"
|
|
|
|
# Verify admin page is accessible (HTTP 200 or 401 = auth required, both are OK).
|
|
ADMIN_CODE=$(curl -s -o /dev/null -w "%{http_code}" "http://127.0.0.1/admin/" 2>/dev/null || echo "000")
|
|
if [ "$ADMIN_CODE" = "200" ] || [ "$ADMIN_CODE" = "401" ]; then
|
|
echo " -> admin page accessible (HTTP $ADMIN_CODE)"
|
|
else
|
|
echo " -> WARNING: admin page returned HTTP $ADMIN_CODE (expected 200 or 401)"
|
|
fi
|
|
|
|
# Clean up temp files.
|
|
rm -f /tmp/admin_deploy.tar.gz
|
|
sudo rm -f /tmp/admin_htpasswd_backup /tmp/admin_config_backup
|
|
EOF
|
|
|
|
# Clean up local temp tarball.
|
|
rm -f /tmp/admin_deploy.tar.gz
|
|
|
|
echo "Deployment complete: $REMOTE_HOST"
|
|
echo ""
|
|
echo "Admin interface: https://laantungir.net/admin/"
|
|
echo "Caching is NOT auto-started. Enable it via the admin UI when ready."
|