#!/usr/bin/env bash # ============================================================================== # Static Web (nginx) Deployment Script — Multi-Instance # ============================================================================== # Deploys an nginx container serving static files behind Traefik. # Each instance is identified by --dir. Multiple instances can coexist. # # Usage: deploy-docker-web.sh --domain web1.an2.io --dir acme # deploy-docker-web.sh --domain web2.an2.io --dir acme-dev # deploy-docker-web.sh --remove --dir acme [--purge] [--yes] # ============================================================================== set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "${SCRIPT_DIR}/common.sh" # --- Parse arguments --- parse_args "$@" # --- Validate --dir --- [[ -n "$ARG_DIR" ]] || fatal "--dir is required. Example: $0 --domain web.an2.io --dir mysite" if ! [[ "$ARG_DIR" =~ ^[a-zA-Z0-9][a-zA-Z0-9_-]*$ ]]; then fatal "--dir value must be alphanumeric (hyphens/underscores ok, no spaces/slashes): ${ARG_DIR}" fi # --- Derive names from --dir --- DIR_NAME="$ARG_DIR" SERVICE_NAME="web-${DIR_NAME}" BASE_DIR="/opt/${DIR_NAME}" CONFIG_NAME="web-${DIR_NAME}" UNIT_NAME="web-${DIR_NAME}-docker" CONTAINER_NAME="web-${DIR_NAME}" # --- Handle --remove --- if [[ "$ARG_REMOVE" == "1" ]]; then require_root do_remove "$SERVICE_NAME" "$CONFIG_NAME" "$UNIT_NAME" "$BASE_DIR" exit 0 fi # --- Validate --domain (required for deploy) --- if [[ -z "$ARG_DOMAIN" ]] && ! [[ -f "${BASE_DIR}/.env" ]]; then fatal "--domain is required for deploy. Example: $0 --domain web.an2.io --dir ${DIR_NAME}" fi # --- Domain resolution --- if [[ -n "$ARG_DOMAIN" ]]; then DOMAIN="$ARG_DOMAIN" elif [[ -f "${BASE_DIR}/.env" ]] && grep -q '^DOMAIN=' "${BASE_DIR}/.env"; then DOMAIN="$(grep '^DOMAIN=' "${BASE_DIR}/.env" | cut -d= -f2)" else fatal "--domain is required for deploy." fi # --- Detect current state for banner --- traefik_status="Not found — will deploy" if docker ps --format '{{.Names}}' 2>/dev/null | grep -q '^traefik$'; then traefik_status="Running" elif [[ -f "${TRAEFIK_DIR}/docker-compose.yml" ]]; then traefik_status="Stopped — will start" fi install_mode="Fresh install" if [[ -f "${BASE_DIR}/.env" ]]; then install_mode="Re-run (preserving data)" fi # --- Print deployment plan --- echo "" echo -e "${CYAN}══════════════════════════════════════════════${NC}" echo -e "${CYAN} Deploying Web: ${DIR_NAME} (Docker/nginx)${NC}" echo -e "${CYAN}══════════════════════════════════════════════${NC}" echo -e " Domain: ${DOMAIN}" echo -e " Data: ${BASE_DIR}/html/" echo -e " Container: ${CONTAINER_NAME}" echo -e " Traefik: ${traefik_status}" echo -e " Mode: ${install_mode}" echo -e "${CYAN}══════════════════════════════════════════════${NC}" echo "" # --- Check if already deployed and running --- if [[ -f "${BASE_DIR}/docker-compose.yml" ]] && \ docker ps --format '{{.Names}}' 2>/dev/null | grep -q "^${CONTAINER_NAME}$"; then echo -e "${GREEN} ${CONTAINER_NAME} is already running — nothing to do.${NC}" echo "" echo -e " Document root: ${BASE_DIR}/html/" echo -e " Backup: ${SCRIPT_DIR}/backup-web.sh --dir ${DIR_NAME}" echo -e " Remove: $0 --remove --dir ${DIR_NAME} [--purge]" echo "" exit 0 fi # --- Shared infrastructure --- require_root detect_os install_prerequisites ensure_docker_network ensure_traefik configure_firewall # --- Backup restore check --- if check_and_restore_backup "$DIR_NAME"; then saved_domain="$DOMAIN" # shellcheck source=/dev/null source "${BASE_DIR}/.env" DOMAIN="$saved_domain" else # --- Fresh install --- if [[ -f "${BASE_DIR}/.env" ]]; then saved_domain="$DOMAIN" # shellcheck source=/dev/null source "${BASE_DIR}/.env" DOMAIN="$saved_domain" fi mkdir -p "${BASE_DIR}/html" # Default placeholder page if [[ ! -f "${BASE_DIR}/html/index.html" ]]; then cat > "${BASE_DIR}/html/index.html" <
Replace this file at ${BASE_DIR}/html/index.html
HTML fi # --- Generate .env --- cat > "${BASE_DIR}/.env" <