#!/bin/bash # # setup-hugo-host.sh # # Richtet einen frischen Debian-12-LXC-Container als Hugo-Hosting-Server ein: # - nginx auf Port 80 (TLS via vorgelagertem Reverse-Proxy, z.B. NPM) # - SFTP-only-User für Deployment (chroot auf /var/www) # - ufw, fail2ban, unattended-upgrades, sysctl-hardening # # Verwendung: # ./setup-hugo-host.sh # # Beispiel: # ./setup-hugo-host.sh example.com # # Wichtig: # Nach dem Lauf ist KEIN interaktiver SSH-Login mehr möglich (nur SFTP). # Administration erfolgt über die Proxmox-Konsole: pct enter # set -euo pipefail # ── KONFIGURATION ───────────────────────────────────────────────────────────── # Public Keys, die SFTP-Zugriff erhalten. Mehrere Keys: eine Zeile pro Key. SSH_PUBKEYS="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDMeSZTfX3tLpgujHXzP+VrbbxO1/cificO8beYvaTyb karim@mac" # ── Argumente ───────────────────────────────────────────────────────────────── if [ $# -ne 1 ]; then echo "Usage: $0 " echo "" echo "Example:" echo " $0 example.com" exit 1 fi DOMAIN="$1" SFTP_USER="webedit-$(echo "$DOMAIN" | tr '.' '-')" if [ "$(id -u)" -ne 0 ]; then echo "Bitte als root ausführen." exit 1 fi echo "===============================================" echo "Hugo-Host Setup" echo " Domain: $DOMAIN" echo " SFTP-User: $SFTP_USER" echo "===============================================" echo "" # ── 1. Pakete ───────────────────────────────────────────────────────────────── echo "[1/9] Pakete installieren..." export DEBIAN_FRONTEND=noninteractive apt-get update -qq apt-get upgrade -y -qq apt-get install -y -qq nginx ufw fail2ban unattended-upgrades curl ca-certificates # ── 2. SSH-Daemon als reiner SFTP-Server ────────────────────────────────────── echo "[2/9] SSH-Daemon auf SFTP-only konfigurieren..." getent group sftp-users >/dev/null || groupadd sftp-users cat > /etc/ssh/sshd_config <<'EOF' PermitRootLogin no PasswordAuthentication no PubkeyAuthentication yes KbdInteractiveAuthentication no X11Forwarding no AllowAgentForwarding no AllowTcpForwarding no PermitTunnel no MaxAuthTries 3 ClientAliveInterval 300 ClientAliveCountMax 2 AllowGroups sftp-users Subsystem sftp internal-sftp Match Group sftp-users ChrootDirectory /var/www ForceCommand internal-sftp -u 0002 AuthorizedKeysFile /etc/ssh/sftp-keys/%u/authorized_keys EOF sshd -t systemctl restart ssh # ── 3. Firewall ─────────────────────────────────────────────────────────────── echo "[3/9] UFW konfigurieren..." ufw --force reset >/dev/null ufw default deny incoming ufw default allow outgoing ufw allow 22/tcp ufw allow 80/tcp ufw allow 443/tcp ufw --force enable # ── 4. fail2ban ─────────────────────────────────────────────────────────────── echo "[4/9] fail2ban konfigurieren..." cat > /etc/fail2ban/jail.local <<'EOF' [DEFAULT] bantime = 1h findtime = 10m maxretry = 4 [sshd] enabled = true [nginx-http-auth] enabled = true [nginx-botsearch] enabled = true EOF systemctl enable --now fail2ban # ── 5. Automatische Security-Updates ────────────────────────────────────────── echo "[5/9] Automatische Updates aktivieren..." cat > /etc/apt/apt.conf.d/20auto-upgrades <<'EOF' APT::Periodic::Update-Package-Lists "1"; APT::Periodic::Unattended-Upgrade "1"; APT::Periodic::AutocleanInterval "7"; EOF sed -i 's|^//Unattended-Upgrade::Automatic-Reboot "false";|Unattended-Upgrade::Automatic-Reboot "true";|' \ /etc/apt/apt.conf.d/50unattended-upgrades sed -i 's|^//Unattended-Upgrade::Automatic-Reboot-Time "02:00";|Unattended-Upgrade::Automatic-Reboot-Time "03:00";|' \ /etc/apt/apt.conf.d/50unattended-upgrades # ── 6. Sysctl-Hardening ─────────────────────────────────────────────────────── echo "[6/9] Sysctl-Hardening..." cat > /etc/sysctl.d/99-hardening.conf <<'EOF' net.ipv4.conf.all.rp_filter = 1 net.ipv4.conf.all.accept_redirects = 0 net.ipv4.conf.all.send_redirects = 0 net.ipv4.tcp_syncookies = 1 net.ipv6.conf.all.accept_redirects = 0 kernel.dmesg_restrict = 1 EOF # Nur unsere eigene Datei anwenden, nicht --system (Debian-Defaults setzen Keys, # die in einem unprivileged LXC read-only sind und set -e auslösen würden). # || true: in unpriv LXC ist z.B. kernel.dmesg_restrict ebenfalls read-only — # nicht kritisch, einfach ignorieren. sysctl -p /etc/sysctl.d/99-hardening.conf >/dev/null 2>&1 || true # ── 7. Nginx-Site einrichten ────────────────────────────────────────────────── echo "[7/9] Nginx-Site für $DOMAIN einrichten..." rm -f /etc/nginx/sites-enabled/default chown root:root /var/www chmod 755 /var/www mkdir -p "/var/www/$DOMAIN" cat > "/etc/nginx/sites-available/$DOMAIN" <$DOMAIN — OK" > "/var/www/$DOMAIN/index.html" nginx -t systemctl reload nginx # ── 8. SFTP-User anlegen ────────────────────────────────────────────────────── echo "[8/9] SFTP-User $SFTP_USER anlegen..." mkdir -p /etc/ssh/sftp-keys chown root:root /etc/ssh/sftp-keys chmod 755 /etc/ssh/sftp-keys if id "$SFTP_USER" >/dev/null 2>&1; then echo " User $SFTP_USER existiert bereits" else adduser --disabled-password --gecos "" --shell /usr/sbin/nologin "$SFTP_USER" # adduser --disabled-password setzt das Shadow-Feld auf "!" → sshd sieht # "Account locked" auch für Key-Auth. passwd -d entfernt das Passwort # komplett → Status "NP" → Key-Auth funktioniert. passwd -d "$SFTP_USER" fi usermod -aG sftp-users "$SFTP_USER" chown "$SFTP_USER:sftp-users" "/var/www/$DOMAIN" chmod 775 "/var/www/$DOMAIN" mkdir -p "/etc/ssh/sftp-keys/$SFTP_USER" chown -R root:root "/etc/ssh/sftp-keys/$SFTP_USER" chmod 755 "/etc/ssh/sftp-keys/$SFTP_USER" # ── 9. Public Keys eintragen ────────────────────────────────────────────────── echo "[9/9] Public Keys eintragen..." AUTH_KEYS="/etc/ssh/sftp-keys/$SFTP_USER/authorized_keys" if ! grep -qE '^(ssh-(rsa|ed25519|dss)|ecdsa-sha2-)' <<<"$SSH_PUBKEYS"; then echo " ⚠ SSH_PUBKEYS enthält keinen gültigen Public Key — bitte oben im Script setzen." exit 1 fi printf '%s\n' "$SSH_PUBKEYS" > "$AUTH_KEYS" chown root:root "$AUTH_KEYS" chmod 644 "$AUTH_KEYS" KEY_COUNT=$(grep -cE '^(ssh-(rsa|ed25519|dss)|ecdsa-sha2-)' "$AUTH_KEYS") echo " ✓ $KEY_COUNT Public Key(s) eingetragen" # ── Fertig ──────────────────────────────────────────────────────────────────── IP=$(hostname -I | awk '{print $1}') echo "" echo "===============================================" echo " FERTIG" echo "===============================================" echo "" echo "Domain: $DOMAIN" echo "Webroot: /var/www/$DOMAIN" echo "Container-IP: $IP" echo "" echo "Deployment (vom lokalen Hugo-Projekt aus):" echo "" echo " hugo --minify" echo " lftp -u $SFTP_USER, sftp://$IP -e \"mirror -R --delete public/ /$DOMAIN/; quit\"" echo "" echo "Alternative mit sftp (ohne --delete):" echo " sftp $SFTP_USER@$IP <<< \"put -r public/* /$DOMAIN/\"" echo "" echo "Tipp: für TLS einen Reverse-Proxy (z.B. Nginx Proxy Manager)" echo " auf $DOMAIN → http://$IP:80 zeigen lassen." echo "" echo "Hinweis: SSH-Shell-Login ist deaktiviert (SFTP-only)." echo " Administration via Proxmox-Konsole: pct enter " echo ""