#!/usr/bin/env bash # ============================================================================ # Podium — a self-updating, multi-site static-site runner. # # 1. Read a list of sites (SITES, a JSON array). For each site: # clone its repo, build it, and serve the output with nginx on its # own container PORT. # 2. Poll every site's branch forever. When a remote HEAD moves, pull, # rebuild, and atomically swap just that site's live files — no reload, # no container restart, no Docker image rebuild. # # A single container can therefore serve many independent repos, each on a # different port. A failed build for one site is logged and that site's # previous version stays live; the other sites are unaffected. # # Declaring sites (SITES, JSON array of objects): # [ # {"repo":"https://github.com/you/app.git","port":8080, # "branch":"main","build":"npm ci && npm run build","output":"dist"}, # {"repo":"https://github.com/you/blog.git","port":8081, # "build":"","output":"."} # ] # Per-object fields: repo (required), port (required, unique), # branch (default "main"), build (default npm build; "" skips building), # output (default "dist"). # # Backward compatible: if SITES is unset, a single site is synthesized from # the legacy REPO_URL / REPO_BRANCH / PORT / BUILD_CMD / OUTPUT_DIR vars. # ============================================================================ set -euo pipefail POLL_INTERVAL="${POLL_INTERVAL:-300}" SITES_DIR="/srv/sites" # per-site working trees + web roots live here HTTPD_DIR="/etc/nginx/http.d" # one generated server-block .conf per site RUN_DIR="/run/podium" log() { echo "[$(date -u '+%Y-%m-%d %H:%M:%S')Z] $*"; } # --- Resolve the site list ------------------------------------------------- # Prefer SITES (JSON). Fall back to the legacy single-repo env vars so older # deployments keep working unchanged. SITES="${SITES:-}" if [ -z "$SITES" ]; then if [ -n "${REPO_URL:-}" ]; then log "No SITES set; using legacy single-repo env vars (REPO_URL=...)." SITES="$(jq -n \ --arg repo "$REPO_URL" \ --arg branch "${REPO_BRANCH:-main}" \ --argjson port "${PORT:-80}" \ --arg build "${BUILD_CMD:-npm ci --no-audit --no-fund && npm run build}" \ --arg output "${OUTPUT_DIR:-dist}" \ '[{repo:$repo,branch:$branch,port:$port,build:$build,output:$output}]')" else log "ERROR: set SITES (a JSON array of sites) or REPO_URL (single site)." exit 1 fi fi if ! echo "$SITES" | jq -e 'type=="array" and length>0' >/dev/null 2>&1; then log "ERROR: SITES must be a non-empty JSON array. Got:" echo "$SITES" | sed 's/^/ /' exit 1 fi # --- Build + deploy one site (never touches the live files on failure) ----- # Args: