Nextcloud Talk: High Performance Backend (HPB)

Nextcloud Talk: High Performance Backend (HPB)

Vorwort

Für die Ablösung von Microsoft Teams nutzen wir zukünftig Nextcloud Talk.

Damit auch Meetings mit 5+ Teilnehmenden gut funktionieren benötigt man ein sogenanntes „High Performance Backend“, welches die Orchestrierung der Teilnehmer untereinander übernimmt (meist ist eine Nextcloud-Instanz auf keinem potenten Server installiert).

Über claude.ai habe ich mir ein Script erstellen lassen, welches unter Ubuntu 24.04 in einem Rutsch das HPB installiert und auch Betriebssystem- und HPB-Updates einrichtet.

Quasi ein All-in-One-Script.

Voraussetzungen

  • frisch installierter Ubuntu Server 24.04 LTS
  • dem Server ist eine öffentliche IP zugewiesen
  • es gibt einen Host-Namen, der auf die öffentliche IP auflöst
  • Abarbeiten der Hinweise von meinem Artikel Ubuntu, Nano, Docker, Docker Compose & Firewall

DAS Script

Öffne eine Datei install-hpb.sh …

nano install-hpb.sh

… und füge den folgenden Inhalt hinzu …

#!/usr/bin/env bash
#
# install-hpb.sh
# ---------------------------------------------------------------------------
# Installiert ein vollständiges High Performance Backend (HPB) für
# Nextcloud Talk auf Ubuntu 24.04 LTS:
#   - coturn        (STUN/TURN)
#   - Janus         (WebRTC-Gateway)
#   - NATS          (Messaging, per Docker)
#   - nextcloud-spreed-signaling  (Signaling-Server, aus Quellcode gebaut)
#   - nginx + Let's Encrypt (Reverse Proxy für den Signaling-Server)
#   - systemd-Timer, der täglich um 02:00 Uhr Betriebssystem- UND
#     HPB-Updates einspielt
#
# Aufruf:  sudo ./install-hpb.sh
# Erneuter Aufruf ist unkritisch (idempotent) - vorhandene Secrets und
# Konfigurationen werden nicht überschrieben, nur ergänzt/aktualisiert.
# ---------------------------------------------------------------------------

set -euo pipefail

########################################################################
# KONFIGURATION – BITTE VOR DEM ERSTEN AUFRUF ANPASSEN
########################################################################
SIGNALING_DOMAIN="talk.example.com"        # FQDN dieses HPB-Servers (DNS muss bereits hierher zeigen!)
NEXTCLOUD_URL="https://cloud.example.com"  # URL der bestehenden Nextcloud-Instanz
LETSENCRYPT_EMAIL="[email protected]"      # Kontakt-Adresse für Let's Encrypt
SIGNALING_VERSION="latest"                 # "latest" = neuestes Git-Tag, oder z.B. "v1.3.0"
########################################################################

SECRETS_FILE="/root/hpb-secrets.env"
SIGNALING_SRC="/opt/nextcloud-spreed-signaling"
SIGNALING_CONF="/etc/nextcloud-signaling.conf"
LOGFILE="/var/log/hpb-install.log"

exec > >(tee -a "$LOGFILE") 2>&1
echo "=== HPB-Installation gestartet: $(date -Is) ==="

if [[ $EUID -ne 0 ]]; then
    echo "Bitte als root ausführen (sudo ./install-hpb.sh)." >&2
    exit 1
fi

if [[ "$SIGNALING_DOMAIN" == "talk.example.com" ]]; then
    echo "FEHLER: Bitte zuerst die KONFIGURATION am Anfang des Skripts anpassen" >&2
    echo "        (SIGNALING_DOMAIN, NEXTCLOUD_URL, LETSENCRYPT_EMAIL)." >&2
    exit 1
fi

. /etc/os-release || true
if [[ "${VERSION_ID:-}" != "24.04" ]]; then
    echo "WARNUNG: Dieses Skript ist für Ubuntu 24.04 LTS getestet (gefunden: ${VERSION_ID:-unbekannt}). Fortfahren in 5s..." >&2
    sleep 5
fi

########################################################################
# 1. Secrets erzeugen (nur beim ersten Lauf) oder laden
########################################################################
if [[ -f "$SECRETS_FILE" ]]; then
    echo "--> Bestehende Secrets aus $SECRETS_FILE werden wiederverwendet."
    # shellcheck disable=SC1090
    source "$SECRETS_FILE"
else
    echo "--> Erzeuge neue Secrets."
    TURN_SECRET=$(openssl rand -hex 16)
    JANUS_API_KEY=$(openssl rand -hex 16)
    SESSION_HASHKEY=$(openssl rand -hex 16)
    SESSION_BLOCKKEY=$(openssl rand -hex 16)
    INTERNAL_SECRET=$(openssl rand -hex 16)
    BACKEND_SECRET=$(openssl rand -hex 16)
    cat > "$SECRETS_FILE" <<EOF
TURN_SECRET=$TURN_SECRET
JANUS_API_KEY=$JANUS_API_KEY
SESSION_HASHKEY=$SESSION_HASHKEY
SESSION_BLOCKKEY=$SESSION_BLOCKKEY
INTERNAL_SECRET=$INTERNAL_SECRET
BACKEND_SECRET=$BACKEND_SECRET
EOF
    chmod 600 "$SECRETS_FILE"
fi

########################################################################
# 2. Basis-Update + Pakete
########################################################################
echo "--> apt update/upgrade"
export DEBIAN_FRONTEND=noninteractive
apt-get update -y
apt-get -y -o Dpkg::Options::="--force-confold" upgrade

echo "--> Installiere benötigte Pakete"
apt-get install -y \
    coturn janus nginx certbot python3-certbot-nginx \
    golang-go git make build-essential automake protobuf-compiler \
    docker.io openssl jq curl unattended-upgrades

########################################################################
# 3. coturn (STUN/TURN)
########################################################################
echo "--> Konfiguriere coturn"
if ! getent group turnserver >/dev/null; then
    groupadd --system turnserver
fi
if ! getent passwd turnserver >/dev/null; then
    useradd --system --gid turnserver --shell /usr/sbin/nologin \
        --comment "Coturn STUN/TURN server" turnserver
fi

cat > /etc/turnserver.conf <<EOF
listening-port=3478
fingerprint
use-auth-secret
static-auth-secret=${TURN_SECRET}
realm=${SIGNALING_DOMAIN}
total-quota=0
bps-capacity=0
no-tls
no-dtls
stale-nonce
no-loopback-peers
no-multicast-peers
proc-user=turnserver
proc-group=turnserver
EOF

echo "TURNSERVER_ENABLED=1" > /etc/default/coturn

# Eigene, robuste systemd-Unit (überschreibt ggf. Paket-Unit, /etc hat Vorrang)
cat > /etc/systemd/system/coturn.service <<'EOF'
[Unit]
Description=coturn STUN/TURN server
Documentation=man:coturn(1) man:turnadmin(1) man:turnserver(1)
After=syslog.target network.target

[Service]
Type=forking
User=turnserver
Group=turnserver
RuntimeDirectory=turnserver
RuntimeDirectoryMode=0750
EnvironmentFile=/etc/default/coturn
PIDFile=/run/turnserver/turnserver.pid
ExecStart=/usr/bin/turnserver --daemon --pidfile /run/turnserver/turnserver.pid --syslog -c /etc/turnserver.conf $EXTRA_OPTIONS
Restart=on-failure
LimitNOFILE=1000000

[Install]
WantedBy=multi-user.target
EOF

update-rc.d coturn disable 2>/dev/null || true
systemctl daemon-reload
systemctl enable --now coturn.service
systemctl restart coturn.service

########################################################################
# 4. Janus (WebRTC-Gateway)
########################################################################
echo "--> Konfiguriere Janus"

python3 - "$JANUS_API_KEY" "$SIGNALING_DOMAIN" <<'PYEOF'
import re, sys

janus_api_key, signaling_domain = sys.argv[1], sys.argv[2]

def set_kv(content, section, key, value):
    pattern = re.compile(r'(' + re.escape(section) + r':\s*\{)(.*?)(\n\})', re.S)
    m = pattern.search(content)
    if not m:
        return content
    header, body, footer = m.group(1), m.group(2), m.group(3)
    kv_pattern = re.compile(r'^[ \t]*#?[ \t]*' + re.escape(key) + r'[ \t]*=.*$', re.M)
    line = f'\t\t{key} = {value}'
    if kv_pattern.search(body):
        body = kv_pattern.sub(line, body, count=1)
    else:
        body = body + '\n' + line
    return content[:m.start()] + header + body + footer + content[m.end():]

# janus.jcfg: nat-Sektion
path = "/etc/janus/janus.jcfg"
with open(path) as f:
    content = f.read()
content = set_kv(content, "nat", "stun_server", f'"{signaling_domain}"')
content = set_kv(content, "nat", "stun_port", "3478")
content = set_kv(content, "nat", "full_trickle", "true")
content = set_kv(content, "nat", "turn_rest_api_key", f'"{janus_api_key}"')
with open(path, "w") as f:
    f.write(content)

# janus.transport.http.jcfg: general-Sektion (nur lokal erreichbar)
path = "/etc/janus/janus.transport.http.jcfg"
with open(path) as f:
    content = f.read()
content = set_kv(content, "general", "base_path", '"/janus"')
content = set_kv(content, "general", "http", "true")
content = set_kv(content, "general", "port", "8088")
content = set_kv(content, "general", "ip", '"127.0.0.1"')
content = set_kv(content, "general", "https", "false")
with open(path, "w") as f:
    f.write(content)

# janus.transport.websockets.jcfg: general-Sektion (nur lokal erreichbar)
path = "/etc/janus/janus.transport.websockets.jcfg"
with open(path) as f:
    content = f.read()
content = set_kv(content, "general", "ws", "true")
content = set_kv(content, "general", "ws_port", "8188")
content = set_kv(content, "general", "ws_ip", '"127.0.0.1"')
content = set_kv(content, "general", "wss", "false")
with open(path, "w") as f:
    f.write(content)
PYEOF

systemctl enable --now janus.service
systemctl restart janus.service

########################################################################
# 5. NATS (per Docker)
########################################################################
echo "--> Richte NATS via Docker ein"
systemctl enable --now docker.service

if ! docker ps -a --format '{{.Names}}' | grep -qx nats; then
    docker run --name=nats -d -p 127.0.0.1:4222:4222 --restart=always nats:latest
else
    docker start nats >/dev/null || true
fi

########################################################################
# 6. nextcloud-spreed-signaling (Signaling-Server)
########################################################################
echo "--> Baue nextcloud-spreed-signaling"

if ! getent group nextcloud-signaling >/dev/null; then
    groupadd --system nextcloud-signaling
fi
if ! getent passwd nextcloud-signaling >/dev/null; then
    useradd --system --gid nextcloud-signaling --shell /usr/sbin/nologin \
        --comment "Nextcloud Talk signaling server" nextcloud-signaling
fi

if [[ ! -d "$SIGNALING_SRC" ]]; then
    git clone https://github.com/strukturag/nextcloud-spreed-signaling.git "$SIGNALING_SRC"
fi

cd "$SIGNALING_SRC"
git fetch --tags --force

if [[ "$SIGNALING_VERSION" == "latest" ]]; then
    TARGET_REF=$(git tag -l 'v*' | sort -V | tail -n1)
    if [[ -z "$TARGET_REF" ]]; then
        TARGET_REF="main"
    fi
else
    TARGET_REF="$SIGNALING_VERSION"
fi
echo "    Verwende Version: $TARGET_REF"
git checkout -q "$TARGET_REF"
make build

cat > "$SIGNALING_CONF" <<EOF
[http]
listen = 127.0.0.1:8090

[sessions]
hashkey = ${SESSION_HASHKEY}
blockkey = ${SESSION_BLOCKKEY}

[clients]
internalsecret = ${INTERNAL_SECRET}

[backend]
backends = backend1
allowall = false

[backend1]
url = ${NEXTCLOUD_URL}
secret = ${BACKEND_SECRET}

[nats]
url = nats://127.0.0.1:4222

[mcu]
type = janus
url = ws://127.0.0.1:8188

[turn]
apikey = ${JANUS_API_KEY}
secret = ${TURN_SECRET}
servers = turn:${SIGNALING_DOMAIN}:3478?transport=udp,turn:${SIGNALING_DOMAIN}:3478?transport=tcp
EOF
chmod 600 "$SIGNALING_CONF"
chown nextcloud-signaling: "$SIGNALING_CONF"

cat > /etc/systemd/system/nextcloud-signaling.service <<EOF
[Unit]
Description=Nextcloud Talk signaling server
After=network.target janus.service coturn.service docker.service

[Service]
ExecStart=${SIGNALING_SRC}/bin/signaling --config ${SIGNALING_CONF}
User=nextcloud-signaling
Group=nextcloud-signaling
Restart=on-failure

NoNewPrivileges=yes
PrivateTmp=yes
ProtectHome=yes
ProtectSystem=strict
ReadWritePaths=${SIGNALING_CONF}

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable --now nextcloud-signaling.service
systemctl restart nextcloud-signaling.service

########################################################################
# 7. nginx + Let's Encrypt
########################################################################
echo "--> Konfiguriere nginx"

cat > /etc/nginx/sites-available/${SIGNALING_DOMAIN}.conf <<EOF
upstream signaling {
    server 127.0.0.1:8090;
}

server {
    listen 80;
    listen [::]:80;
    server_name ${SIGNALING_DOMAIN};

    location /standalone-signaling/ {
        proxy_pass http://signaling/;
        proxy_http_version 1.1;
        proxy_set_header Host \$host;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
    }

    location /standalone-signaling/spreed {
        proxy_pass http://signaling/spreed;
        proxy_http_version 1.1;
        proxy_set_header Upgrade \$http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Host \$host;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
    }
}
EOF

ln -sf /etc/nginx/sites-available/${SIGNALING_DOMAIN}.conf /etc/nginx/sites-enabled/${SIGNALING_DOMAIN}.conf
nginx -t
systemctl reload nginx

echo "--> Fordere Let's-Encrypt-Zertifikat an (setzt voraus, dass DNS für ${SIGNALING_DOMAIN} bereits auf diesen Server zeigt und Port 80 von außen erreichbar ist)"
if certbot certificates 2>/dev/null | grep -q "Domains: ${SIGNALING_DOMAIN}"; then
    echo "    Zertifikat existiert bereits, überspringe Anforderung."
else
    certbot --nginx -d "${SIGNALING_DOMAIN}" --non-interactive --agree-tos \
        -m "${LETSENCRYPT_EMAIL}" --redirect || \
        echo "    WARNUNG: certbot ist fehlgeschlagen. Bitte DNS/Port 80 prüfen und certbot manuell erneut ausführen."
fi

########################################################################
# 8. Firewall (nur falls ufw aktiv ist)
########################################################################
if command -v ufw >/dev/null && ufw status | grep -q "Status: active"; then
    echo "--> ufw ist aktiv, öffne benötigte Ports"
    ufw allow 80/tcp
    ufw allow 443/tcp
    ufw allow 3478/tcp
    ufw allow 3478/udp
fi

########################################################################
# 9. Update-Skript + systemd-Timer für 02:00 Uhr
########################################################################
echo "--> Richte automatische tägliche Updates (02:00 Uhr) ein"

cat > /usr/local/sbin/hpb-update.sh <<EOF
#!/usr/bin/env bash
# Automatisch von install-hpb.sh erzeugt.
# Aktualisiert Betriebssystem-Pakete UND alle HPB-Komponenten.
set -euo pipefail
export DEBIAN_FRONTEND=noninteractive

LOG="/var/log/hpb-update.log"
exec >> "\$LOG" 2>&1
echo "=== HPB-Update gestartet: \$(date -Is) ==="

# 1) Betriebssystem- und Paket-Updates (deckt u.a. coturn, janus, nginx ab)
apt-get update -y
apt-get -y -o Dpkg::Options::="--force-confold" dist-upgrade
apt-get -y autoremove --purge
apt-get -y clean

# 2) NATS-Docker-Image aktualisieren
docker pull nats:latest
RUNNING_ID=\$(docker inspect --format '{{.Image}}' nats 2>/dev/null || echo "")
LATEST_ID=\$(docker inspect --format '{{.Id}}' nats:latest 2>/dev/null || echo "")
if [[ "\$RUNNING_ID" != "\$LATEST_ID" ]]; then
    echo "Neues NATS-Image gefunden, Container wird neu erstellt."
    docker rm -f nats || true
    docker run --name=nats -d -p 127.0.0.1:4222:4222 --restart=always nats:latest
fi

# 3) nextcloud-spreed-signaling auf neueste Version aktualisieren
cd "${SIGNALING_SRC}"
CURRENT_REF=\$(git rev-parse HEAD)
git fetch --tags --force
LATEST_TAG=\$(git tag -l 'v*' | sort -V | tail -n1)
if [[ -n "\$LATEST_TAG" ]]; then
    LATEST_REF=\$(git rev-parse "\$LATEST_TAG")
    if [[ "\$CURRENT_REF" != "\$LATEST_REF" ]]; then
        echo "Aktualisiere Signaling-Server auf \$LATEST_TAG"
        git checkout -q "\$LATEST_TAG"
        make build
        systemctl restart nextcloud-signaling.service
    fi
fi

# 4) Dienste durchstarten, falls Pakete aktualisiert wurden
systemctl restart coturn.service janus.service nginx.service || true

# 5) Hinweis, falls ein Reboot nötig ist (kein automatischer Reboot,
#    um laufende Gespräche nicht zu unterbrechen)
if [[ -f /var/run/reboot-required ]]; then
    echo "HINWEIS: Ein Neustart des Servers ist erforderlich (siehe /var/run/reboot-required)."
fi

echo "=== HPB-Update abgeschlossen: \$(date -Is) ==="
EOF
chmod 750 /usr/local/sbin/hpb-update.sh

cat > /etc/systemd/system/hpb-update.service <<'EOF'
[Unit]
Description=Tägliches Update von Betriebssystem und Nextcloud Talk HPB

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/hpb-update.sh
EOF

cat > /etc/systemd/system/hpb-update.timer <<'EOF'
[Unit]
Description=Startet hpb-update.service täglich um 02:00 Uhr

[Timer]
OnCalendar=*-*-* 02:00:00
RandomizedDelaySec=300
Persistent=true

[Install]
WantedBy=timers.target
EOF

systemctl daemon-reload
systemctl enable --now hpb-update.timer

########################################################################
# 10. Zusammenfassung
########################################################################
cat <<SUMMARY

============================================================================
 Installation abgeschlossen: $(date -Is)
============================================================================

Trage in Nextcloud unter Einstellungen -> Talk folgende Werte ein:

  STUN-Server:
    ${SIGNALING_DOMAIN}:3478

  TURN-Server:
    Server:  ${SIGNALING_DOMAIN}:3478
    Secret:  ${TURN_SECRET}
    (Protokolle UDP und TCP wie vorgegeben belassen)

  Signaling-Server (High-Performance-Backend):
    URL:     https://${SIGNALING_DOMAIN}/standalone-signaling/
    Secret:  ${BACKEND_SECRET}

Alle erzeugten Secrets liegen zusätzlich in: ${SECRETS_FILE} (chmod 600)

Automatische Updates:
  - systemd-Timer 'hpb-update.timer' läuft täglich um 02:00 Uhr
    (+ bis zu 5 Min. zufällige Verzögerung)
  - Aktualisiert: Betriebssystem-Pakete, coturn, Janus, nginx,
    NATS-Docker-Image sowie nextcloud-spreed-signaling (neuestes Git-Tag)
  - Log: /var/log/hpb-update.log
  - Status prüfen: systemctl list-timers hpb-update.timer

Wichtig:
  - Stelle sicher, dass DNS für ${SIGNALING_DOMAIN} auf diesen Server zeigt
    und die Ports 80/443 (TCP) sowie 3478 (TCP+UDP) von außen erreichbar sind.
  - Falls certbot oben fehlgeschlagen ist: erneut ausführen mit
      certbot --nginx -d ${SIGNALING_DOMAIN}
============================================================================
SUMMARY
  • Passe nun die folgenden Variablen im Script an:
SIGNALING_DOMAIN="talk.example.com"        # muss per DNS bereits auf den Server zeigen
NEXTCLOUD_URL="https://cloud.example.com"  # deine bestehende Nextcloud
LETSENCRYPT_EMAIL="[email protected]"

Beende den Editor, gib dem Script die Ausführen-Berechtigung und starte es …

sudo chmod +x install-hpb.sh
sudo ./install-hpb.sh

Konfiguration in Nextcloud

Trage nun die angezeigten Werte so in deine Nextcloud-Installation im Bereich „Talk“ ein, wie es dir das Setup-Script sagt.
Wenn du alles korrekt eingetragen hast solltest du lauter „grüne Haken“ sehen.

Nextcloud Talk: High Performance Backend (HPB)

HPB-Server härten (gegen Angriffe absichern)

Öffne eine Datei harden-hpb.sh …

sudo nano harden-hpb.sh

… und füge folgenden Inhalt ein …

#!/usr/bin/env bash
#
# harden-hpb.sh
# ---------------------------------------------------------------------------
# Härtet den HPB-Server:
#   - ufw: standardmäßig alles blockieren, nur die nötigen Ports öffnen
#     * SSH nur von den angegebenen Admin-IPs
#     * 80/443 (nginx / Let's Encrypt)
#     * 3478 tcp+udp (coturn STUN/TURN)
#     * TURN-Relay-Portbereich (udp) für Media-Relay
#     Janus/NATS/Signaling-Server bleiben unangetastet, da sie ohnehin nur
#     auf 127.0.0.1 lauschen (siehe install-hpb.sh) und keine öffentlichen
#     Ports brauchen.
#   - fail2ban: Bannt IPs mit fehlgeschlagenen SSH-Logins bzw. auffälligem
#     nginx-Verhalten automatisch.
#
# Aufruf:  sudo ./harden-hpb.sh
# ---------------------------------------------------------------------------

set -euo pipefail

########################################################################
# KONFIGURATION – BEI BEDARF ANPASSEN
########################################################################
SSH_PORT=22
SSH_ALLOWED_IPS=("1.2.3.4" "5.6.7.8")
TURN_RELAY_MIN=49152   # muss zu min-port in /etc/turnserver.conf passen (Standard, falls dort nicht gesetzt)
TURN_RELAY_MAX=65535   # muss zu max-port in /etc/turnserver.conf passen (Standard, falls dort nicht gesetzt)
########################################################################

LOGFILE="/var/log/hpb-harden.log"
exec > >(tee -a "$LOGFILE") 2>&1
echo "=== Härtung gestartet: $(date -Is) ==="

if [[ $EUID -ne 0 ]]; then
    echo "Bitte als root ausführen (sudo ./harden-hpb.sh)." >&2
    exit 1
fi

echo "--> Installiere ufw und fail2ban"
export DEBIAN_FRONTEND=noninteractive
apt-get update -y
apt-get install -y ufw fail2ban

########################################################################
# 1. ufw: Grundregeln
########################################################################
echo "--> Setze ufw-Grundregeln"
ufw default deny incoming
ufw default allow outgoing

# Vorhandene, zu offene SSH-Regeln entfernen (falls z.B. "OpenSSH" oder
# "22/tcp" bisher für alle IPs offen war)
ufw delete allow OpenSSH 2>/dev/null || true
ufw delete allow "${SSH_PORT}/tcp" 2>/dev/null || true
ufw delete allow ssh 2>/dev/null || true

########################################################################
# 2. SSH nur von den Admin-IPs
########################################################################
echo "--> Erlaube SSH (Port ${SSH_PORT}) nur von den Admin-IPs"
for ip in "${SSH_ALLOWED_IPS[@]}"; do
    ufw allow from "${ip}" to any port "${SSH_PORT}" proto tcp comment "SSH Admin-Zugriff"
done

########################################################################
# 3. Öffentlich benötigte HPB-Ports
########################################################################
echo "--> Öffne öffentlich benötigte Ports (HTTP/HTTPS, TURN)"
ufw allow 80/tcp comment "nginx und Lets Encrypt"
ufw allow 443/tcp comment "nginx HTTPS und Signaling Proxy"
ufw allow 3478/tcp comment "coturn STUN und TURN"
ufw allow 3478/udp comment "coturn STUN und TURN"
ufw allow "${TURN_RELAY_MIN}:${TURN_RELAY_MAX}/udp" comment "coturn Media Relay"

########################################################################
# 4. ufw aktivieren
########################################################################
echo "--> Aktiviere ufw"
ufw --force enable
ufw status verbose

########################################################################
# 5. fail2ban konfigurieren
########################################################################
echo "--> Konfiguriere fail2ban"

IGNORE_IPS="127.0.0.1/8 ::1"
for ip in "${SSH_ALLOWED_IPS[@]}"; do
    IGNORE_IPS="${IGNORE_IPS} ${ip}"
done

cat > /etc/fail2ban/jail.local <<EOF
[DEFAULT]
bantime  = 1h
findtime = 10m
maxretry = 5
ignoreip = ${IGNORE_IPS}
backend  = systemd

[sshd]
enabled = true
port    = ${SSH_PORT}

[nginx-http-auth]
enabled  = true
logpath  = /var/log/nginx/error.log

[nginx-botsearch]
enabled  = true
logpath  = /var/log/nginx/access.log

# Wiederholungstäter (z.B. mehrfach in anderen Jails gebannt) langfristig sperren
[recidive]
enabled  = true
bantime  = 1w
findtime = 1d
maxretry = 5
logpath  = /var/log/fail2ban.log
EOF

systemctl enable --now fail2ban
systemctl restart fail2ban

sleep 2
fail2ban-client status

########################################################################
# 6. Zusammenfassung
########################################################################
cat <<SUMMARY

============================================================================
 Härtung abgeschlossen: $(date -Is)
============================================================================

ufw:
  - Standard: eingehend blockiert, ausgehend erlaubt
  - SSH (${SSH_PORT}/tcp): nur von ${SSH_ALLOWED_IPS[*]}
  - 80/tcp, 443/tcp: öffentlich (nginx / Let's Encrypt)
  - 3478/tcp+udp: öffentlich (STUN/TURN)
  - ${TURN_RELAY_MIN}-${TURN_RELAY_MAX}/udp: öffentlich (TURN-Media-Relay)
  - Alles andere: blockiert
  Status jederzeit prüfen mit: ufw status verbose

fail2ban:
  - sshd-Jail aktiv (zusätzliche Absicherung, falls die ufw-Regel je
    entfernt/geändert wird)
  - nginx-http-auth / nginx-botsearch-Jails aktiv (Schutz vor Scans/Bots
    gegen den öffentlichen nginx-Reverse-Proxy)
  - recidive-Jail sperrt Wiederholungstäter für 1 Woche
  - Admin-IPs (${SSH_ALLOWED_IPS[*]}) sind von Bans ausgenommen
  Status jederzeit prüfen mit: fail2ban-client status
  Bestimmten Jail prüfen mit:  fail2ban-client status sshd

WICHTIG:
  - Bevor du dich abmeldest: In einer ZWEITEN Terminal-Sitzung testen, ob
    SSH von einer der beiden erlaubten IPs noch funktioniert, bevor du die
    aktuelle Sitzung schließt – sonst sperrst du dich ggf. aus, falls
    SSH_ALLOWED_IPS falsch eingetragen wurde.
  - Der TURN-Relay-Portbereich muss mit min-port/max-port in
    /etc/turnserver.conf übereinstimmen. Ist dort nichts gesetzt, gilt der
    coturn-Standardbereich (49152-65535), passend zu diesem Skript.
============================================================================
SUMMARY
  • passe die Variable SSH_ALLOWED_IPS=("1.2.3.4" "5.6.7.8") an deine IP-Adresse(n) an (wenn du eine fixe IP-Adresse besitzt), über die du ggf. den SSH-Zugriff auf deinen Server beschränken möchtest
  • setze die Berechtigung des Script auf „ausführbar“ und starte es
sudo chmod +x harden-hpb.sh
sudo ./harden-hpb.sh

Ersten Kommentar schreiben

Antworten

Deine E-Mail-Adresse wird nicht veröffentlicht.


*