Initial commit: Hugo-Host LXC Setup Script

This commit is contained in:
2026-05-25 23:14:34 +02:00
commit b3b3e740d3
2 changed files with 400 additions and 0 deletions
+276
View File
@@ -0,0 +1,276 @@
#!/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 <domain>
#
# 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 <vmid>
#
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 <domain>"
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
sysctl --system >/dev/null
# ── 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" <<EOF
server {
listen 80;
listen [::]:80;
server_name $DOMAIN www.$DOMAIN;
root /var/www/$DOMAIN;
index index.html;
location / {
try_files \$uri \$uri/ \$uri.html =404;
}
location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff2?)\$ {
expires 30d;
add_header Cache-Control "public, immutable";
access_log off;
}
location ~ /\. {
deny all;
return 404;
}
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
}
EOF
ln -sf "/etc/nginx/sites-available/$DOMAIN" "/etc/nginx/sites-enabled/$DOMAIN"
echo "<h1>$DOMAIN — OK</h1>" > "/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 <vmid>"
echo ""