#!/bin/sh # launch (or restart) the ani-web server cd "$(dirname "$0")" || exit 1 [ -x .venv/bin/python ] || { echo "no .venv — run: uv venv .venv && uv pip install --python .venv/bin/python -r requirements.txt"; exit 1; } # stop the old instance via its PID file. Only when no pid file exists (first # boot under this scheme) fall back to pkill — and then PORT-SCOPED: the old # global "uvicorn .*app:app" pattern also matched the throwaway test server # (server.app:app --host 127.0.0.1 --port 8399), so an ani-web restart killed # running test sessions, and a stray test server kept port 8321's holder alive. PIDF=server.pid if [ -f "$PIDF" ]; then oldpid=$(cat "$PIDF" 2>/dev/null) if [ -n "$oldpid" ] && kill -0 "$oldpid" 2>/dev/null; then kill "$oldpid" 2>/dev/null i=0 while kill -0 "$oldpid" 2>/dev/null && [ "$i" -lt 10 ]; do sleep 0.5; i=$((i + 1)); done kill -9 "$oldpid" 2>/dev/null fi rm -f "$PIDF" else pkill -f "app:app --host 0.0.0.0 --port 8321" 2>/dev/null sleep 1 fi # ANIWEB_SECURE=1: session cookie is Secure — only usable via the HTTPS # proxy (plain http://:8321 can no longer hold a session). # ANIWEB_TRUST_XFF=1: prod traffic arrives via the local HTTPS proxy, so the # per-IP login budget keys on X-Forwarded-For; without the flag auth.py uses # the socket peer only (the header is spoofable on a direct connection). ANIWEB_SECURE=1 ANIWEB_TRUST_XFF=1 nohup .venv/bin/python -m uvicorn server.app:app --host 0.0.0.0 --port 8321 --timeout-graceful-shutdown 3 > server.log 2>&1 & echo $! > "$PIDF" echo "ani-web on http://localhost:8321 (pid $(cat "$PIDF")) — use the HTTPS proxy to log in"