#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" ENV_FILE="$ROOT_DIR/.env" ENV_EXAMPLE="$ROOT_DIR/.env.example" COMPOSE_FILE="$ROOT_DIR/docker-compose.selfhost.yml" MODE="" START_STACK="ask" FORCE="false" TTY_INPUT="${FEDEO_TTY_INPUT:-/dev/tty}" TTY_FD="" if { exec 3<"$TTY_INPUT"; } 2>/dev/null; then TTY_FD="3" fi read_interactive() { if [[ -n "$TTY_FD" ]]; then read -u "$TTY_FD" "$@" else read "$@" fi } compose() { if [[ "${FEDEO_USE_SUDO_DOCKER:-false}" == "true" ]]; then sudo docker compose "$@" else docker compose "$@" fi } usage() { cat <<'USAGE' FEDEO Selfhost Setup Nutzung: bash scripts/selfhost-setup.sh bash scripts/selfhost-setup.sh --simple bash scripts/selfhost-setup.sh --advanced bash scripts/selfhost-setup.sh --simple --start Optionen: --simple Kurzer Assistent mit lokalen Diensten und sicheren Defaults --advanced Fragt zusätzliche Integrationen wie SMTP, OpenAI und DATEV-nahes Umfeld ab --start Startet den Stack nach dem Schreiben der Konfiguration --no-start Schreibt nur Konfiguration und Verzeichnisse --force Überschreibt eine vorhandene .env ohne Rückfrage USAGE } while [[ $# -gt 0 ]]; do case "$1" in --simple) MODE="simple" ;; --advanced) MODE="advanced" ;; --start) START_STACK="yes" ;; --no-start) START_STACK="no" ;; --force) FORCE="true" ;; -h|--help) usage exit 0 ;; *) echo "Unbekannte Option: $1" >&2 usage exit 1 ;; esac shift done need_file() { if [[ ! -f "$1" ]]; then echo "Fehlt: $1" >&2 exit 1 fi } random_secret() { if command -v openssl >/dev/null 2>&1; then openssl rand -base64 48 | tr -d '\n' else LC_ALL=C tr -dc 'A-Za-z0-9' &2 done } prompt_secret() { local label="$1" local default_value="${2:-}" local value if [[ -n "$default_value" ]]; then read_interactive -r -s -p "$label [vorbelegt, Enter übernimmt]: " value echo >&2 echo "${value:-$default_value}" else read_interactive -r -s -p "$label: " value echo >&2 echo "$value" fi } yes_no() { local label="$1" local default_value="${2:-n}" local answer while true; do read_interactive -r -p "$label [$default_value]: " answer answer="${answer:-$default_value}" case "$answer" in y|Y|j|J|yes|Yes|ja|Ja) return 0 ;; n|N|no|No|nein|Nein) return 1 ;; *) echo "Bitte ja oder nein eingeben." ;; esac done } choose_mode() { if [[ -n "$MODE" ]]; then return fi echo echo "Setup-Modus" echo " 1) einfach - Domain, Admin, lokale Datenbank, MinIO, Matrix" echo " 2) advanced - zusätzlich SMTP, externe Schlüssel und optionale Dienste" echo local choice while true; do read_interactive -r -p "Modus wählen [1]: " choice case "${choice:-1}" in 1|einfach|simple) MODE="simple" return ;; 2|advanced|erweitert) MODE="advanced" return ;; *) echo "Bitte 1 oder 2 wählen." ;; esac done } print_structure_guide() { cat <"$ENV_FILE" <")" echo echo "Advanced: optionale Schlüssel" pdf_license="$(prompt "PDF-Lizenz" "$pdf_license")" openai_key="$(prompt_secret "OpenAI API Key" "$openai_key")" stirling_key="$(prompt_secret "Stirling API Key" "$stirling_key")" web_push_public="$(prompt "Web Push Public Key" "$web_push_public")" web_push_private="$(prompt_secret "Web Push Private Key" "$web_push_private")" echo echo "Advanced: Banking und Dokubox" gocardless_secret_id="$(prompt "GoCardless Secret ID" "$gocardless_secret_id")" gocardless_secret_key="$(prompt_secret "GoCardless Secret Key" "$gocardless_secret_key")" dokubox_host="$(prompt "Dokubox IMAP Host" "$dokubox_host")" dokubox_port="$(prompt "Dokubox IMAP Port" "$dokubox_port")" dokubox_secure="$(prompt "Dokubox IMAP Secure true/false" "$dokubox_secure")" dokubox_user="$(prompt "Dokubox IMAP Benutzer" "$dokubox_user")" dokubox_password="$(prompt_secret "Dokubox IMAP Passwort" "$dokubox_password")" fi write_env \ "$domain" "$contact_email" "$db_password" "$minio_password" \ "$cookie_secret" "$jwt_secret" "$encryption_key" "$m2m_key" \ "$admin_email" "$admin_password" "$admin_first_name" "$admin_last_name" \ "$tenant_name" "$tenant_short" "$matrix_db_password" "$matrix_turn_secret" \ "$matrix_registration_secret" "$livekit_secret" "$mailer_host" "$mailer_port" \ "$mailer_ssl" "$mailer_user" "$mailer_pass" "$mailer_from" "$web_push_public" \ "$web_push_private" "$pdf_license" "$openai_key" "$stirling_key" \ "$gocardless_secret_id" "$gocardless_secret_key" "$dokubox_host" \ "$dokubox_port" "$dokubox_secure" "$dokubox_user" "$dokubox_password" prepare_directories echo echo "Konfiguration geschrieben:" echo " $ENV_FILE" echo echo "Vor dem Start prüfen:" echo " 1. DNS zeigt auf diesen Server: $domain" echo " 2. Ports 80, 443, 3478/tcp, 3478/udp, 5349/tcp, 49160-49200/udp sind offen" echo " 3. Platzhalter für optionale Dienste in .env bei Bedarf ersetzen" if [[ "$START_STACK" == "ask" ]]; then if yes_no "Stack jetzt mit Docker Compose starten?" "n"; then START_STACK="yes" else START_STACK="no" fi fi if [[ "$START_STACK" == "yes" ]]; then compose -f "$COMPOSE_FILE" up -d else echo echo "Start später mit:" if [[ "${FEDEO_USE_SUDO_DOCKER:-false}" == "true" ]]; then echo " sudo docker compose -f $COMPOSE_FILE up -d" else echo " docker compose -f $COMPOSE_FILE up -d" fi fi } main