CI / backend-tests (push) Failing after 1s
Zielserver (minimales Debian-13-LXC) hat kein sudo vorinstalliert; zusätzlich führte die vorherige su -c "$*"-Konstruktion zu Word-Splitting der SQL-Statements. Fix: psql läuft über su -s /bin/bash postgres -c "psql -tA -d '<db>'" mit SQL via stdin. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L85hmKbvX7Cqkq47KnQhFt
99 lines
4.1 KiB
Bash
Executable File
99 lines
4.1 KiB
Bash
Executable File
#!/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
|
||
|
||
# Kein sudo-Dependency: minimale LXC-Images haben sudo oft nicht vorinstalliert,
|
||
# Skript läuft ohnehin als root (Ausführung dokumentiert das oben).
|
||
# SQL wird bewusst über stdin an psql gepiped statt als su-Argument übergeben –
|
||
# vermeidet doppelte Shell-Quoting-/Word-Splitting-Fallstricke (Bugfix nach Testlauf).
|
||
run_psql() {
|
||
local db="$1" sql="$2"
|
||
printf '%s\n' "${sql}" | su -s /bin/bash postgres -c "psql -tA -d '${db}'"
|
||
}
|
||
|
||
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 [ "$(run_psql postgres "SELECT 1 FROM pg_roles WHERE rolname='${DB_USER}';")" != "1" ]; then
|
||
run_psql postgres "CREATE ROLE ${DB_USER} WITH LOGIN PASSWORD '${DB_PASSWORD}';"
|
||
echo "Rolle ${DB_USER} angelegt."
|
||
else
|
||
echo "Rolle ${DB_USER} existiert bereits, überspringe."
|
||
fi
|
||
|
||
if [ "$(run_psql postgres "SELECT 1 FROM pg_database WHERE datname='${DB_NAME}';")" != "1" ]; then
|
||
run_psql postgres "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).
|
||
run_psql "${DB_NAME}" "CREATE EXTENSION IF NOT EXISTS pgcrypto;"
|
||
|
||
echo "== PostgreSQL: Speicher-Tuning für kleinen VPS (4GB RAM) =="
|
||
PG_CONF_DIR=$(run_psql postgres "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)."
|