Baseline-Regeln für Webserver, die den Neustart überleben
Eine korrekt konfigurierte Firewall ist die erste Verteidigungslinie jedes Servers im Internet. Dieser Artikel zeigt praxisnah, wie iptables als Kernel Paketfilter tatsächlich funktioniert, wie ufw als einfaches Frontend darauf aufsetzt, welche Baseline Regeln ein produktiver Webserver für SSH, HTTP und HTTPS wirklich braucht und wie man zuverlässig verifiziert, dass diese Regeln aktiv bleiben und jeden Neustart unbeschadet überleben.
Inhaltsverzeichnis
- 1. Warum eine Firewall auf jedem Server Pflicht ist
- 2. iptables als Kernel Firewall: Tables, Chains und Regeln
- 3. ufw als einfaches Frontend für iptables
- 4. Die Baseline-Regel für Webserver: SSH, HTTP, HTTPS
- 5. Erweiterte ufw-Regeln: Rate Limiting, Whitelisting, Logging
- 6. Wenn ufw nicht reicht: iptables direkt einsetzen
- 7. Persistenz sicherstellen: Regeln überleben den Reboot
- 8. Verifizierung: Sind die Regeln wirklich aktiv?
- 9. ufw und iptables im direkten Vergleich
- 10. Zusammenfassung
- 11. FAQ
1. Warum eine Firewall auf jedem Server Pflicht ist
Jeder Linux-Server, der mit einer öffentlichen IP-Adresse im Internet hängt, wird innerhalb weniger Minuten nach dem ersten Boot von automatisierten Portscans erfasst. Standardinstallationen bringen oft mehr offene Dienste mit als tatsächlich gebraucht werden: SSH auf Port 22, manchmal ein Datenbankport, gelegentlich ein Testdienst, der nie wieder abgeschaltet wurde. Jeder offene Port ohne bewusste Freigabe ist eine potenzielle Angriffsfläche, unabhängig davon, ob die dahinterliegende Anwendung fehlerfrei ist. Eine Firewall ist deshalb keine optionale Härtungsmaßnahme für später, sondern der erste Schritt nach der Betriebssystem-Installation, noch vor dem Deployment der eigentlichen Anwendung.
Unter Linux übernimmt der Kernel selbst die Paketfilterung über das Netfilter-Framework, gesteuert durch das Kommandozeilenwerkzeug iptables. ufw (Uncomplicated Firewall) setzt als Frontend darüber und übersetzt einfache Befehle wie ufw allow 80/tcp im Hintergrund in die entsprechenden iptables-Regeln. Für den Alltag auf einem Webserver reicht ufw fast immer aus, während iptables direkt für komplexere Szenarien wie Portweiterleitung oder feingranulare Regelketten notwendig bleibt. Dieser Artikel zeigt beide Ebenen und eine praxiserprobte Baseline-Konfiguration.
2. iptables als Kernel Firewall: Tables, Chains und Regeln
iptables konfiguriert das Netfilter-Subsystem des Linux-Kernels über sogenannte Tables und Chains. Die wichtigste Table für eine Firewall ist filter, sie enthält die drei Standard-Chains INPUT für eingehende Pakete an den lokalen Host, OUTPUT für ausgehende Pakete und FORWARD für Pakete, die durch den Host geroutet werden, etwa bei einem Gateway. Jede Chain hat eine Default-Policy, meist ACCEPT oder DROP, die greift, wenn keine Regel in der Chain zutrifft. Regeln werden von oben nach unten abgearbeitet, die erste passende Regel entscheidet über das Schicksal des Pakets, alle folgenden Regeln werden für dieses Paket nicht mehr geprüft.
Jede Regel besteht aus Match-Kriterien wie Protokoll, Quell- und Ziel-IP, Port und Verbindungszustand, sowie einem Target wie ACCEPT, DROP oder REJECT. Der Unterschied zwischen DROP und REJECT ist wichtig: DROP verwirft das Paket stillschweigend, der Absender erhält keine Antwort und wartet auf einen Timeout, REJECT sendet aktiv eine Ablehnung zurück. Für die Außengrenze eines Servers ist DROP meist die bessere Wahl, weil es Portscans verlangsamt und keine Information über die Existenz eines Dienstes preisgibt.
#!/usr/bin/env bash
# Inspect the current netfilter state before making any changes
iptables -L -n -v --line-numbers
# List only the filter table's INPUT chain with packet counters
iptables -L INPUT -n -v
# Show the currently active default policies per chain
iptables -S | grep '^-P'
# Count total rules across all filter-table chains
iptables -L -n | grep -c 'ACCEPT\|DROP\|REJECT'
3. ufw als einfaches Frontend für iptables
ufw ist seit Ubuntu 8.04 Teil der Standardinstallation und mittlerweile auch auf Debian-basierten Distributionen verfügbar. Es ist kein eigenständiger Paketfilter, sondern lediglich eine Verwaltungsschicht über iptables beziehungsweise nftables auf neueren Systemen, die komplexe Regelsyntax in lesbare Befehle übersetzt. Die Installation erfolgt über apt install ufw, auf vielen Ubuntu-Systemen ist das Paket bereits vorinstalliert, aber standardmäßig deaktiviert. Der Grundzustand nach der Installation lässt alle Verbindungen zu, ufw muss also erst konfiguriert und aktiv geschaltet werden, bevor es tatsächlich schützt.
Die Grundsyntax orientiert sich an natürlicher Sprache: ufw allow 22/tcp öffnet einen Port, ufw deny 23/tcp blockiert ihn, ufw status verbose zeigt den aktuellen Zustand inklusive aller aktiven Regeln in ihrer Anwendungsreihenfolge. Statt Portnummern lassen sich auch registrierte Anwendungsprofile verwenden, etwa ufw allow OpenSSH oder ufw allow Nginx Full, die unter /etc/ufw/applications.d/ definiert sind. Dieser Abstraktionsgrad reicht für die überwiegende Mehrheit produktiver Webserver aus und reduziert die Fehlerquote gegenüber manuell geschriebenen iptables-Regeln erheblich.
4. Die Baseline-Regel für Webserver: SSH, HTTP, HTTPS
Die Baseline-Konfiguration für einen typischen Webserver folgt einem einfachen Prinzip: eingehenden Traffic standardmäßig ablehnen, ausgehende Verbindungen erlauben, und dann gezielt die drei Ports öffnen, die tatsächlich gebraucht werden: 22 für die SSH-Administration, 80 für HTTP und 443 für HTTPS. Die Reihenfolge der Befehle ist entscheidend. Die SSH-Regel muss gesetzt sein, bevor ufw aktiviert wird, sonst sperrt man sich selbst aus der laufenden SSH-Sitzung aus, sobald die Default-Policy für eingehenden Traffic auf deny wechselt. Ein zweites Terminalfenster mit einer offenen Verbindung als Rückfallebene ist bei der ersten Konfiguration immer empfehlenswert.
Nach dem Setzen der drei Regeln zeigt ufw status numbered eine nummerierte Liste aller aktiven Regeln, über die einzelne Einträge später gezielt mit ufw delete <Nummer> entfernt werden können. Diese Baseline deckt den Standardfall eines reinen Webservers ab, jeder zusätzliche Dienst wie ein Datenbankport für Replikation oder ein Monitoring-Agent muss bewusst und möglichst mit eingeschränkter Quell-IP freigegeben werden, statt pauschal für alle Adressen geöffnet zu werden.
#!/usr/bin/env bash
set -euo pipefail
# Reset to a known clean state before building the baseline
ufw --force reset
# Deny everything incoming by default, allow everything outgoing
ufw default deny incoming
ufw default allow outgoing
# Allow SSH first, otherwise the next command locks out the current session
ufw allow OpenSSH
ufw allow 80/tcp comment 'HTTP for ACME challenge and redirects'
ufw allow 443/tcp comment 'HTTPS production traffic'
# Enable last, only after SSH access is confirmed reachable
ufw --force enable
ufw status numbered
5. Erweiterte ufw-Regeln: Rate Limiting, Whitelisting, Logging
Über die Baseline hinaus bietet ufw drei Mechanismen, die im Produktivbetrieb regelmäßig gebraucht werden. Rate Limiting mit ufw limit ssh blockiert eine IP-Adresse automatisch für eine gewisse Zeit, wenn von dort innerhalb von 30 Sekunden mehr als sechs Verbindungsversuche eingehen, ein einfacher, aber wirksamer Schutz gegen SSH-Brute-Force-Angriffe, ganz ohne fail2ban. IP-Whitelisting mit ufw allow from 203.0.113.10 to any port 22 proto tcp beschränkt einen sensiblen Port auf eine bekannte Quelladresse, etwa das Büronetzwerk oder einen Bastion-Host, statt ihn für das gesamte Internet offen zu lassen.
Logging lässt sich über ufw logging low, medium, high oder full granular steuern, wobei high und full spürbar mehr Systemlast und Log-Volumen erzeugen und in der Praxis meist nur zur kurzfristigen Fehlersuche sinnvoll sind. Die zentrale Konfigurationsdatei /etc/default/ufw steuert grundlegende Optionen wie IPv6-Unterstützung und Standard-Loglevel dauerhaft, während die einzelnen Regeln weiterhin über die ufw-Kommandozeile verwaltet werden. Änderungen an dieser Datei erfordern einen Neustart von ufw mit systemctl restart ufw, damit sie wirksam werden.
# /etc/default/ufw - core ufw configuration
# Apply changes with: systemctl restart ufw
# Enable IPv6 filtering alongside IPv4
IPV6=yes
# Default policies, individual "ufw allow/deny" rules override these
DEFAULT_INPUT_POLICY="DROP"
DEFAULT_OUTPUT_POLICY="ACCEPT"
DEFAULT_FORWARD_POLICY="DROP"
# Logging level: off, low, medium, high, full
LOGLEVEL=low
# Kernel modules loaded for connection tracking
IPT_MODULES="nf_conntrack_ftp nf_nat_ftp"
6. Wenn ufw nicht reicht: iptables direkt einsetzen
ufw deckt die überwiegende Mehrheit der Anwendungsfälle ab, stößt aber an Grenzen, sobald komplexere Anforderungen ins Spiel kommen: Portweiterleitung über die nat-Table, benutzerdefinierte Chains für strukturierte Regelwerke, Connection-Limiting pro Quell-IP über das connlimit-Modul, oder die Koexistenz mit Docker, das eigene iptables-Regeln in einer separaten Chain namens DOCKER-USER verwaltet und dabei ufw-Regeln unter Umständen umgeht. In solchen Fällen führt kein Weg an direkten iptables-Aufrufen vorbei, entweder manuell über die Kommandozeile oder deklarativ über ein Konfigurationsmanagement-Tool wie Ansible.
Der Vorteil von Ansible gegenüber manuell getippten iptables-Befehlen liegt in der Reproduzierbarkeit über mehrere Server hinweg und in der Versionskontrolle des Regelwerks in Git. Das Modul ansible.builtin.iptables bildet die wichtigsten iptables-Optionen als deklarative Tasks ab, läuft idempotent und lässt sich problemlos in bestehende Provisioning-Pipelines integrieren, ohne dass am Ende jemand manuell prüfen muss, welche Regel auf welchem Server tatsächlich gesetzt wurde.
---
# playbook: harden-firewall.yml
# Apply the same baseline iptables ruleset across all web servers
- name: Configure baseline firewall with iptables
hosts: webservers
become: true
tasks:
- name: Allow established and related connections
ansible.builtin.iptables:
chain: INPUT
ctstate: ESTABLISHED,RELATED
jump: ACCEPT
- name: Allow loopback traffic
ansible.builtin.iptables:
chain: INPUT
in_interface: lo
jump: ACCEPT
- name: Allow SSH from the management network only
ansible.builtin.iptables:
chain: INPUT
protocol: tcp
destination_port: "22"
source: 10.0.5.0/24
jump: ACCEPT
- name: Allow HTTP and HTTPS from anywhere
ansible.builtin.iptables:
chain: INPUT
protocol: tcp
destination_port: "{{ item }}"
jump: ACCEPT
loop:
- "80"
- "443"
- name: Drop everything else on INPUT
ansible.builtin.iptables:
chain: INPUT
jump: DROP
7. Persistenz sicherstellen: Regeln überleben den Reboot
iptables-Regeln, die per Hand über die Kommandozeile gesetzt werden, leben nur im Kernel-Speicher und verschwinden beim nächsten Neustart spurlos, ein häufig übersehener Stolperstein, der dazu führt, dass ein Server nach einem geplanten Reboot plötzlich wieder komplett offen dasteht. Das Paket iptables-persistent, unter Debian und Ubuntu über apt install iptables-persistent installierbar, löst dieses Problem, indem es den aktuellen Regelsatz mit netfilter-persistent save in die Dateien /etc/iptables/rules.v4 und rules.v6 schreibt und beim Systemstart automatisch wieder einliest.
ufw löst dasselbe Problem auf einer höheren Ebene: Der Befehl ufw enable aktiviert nicht nur die aktuelle Session, sondern richtet gleichzeitig einen systemd-Dienst ein, der beim Boot automatisch startet und die in /etc/ufw/ gespeicherten Regeln lädt. Ein Blick mit systemctl is-enabled ufw sollte enabled zurückgeben, sonst überlebt die Konfiguration den nächsten Wartungs-Reboot nicht. Wer beide Werkzeuge parallel nutzt, sollte konsequent eines davon als Quelle der Wahrheit definieren, da parallele, unkoordinierte Änderungen an beiden Ebenen schnell zu widersprüchlichen und schwer nachvollziehbaren Regelwerken führen.
8. Verifizierung: Sind die Regeln wirklich aktiv?
Eine gesetzte Regel ist nicht automatisch eine wirksame Regel, deshalb gehört die Verifizierung fest zum Konfigurationsprozess. ufw status verbose zeigt zwar die eigene Sicht auf die aktiven Regeln, spiegelt aber nicht zwangsläufig den tatsächlichen Kernel-Zustand wider, wenn parallel auch direkt mit iptables gearbeitet wurde. Der zuverlässigere Blick erfolgt über iptables -L -n -v, das die tatsächlich im Kernel aktiven Chains mit Regeln und Paketzählern zeigt, unabhängig davon, über welches Werkzeug sie gesetzt wurden. Ein Paketzähler von 0 bei einer DROP-Regel nach einigen Minuten Betrieb ist normal, ein stetig wachsender Zähler zeigt aktiv abgewehrten Traffic.
Der externe Blick ist mindestens genauso wichtig wie der lokale: Ein Portscan von einem zweiten Server aus, etwa mit nmap -p 22,80,443,3306 <server-ip>, zeigt, welche Ports von außen tatsächlich erreichbar sind, unabhängig von der lokalen Konfiguration. Nur so lässt sich ausschließen, dass eine vorgelagerte Cloud-Firewall wie eine AWS Security Group oder ein Hetzner Cloud Firewall-Regelwerk die lokale ufw-Konfiguration überlagert oder ihr widerspricht. Für automatisiertes Monitoring lohnt sich ein regelmäßiger Cronjob, der den Firewall-Status strukturiert protokolliert und bei Abweichungen vom Soll-Zustand alarmiert.
{
"hostname": "web-prod-01",
"checked_at": "2026-07-12T06:00:00Z",
"ufw_active": true,
"default_incoming_policy": "deny",
"open_ports": [
{ "port": 22, "protocol": "tcp", "source": "10.0.5.0/24", "rule": "allow" },
{ "port": 80, "protocol": "tcp", "source": "any", "rule": "allow" },
{ "port": 443, "protocol": "tcp", "source": "any", "rule": "allow" }
],
"unexpected_listeners": [],
"external_scan_matches_local_rules": true
}
9. ufw und iptables im direkten Vergleich
Die Wahl zwischen ufw und direkten iptables-Aufrufen ist keine Frage von richtig oder falsch, sondern hängt von der Komplexität der Anforderung ab. Für den überwiegenden Teil der alltäglichen Firewall-Aufgaben auf einem Webserver liefert ufw kürzere, weniger fehleranfällige Befehle, für komplexe Netzwerkszenarien bleibt iptables die einzige Option mit voller Kontrolle über das Netfilter-Framework.
| Aufgabe | Unsicher / Umständlich | Empfohlenes Pattern | Vorteil |
|---|---|---|---|
| Neue Regel setzen | iptables -A INPUT -p tcp --dport 80 -j ACCEPT |
ufw allow 80/tcp |
Kürzer, weniger fehleranfällig |
| Regeln nach Reboot behalten | Regeln gehen ohne Zusatzpaket verloren | ufw enable oder netfilter-persistent save |
Überlebt automatisch jeden Neustart |
| SSH gegen Brute-Force schützen | Kein eingebauter Schutz, externes fail2ban nötig | ufw limit ssh |
Automatische temporäre Sperre bei zu vielen Versuchen |
| Zugriff auf bekannte IP beschränken | Lange iptables-Syntax mit mehreren Optionen | ufw allow from <IP> to any port 22 |
Lesbar, schnell geprüft |
| NAT / Portweiterleitung | ufw stößt an funktionale Grenzen | iptables -t nat -A PREROUTING ... |
Volle Kontrolle über Netfilter-Tables |
In der Praxis hat sich ein hybrider Ansatz bewährt: ufw für die tägliche Verwaltung einfacher Regeln, direkte iptables-Eingriffe oder Ansible-Playbooks für alles, was über einfache Port-Freigaben hinausgeht, etwa NAT oder Docker-Integration. Wichtig ist, dass beide Ebenen konsistent bleiben und niemand parallel widersprüchliche Regeln setzt, ohne die jeweils andere Seite zu kennen.
Mironsoft
Server-Hardening, Firewall-Audits und Deployment-Infrastruktur für Magento und Hyvä
Firewall-Konfiguration, die im Ernstfall wirklich hält?
Wir prüfen bestehende ufw- und iptables-Konfigurationen, schließen unnötig offene Ports und richten eine reproduzierbare, persistente Baseline für euren Server- und Deployment-Stack ein.
Firewall-Audit
Abgleich von ufw-Status, iptables-Regeln und externem Portscan
Baseline-Hardening
SSH-Absicherung, Rate Limiting und minimale Angriffsfläche für Webserver
Persistenz & Automatisierung
Ansible-Playbooks für reproduzierbare Regeln über den gesamten Serverpark
10. Zusammenfassung
Die Firewall-Konfiguration mit ufw und iptables löst ein Kernproblem jedes internetfähigen Servers: unnötig offene Ports sind eine vermeidbare Angriffsfläche. iptables steuert als Kernel-Mechanismus die tatsächliche Paketfilterung über Tables und Chains, ufw übersetzt die häufigsten Anwendungsfälle in lesbare Befehle wie ufw allow OpenSSH. Die Baseline aus SSH, HTTP und HTTPS mit einer Default-Deny-Policy für eingehenden Traffic deckt den Standardfall eines Webservers vollständig ab, solange die SSH-Regel vor dem Enable gesetzt wird.
Der entscheidende Unterschied zwischen einer scheinbar sicheren und einer tatsächlich sicheren Konfiguration liegt in der Verifizierung: iptables -L -n -v für den lokalen Kernel-Zustand, ein externer Portscan für die Außensicht, und ein persistenter Systemd-Dienst oder netfilter-persistent für die Sicherheit, dass die Regeln auch den nächsten Reboot überleben. Wer diese drei Schritte konsequent kombiniert, betreibt eine Firewall, die nicht nur einmalig gesetzt, sondern dauerhaft wirksam ist.
Firewall-Konfiguration mit ufw und iptables: Das Wichtigste auf einen Blick
Grundprinzip
iptables filtert im Kernel über Tables und Chains. ufw ist ein Frontend, das komplexe Syntax in lesbare Befehle übersetzt.
Baseline für Webserver
ufw default deny incoming, dann SSH, 80/tcp und 443/tcp erlauben, SSH-Regel immer vor ufw enable setzen.
Persistenz
ufw enable richtet einen systemd-Dienst ein. Reines iptables braucht iptables-persistent mit netfilter-persistent save.
Verifizierung
iptables -L -n -v für den Kernel-Zustand, externer Scan mit nmap für die tatsächliche Erreichbarkeit von außen.