Skip to main content

Server stealth absicherung

Diese Anleitung beschreibt verschiedene Methoden, um einen Server im Internet zu "verstecken", vor Port-Scans und DDoS-Angriffen zu schützen und SSH maximal abzusichern – während die gewünschten Dienste weiterhin erreichbar bleiben.

Anpassbare Werte in dieser Anleitung:

  • luna → Dein Benutzername
  • 226 → Dein SSH-Port
  • 7000,8000,9000 → Deine Port-Knocking-Sequenz
  • 100.64.0.x → Deine VPN/NetBird-IPs

Teil 1: Grundkonzept – Was bedeutet "unsichtbar"?

Angriffsvektoren verstehen

Bevor wir den Server schützen, müssen wir verstehen, wie Angreifer vorgehen:

Phase Angreifer-Aktion Unser Ziel
1. Reconnaissance Port-Scans (Nmap, Masscan, Shodan) Keine offenen Ports zeigen
2. Enumeration Banner-Grabbing, Versionserkennung Keine Informationen preisgeben
3. Exploitation Brute-Force, CVE-Exploits Angriffe blockieren/verlangsamen
4. DDoS Traffic-Flut, Ressourcenerschöpfung Traffic filtern, Rate-Limiting

Stealth-Stufen

Stufe 0: Standard-Server
├── Alle Ports antworten (REJECT)
├── Banner zeigen Versionen
└── SSH auf Port 22 offen
    → Innerhalb von Minuten in Shodan/Censys

Stufe 1: Basis-Härtung
├── Nicht benötigte Ports geschlossen
├── SSH auf nicht-standard Port
└── Fail2ban aktiv
    → Reduziert automatisierte Angriffe

Stufe 2: Stealth-Modus
├── DROP statt REJECT (keine Antwort)
├── Keine ICMP-Antworten
├── Banner entfernt/gefälscht
└── Anti-Scan-Regeln
    → Erscheint für Portscanner als offline

Stufe 3: Maximale Stealth
├── SSH nur via VPN/Knocking
├── Alle Ports unsichtbar
├── Dienste via Reverse Proxy
└── DDoS-Schutz aktiv
    → Praktisch unsichtbar, nur Dienste erreichbar

Teil 2: Firewall-Stealth-Konfiguration

Methode 1: UFW (Einfach)

Für Einsteiger – schnell eingerichtet, aber weniger granular.

# Defaults setzen
sudo ufw default deny incoming
sudo ufw default allow outgoing

# Nur benötigte Ports öffnen
sudo ufw allow 80/tcp comment 'HTTP'
sudo ufw allow 443/tcp comment 'HTTPS'
sudo ufw allow 443/udp comment 'QUIC'

# SSH eingeschränkt (siehe SSH-Schutz-Kapitel)
sudo ufw allow 226/tcp comment 'SSH'

# Aktivieren
sudo ufw enable

Limitation: UFW verwendet standardmäßig REJECT, nicht DROP. Portscanner sehen den Server als "gefiltert".

UFW auf DROP umstellen

# /etc/ufw/after.rules am Ende hinzufügen:
sudo nano /etc/ufw/after.rules
# Am Ende der Datei hinzufügen (vor COMMIT):
-A ufw-reject-input -j DROP
-A ufw-reject-forward -j DROP
# UFW neu laden
sudo ufw reload

Methode 2: iptables (Fortgeschritten)

Maximale Kontrolle, aber komplexer.

sudo nano /etc/iptables/rules.v4
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]

# ══════════════════════════════════════════════════════════════
# GRUNDREGELN
# ══════════════════════════════════════════════════════════════

# Loopback erlauben
-A INPUT -i lo -j ACCEPT

# Established Connections
-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# Ungültige Pakete verwerfen
-A INPUT -m conntrack --ctstate INVALID -j DROP

# ══════════════════════════════════════════════════════════════
# ANTI-SCAN REGELN
# ══════════════════════════════════════════════════════════════

# Fragmentierte Pakete droppen
-A INPUT -f -j DROP

# XMAS-Pakete (Nmap -sX)
-A INPUT -p tcp --tcp-flags ALL ALL -j DROP

# NULL-Pakete (Nmap -sN)
-A INPUT -p tcp --tcp-flags ALL NONE -j DROP

# SYN-FIN (ungültige Kombination)
-A INPUT -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP

# SYN-RST (ungültige Kombination)
-A INPUT -p tcp --tcp-flags SYN,RST SYN,RST -j DROP

# FIN ohne ACK
-A INPUT -p tcp --tcp-flags FIN,ACK FIN -j DROP

# PSH ohne ACK
-A INPUT -p tcp --tcp-flags PSH,ACK PSH -j DROP

# URG ohne ACK
-A INPUT -p tcp --tcp-flags URG,ACK URG -j DROP

# ══════════════════════════════════════════════════════════════
# ICMP (OPTIONAL: Für maximale Stealth auskommentieren)
# ══════════════════════════════════════════════════════════════

# Ping mit Rate-Limit (oder komplett droppen für Stealth)
# -A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s --limit-burst 2 -j ACCEPT
-A INPUT -p icmp --icmp-type echo-request -j DROP

# ══════════════════════════════════════════════════════════════
# DIENSTE
# ══════════════════════════════════════════════════════════════

# HTTP/HTTPS
-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT
-A INPUT -p udp --dport 443 -j ACCEPT

# SSH (später einschränken, siehe SSH-Kapitel)
-A INPUT -p tcp --dport 226 -m conntrack --ctstate NEW -m recent --set --name SSH
-A INPUT -p tcp --dport 226 -m conntrack --ctstate NEW -m recent --update --seconds 60 --hitcount 4 --name SSH -j DROP
-A INPUT -p tcp --dport 226 -j ACCEPT

# NetBird/WireGuard (falls benötigt)
-A INPUT -p udp --dport 51820 -j ACCEPT

# ══════════════════════════════════════════════════════════════
# LOGGING (Optional - für Debugging)
# ══════════════════════════════════════════════════════════════

# Gedropte Pakete loggen (auskommentieren für Produktion)
# -A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables-dropped: " --log-level 4

# ══════════════════════════════════════════════════════════════
# STANDARD-POLICY: ALLES ANDERE DROPPEN (NICHT REJECTEN!)
# ══════════════════════════════════════════════════════════════

-A INPUT -j DROP

COMMIT

*raw
:PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]

# Schutz vor Port-Scans bereits vor Connection-Tracking
-A PREROUTING -p tcp --tcp-flags ALL NONE -j DROP
-A PREROUTING -p tcp --tcp-flags ALL ALL -j DROP
-A PREROUTING -p tcp --tcp-flags ALL FIN,URG,PSH -j DROP
-A PREROUTING -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP
-A PREROUTING -p tcp --tcp-flags SYN,RST SYN,RST -j DROP
-A PREROUTING -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
-A PREROUTING -m conntrack --ctstate INVALID -j DROP

COMMIT
# Regeln anwenden
sudo iptables-restore < /etc/iptables/rules.v4

# Persistent machen
sudo apt install iptables-persistent -y
sudo netfilter-persistent save

Methode 3: nftables (Modern)

Der moderne Nachfolger von iptables, in neueren Distributionen Standard.

sudo nano /etc/nftables.conf
#!/usr/sbin/nft -f

flush ruleset

table inet filter {
    # Rate-Limit für SSH
    set ssh_meter {
        type ipv4_addr
        flags dynamic
        timeout 1m
    }

    chain input {
        type filter hook input priority 0; policy drop;

        # Loopback
        iif "lo" accept

        # Established
        ct state established,related accept
        ct state invalid drop

        # Anti-Scan
        tcp flags & (fin|syn|rst|psh|ack|urg) == 0 drop
        tcp flags & (fin|syn|rst|psh|ack|urg) == fin|syn|rst|psh|ack|urg drop
        tcp flags & (fin|syn) == fin|syn drop
        tcp flags & (syn|rst) == syn|rst drop

        # ICMP droppen (Stealth)
        ip protocol icmp drop
        ip6 nexthdr icmpv6 drop

        # HTTP/HTTPS
        tcp dport { 80, 443 } accept
        udp dport 443 accept

        # SSH mit Rate-Limit
        tcp dport 226 ct state new add @ssh_meter { ip saddr limit rate 3/minute burst 5 packets } accept
        tcp dport 226 ct state new drop

        # Alles andere: DROP
    }

    chain forward {
        type filter hook forward priority 0; policy drop;
    }

    chain output {
        type filter hook output priority 0; policy accept;
    }
}
# Anwenden
sudo nft -f /etc/nftables.conf

# Aktivieren
sudo systemctl enable nftables
sudo systemctl start nftables

Teil 3: SSH-Schutz – Mehrere Methoden

Grundhärtung (Immer anwenden)

sudo nano /etc/ssh/sshd_config.d/99-hardening.conf
# Port ändern
Port 226                                # ← Anpassen

# Nur bestimmte User
AllowUsers luna                         # ← Anpassen

# Kein Root-Login
PermitRootLogin no

# Nur Key-Authentifizierung
PasswordAuthentication no
PubkeyAuthentication yes
AuthenticationMethods publickey

# Brute-Force erschweren
MaxAuthTries 3
LoginGraceTime 20
MaxSessions 3
MaxStartups 3:50:10

# Timeouts
ClientAliveInterval 300
ClientAliveCountMax 2

# Keine unnötigen Features
X11Forwarding no
AllowTcpForwarding no
AllowAgentForwarding no
PermitTunnel no
PermitUserEnvironment no

# Sichere Algorithmen
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com

# Banner entfernen (keine Versionsinformationen)
Banner none
DebianBanner no
sudo systemctl restart sshd

Methode 1: Fail2ban (Basis)

Blockiert IPs nach fehlgeschlagenen Login-Versuchen.

sudo apt install fail2ban -y
sudo nano /etc/fail2ban/jail.local
[DEFAULT]
bantime = 86400
findtime = 600
maxretry = 3
ignoreip = 127.0.0.1/8 ::1

[sshd]
enabled = true
port = 226                              # ← SSH-Port anpassen
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 604800
findtime = 3600
sudo systemctl enable fail2ban
sudo systemctl restart fail2ban

# Status prüfen
sudo fail2ban-client status sshd

Methode 2: CrowdSec (Community-basiert)

Wie Fail2ban, aber mit geteilten Blocklisten aus der Community.

# Installation
curl -s https://install.crowdsec.net | sudo sh

# SSH-Kollektion installieren
sudo cscli collections install crowdsecurity/sshd

# Firewall-Bouncer
sudo apt install crowdsec-firewall-bouncer-iptables -y

# Status
sudo cscli metrics
sudo cscli decisions list

Methode 3: Geo-Blocking

SSH nur aus bestimmten Ländern erlauben.

Mit iptables + xtables-addons

# Installation
sudo apt install xtables-addons-common libtext-csv-xs-perl -y

# GeoIP-Datenbank herunterladen
sudo mkdir -p /usr/share/xt_geoip
cd /tmp
/usr/lib/xtables-addons/xt_geoip_dl
/usr/lib/xtables-addons/xt_geoip_build -D /usr/share/xt_geoip *.csv
# SSH nur aus Deutschland und Österreich erlauben
sudo iptables -I INPUT -p tcp --dport 226 -m geoip ! --src-cc DE,AT -j DROP

Mit CrowdSec

# GeoIP-Bouncer installieren
sudo cscli scenarios install crowdsecurity/ssh-bf-geoip

# Konfiguration
sudo nano /etc/crowdsec/scenarios/ssh-bf-geoip.yaml

Methode 4: Port Knocking

SSH-Port ist komplett geschlossen, öffnet sich nur nach "Klopfsequenz".

sudo apt install knockd -y
sudo nano /etc/knockd.conf
[options]
    UseSyslog
    Interface = eth0                    # ← Netzwerk-Interface anpassen

[openSSH]
    sequence      = 7000,8000,9000      # ← Geheime Sequenz wählen
    seq_timeout   = 5
    tcpflags      = syn
    start_command = /sbin/iptables -I INPUT -s %IP% -p tcp --dport 226 -j ACCEPT
    cmd_timeout   = 30
    stop_command  = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 226 -j ACCEPT

[closeSSH]
    sequence      = 9000,8000,7000      # ← Umgekehrte Sequenz
    seq_timeout   = 5
    tcpflags      = syn
    command       = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 226 -j ACCEPT
# SSH-Port aus Firewall entfernen (knockd verwaltet das)
sudo iptables -D INPUT -p tcp --dport 226 -j ACCEPT

# knockd aktivieren
sudo nano /etc/default/knockd
# START_KNOCKD=1 setzen
# KNOCKD_OPTS="-i eth0"

sudo systemctl enable knockd
sudo systemctl start knockd

Client-Verbindung

# knock installieren (Client)
sudo apt install knockd -y

# Verbinden
knock SERVER-IP 7000 8000 9000 && ssh luna@SERVER-IP -p 226

# Nach Session schließen (optional)
knock SERVER-IP 9000 8000 7000

Knock-Script für einfache Nutzung

#!/bin/bash
# ~/bin/ssh-knock.sh

SERVER="dein-server.de"
SSH_PORT="226"
KNOCK_SEQ="7000 8000 9000"
USER="luna"

echo "Knocking..."
knock $SERVER $KNOCK_SEQ
sleep 1
echo "Connecting..."
ssh -p $SSH_PORT $USER@$SERVER

Methode 5: SSH nur via VPN (Empfohlen)

SSH ist nur über das VPN-Netzwerk erreichbar – nicht aus dem Internet.

Mit NetBird

# iptables: SSH nur von NetBird-Interface
sudo iptables -A INPUT -i wt0 -p tcp --dport 226 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 226 -j DROP

Oder in der Haupt-Firewall-Konfiguration:

# In /etc/iptables/rules.v4:
# Statt:
-A INPUT -p tcp --dport 226 -j ACCEPT

# Ersetzen durch:
-A INPUT -i wt0 -p tcp --dport 226 -j ACCEPT
# Kein weiterer SSH-Eintrag = SSH aus Internet blockiert

Mit WireGuard

# SSH nur über WireGuard-Subnetz erlauben
sudo iptables -A INPUT -s 10.0.0.0/24 -p tcp --dport 226 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 226 -j DROP

Mit Tailscale

# SSH nur über Tailscale-Interface
sudo iptables -A INPUT -i tailscale0 -p tcp --dport 226 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 226 -j DROP

Methode 6: 2FA (TOTP)

Zusätzlich zum SSH-Key wird ein TOTP-Code benötigt.

sudo apt install libpam-google-authenticator -y

# Als User einrichten
google-authenticator
# Alle Fragen mit 'y' beantworten
# QR-Code mit Authenticator-App scannen
sudo nano /etc/pam.d/sshd
# Am Anfang hinzufügen:
auth required pam_google_authenticator.so
sudo nano /etc/ssh/sshd_config.d/99-hardening.conf
# Hinzufügen/Ändern:
ChallengeResponseAuthentication yes
AuthenticationMethods publickey,keyboard-interactive
sudo systemctl restart sshd

Methode 7: SSHGuard (Alternative zu Fail2ban)

Leichtgewichtiger als Fail2ban, unterstützt mehrere Backends.

sudo apt install sshguard -y

# Konfiguration
sudo nano /etc/sshguard/sshguard.conf
# Blockier-Einstellungen
THRESHOLD=30
BLOCK_TIME=120
DETECTION_TIME=1800

# Backend (nftables oder iptables)
BACKEND="/usr/libexec/sshguard/sshg-fw-nft-sets"
sudo systemctl enable sshguard
sudo systemctl start sshguard

Empfohlene Kombinationen

Sicherheitslevel Kombination
Basis Grundhärtung + Fail2ban + nicht-standard Port
Mittel Basis + Geo-Blocking + 2FA
Hoch Basis + Port Knocking + 2FA
Maximal SSH nur via VPN + 2FA (kein Internet-Zugang)

Teil 4: Anti-Scan-Techniken

Scan-Erkennung und -Blockierung

Methode 1: PSAD (Port Scan Attack Detector)

sudo apt install psad -y

# Konfiguration
sudo nano /etc/psad/psad.conf
# Wichtige Einstellungen
EMAIL_ADDRESSES     root@localhost;     # ← E-Mail für Alerts
HOSTNAME            mein-server;
HOME_NET            any;
DANGER_LEVEL1       5;
DANGER_LEVEL2       15;
DANGER_LEVEL3       25;
DANGER_LEVEL4       50;
DANGER_LEVEL5       100;

# Auto-Block bei Danger Level 3+
ENABLE_AUTO_IDS     Y;
AUTO_IDS_DANGER_LEVEL 3;
AUTO_BLOCK_TIMEOUT  3600;
# iptables-Logging aktivieren (PSAD braucht das)
sudo iptables -A INPUT -j LOG --log-prefix "iptables: "
sudo iptables -A FORWARD -j LOG --log-prefix "iptables: "

# PSAD starten
sudo systemctl enable psad
sudo systemctl start psad

# Status
sudo psad -S

Methode 2: PortSentry

sudo apt install portsentry -y

# Konfiguration
sudo nano /etc/portsentry/portsentry.conf
# Modus: atcp/audp für Stealth-Erkennung
TCP_MODE="atcp"
UDP_MODE="audp"

# Block-Methode
BLOCK_UDP="1"
BLOCK_TCP="1"

# iptables zum Blocken
KILL_ROUTE="/sbin/iptables -I INPUT -s $TARGET$ -j DROP"
# Aktivieren
sudo nano /etc/default/portsentry
# TCP_MODE="atcp"
# UDP_MODE="audp"

sudo systemctl enable portsentry
sudo systemctl restart portsentry

Methode 3: Tarpit (Honeypot)

Verlangsamt Portscanner extrem, indem Verbindungen absichtlich verzögert werden.

# Mit iptables TARPIT-Target (benötigt xtables-addons)
sudo apt install xtables-addons-common -y

# Häufig gescannte Ports in Tarpit
sudo iptables -A INPUT -p tcp --dport 23 -j TARPIT      # Telnet
sudo iptables -A INPUT -p tcp --dport 3389 -j TARPIT    # RDP
sudo iptables -A INPUT -p tcp --dport 5900 -j TARPIT    # VNC
sudo iptables -A INPUT -p tcp --dport 1433 -j TARPIT    # MSSQL
sudo iptables -A INPUT -p tcp --dport 3306 -j TARPIT    # MySQL (falls nicht benötigt)

Methode 4: Endlessh (SSH-Tarpit)

Fake-SSH-Server auf Port 22, der Angreifer stundenlang beschäftigt.

# Installation
sudo apt install endlessh -y

# Konfiguration
sudo nano /etc/endlessh/config
Port 22
Delay 10000
MaxLineLength 32
MaxClients 4096
LogLevel 1
# Port 22 für endlessh freigeben
sudo setcap 'cap_net_bind_service=+ep' /usr/bin/endlessh

# Starten
sudo systemctl enable endlessh
sudo systemctl start endlessh

# Echter SSH läuft auf Port 226 (oder via VPN)

Banner und Fingerprinting verhindern

SSH-Banner entfernen

# In /etc/ssh/sshd_config.d/99-hardening.conf:
Banner none
DebianBanner no

# Version aus Banner entfernen (kompiliert, daher nur begrenzt möglich)
# Alternative: SSH nur via VPN erreichbar machen

Webserver-Banner entfernen

# Caddy: Automatisch keine Version
# In Caddyfile:
{
    servers {
        protocols h1 h2 h3
    }
}

example.de {
    header -Server
    # ...
}
# Nginx:
# In /etc/nginx/nginx.conf:
http {
    server_tokens off;
    more_clear_headers Server;
}

OS-Fingerprinting erschweren

# TCP-Timestamps deaktivieren
sudo sysctl -w net.ipv4.tcp_timestamps=0

# In /etc/sysctl.d/99-stealth.conf:
net.ipv4.tcp_timestamps = 0
net.ipv4.icmp_echo_ignore_all = 1

Teil 5: DDoS-Schutz

Grundlagen

DDoS-Schutz auf Server-Ebene ist begrenzt – bei volumetrischen Angriffen hilft nur Upstream-Filterung (Provider, CDN). Folgende Maßnahmen helfen bei kleineren Angriffen und Application-Layer-Attacks.

Methode 1: Kernel-Tuning

sudo nano /etc/sysctl.d/99-ddos.conf
# SYN-Flood-Schutz
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 4096
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 2

# Connection-Tracking-Limits erhöhen
net.netfilter.nf_conntrack_max = 1000000
net.netfilter.nf_conntrack_tcp_timeout_established = 1800
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 30

# TIME_WAIT-Recycling
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15

# Backlog für hohe Last
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 65535

# ICMP-Limits
net.ipv4.icmp_ratelimit = 100
net.ipv4.icmp_ratemask = 88089

# Reverse Path Filtering
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

# Bogus ICMP ignorieren
net.ipv4.icmp_ignore_bogus_error_responses = 1
sudo sysctl -p /etc/sysctl.d/99-ddos.conf

Methode 2: iptables Rate-Limiting

# SYN-Flood-Schutz
sudo iptables -A INPUT -p tcp --syn -m limit --limit 10/s --limit-burst 20 -j ACCEPT
sudo iptables -A INPUT -p tcp --syn -j DROP

# Allgemeines Rate-Limit pro IP
sudo iptables -A INPUT -p tcp -m conntrack --ctstate NEW -m recent --set
sudo iptables -A INPUT -p tcp -m conntrack --ctstate NEW -m recent --update --seconds 1 --hitcount 20 -j DROP

# HTTP/HTTPS Rate-Limit
sudo iptables -A INPUT -p tcp --dport 443 -m conntrack --ctstate NEW -m limit --limit 50/s --limit-burst 100 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -m conntrack --ctstate NEW -j DROP

# Conntrack-Limit pro IP
sudo iptables -A INPUT -p tcp -m connlimit --connlimit-above 50 --connlimit-mask 32 -j DROP

Methode 3: nftables Rate-Limiting

sudo nano /etc/nftables.conf
table inet ddos_filter {
    set blacklist {
        type ipv4_addr
        flags dynamic,timeout
        timeout 1h
    }

    set rate_limit {
        type ipv4_addr
        flags dynamic
        timeout 1m
    }

    chain input {
        type filter hook input priority -100; policy accept;

        # Blacklist
        ip saddr @blacklist drop

        # SYN-Flood-Schutz
        tcp flags syn limit rate 10/second burst 20 packets accept
        tcp flags syn add @blacklist { ip saddr timeout 1h } drop

        # Allgemeines Rate-Limit
        ct state new add @rate_limit { ip saddr limit rate over 20/second burst 50 packets } add @blacklist { ip saddr timeout 1h } drop
    }
}

Methode 4: CrowdSec DDoS-Szenarios

# HTTP-DDoS-Erkennung
sudo cscli scenarios install crowdsecurity/http-crawl-non_statics
sudo cscli scenarios install crowdsecurity/http-bad-user-agent
sudo cscli scenarios install crowdsecurity/http-probing

# Aggressive Mode
sudo nano /etc/crowdsec/profiles.yaml
name: aggressive_profile
filters:
 - Alert.Remediation == true
decisions:
 - type: ban
   duration: 24h    # Längere Bans

Methode 5: Rate-Limiting im Reverse Proxy

Caddy mit Rate-Limiting

# Caddyfile
{
    order rate_limit before basicauth
}

example.de {
    rate_limit {
        zone static_zone {
            key    {remote_host}
            events 100
            window 1m
        }
    }
    
    reverse_proxy 100.64.0.1:3000
}

Hinweis: Das rate_limit-Modul muss separat installiert werden oder Caddy mit diesem Plugin gebaut werden.

Nginx Rate-Limiting

# /etc/nginx/nginx.conf
http {
    # Rate-Limit-Zonen definieren
    limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
    limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
    limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
}

# In Server-Block:
server {
    location / {
        limit_req zone=general burst=20 nodelay;
        limit_conn conn_limit 10;
        
        proxy_pass http://backend;
    }
    
    location /login {
        limit_req zone=login burst=5 nodelay;
        proxy_pass http://backend;
    }
}

Methode 6: Upstream-DDoS-Schutz

Bei größeren Angriffen hilft nur Filterung vor dem Server:

Anbieter Typ Kosten Empfohlen für
Hetzner Basis L3/L4 Inklusive Einfache Angriffe
OVH VAC (L3-L7) Inklusive Gaming, Webserver
Cloudflare CDN + DDoS Kostenlos/Pro Webseiten (US-Bedenken)
BunnyNet CDN + DDoS Pay-per-use EU-Alternative
Path.net DDoS-Schutz Ab ~20€/Monat Dedizierter Schutz

Teil 6: Dienste trotzdem erreichbar machen

Reverse Proxy als einziger Eintrittspunkt

Das Konzept: Der Server ist "unsichtbar" – nur Port 80/443 sind offen, alles andere ist DROP. Dienste werden über einen Reverse Proxy bereitgestellt.

Internet
    │
    ▼
┌─────────────────────────┐
│   Reverse Proxy (VPS)   │
│                         │
│  Port 80  ───┐          │
│  Port 443 ───┼──► Caddy │
│              │          │
│  Alle anderen Ports:    │
│  DROP (unsichtbar)      │
└────────────┬────────────┘
             │
      NetBird/WireGuard
      (verschlüsselt)
             │
             ▼
┌─────────────────────────┐
│      Homeserver         │
│                         │
│  Wiki, Vaultwarden, ... │
│  (nur via VPN erreichbar)│
└─────────────────────────┘

Multi-Domain-Setup

# Caddyfile für mehrere Dienste
{
    email admin@example.de
}

# Wiki
wiki.example.de {
    reverse_proxy 100.64.0.1:3000
    header -Server
}

# Vaultwarden
vault.example.de {
    reverse_proxy 100.64.0.1:8080
    header -Server
}

# Git
git.example.de {
    reverse_proxy 100.64.0.1:3001
    header -Server
}

# Standard: Nichts zeigen
:80, :443 {
    respond "Not Found" 404
}

Wildcard-SSL für unbekannte Subdomains

# Alle Subdomains auf einen Catch-All
*.example.de {
    tls {
        dns cloudflare {env.CF_API_TOKEN}
    }
    respond "Not Found" 404
}

# Bekannte Dienste
wiki.example.de {
    reverse_proxy 100.64.0.1:3000
}

Teil 7: Monitoring und Alerting

Log-Überwachung

# Fail2ban-Aktivität
sudo tail -f /var/log/fail2ban.log

# SSH-Versuche
sudo tail -f /var/log/auth.log | grep sshd

# Firewall-Drops (wenn Logging aktiv)
sudo tail -f /var/log/syslog | grep iptables

Monitoring-Tools

Netdata (Echtzeit-Dashboard)

# Installation
bash <(curl -Ss https://my-netdata.io/kickstart.sh)

# Nur auf localhost (Zugriff via SSH-Tunnel oder VPN)
sudo nano /etc/netdata/netdata.conf
[web]
    bind to = 127.0.0.1

Prometheus + Grafana (Fortgeschritten)

# node_exporter für System-Metriken
sudo apt install prometheus-node-exporter -y

# Nur auf VPN-Interface binden
sudo nano /etc/default/prometheus-node-exporter
# ARGS="--web.listen-address=100.64.0.2:9100"

Alerts einrichten

# Einfaches Alert-Script
sudo nano /usr/local/bin/security-alert.sh
#!/bin/bash
# Bei zu vielen Failed SSH-Logins

THRESHOLD=10
COUNT=$(grep "Failed password" /var/log/auth.log | wc -l)

if [ $COUNT -gt $THRESHOLD ]; then
    echo "Alert: $COUNT failed SSH attempts" | mail -s "Security Alert" admin@example.de
fi
chmod +x /usr/local/bin/security-alert.sh

# Cronjob
echo "*/5 * * * * root /usr/local/bin/security-alert.sh" | sudo tee /etc/cron.d/security-alert

Zusammenfassung: Sicherheitslevel

Level Maßnahmen Aufwand
Basis UFW, Fail2ban, SSH-Härtung, nicht-standard Port 30 Min
Mittel + iptables Stealth, Anti-Scan, CrowdSec, 2FA 1-2 Std
Hoch + Port Knocking, Geo-Blocking, Kernel-Hardening 2-3 Std
Maximal + SSH nur VPN, Endlessh-Tarpit, PSAD, DDoS-Tuning 3-5 Std

Schnellstart-Befehle

# Basis-Härtung in 5 Minuten:
sudo apt update && sudo apt install -y ufw fail2ban

# SSH auf neuen Port (z.B. 226)
echo "Port 226" | sudo tee /etc/ssh/sshd_config.d/port.conf
sudo systemctl restart sshd

# Firewall
sudo ufw default deny incoming
sudo ufw allow 226/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw --force enable

# Fail2ban aktivieren
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

echo "Basis-Härtung abgeschlossen!"

Letzte Aktualisierung: 2025