#!/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 "== TLS: selbstsigniertes Zertifikat (LAN-Betrieb ohne Domain, Karte owasp-Review) ==" mkdir -p /etc/nginx/ssl if [ ! -f /etc/nginx/ssl/mabea.crt ]; then openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \ -keyout /etc/nginx/ssl/mabea.key -out /etc/nginx/ssl/mabea.crt \ -subj "/CN=${APP_DOMAIN}" chmod 600 /etc/nginx/ssl/mabea.key echo "Selbstsigniertes Zertifikat erzeugt (10 Jahre gültig) - Browser warnen beim ersten Zugriff, bis manuell akzeptiert/importiert." else echo "Zertifikat existiert bereits, überspringe." fi echo "== nginx Reverse-Proxy Config (inkl. Security-Header, TLS) ==" 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}" <