diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..30faff6 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,106 @@ +name: CI + +on: + push: + branches: ['**'] + pull_request: + workflow_dispatch: + +jobs: + shell-lint: + name: Bash & ShellCheck + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Bash syntax check + run: bash -n install.sh + + - name: Install ShellCheck + run: | + sudo apt-get update -qq + sudo apt-get install -y -q shellcheck + + - name: ShellCheck (errors only) + run: shellcheck -S error install.sh + + - name: ShellCheck (full report, non-blocking) + run: shellcheck install.sh || true + + php-lint: + name: Embedded PHP lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + tools: none + coverage: none + + - name: Extract embedded PHP files + run: bash tests/extract-php.sh + + - name: php -l on every extracted file + run: | + set -e + for f in tests/_extracted/*.php; do + echo "::group::Linting $f" + php -l "$f" + echo "::endgroup::" + done + + bats-tests: + name: Bash unit tests (bats) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install bats + run: | + sudo apt-get update -qq + sudo apt-get install -y -q bats + + - name: Run bats + run: bats --tap tests/install.bats + + php-validators: + name: PHP validator unit tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + coverage: none + + - name: Run validator tests + run: php tests/test-validators.php + + caddyfile-validation: + name: Validate Caddyfile syntax + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Caddy + run: | + sudo apt-get update -qq + sudo apt-get install -y -q debian-keyring debian-archive-keyring apt-transport-https curl gnupg + curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \ + | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg + curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \ + | sudo tee /etc/apt/sources.list.d/caddy-stable.list + sudo apt-get update -qq + sudo apt-get install -y -q caddy + + - name: Prepare log directory (caddy validate öffnet Log-Files real) + run: | + sudo mkdir -p /var/log/caddy + sudo chmod 1777 /var/log/caddy + + - name: Validate sample Caddyfile (representative shape) + run: caddy validate --config tests/sample-caddyfile --adapter caddyfile diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a411fea --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# Vom Test-Extractor zur Laufzeit erzeugt +tests/_extracted/ diff --git a/install.sh b/install.sh index d1b3b36..4c22533 100644 --- a/install.sh +++ b/install.sh @@ -1,1463 +1,1400 @@ #!/bin/bash - ################################################################################ -# Caddy Reverse Proxy Admin Panel - Automatisches Installations-Script -# -# Autor: Techie -# Website: https://callmetechie.de -# -# Dieses Script installiert und konfiguriert: -# - Caddy v2 mit Let's Encrypt -# - PHP und Apache/Nginx -# - Admin Panel Web-GUI -# - Alle erforderlichen Berechtigungen und Konfigurationen +# Caddy Reverse Proxy Admin Panel - Hardened Installer (v2.0) +# +# Original-Idee: Techie (https://callmetechie.de) +# Hardened-Variante: behebt kritische Sicherheitsprobleme + Bugs des Originals. +# +# Was wurde gegenüber v1 geändert: +# - Authentifizierung: Login-Form, bcrypt-Hash, PHP-Sessions, Brute-Force-Limit +# - CSRF-Schutz für alle mutierenden API-Endpunkte +# - Same-Origin: kein "Access-Control-Allow-Origin: *" mehr +# - Caddyfile-Sanitizer: strikte Domain-/IP-/Port-Validierung, Logpfad escaped, +# Direktiven-Injection ("additional_config") entfernt +# - Sudoers ohne Argumente: Reload-Helper liest fixen Stage-Pfad +# - Echtes Let's Encrypt via globaler email-Direktive (kein "tls internal" mehr) +# - SSL-Verify in curl aktiviert +# - flock() für domains.json gegen Race Conditions +# - Caddy + PHP-FPM nativ (Apache/Nginx-Doppelstack entfernt) +# - Login-Credentials und Konfiguration werden interaktiv abgefragt # # Verwendung: sudo bash install.sh ################################################################################ -set -e # Bei Fehler abbrechen +set -euo pipefail -# Farben für Output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' # No Color +RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m' -# Konfigurationsvariablen +# Konfigurationspfade (fest) INSTALL_DIR="/var/www/caddy-admin" CADDY_CONFIG_DIR="/etc/caddy" +CADDY_LIVE_FILE="${CADDY_CONFIG_DIR}/Caddyfile" +ADMIN_CONFIG_DIR="/etc/caddy-admin" +ADMIN_CONFIG_FILE="${ADMIN_CONFIG_DIR}/config.json" +ADMIN_AUTH_FILE="${ADMIN_CONFIG_DIR}/auth.json" +STAGE_DIR="/var/lib/caddy-admin" +STAGE_FILE="${STAGE_DIR}/Caddyfile.staged" +RATE_LIMIT_FILE="${STAGE_DIR}/rate-limit.json" BACKUP_DIR="/var/backups/caddy" LOG_DIR="/var/log/caddy" -ADMIN_PORT="8080" +RELOAD_HELPER="/usr/local/bin/caddy-admin-reload" +SUDOERS_FILE="/etc/sudoers.d/caddy-admin" + +# Aus Eingaben befüllt +ADMIN_PORT="" ADMIN_DOMAIN="" ADMIN_EMAIL="" -USE_NGINX=false +ADMIN_USER="" +ADMIN_PASS="" ENABLE_SSL=false ENABLE_FIREWALL=true -# Script muss als root ausgeführt werden +# Aus detect_*-Schritten befüllt +OS_ID="" +PKG_INSTALL="" +PKG_UPDATE="" +PHP_VERSION="" +PHP_FPM_SOCK="" +PHP_FPM_SERVICE="" +WEB_USER="" +WEB_GROUP="" + +# ---- Helper ----------------------------------------------------------------- + +err() { echo -e "${RED}✗ $*${NC}" >&2; exit 1; } +warn() { echo -e "${YELLOW}! $*${NC}" >&2; } +info() { echo -e "${YELLOW}→ $*${NC}"; } +ok() { echo -e "${GREEN}✓ $*${NC}"; } +hr() { echo -e "${BLUE}══════════════════════════════════════════════════════════════${NC}"; } + check_root() { - if [[ $EUID -ne 0 ]]; then - echo -e "${RED}Dieses Script muss als root ausgeführt werden!${NC}" - echo "Verwendung: sudo bash install.sh" - exit 1 - fi + [[ $EUID -eq 0 ]] || err "Dieses Script muss als root ausgeführt werden (sudo bash install.sh)" } -# Banner anzeigen show_banner() { clear echo -e "${BLUE}╔══════════════════════════════════════════════════════════════╗${NC}" - echo -e "${BLUE}║ ║${NC}" - echo -e "${BLUE}║ ${GREEN}Caddy Reverse Proxy Admin Panel - Installer${BLUE} ║${NC}" - echo -e "${BLUE}║ Version 1.0 ║${NC}" - echo -e "${BLUE}║ ║${NC}" + echo -e "${BLUE}║ ${GREEN}Caddy Reverse Proxy Admin Panel - Hardened Installer${BLUE} ║${NC}" + echo -e "${BLUE}║ Version 2.0 ║${NC}" echo -e "${BLUE}╚══════════════════════════════════════════════════════════════╝${NC}" - echo "" + echo } -# Betriebssystem erkennen detect_os() { - echo -e "${YELLOW}→ Erkenne Betriebssystem...${NC}" - - if [[ -f /etc/os-release ]]; then - . /etc/os-release - OS=$NAME - OS_VERSION=$VERSION_ID - OS_ID=$ID - - echo -e "${GREEN}✓ Erkannt: $OS $OS_VERSION${NC}" - - case $OS_ID in - ubuntu|debian) - PKG_MANAGER="apt" - PKG_UPDATE="apt update" - PKG_INSTALL="apt install -y" - PHP_VERSION=$(apt-cache show php | grep -E "^Version:" | head -1 | cut -d' ' -f2 | cut -d'+' -f1 | cut -d'.' -f1,2) - ;; - centos|rhel|fedora) - PKG_MANAGER="yum" - PKG_UPDATE="yum update -y" - PKG_INSTALL="yum install -y" - if [[ "$OS_ID" == "fedora" ]]; then - PKG_MANAGER="dnf" - PKG_UPDATE="dnf update -y" - PKG_INSTALL="dnf install -y" - fi - ;; - *) - echo -e "${RED}✗ Nicht unterstütztes Betriebssystem: $OS_ID${NC}" - exit 1 - ;; - esac - else - echo -e "${RED}✗ Betriebssystem konnte nicht erkannt werden${NC}" - exit 1 - fi + info "Erkenne Betriebssystem..." + [[ -f /etc/os-release ]] || err "Betriebssystem konnte nicht erkannt werden" + # shellcheck disable=SC1091 + . /etc/os-release + OS_ID="${ID:-}" + case "$OS_ID" in + ubuntu|debian) + PKG_INSTALL="apt-get install -y -q" + PKG_UPDATE="apt-get update -q" + ;; + centos|rhel|rocky|almalinux) + PKG_INSTALL="yum install -y -q" + PKG_UPDATE="yum makecache -q" + ;; + fedora) + PKG_INSTALL="dnf install -y -q" + PKG_UPDATE="dnf makecache -q" + ;; + *) + err "Nicht unterstütztes Betriebssystem: $OS_ID (unterstützt: Debian, Ubuntu, CentOS, RHEL, Rocky, AlmaLinux, Fedora)" + ;; + esac + ok "Erkannt: ${PRETTY_NAME:-$OS_ID}" } -# Benutzereinstellungen abfragen -get_user_input() { - echo "" - echo -e "${BLUE}══════════════════════════════════════════════════════════════${NC}" +# ---- Eingaben --------------------------------------------------------------- + +is_valid_domain() { + [[ "$1" =~ ^(\*\.)?([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,}$ ]] +} + +is_valid_email() { + [[ "$1" =~ ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$ ]] +} + +prompt_config() { + hr echo -e "${YELLOW}Konfigurationseinstellungen:${NC}" - echo -e "${BLUE}══════════════════════════════════════════════════════════════${NC}" - echo "" - - # Admin Domain - read -p "Domain für Admin Panel (z.B. admin.example.com) [localhost]: " ADMIN_DOMAIN - ADMIN_DOMAIN=${ADMIN_DOMAIN:-localhost} - - # Admin E-Mail - read -p "E-Mail für Let's Encrypt (erforderlich für SSL): " ADMIN_EMAIL - - # SSL aktivieren? - if [[ "$ADMIN_DOMAIN" != "localhost" ]] && [[ -n "$ADMIN_EMAIL" ]]; then - read -p "SSL für Admin Panel aktivieren? (j/n) [j]: " ssl_choice - ssl_choice=${ssl_choice:-j} - if [[ "$ssl_choice" == "j" ]] || [[ "$ssl_choice" == "J" ]]; then + hr + echo + + while true; do + read -r -p "Domain für Admin Panel (z.B. admin.example.com) [localhost]: " ADMIN_DOMAIN + ADMIN_DOMAIN="${ADMIN_DOMAIN:-localhost}" + if [[ "$ADMIN_DOMAIN" == "localhost" ]] || is_valid_domain "$ADMIN_DOMAIN"; then + break + fi + echo -e "${RED}Ungültige Domain. Beispiel: admin.example.com${NC}" + done + + while true; do + read -r -p "E-Mail für Let's Encrypt: " ADMIN_EMAIL + if is_valid_email "$ADMIN_EMAIL"; then + break + fi + echo -e "${RED}Ungültige E-Mail-Adresse${NC}" + done + + if [[ "$ADMIN_DOMAIN" != "localhost" ]]; then + read -r -p "SSL via Let's Encrypt für Admin-Domain aktivieren? (j/n) [j]: " ans + ans="${ans:-j}" + if [[ "$ans" =~ ^[jJ]$ ]]; then ENABLE_SSL=true + else + ENABLE_SSL=false fi + else + ENABLE_SSL=false + echo -e "${YELLOW} (localhost → kein Let's Encrypt möglich; lokales TLS via 'tls internal')${NC}" fi - - # Webserver auswählen - echo "" - echo "Welchen Webserver möchten Sie verwenden?" - echo "1) Apache (Standard)" - echo "2) Nginx" - read -p "Auswahl [1]: " webserver_choice - webserver_choice=${webserver_choice:-1} - - if [[ "$webserver_choice" == "2" ]]; then - USE_NGINX=true - fi - - # Admin Port - read -p "Port für Admin Panel [8080]: " ADMIN_PORT - ADMIN_PORT=${ADMIN_PORT:-8080} - - # Firewall konfigurieren? - read -p "Firewall automatisch konfigurieren? (j/n) [j]: " fw_choice - fw_choice=${fw_choice:-j} - if [[ "$fw_choice" == "n" ]] || [[ "$fw_choice" == "N" ]]; then + + while true; do + read -r -p "Port für Admin Panel [8080]: " ADMIN_PORT + ADMIN_PORT="${ADMIN_PORT:-8080}" + if [[ "$ADMIN_PORT" =~ ^[0-9]+$ ]] && (( ADMIN_PORT >= 1024 && ADMIN_PORT <= 65535 )); then + break + fi + echo -e "${RED}Port muss eine Zahl zwischen 1024 und 65535 sein${NC}" + done + + echo + echo -e "${BLUE}Login-Credentials für das Admin Panel:${NC}" + + while true; do + read -r -p "Admin-Benutzername (3-32 Zeichen, a-z 0-9 _): " ADMIN_USER + if [[ "$ADMIN_USER" =~ ^[a-z0-9_]{3,32}$ ]]; then + break + fi + echo -e "${RED}Ungültiger Benutzername (nur Kleinbuchstaben, Zahlen, Unterstrich; 3-32 Zeichen)${NC}" + done + + while true; do + read -r -s -p "Admin-Passwort (mind. 12 Zeichen): " ADMIN_PASS + echo + if [[ ${#ADMIN_PASS} -lt 12 ]]; then + echo -e "${RED}Passwort zu kurz (mindestens 12 Zeichen)${NC}" + continue + fi + read -r -s -p "Passwort bestätigen: " confirm + echo + if [[ "$ADMIN_PASS" != "$confirm" ]]; then + echo -e "${RED}Passwörter stimmen nicht überein${NC}" + continue + fi + break + done + + echo + read -r -p "Firewall (UFW) automatisch konfigurieren? (j/n) [j]: " ans + ans="${ans:-j}" + if [[ "$ans" =~ ^[nN]$ ]]; then ENABLE_FIREWALL=false fi - - echo "" - echo -e "${GREEN}Konfiguration:${NC}" - echo -e " Domain: ${BLUE}$ADMIN_DOMAIN${NC}" - echo -e " E-Mail: ${BLUE}$ADMIN_EMAIL${NC}" - echo -e " SSL: ${BLUE}$(if $ENABLE_SSL; then echo "Ja"; else echo "Nein"; fi)${NC}" - echo -e " Webserver: ${BLUE}$(if $USE_NGINX; then echo "Nginx"; else echo "Apache"; fi)${NC}" - echo -e " Port: ${BLUE}$ADMIN_PORT${NC}" - echo -e " Firewall: ${BLUE}$(if $ENABLE_FIREWALL; then echo "Ja"; else echo "Nein"; fi)${NC}" - echo "" - - read -p "Fortfahren mit diesen Einstellungen? (j/n) [j]: " confirm - confirm=${confirm:-j} - if [[ "$confirm" != "j" ]] && [[ "$confirm" != "J" ]]; then - echo -e "${RED}Installation abgebrochen${NC}" - exit 1 - fi -} -# System aktualisieren -update_system() { - echo "" - echo -e "${YELLOW}→ Aktualisiere System...${NC}" - $PKG_UPDATE > /dev/null 2>&1 - echo -e "${GREEN}✓ System aktualisiert${NC}" + echo + echo -e "${GREEN}Zusammenfassung:${NC}" + echo -e " Domain: ${BLUE}${ADMIN_DOMAIN}${NC}" + echo -e " E-Mail: ${BLUE}${ADMIN_EMAIL}${NC}" + echo -e " SSL: ${BLUE}$($ENABLE_SSL && echo "Ja (Let's Encrypt)" || echo "Nein")${NC}" + echo -e " Port: ${BLUE}${ADMIN_PORT}${NC}" + echo -e " Benutzer: ${BLUE}${ADMIN_USER}${NC}" + echo -e " Passwort: ${BLUE}(${#ADMIN_PASS} Zeichen, gehasht gespeichert)${NC}" + echo -e " Firewall: ${BLUE}$($ENABLE_FIREWALL && echo Ja || echo Nein)${NC}" + echo + read -r -p "Mit diesen Einstellungen fortfahren? (j/n) [j]: " ans + ans="${ans:-j}" + [[ "$ans" =~ ^[jJ]$ ]] || err "Installation vom Benutzer abgebrochen" } -# Basis-Pakete installieren -install_base_packages() { - echo -e "${YELLOW}→ Installiere Basis-Pakete...${NC}" - - PACKAGES="curl wget git sudo ufw software-properties-common gnupg2 lsb-release" - - if [[ "$OS_ID" == "ubuntu" ]] || [[ "$OS_ID" == "debian" ]]; then - PACKAGES="$PACKAGES apt-transport-https ca-certificates" - fi - - $PKG_INSTALL $PACKAGES > /dev/null 2>&1 - echo -e "${GREEN}✓ Basis-Pakete installiert${NC}" +# ---- Installation ----------------------------------------------------------- + +update_system() { + info "Aktualisiere Paketindex..." + $PKG_UPDATE >/dev/null + ok "Paketindex aktualisiert" } -# Caddy installieren install_caddy() { - echo -e "${YELLOW}→ Installiere Caddy...${NC}" - - if [[ "$OS_ID" == "ubuntu" ]] || [[ "$OS_ID" == "debian" ]]; then - # Caddy GPG key und Repository hinzufügen - curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg - curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list - - $PKG_UPDATE > /dev/null 2>&1 - $PKG_INSTALL caddy > /dev/null 2>&1 - - elif [[ "$OS_ID" == "centos" ]] || [[ "$OS_ID" == "rhel" ]] || [[ "$OS_ID" == "fedora" ]]; then - # Caddy über COPR installieren + info "Installiere Caddy..." + if [[ "$OS_ID" == "ubuntu" || "$OS_ID" == "debian" ]]; then + $PKG_INSTALL curl gnupg ca-certificates apt-transport-https debian-keyring debian-archive-keyring >/dev/null + if [[ ! -f /usr/share/keyrings/caddy-stable-archive-keyring.gpg ]]; then + curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \ + | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg + fi + curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \ + >/etc/apt/sources.list.d/caddy-stable.list + $PKG_UPDATE >/dev/null + $PKG_INSTALL caddy >/dev/null + else if [[ "$OS_ID" == "fedora" ]]; then - dnf copr enable @caddy/caddy -y > /dev/null 2>&1 - dnf install caddy -y > /dev/null 2>&1 + $PKG_INSTALL 'dnf-command(copr)' >/dev/null 2>&1 || true + dnf copr enable -y @caddy/caddy >/dev/null else - yum copr enable @caddy/caddy -y > /dev/null 2>&1 - yum install caddy -y > /dev/null 2>&1 + yum install -y -q yum-plugin-copr >/dev/null 2>&1 || true + yum copr enable -y @caddy/caddy >/dev/null fi + $PKG_INSTALL caddy >/dev/null fi - - # Caddy Service aktivieren - systemctl enable caddy > /dev/null 2>&1 - - echo -e "${GREEN}✓ Caddy installiert${NC}" + systemctl enable caddy >/dev/null + ok "Caddy installiert" } -# PHP installieren install_php() { - echo -e "${YELLOW}→ Installiere PHP...${NC}" - - if [[ "$OS_ID" == "ubuntu" ]] || [[ "$OS_ID" == "debian" ]]; then - $PKG_INSTALL php php-cli php-fpm php-json php-curl php-mbstring php-xml php-zip > /dev/null 2>&1 - - # PHP-FPM für Nginx konfigurieren - if $USE_NGINX; then - PHP_FPM_SERVICE="php${PHP_VERSION}-fpm" - systemctl enable $PHP_FPM_SERVICE > /dev/null 2>&1 - systemctl start $PHP_FPM_SERVICE > /dev/null 2>&1 - fi - - elif [[ "$OS_ID" == "centos" ]] || [[ "$OS_ID" == "rhel" ]] || [[ "$OS_ID" == "fedora" ]]; then - $PKG_INSTALL php php-cli php-fpm php-json php-mbstring php-xml php-zip > /dev/null 2>&1 - - if $USE_NGINX; then - systemctl enable php-fpm > /dev/null 2>&1 - systemctl start php-fpm > /dev/null 2>&1 - fi + info "Installiere PHP-FPM..." + if [[ "$OS_ID" == "ubuntu" || "$OS_ID" == "debian" ]]; then + $PKG_INSTALL php-fpm php-cli php-curl php-mbstring php-xml >/dev/null + WEB_USER="www-data" + WEB_GROUP="www-data" + else + $PKG_INSTALL php php-fpm php-cli php-mbstring php-xml >/dev/null + WEB_USER="apache" + WEB_GROUP="apache" fi - - echo -e "${GREEN}✓ PHP installiert${NC}" + + PHP_VERSION="$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')" + [[ -n "$PHP_VERSION" ]] || err "PHP-Version konnte nicht ermittelt werden" + + if [[ "$OS_ID" == "ubuntu" || "$OS_ID" == "debian" ]]; then + PHP_FPM_SERVICE="php${PHP_VERSION}-fpm" + PHP_FPM_SOCK="/run/php/php${PHP_VERSION}-fpm.sock" + else + PHP_FPM_SERVICE="php-fpm" + PHP_FPM_SOCK="/run/php-fpm/www.sock" + fi + + systemctl enable "$PHP_FPM_SERVICE" >/dev/null + systemctl restart "$PHP_FPM_SERVICE" + + if id caddy >/dev/null 2>&1; then + usermod -a -G "$WEB_GROUP" caddy || true + fi + + ok "PHP ${PHP_VERSION} mit FPM-Service ${PHP_FPM_SERVICE} installiert" } -# Webserver installieren -install_webserver() { - if $USE_NGINX; then - echo -e "${YELLOW}→ Installiere Nginx...${NC}" - $PKG_INSTALL nginx > /dev/null 2>&1 - systemctl enable nginx > /dev/null 2>&1 - echo -e "${GREEN}✓ Nginx installiert${NC}" +# ---- Verzeichnisse --------------------------------------------------------- + +setup_directories() { + info "Erstelle Verzeichnisse..." + install -d -m 750 -o "$WEB_USER" -g "$WEB_GROUP" "$INSTALL_DIR" + install -d -m 750 -o root -g "$WEB_GROUP" "$ADMIN_CONFIG_DIR" + install -d -m 750 -o "$WEB_USER" -g "$WEB_GROUP" "$STAGE_DIR" + install -d -m 755 -o root -g root "$BACKUP_DIR" + if id caddy >/dev/null 2>&1; then + install -d -m 755 -o caddy -g caddy "$LOG_DIR" else - echo -e "${YELLOW}→ Installiere Apache...${NC}" - - if [[ "$OS_ID" == "ubuntu" ]] || [[ "$OS_ID" == "debian" ]]; then - $PKG_INSTALL apache2 libapache2-mod-php > /dev/null 2>&1 - systemctl enable apache2 > /dev/null 2>&1 - - # Module aktivieren - a2enmod rewrite > /dev/null 2>&1 - a2enmod proxy > /dev/null 2>&1 - a2enmod proxy_http > /dev/null 2>&1 - - elif [[ "$OS_ID" == "centos" ]] || [[ "$OS_ID" == "rhel" ]] || [[ "$OS_ID" == "fedora" ]]; then - $PKG_INSTALL httpd mod_php > /dev/null 2>&1 - systemctl enable httpd > /dev/null 2>&1 - fi - - echo -e "${GREEN}✓ Apache installiert${NC}" + install -d -m 755 "$LOG_DIR" fi + ok "Verzeichnisse vorbereitet" +} + +# ---- Konfigurationsdateien ------------------------------------------------- + +write_config_files() { + info "Schreibe Konfiguration und Auth-Datei..." + + local pw_hash + pw_hash="$(ADMIN_PASS_RAW="$ADMIN_PASS" php -r ' + echo password_hash(getenv("ADMIN_PASS_RAW"), PASSWORD_BCRYPT, ["cost" => 12]); + ')" + [[ -n "$pw_hash" ]] || err "Konnte Passwort-Hash nicht erzeugen" + + php -r ' + echo json_encode(["username" => $argv[1], "password_hash" => $argv[2]], JSON_PRETTY_PRINT); + ' "$ADMIN_USER" "$pw_hash" > "$ADMIN_AUTH_FILE" + chown "root:${WEB_GROUP}" "$ADMIN_AUTH_FILE" + chmod 640 "$ADMIN_AUTH_FILE" + + php -r ' + $cfg = [ + "admin_domain" => $argv[1], + "admin_email" => $argv[2], + "admin_port" => intval($argv[3]), + "enable_ssl" => $argv[4] === "true", + "install_dir" => $argv[5], + "log_dir" => $argv[6], + "stage_file" => $argv[7], + "live_caddyfile" => $argv[8], + "rate_limit_file" => $argv[9], + ]; + echo json_encode($cfg, JSON_PRETTY_PRINT); + ' "$ADMIN_DOMAIN" "$ADMIN_EMAIL" "$ADMIN_PORT" "$($ENABLE_SSL && echo true || echo false)" \ + "$INSTALL_DIR" "$LOG_DIR" "$STAGE_FILE" "$CADDY_LIVE_FILE" "$RATE_LIMIT_FILE" \ + > "$ADMIN_CONFIG_FILE" + chown "root:${WEB_GROUP}" "$ADMIN_CONFIG_FILE" + chmod 640 "$ADMIN_CONFIG_FILE" + + ADMIN_PASS="" + + ok "Auth- und Konfigdatei geschrieben (Passwort als bcrypt-Hash, mode 0640)" } -# Admin Panel Dateien erstellen -create_admin_panel_files() { - echo -e "${YELLOW}→ Erstelle Admin Panel Dateien...${NC}" - - # Verzeichnis erstellen - mkdir -p $INSTALL_DIR - - # index.html erstellen - cat > $INSTALL_DIR/index.html << 'EOHTML' +# ---- Panel-Dateien ---------------------------------------------------------- + +write_panel_files() { + info "Schreibe Admin-Panel-Dateien..." + + cat > "${INSTALL_DIR}/index.php" <<'EOPHP' + + Caddy Reverse Proxy Verwaltung - - - - -
- -
-
-
-
-
Aktive Domains
-

0

-
-
-
-
-
-
-
Online
-

0

-
-
-
-
-
-
-
Offline
-

0

-
-
-
+ + +
+
+
+
Domains

0

+
+
+
Online

0

+
+
+
Offline

0

+
+
- -
-
- - -
-
+
+ + +
- -
- -
-
+
+
- -