Publish deployment and backup scripts
This commit is contained in:
190
deploy-docker-web.sh
Executable file
190
deploy-docker-web.sh
Executable file
@@ -0,0 +1,190 @@
|
||||
#!/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" <<HTML
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head><meta charset="utf-8"><title>${DOMAIN}</title></head>
|
||||
<body><h1>${DOMAIN}</h1><p>Replace this file at ${BASE_DIR}/html/index.html</p></body>
|
||||
</html>
|
||||
HTML
|
||||
fi
|
||||
|
||||
# --- Generate .env ---
|
||||
cat > "${BASE_DIR}/.env" <<DOTENV
|
||||
# Generated by deploy-docker-web.sh on $(date -Iseconds)
|
||||
DOMAIN=${DOMAIN}
|
||||
DIR_NAME=${DIR_NAME}
|
||||
DOTENV
|
||||
chmod 600 "${BASE_DIR}/.env"
|
||||
ok ".env written."
|
||||
|
||||
# --- Generate docker-compose.yml ---
|
||||
cat > "${BASE_DIR}/docker-compose.yml" <<COMPOSE
|
||||
services:
|
||||
web:
|
||||
image: nginx:alpine
|
||||
container_name: ${CONTAINER_NAME}
|
||||
restart: unless-stopped
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
mem_limit: 512M
|
||||
read_only: true
|
||||
tmpfs:
|
||||
- /var/cache/nginx
|
||||
- /var/run
|
||||
- /tmp
|
||||
volumes:
|
||||
- ./html:/usr/share/nginx/html:ro
|
||||
networks:
|
||||
- traefik-public
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "50m"
|
||||
max-file: "5"
|
||||
|
||||
networks:
|
||||
traefik-public:
|
||||
external: true
|
||||
COMPOSE
|
||||
ok "docker-compose.yml written."
|
||||
fi
|
||||
|
||||
# --- Always do these (fresh or restored) ---
|
||||
write_traefik_dynamic_config "$CONFIG_NAME" "$DOMAIN" "http://${CONTAINER_NAME}:80"
|
||||
install_systemd_unit "$UNIT_NAME" "$BASE_DIR"
|
||||
(cd "$BASE_DIR" && docker compose up -d)
|
||||
wait_for_healthy "$CONTAINER_NAME" "http://localhost:80/" 60
|
||||
|
||||
# --- Summary ---
|
||||
echo ""
|
||||
echo -e "${GREEN}══════════════════════════════════════════════${NC}"
|
||||
echo -e "${GREEN} Web (${DIR_NAME}) deployed successfully${NC}"
|
||||
echo -e "${GREEN}══════════════════════════════════════════════${NC}"
|
||||
echo -e " URL: https://${DOMAIN}"
|
||||
echo -e " Doc root: ${BASE_DIR}/html/"
|
||||
echo -e " Traefik: ${TRAEFIK_DYNAMIC_DIR}/${CONFIG_NAME}.yml"
|
||||
echo -e " Systemd: systemctl status ${UNIT_NAME}"
|
||||
echo -e " Logs: docker logs -f ${CONTAINER_NAME}"
|
||||
echo -e "${GREEN}══════════════════════════════════════════════${NC}"
|
||||
echo ""
|
||||
Reference in New Issue
Block a user