Caddy + CrowdSec + VPN  Mein Self-Hosting Security Setup mit Docker

Lesedauer 2 Minuten

Wer einen öffentlich erreichbaren Server betreibt, weiß: Es dauert keine Stunden, bis die ersten automatisierten Scanner anklopfen. In diesem Post zeige ich, wie ich meinen Server mit CaddyCrowdSec und einer VPN-IP absichere — alles als Docker Compose Setup — und was die Live-Daten bereits zeigen.


Die Architektur

                    ┌─────────────────┐
                    │  🌐  Besucher   │
                    └────────┬────────┘
                             │
                             ▼
                    ┌─────────────────┐
                    │  🔒  VPN-IP     │
                    └────────┬────────┘
                             │
                             ▼
                    ┌─────────────────────────────────┐
                    │      🛡️  CrowdSec Bouncer        │
                    │                                 │
                    │  • Credential Scan / Brute Force│
                    │  • Bad User Agents              │
                    │  • Bekannte Bad IPs (Community) │
                    │  • Path Scanning (/wp-admin…)   │
                    └────────┬──────────┬─────────────┘
                             │          │
                      ✅ OK  │          │  🚫 Bot / Bad UA
                             │          │
                             ▼          ▼
                    ┌──────────────┐  ┌──────────────┐
                    │    Caddy     │  │403 Forbidden │
                    │  Rev. Proxy  │  └──────────────┘
                    └──────┬───────┘
                           │
                           ▼
                    ┌─────────────────┐
                    │  🔧  Service    │
                    │    Backend      │
                    └─────────────────┘

Das Docker Compose Setup

Alles läuft in Containern. Caddy bringt den CrowdSec Bouncer direkt als Plugin mit — kein separater Prozess, kein Sidecar. CrowdSec selbst läuft als eigener Container und liest die Caddy-Logs über ein gemeinsames Volume.

services:
  caddy:
    image: caddy:crowdsec          # custom build mit bouncer plugin
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
      - caddy_logs:/var/log/caddy  # logs werden von crowdsec gelesen
    depends_on:
      - crowdsec

  crowdsec:
    image: crowdsecurity/crowdsec:latest
    restart: unless-stopped
    environment:
      COLLECTIONS: >
        crowdsecurity/caddy
        crowdsecurity/http-cve
        crowdsecurity/wordpress
    volumes:
      - ./crowdsec/config:/etc/crowdsec
      - ./crowdsec/data:/var/lib/crowdsec/data
      - caddy_logs:/var/log/caddy:ro   # read-only zugriff auf caddy logs

volumes:
  caddy_data:
  caddy_logs:

Der entscheidende Punkt: Caddy schreibt Logs in ein Volume, CrowdSec liest genau dieses Volume. Der Bouncer im Caddy-Container fragt CrowdSec per lokaler API bei jedem Request an.


Wie ein Block konkret aussieht

Ein reales Beispiel aus den Logs, IP anonymisiert:

Ein Scanner aus einem Hyperscaler Netz startet morgens um 08:28 Uhr und feuert in weniger als 3 Minuten mehrere Angriffsmuster ab:

08:28:21  local/http-php-scan          → Suche nach PHP-Shells und Backdoors
08:28:55  crowdsecurity/http-probing   → Allgemeines Path-Scanning
08:29:03  crowdsecurity/http-wordpress-scan → /wp-login, /xmlrpc.php etc.
08:29:04  → BAN ausgelöst, 30 Tage gesperrt

Ab diesem Zeitpunkt antwortet Caddy auf jeden weiteren Request dieser IP sofort mit:

HTTP/1.1 403 Forbidden

Kein Log-Eintrag im Backend, kein Traffic zum Service — der Bouncer blockt direkt im Caddy-Layer, bevor die Anfrage auch nur geroutet wird.


Was nach kurzer Laufzeit bereits geblockt wurde

Aktive Bans: 27 IPs (+ 73 weitere Duplikate in der Datenbank)

Die häufigsten Angriffsmuster:

RegelWas wird erkannt
http-generic-bfBrute Force auf Login-Endpunkte
http-probingAllgemeines Abscannen von Pfaden
http-sensitive-filesZugriff auf .env, Backups, Configs
http-wordpress-scanWordPress-spezifische Scanner
http-php-scanPHP-Shell und Backdoor-Suche
http-git-probeVersuch .git/ auszulesen
jira_cve-2021-26086Gezielter CVE-Exploit-Versuch
http-path-traversal-probingDirectory Traversal
http-admin-probeSuche nach Admin-Panels
http-backup-probeSuche nach Backup-Dateien

Auffällig: Der Großteil der angreifenden IPs kommen aus den Hyperscaler — also gemietete Cloud-VMs, die als Scanner-Plattform missbraucht werden. Herkunftsländer: gemischt — quer durch alle Zeitzonen, rund um die Uhr.


Fazit

Das Setup ist ressourcenschonend, braucht keine manuelle Pflege von Firewall-Regeln und funktioniert out-of-the-box. Docker Compose macht es auf jedem VPS reproduzierbar deploybar.

Was mich am meisten überzeugt: Die Kombination aus VPN-IP und CrowdSec bedeutet, dass der echte Server nie direkt exponiert ist — und selbst wenn ein Scanner die VPN-IP trifft, fliegt er nach wenigen Requests automatisch raus.

0 Comments

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert