#!/usr/bin/env bash # ============================================================================= # Deploy visit.waterschurch.org to the cPanel host over SSH. # # deploy/deploy.sh # build + upload + configure (goes live) # deploy/deploy.sh --no-build # upload the existing ./out # deploy/deploy.sh --keep-redirect # deploy but keep sending visitors to # # the Church Center form (pre-launch) # # Requires: the SSH alias "waterschurch" from ~/.ssh/config, rsync, node, npm. # Idempotent: safe to re-run for every content update. # # On the server (as the cPanel user) it: # 1. ensures the subdomain exists with document root ~/visit.waterschurch.org # 2. creates ~/visit-private/{data,logs} and a .env from .env.example if missing # 3. rsyncs ./out → ~/visit.waterschurch.org, preserving cPanel's own files # (.user.ini, php.ini, .well-known/) and rebuilding .htaccess from: # cPanel-generated PHP blocks + [pre-launch redirect] + deploy/htaccess.root # 4. installs the 5-minute retry cron job if absent # 5. requests an AutoSSL check and prints the health endpoint # It never touches DNS, the main site, or an existing .env. # ============================================================================= set -euo pipefail SSH_HOST="${SSH_HOST:-waterschurch}" SUBDOMAIN="visit" ROOTDOMAIN="waterschurch.org" FQDN="$SUBDOMAIN.$ROOTDOMAIN" REMOTE_DOCROOT="visit.waterschurch.org" # relative to $HOME on the server REMOTE_PRIVATE="visit-private" # relative to $HOME on the server BUILD=1 KEEP_REDIRECT=0 for arg in "$@"; do case "$arg" in --no-build) BUILD=0 ;; --keep-redirect) KEEP_REDIRECT=1 ;; *) echo "unknown option: $arg"; exit 2 ;; esac done cd "$(dirname "$0")/.." if [[ $BUILD -eq 1 ]]; then echo "▶ building" npm run build fi [[ -f out/index.html && -f out/.htaccess && -f out/api/plan-visit.php ]] || { echo "out/ is incomplete — run npm run build"; exit 1; } echo "▶ preparing server" ssh "$SSH_HOST" bash -s -- "$SUBDOMAIN" "$ROOTDOMAIN" "$REMOTE_DOCROOT" "$REMOTE_PRIVATE" <<'REMOTE' set -euo pipefail SUB="$1"; ROOT="$2"; DOCROOT="$HOME/$3"; PRIV="$HOME/$4"; FQDN="$SUB.$ROOT" if uapi --output=json DomainInfo list_domains 2>/dev/null | grep -q "\"$FQDN\""; then CUR=$(uapi --output=json DomainInfo single_domain_data domain="$FQDN" 2>/dev/null | python3 -c 'import json,sys; print(json.load(sys.stdin)["result"]["data"].get("documentroot",""))' 2>/dev/null || true) echo " subdomain $FQDN exists (docroot: ${CUR:-unknown})" if [[ -n "$CUR" && "$CUR" != "$DOCROOT" ]]; then echo " ⚠ document root differs — pointing it at $DOCROOT" uapi --output=json SubDomain changedocroot subdomain="$SUB" rootdomain="$ROOT" dir="$DOCROOT" >/dev/null fi else echo " creating subdomain $FQDN → $DOCROOT" uapi --output=json SubDomain addsubdomain domain="$SUB" rootdomain="$ROOT" dir="$DOCROOT" | python3 -c 'import json,sys; r=json.load(sys.stdin)["result"]; print(" ", "ok" if r["status"] else r["errors"])' fi mkdir -p "$DOCROOT" # Preserve cPanel-generated .htaccess blocks (PHP ini directives + PHP handler) before we replace the file. if [[ -f "$DOCROOT/.htaccess" ]]; then awk '/^# BEGIN cPanel-generated/,/^# END cPanel-generated/ {print} /^# php -- BEGIN cPanel-generated/,/^# php -- END cPanel-generated/ {print}' "$DOCROOT/.htaccess" > "$DOCROOT/.htaccess.cpanel-blocks" echo " preserved $(grep -c . "$DOCROOT/.htaccess.cpanel-blocks") lines of cPanel-generated .htaccess directives" fi mkdir -p "$PRIV/data" "$PRIV/logs" chmod 750 "$PRIV" "$PRIV/data" "$PRIV/logs" echo " private dir: $PRIV" REMOTE echo "▶ uploading build" rsync -az --delete \ --exclude '/.htaccess' --exclude '/.htaccess.*' \ --exclude '/.user.ini' --exclude '/php.ini' --exclude '/.well-known/' \ --exclude 'api/data/' \ --chmod=Du=rwx,Dgo=rx,Fu=rw,Fgo=r \ out/ "$SSH_HOST:$REMOTE_DOCROOT/" scp -q out/.htaccess "$SSH_HOST:$REMOTE_DOCROOT/.htaccess.visit" scp -q deploy/htaccess.prelaunch-redirect "$SSH_HOST:$REMOTE_DOCROOT/.htaccess.prelaunch" scp -q .env.example "$SSH_HOST:$REMOTE_PRIVATE/.env.example" echo "▶ configuring" ssh "$SSH_HOST" bash -s -- "$REMOTE_DOCROOT" "$REMOTE_PRIVATE" "$FQDN" "$KEEP_REDIRECT" <<'REMOTE' set -euo pipefail DOCROOT="$HOME/$1"; PRIV="$HOME/$2"; FQDN="$3"; KEEP="$4" # --- .env (never overwritten) if [[ ! -f "$PRIV/.env" ]]; then cp "$PRIV/.env.example" "$PRIV/.env" SALT=$(head -c 32 /dev/urandom | od -An -tx1 | tr -d ' \n') sed -i "s|^HASH_SALT=.*|HASH_SALT=$SALT|; s|^ALLOWED_ORIGINS=.*|ALLOWED_ORIGINS=|; s|^DEBUG_GEO=.*|DEBUG_GEO=false|" "$PRIV/.env" echo " created $PRIV/.env (INTEGRATION_MODE=mock — add API keys, then set live)" else echo " kept existing $PRIV/.env" fi chmod 640 "$PRIV/.env" # --- assemble .htaccess: cPanel blocks + [pre-launch redirect] + site config { [[ -f "$DOCROOT/.htaccess.cpanel-blocks" ]] && cat "$DOCROOT/.htaccess.cpanel-blocks" && echo if [[ "$KEEP" == "1" ]]; then cat "$DOCROOT/.htaccess.prelaunch"; fi sed "s|^# SetEnv VISIT_PRIVATE_DIR .*|SetEnv VISIT_PRIVATE_DIR $PRIV|" "$DOCROOT/.htaccess.visit" } > "$DOCROOT/.htaccess.new" mv -f "$DOCROOT/.htaccess.new" "$DOCROOT/.htaccess" rm -f "$DOCROOT/.htaccess.visit" "$DOCROOT/.htaccess.prelaunch" "$DOCROOT/.htaccess.cpanel-blocks" chmod 644 "$DOCROOT/.htaccess" if [[ "$KEEP" == "1" ]]; then echo " .htaccess: PRE-LAUNCH redirect to Church Center is ACTIVE"; else echo " .htaccess: site is LIVE (no redirect)"; fi # --- PHP binary for cron PHP_BIN=$(command -v php || true) for c in /usr/local/bin/php /opt/cpanel/ea-php83/root/usr/bin/php /opt/cpanel/ea-php82/root/usr/bin/php; do [[ -z "$PHP_BIN" && -x "$c" ]] && PHP_BIN="$c" done echo " php: ${PHP_BIN:-NOT FOUND} $($PHP_BIN -r 'echo PHP_VERSION;' 2>/dev/null || true)" # --- cron (idempotent) CRON="*/5 * * * * VISIT_PRIVATE_DIR=$PRIV $PHP_BIN $DOCROOT/api/cron/retry-integrations.php >> $PRIV/logs/cron.log 2>&1" if ! crontab -l 2>/dev/null | grep -qF "retry-integrations.php"; then ( crontab -l 2>/dev/null || true; echo "$CRON" ) | crontab - echo " cron installed (every 5 minutes)" else echo " cron already present" fi # --- SSL if uapi --output=json SSL start_autossl_check >/dev/null 2>&1; then echo " AutoSSL check requested"; else echo " (AutoSSL check not available via UAPI; use cPanel → SSL/TLS Status if needed)"; fi echo " build: $(head -1 "$DOCROOT/BUILD.txt")" REMOTE echo "▶ verifying" sleep 2 printf " https://%s/ → " "$FQDN"; curl -s -o /dev/null -w "%{http_code} %{redirect_url}\n" --max-time 20 "https://$FQDN/" || true printf " /api/health.php → "; curl -s --max-time 20 "https://$FQDN/api/health.php" | head -c 600 || true echo if [[ $KEEP_REDIRECT -eq 1 ]]; then echo "Deployed behind the pre-launch redirect. To go live: deploy/deploy.sh --no-build" else echo "Live. Next: fill in $REMOTE_PRIVATE/.env on the server, set INTEGRATION_MODE=live, and run docs/LAUNCH-CHECKLIST.md." fi