Deployment-Setup (PostgreSQL+nginx-Installer) + Sprint-0-Fixes aus Subagenten-Reviews
CI / backend-tests (push) Failing after 1s
CI / backend-tests (push) Failing after 1s
Installer (deploy/): - install_server.sh: PostgreSQL+nginx auf Debian 13, idempotente Rolle/DB-Anlage, pgcrypto-Extension, Speicher-Tuning für 4GB-VPS, Zugangsdaten in chmod-600-Datei statt stdout (postgres-expert/owasp-Review) - nginx-Template mit Security-Headern + Rate-Limit auf /auth/login - systemd-Unit-Template mit Sandboxing (NoNewPrivileges/ProtectSystem/PrivateTmp) Backend-Fixes (fastapi-expert-Review): - get_db: einheitliche commit/rollback-Konvention statt Endpunkt-Copy-Paste - Test-Fixtures auf SQLAlchemy-2.0-Savepoint-Pattern umgestellt (join_transaction_mode), da get_db jetzt selbst committet - Lifespan-Handler: Startup-Guard gegen JWT-Secret-Platzhalter, engine.dispose() beim Shutdown - JWT-Payload ohne ungenutztes roles-Claim (Rollen kommen immer frisch aus der DB) Zusätzlich: Subagenten-Definitionen (~/.claude/agents/) auf lauffähiges Modell fixiert. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L85hmKbvX7Cqkq47KnQhFt
This commit is contained in:
Executable
+89
@@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env bash
|
||||
# MABEA – Server-Setup (Debian 13). Installiert PostgreSQL + nginx, legt DB/Rolle an,
|
||||
# richtet nginx als Reverse-Proxy vor dem späteren FastAPI/Uvicorn-Backend ein.
|
||||
# Idempotent: mehrfacher Aufruf überschreibt keine bestehende DB-Rolle/DB.
|
||||
#
|
||||
# Ausführung auf dem Zielserver als root:
|
||||
# DB_PASSWORD=... APP_DOMAIN=mabea.example.org ./install_server.sh
|
||||
# Ohne DB_PASSWORD wird ein zufälliges Passwort erzeugt und am Ende ausgegeben
|
||||
# (sofort sichern, z. B. in backend/.env auf dem Server – nicht committen).
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
DB_NAME="${DB_NAME:-mabea}"
|
||||
DB_USER="${DB_USER:-mabea}"
|
||||
DB_PASSWORD="${DB_PASSWORD:-$(openssl rand -base64 24)}"
|
||||
JWT_SECRET_KEY="${JWT_SECRET_KEY:-$(openssl rand -base64 48)}"
|
||||
APP_DOMAIN="${APP_DOMAIN:-_}" # "_" = nginx catch-all, solange keine Domain feststeht
|
||||
|
||||
echo "== apt update/install =="
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq postgresql nginx python3-venv python3-pip git openssl
|
||||
|
||||
echo "== PostgreSQL: Rolle + Datenbank =="
|
||||
if ! sudo -u postgres psql -tAc "SELECT 1 FROM pg_roles WHERE rolname='${DB_USER}'" | grep -q 1; then
|
||||
sudo -u postgres psql -c "CREATE ROLE ${DB_USER} WITH LOGIN PASSWORD '${DB_PASSWORD}';"
|
||||
echo "Rolle ${DB_USER} angelegt."
|
||||
else
|
||||
echo "Rolle ${DB_USER} existiert bereits, überspringe."
|
||||
fi
|
||||
|
||||
if ! sudo -u postgres psql -tAc "SELECT 1 FROM pg_database WHERE datname='${DB_NAME}'" | grep -q 1; then
|
||||
sudo -u postgres psql -c "CREATE DATABASE ${DB_NAME} OWNER ${DB_USER};"
|
||||
echo "Datenbank ${DB_NAME} angelegt."
|
||||
else
|
||||
echo "Datenbank ${DB_NAME} existiert bereits, überspringe."
|
||||
fi
|
||||
|
||||
# gen_random_uuid() ist seit PG13 built-in, aber pgcrypto schadet nicht und macht es
|
||||
# explizit/robust gegen ältere Backports (Review-Fund postgres-expert).
|
||||
sudo -u postgres psql -d "${DB_NAME}" -c "CREATE EXTENSION IF NOT EXISTS pgcrypto;"
|
||||
|
||||
echo "== PostgreSQL: Speicher-Tuning für kleinen VPS (4GB RAM) =="
|
||||
PG_CONF_DIR=$(sudo -u postgres psql -tAc "SHOW config_file;" | xargs dirname)
|
||||
mkdir -p "${PG_CONF_DIR}/conf.d"
|
||||
cat > "${PG_CONF_DIR}/conf.d/mabea-tuning.conf" <<'PGCONF'
|
||||
# MABEA: konservatives Tuning für ~4GB RAM VPS, nicht enterprise-scale.
|
||||
shared_buffers = 1GB
|
||||
effective_cache_size = 3GB
|
||||
maintenance_work_mem = 256MB
|
||||
work_mem = 8MB
|
||||
max_connections = 50
|
||||
PGCONF
|
||||
grep -q "conf.d/\*.conf" "${PG_CONF_DIR}/postgresql.conf" || \
|
||||
echo "include_dir = 'conf.d'" >> "${PG_CONF_DIR}/postgresql.conf"
|
||||
|
||||
echo "== nginx Reverse-Proxy Config (inkl. Security-Header) =="
|
||||
sed -e "s/__APP_DOMAIN__/${APP_DOMAIN}/g" \
|
||||
"$(dirname "$0")/nginx_mabea.conf.template" > /etc/nginx/sites-available/mabea.conf
|
||||
ln -sf /etc/nginx/sites-available/mabea.conf /etc/nginx/sites-enabled/mabea.conf
|
||||
rm -f /etc/nginx/sites-enabled/default
|
||||
nginx -t
|
||||
|
||||
echo "== Dienste aktivieren =="
|
||||
systemctl enable --now postgresql
|
||||
systemctl restart postgresql # Tuning-Konfiguration laden
|
||||
systemctl enable --now nginx
|
||||
systemctl reload nginx
|
||||
|
||||
echo "== Zugangsdaten sichern =="
|
||||
CRED_FILE="/root/mabea_db_credentials.env"
|
||||
umask 077
|
||||
cat > "${CRED_FILE}" <<EOF
|
||||
DB_NAME=${DB_NAME}
|
||||
DB_USER=${DB_USER}
|
||||
DB_PASSWORD=${DB_PASSWORD}
|
||||
DATABASE_URL=postgresql+asyncpg://${DB_USER}:${DB_PASSWORD}@localhost:5432/${DB_NAME}
|
||||
JWT_SECRET_KEY=${JWT_SECRET_KEY}
|
||||
EOF
|
||||
chmod 600 "${CRED_FILE}"
|
||||
|
||||
echo
|
||||
echo "=== Fertig ==="
|
||||
echo "Zugangsdaten liegen (chmod 600) in ${CRED_FILE} – NICHT auf stdout ausgegeben (Review-Fund: keine Secrets im Terminal-Scrollback)."
|
||||
echo "DATABASE_URL von dort in backend/.env auf dem Server übernehmen (siehe backend/example.env)."
|
||||
echo "Backend selbst ist noch nicht deployt – siehe deploy/mabea-backend.service.template für den späteren systemd-Dienst."
|
||||
echo
|
||||
echo "Hinweis: nginx läuft aktuell nur über Port 80 (kein TLS). Für echten Betrieb vor Domain-Vergabe"
|
||||
echo "TLS nachziehen (Let's Encrypt bei Domain, sonst selbstsigniertes Zertifikat fürs LAN)."
|
||||
Reference in New Issue
Block a user