#!/usr/bin/env bash set -euo pipefail # --------------------------- # Config # --------------------------- REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" NGINX_ETC="/etc/nginx" SITES_AVAIL="$NGINX_ETC/sites-available" SITES_ENABLED="$NGINX_ETC/sites-enabled" SNIPPETS="$NGINX_ETC/snippets" CONFD="$NGINX_ETC/conf.d" # Where to deploy static files from ./http and ./robots.txt WEB_ROOT="${WEB_ROOT:-/var/www/nginx-conf}" # Which sites to ensure are enabled (symlinked) ENABLE_SITES=( "default" "nik4nao.home.arpa" "nik4nao.xyz" "prv-api.nik4nao.xyz" ) # Backup location BACKUP_BASE="/var/backups/nginx-conf-deploy" # --------------------------- # Helpers # --------------------------- usage() { cat <<'EOF' Usage: sudo ./deploy-nginx.sh [--dry-run] Options: --dry-run Show actions, do not write/reload. Env: WEB_ROOT=/some/path Override static deploy directory (default: /var/www/nginx-conf) EOF } need_root() { if [[ "${EUID}" -ne 0 ]]; then echo "ERROR: run as root (use sudo)." >&2 exit 1 fi } log() { echo "==> $*"; } DRY_RUN=0 if [[ "${1:-}" == "--dry-run" ]]; then DRY_RUN=1 elif [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then usage exit 0 elif [[ -n "${1:-}" ]]; then echo "Unknown option: $1" >&2 usage exit 1 fi need_root timestamp="$(date +%Y%m%d-%H%M%S)" backup_dir="${BACKUP_BASE}/${timestamp}" backup_tar="${backup_dir}/backup.tar.gz" mkdir_p() { if (( DRY_RUN )); then log "[dry-run] mkdir -p $*" else mkdir -p "$@" fi } copy_file() { local src="$1" local dst="$2" if [[ ! -f "$src" ]]; then echo "ERROR: missing source file: $src" >&2 exit 1 fi if (( DRY_RUN )); then log "[dry-run] install -m 0644 $src -> $dst" else install -m 0644 -D "$src" "$dst" fi } sync_dir() { local src="$1" local dst="$2" if [[ ! -d "$src" ]]; then echo "ERROR: missing source dir: $src" >&2 exit 1 fi if (( DRY_RUN )); then log "[dry-run] rsync -a --delete $src/ -> $dst/" else rsync -a --delete "${src}/" "${dst}/" fi } make_symlink() { local target="$1" local linkpath="$2" if (( DRY_RUN )); then log "[dry-run] ln -sfn $target $linkpath" else ln -sfn "$target" "$linkpath" fi } backup_paths=() add_backup_path() { local p="$1" if [[ -e "$p" || -L "$p" ]]; then backup_paths+=("$p") fi } do_backup() { mkdir_p "$backup_dir" # Backup only what we touch (and their symlinks) add_backup_path "$NGINX_ETC/nginx.conf" add_backup_path "$CONFD/upstreams.conf" add_backup_path "$SNIPPETS/proxy-common.conf" for s in "${ENABLE_SITES[@]}"; do add_backup_path "$SITES_AVAIL/$s" add_backup_path "$SITES_ENABLED/$s" done if (( DRY_RUN )); then log "[dry-run] tar -czf $backup_tar -P ${backup_paths[*]}" return fi if ((${#backup_paths[@]} == 0)); then log "No existing paths found to backup (first deploy?)." # still create empty backup dir for consistency return fi log "Creating backup: $backup_tar" tar -czf "$backup_tar" -P "${backup_paths[@]}" } restore_backup() { if (( DRY_RUN )); then log "[dry-run] restore from $backup_tar" return fi if [[ ! -f "$backup_tar" ]]; then log "No backup tar found to restore: $backup_tar" return fi log "Restoring from backup..." tar -xzf "$backup_tar" -P } nginx_test() { if (( DRY_RUN )); then log "[dry-run] nginx -t" return 0 fi nginx -t } nginx_reload() { if (( DRY_RUN )); then log "[dry-run] systemctl reload nginx" return 0 fi systemctl reload nginx } # --------------------------- # Deploy # --------------------------- log "Repo: $REPO_DIR" log "Deploying to: $NGINX_ETC" log "Static WEB_ROOT: $WEB_ROOT" do_backup # Ensure target dirs exist mkdir_p "$SITES_AVAIL" "$SITES_ENABLED" "$SNIPPETS" "$CONFD" "$WEB_ROOT" # Copy core config/snippets copy_file "$REPO_DIR/nginx.conf" "$NGINX_ETC/nginx.conf" copy_file "$REPO_DIR/upstreams.conf" "$CONFD/upstreams.conf" copy_file "$REPO_DIR/proxy-common.conf" "$SNIPPETS/proxy-common.conf" # Copy site configs (repo *.conf -> /etc/nginx/sites-available/) copy_file "$REPO_DIR/default.conf" "$SITES_AVAIL/default" copy_file "$REPO_DIR/nik4nao.home.arpa.conf" "$SITES_AVAIL/nik4nao.home.arpa" copy_file "$REPO_DIR/nik4nao.xyz.conf" "$SITES_AVAIL/nik4nao.xyz" copy_file "$REPO_DIR/prv-api.nik4nao.xyz.conf" "$SITES_AVAIL/prv-api.nik4nao.xyz" # Enable sites (symlinks) for s in "${ENABLE_SITES[@]}"; do make_symlink "$SITES_AVAIL/$s" "$SITES_ENABLED/$s" done # Deploy static content sync_dir "$REPO_DIR/http" "$WEB_ROOT" if [[ -f "$REPO_DIR/robots.txt" ]]; then copy_file "$REPO_DIR/robots.txt" "$WEB_ROOT/robots.txt" fi # Test + reload (rollback on failure) log "Testing nginx config..." if nginx_test; then log "Reloading nginx..." nginx_reload log "Done ✅" else log "nginx -t failed ❌" log "Rolling back..." restore_backup log "Re-testing after rollback..." nginx_test || true exit 2 fi