Files
proxmox/scripts/mim4u-install-nginx-and-fix-502.sh
defiQUG 4f97e27f69
Some checks failed
Deploy to Phoenix / deploy (push) Has been cancelled
MIM4U: nginx install/deploy/backup scripts, rate limit, CSP, docs; submodule pointer; txpool retry script
Made-with: Cursor
2026-02-26 22:35:24 -08:00

102 lines
4.3 KiB
Bash
Executable File

#!/usr/bin/env bash
# Install nginx on MIM4U web container (VMID 7810) and apply security-enabled config to fix 502.
# Run from a host that can SSH to the Proxmox node (e.g. r630-02). Requires root on Proxmox.
#
# Usage: ./scripts/mim4u-install-nginx-and-fix-502.sh [--dry-run]
# Optional: set PROXMOX_HOST_R630_02 and MIM_API_IP in env or config/ip-addresses.conf
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
[[ -f "$PROJECT_ROOT/config/ip-addresses.conf" ]] && source "$PROJECT_ROOT/config/ip-addresses.conf" 2>/dev/null || true
VMID_MIM_WEB="${VMID_MIM_WEB:-7810}"
PROXMOX_HOST="${PROXMOX_HOST_R630_02:-192.168.11.12}"
# API backend (VMID 7811) for /api/ proxy
MIM_API_IP="${MIM_API_IP:-192.168.11.36}"
MIM_API_PORT="${MIM_API_PORT:-3001}"
DRY_RUN="${1:-}"
run_remote() {
if [[ "$DRY_RUN" == "--dry-run" ]]; then
echo "[dry-run] ssh root@$PROXMOX_HOST pct exec $VMID_MIM_WEB -- $*"
return 0
fi
ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new "root@$PROXMOX_HOST" "pct exec $VMID_MIM_WEB -- $*"
}
echo "=== MIM4U 502 fix: install nginx on VMID $VMID_MIM_WEB (Proxmox $PROXMOX_HOST) ==="
echo "API backend: $MIM_API_IP:$MIM_API_PORT"
echo ""
# 1) Install nginx if missing
echo "[1/4] Installing nginx..."
run_remote bash -c 'export DEBIAN_FRONTEND=noninteractive && apt-get update -qq && apt-get install -y -qq nginx' 2>/dev/null || true
# 2a) Rate limit zones (http context via conf.d)
echo "[2/4] Writing nginx config (site + rate limit)..."
RATE_LIMIT_CONF='# MIM4U rate limits (included from main nginx.conf)
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=general:10m rate=30r/s;
'
if [[ "$DRY_RUN" != "--dry-run" ]]; then
echo "$RATE_LIMIT_CONF" | ssh "root@$PROXMOX_HOST" "pct exec $VMID_MIM_WEB -- bash -c 'cat > /etc/nginx/conf.d/mim4u-rate-limit.conf'"
fi
# 2b) Write nginx site config (security headers + SPA + /api proxy)
# CSP: font-src 'self' only (Inter is self-hosted via @fontsource)
NGINX_CONF="server {
listen 80;
server_name mim4u.org www.mim4u.org secure.mim4u.org training.mim4u.org _;
root /var/www/html;
index index.html;
add_header X-Content-Type-Options \"nosniff\" always;
add_header X-Frame-Options \"SAMEORIGIN\" always;
add_header X-XSS-Protection \"1; mode=block\" always;
add_header Referrer-Policy \"strict-origin-when-cross-origin\" always;
add_header Content-Security-Policy \"default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; font-src 'self'; img-src 'self' data: https:; connect-src 'self' https://mim4u.org; frame-ancestors 'self';\" always;
location /health {
default_type text/plain;
return 200 'ok';
add_header Content-Type text/plain;
}
location / {
limit_req zone=general burst=20 nodelay;
try_files \$uri \$uri/ /index.html =404;
}
location /api/ {
limit_req zone=api burst=5 nodelay;
proxy_pass http://${MIM_API_IP}:${MIM_API_PORT};
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
}
}"
if [[ "$DRY_RUN" != "--dry-run" ]]; then
echo "$NGINX_CONF" | ssh "root@$PROXMOX_HOST" "pct exec $VMID_MIM_WEB -- bash -c 'cat > /etc/nginx/sites-available/default'"
fi
# 3) Ensure /var/www/html exists and has index (placeholder if no app deployed yet)
echo "[3/4] Ensuring web root..."
run_remote mkdir -p /var/www/html
run_remote bash -c 'test -f /var/www/html/index.html || cat >/var/www/html/index.html <<END
<!DOCTYPE html><html><head><title>MIM4U</title></head><body><p>Miracles in Motion - site coming soon.</p></body></html>
END'
# 4) Test and reload nginx
echo "[4/4] Testing and reloading nginx..."
run_remote nginx -t 2>/dev/null && run_remote systemctl enable nginx 2>/dev/null || true
run_remote systemctl reload nginx 2>/dev/null || run_remote systemctl start nginx 2>/dev/null || true
MIM_WEB_IP="${IP_MIM_WEB:-192.168.11.37}"
echo ""
echo "Done. Verify from LAN: curl -I http://${MIM_WEB_IP}:80/"
echo "Then ensure NPMplus proxy hosts point to ${MIM_WEB_IP} (see docs/04-configuration/MIM4U_502_ERROR_RESOLUTION.md)."