footer-logofooter-logo
Verstandige standaard firewallregels voor een Linux-serverTerug

Verstandige standaard firewallregels voor een Linux-server

Een verse Linux-server wordt geleverd zonder enige firewallregel. Elke listener die je start, is meteen vanaf het hele internet bereikbaar. De oplossing is een korte, goed doordachte basisconfiguratie: default-deny voor inkomend verkeer, established traffic toestaan, en een expliciete allow-list voor de services die je daadwerkelijk draait. Deze gids bouwt die basisconfiguratie regel voor regel op in nftables, legt uit waar iedereen de fout ingaat (ICMP en IPv6), laat hetzelfde beleid zien in ufw en firewalld, en behandelt hoe je voorkomt dat je jezelf buitensluit, plus de valkuil van Docker-poortpublicatie.

08 juli 2026

door Jesse Schokker

Firewall

nftables

Security

Linux

Loading...

Eerst het antwoord: de filosofie van drie regels

Elke goede serverfirewall is gebouwd op dezelfde drie beslissingen; zodra je die hebt geïnternaliseerd, is de rest detail:

  1. Default-deny inbound. Het beleid voor inkomend verkeer is drop. Alles wat niet expliciet is toegestaan, bereikt nooit een service, ook niet de service waarvan je vergeten was dat die draaide.
  2. Sta established en related verkeer toe. Antwoorden op verbindingen die je server zelf initieerde, en de retourhelft van verbindingen die je hebt geaccepteerd, stromen ongehinderd door. Deze ene stateful regel is wat default-deny praktisch bruikbaar maakt.
  3. Zet je services expliciet op de allow-list. SSH, je webpoorten, en verder niets, totdat iets anders daadwerkelijk bereikbaar moet zijn.

Uitgaand verkeer blijft op de meeste servers default-allow; outbound filtering heeft wel degelijk nut, maar het is een opt-in hardeningsstap, geen onderdeel van een verstandige standaardconfiguratie (meer daarover verderop).

Dat is belangrijk, want een verse installatie geeft je hier niets van. Debian en Ubuntu leveren met geen enkele actieve firewallregel; elke daemon die aan 0.0.0.0 bindt, ligt vanaf het moment dat hij start open voor het internet, en honeypot-onderzoek toont aan dat de eerste probes binnen enkele minuten na het live gaan van een IP-adres binnenkomen. Een baseline-firewall is tien minuten werk. Hier is hij.

De baseline ruleset, in nftables

nftables is het native firewalkader op elke huidige grote distributie (het iptables-commando op een modern systeem is in werkelijkheid een compatibiliteitslaag boven op nftables), en één inet-tabel dekt IPv4 en IPv6 tegelijk, wat de meest voorkomende firewallfout meteen ondervangt. Sla dit op als /etc/nftables.conf:

#!/usr/sbin/nft -f
flush ruleset

table inet filter {
  chain input {
    type filter hook input priority filter; policy drop;

    # 1. Loopback is always fine
    iif "lo" accept

    # 2. The stateful core: replies and related traffic
    ct state established,related accept
    ct state invalid drop

    # 3. ICMP — the minimum the internet needs to work
    icmp type { echo-request, destination-unreachable, time-exceeded, parameter-problem } accept
    icmpv6 type { echo-request, destination-unreachable, packet-too-big, time-exceeded, parameter-problem,
                  nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } accept

    # 4. Your services — the explicit allow-list
    tcp dport 22 accept comment "SSH"
    tcp dport { 80, 443 } accept comment "HTTP/HTTPS"
    udp dport 443 accept comment "HTTP/3 (remove if unused)"

    # 5. Optional: see what you're dropping, without flooding the log
    limit rate 5/minute log prefix "input drop: "
  }

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

  chain output {
    type filter hook output priority filter; policy accept;
  }
}

Pas het toe met nft -f /etc/nftables.conf en maak het persistent met systemctl enable nftables. (Op Debian en Ubuntu koppelt het nftables-pakket precies dit bestand aan die service.)

Nu de redenering, regel voor regel.

Regel 1: loopback

Talloze onderdelen van een Linux-systeem praten met zichzelf via 127.0.0.1 en ::1: resolvers, databases, metrics-agents. lo onvoorwaardelijk accepteren is veilig (loopback-verkeer komt nooit van de kabel binnen), en het vergeten ervan levert onder een drop-beleid onbegrijpelijke storingen op.

Regel 2: de stateful kern

ct state established,related accept is de regel die het meeste werk doet. Connection tracking (conntrack) onthoudt elke flow die de firewall heeft goedgekeurd; deze regel laat de rest van elk goedgekeurd gesprek door, zonder de allow-list per packet opnieuw te evalueren. related dekt protocollen die legitiem secundaire flows opstarten (een ICMP-foutmelding over je verbinding, FTP-datakanalen).

ct state invalid drop verwerpt packets die bij geen enkele bekende flow horen en ook geen geldige nieuwe flow kunnen starten: out-of-window dwalende ACK's, rommel van scanners midden in een verbinding, restanten van aanvallen. Ze vroeg droppen is gratis hygiëne.

Eén eerlijke kanttekening: conntrack is zelf ook state, en state kan uitgeput raken; dat is precies waar DDoS-aanvallen op protocolfamilies op mikken. Voor een normale server volstaan de standaardwaarden plus SYN cookies; draai je een dienst met een zeer hoog verbindingstempo, dan hoort het verhogen van net.netfilter.nf_conntrack_max op je tuninglijst thuis.

Regel 3: ICMP, goed gedaan

Het hardnekkigste stukje firewallfolklore is: "blokkeer ping, blokkeer ICMP, dat is veiliger." Dat is het niet; het breekt het control plane van het internet:

  • destination-unreachable (en daarbinnen, IPv4's fragmentation-needed) is hoe Path MTU Discovery werkt. Drop je dit, dan hangen verbindingen via elk pad met een kleinere MTU (VPN's, tunnels, sommige transit) op mysterieuze wijze vast bij grote overdrachten: de klassieke "SSH werkt maar SCP hapert"-bug.
  • packet-too-big is het IPv6-equivalent, en IPv6 is strenger: routers fragmenteren nooit in IPv6, dus is PMTUD verplicht. ICMPv6 in zijn geheel droppen breekt IPv6, punt uit.
  • Neighbour discovery (nd-neighbor-solicit, nd-neighbor-advert, nd-router-advert) is de ARP van IPv6. Drop je dit, dan verliest je server zijn default gateway zodra de neighbour cache verloopt.
  • echo-request (ping) is het toestaan waard op een server: het kost niets noemenswaardigs (je adres is toch al vindbaar voor scanners) en je zult je eigen machine willen pingen tijdens het debuggen. Maak je je zorgen over ping floods, rate-limit het dan (icmp type echo-request limit rate 10/second accept) in plaats van het te droppen.

De baseline hierboven staat precies de controleberichten toe die de protocollen vereisen, en verder niets: geen timestamps, geen redirects, geen router solicitations die je niet inbound nodig hebt.

Regel 4: de allow-list

Dit onderdeel hoort een accurate inventarisatie te zijn van waar de server voor is. Twee gewoontes houden het eerlijk:

  • Voeg een comment toe aan elke regel. Over een half jaar is tcp dport 8472 accept comment "flannel VXLAN" documentatie; een kaal poortnummer is archeologie.
  • Als een service intern is, zeg dat dan ook in de regel. Moet PostgreSQL alleen bereikbaar zijn vanaf je app-servers op een privénetwerk, codeer dat dan: ip saddr 10.0.0.0/24 tcp dport 5432 accept, geen kale port-5432 allow. (Adressen hier en verderop zijn documentatiereeksen; vervang ze door je eigen adressen.)

Regel 5: de drops loggen

Volledige drop-logging op een internet-facing server is een schijf-vulmachine; achtergrondscans zijn constant. De limit rate 5/minute-steekproef geeft je genoeg in journalctl -k om patronen te herkennen (en om "waarom bereik ik mijn nieuwe service niet"-momenten te debuggen: zie je de drop gelogd, dan is de firewall je probleem) zonder de ruis.

De vergeten helft: IPv6-pariteit

Het historische faalpatroon: een zorgvuldige iptables-ruleset voor IPv4, terwijl ip6tables nooit werd aangeraakt, waardoor elke service op dual-stack machines wagenwijd openstond over IPv6. Onderzoeken uit dat tijdperk vonden geregeld v6-blootstelling waarvan mensen niet wisten dat ze die hadden.

De baseline hierboven is door zijn constructie immuun: een nftables-tabel van het type inet past elke regel tegelijk toe op beide families, en de ICMPv6-regels geven v6 precies de controleberichten die het nodig heeft. Gebruik je in plaats daarvan ufw of firewalld, dan beheren beide standaard ook v6 naast v4. De vuistregel overleeft elke toolkeuze: elke firewallbeslissing die je neemt, moet voor beide adresfamilies opgaan. Heeft je server een AAAA-record, test je services dan ook over v6 na het toepassen van regels, niet alleen over v4.

Rate-limiting voor SSH (en waar fail2ban past)

Poort 22 zal voor altijd brute-force-pogingen blijven ontvangen; met alleen key-authenticatie zijn die pogingen ruis, maar ze goedkoop throttlen blijft de moeite waard. nftables kan native per-bron rate limiting doen met een dynamische set. Vervang de simpele SSH-regel door:

    set ssh_ratelimit {
      type ipv4_addr
      flags dynamic
      timeout 10m
    }
    set ssh_ratelimit6 {
      type ipv6_addr
      flags dynamic
      timeout 10m
    }

    tcp dport 22 ct state new add @ssh_ratelimit { ip saddr limit rate 4/minute } accept comment "SSH v4, per-IP throttle"
    tcp dport 22 ct state new add @ssh_ratelimit6 { ip6 saddr limit rate 4/minute } accept comment "SSH v6, per-IP throttle"

Elk bronadres krijgt vier nieuwe SSH-verbindingen per minuut; de vijfde wordt stilzwijgend gedropt totdat het tempo weer daalt. Dit is blind voor intentie (het weet het verschil niet tussen een mislukte en een geslaagde login), en daarom blijft fail2ban een aanvulling: het leest het auth-log en verbant adressen die daadwerkelijk falen bij authenticatie. Rate limit in de firewall, verban op bewijs met fail2ban, en eis keys; die combinatie maakt een einde aan het SSH-ruisprobleem.

Dezelfde baseline in ufw en firewalld

Is de conventie van je distributie een frontend, gebruik dan die frontend; handgeschreven regels mixen met de regels van een frontend is precies waar firewalls archeologie worden. Hetzelfde beleid:

ufw (de standaardfrontend van Ubuntu; onder de motorkap stuurt het iptables aan, wat via de compatibiliteitslaag alsnog in nftables uitkomt):

ufw default deny incoming
ufw default allow outgoing
ufw limit 22/tcp comment 'SSH, rate-limited'
ufw allow 80/tcp
ufw allow 443
ufw enable

ufw limit past een ingebouwde brute-force-throttle toe (zes verbindingen per dertig seconden per bron). ufw regelt loopback, conntrack en verstandige ICMP-standaardwaarden voor je.

firewalld (de standaard van de RHEL-familie, sinds 2018 op nftables gebaseerd):

firewall-cmd --set-default-zone=public
firewall-cmd --permanent --zone=public --add-service=ssh
firewall-cmd --permanent --zone=public --add-service=http
firewall-cmd --permanent --zone=public --add-service=https
firewall-cmd --reload

firewalld denkt in zones en services in plaats van regels; de public-zone is default-deny met de vermelde services opengezet, en ICMP wordt out of the box verstandig afgehandeld.

Hoe je jezelf niet buitensluit

Firewallwijzigingen op een remote server zijn de klassieke zelf veroorzaakte storing. De gewoontes die ze saai maken:

  • Controleer de syntax voordat je toepast: nft -c -f /etc/nftables.conf valideert het bestand zonder het te laden.
  • Plan een automatische rollback voordat je riskante wijzigingen doorvoert, en annuleer die zodra je bevestigt dat je nog steeds toegang hebt:
# revert to the known-good ruleset in 3 minutes unless cancelled
systemd-run --on-active=3m --unit=fw-rollback nft -f /etc/nftables.known-good
# ...apply your change, confirm SSH still works, then cancel the rollback:
systemctl stop fw-rollback.timer

En houd de hele tijd een tweede SSH-sessie open; bewaar de nieuwe ruleset pas als known-good nadat een verse verbinding is gelukt.

  • Test een wijziging van het default-drop-beleid nooit zonder out-of-band toegang. Op een dedicated server betekent dat KVM-over-IP/IPMI-consoletoegang (onze servers hebben dat inbegrepen), wat een lockout verandert van een incident in een fix van twee minuten.
  • Volgorde maakt in nftables minder uit dan je vreest, maar de accept-established-regel moet vóór je drops staan, en het hele bestand wordt atomisch toegepast door nft -f, dus een half geladen ruleset kan je niet stranden zoals opeenvolgende iptables-commando's historisch konden.

Docker omzeilt ufw en je input-chain

Draai je Docker met gepubliceerde poorten (-p 8080:80), weet dan dit: Docker programmeert de NAT- en forwarding-regels van de kernel rechtstreeks, en gepubliceerde poorten omzeilen ufw en je input-chain volledig. Je zorgvuldig default-deny firewall is niet van toepassing op met -p gepubliceerde containers; verkeer wordt omgeleid voordat je input-chain het ooit te zien krijgt. Dit is al lang bestaand, gedocumenteerd gedrag, geen bug die in de volgende release wordt opgelost (de native nftables-backend van Docker Engine 29 is experimenteel en verandert niets aan de semantiek).

De geaccepteerde oplossingen:

  • Bind poorten die je niet publiek wilt hebben aan localhost of een privéadres: -p 127.0.0.1:8080:80 of -p 10.0.0.5:5432:5432.
  • Zet restricties in de DOCKER-USER-chain, die Docker gegarandeerd evalueert vóór zijn eigen regels: dat is de ondersteunde hook voor "firewall mijn containers".
  • Behandel elke -p met een kaal poortnummer als "dit staat nu op het internet", want dat is ook zo.

Outbound filtering: wanneer het de moeite waard is

Een default-accept output-beleid is de juiste standaard: servers praten legitiem uitgaand met package mirrors, DNS, NTP, API's en monitoring. Outbound filtering verdient zijn complexiteit in specifieke situaties: compliance-regimes die egress-controle vereisen, servers die untrusted input verwerken waarbij je reverse shells en data-exfiltratie wilt afremmen, en single-purpose machines waarvan het volledige verkeersprofiel bekend is (een databaseserver heeft niets te zoeken bij het openen van verbindingen naar willekeurige internethosts).

Voer je het toch in, doe het dan op dezelfde manier als inbound: inventariseer wat de server nodig heeft (DNS naar je resolvers, 80/443 naar mirrors, je monitoring-endpoint), sta die toe, default-drop de rest, en log de drops een week lang voordat je handhaaft; het log leert je wat je vergeten bent.

Veelgestelde vragen

Moet ik nftables direct gebruiken, of ufw of firewalld?

Volg de conventie van je distributie en de gewoontes van je fleet. Op Debian is native nftables schoon en eersteklas; op Ubuntu is ufw het beproefde pad; op RHEL/AlmaLinux/Rocky is firewalld de ondersteunde interface en gaat de documentatie daarvan uit. Alle drie produceren uiteindelijk nftables-regels in de kernel. Het enige echte anti-pattern is het mixen van lagen: handmatig nft-regels toevoegen op een machine die firewalld beheert, leidt tot regels die bij een reload verdwijnen.

Is het blokkeren van ping een goede beveiligingsmaatregel?

Nee. Het bestaan van je server blijft niet verborgen door echo requests te droppen (scanners vinden actieve hosts op talloze andere manieren), en je verliest een basale diagnosetool die je zelf ook wilt gebruiken. Erger nog: mensen die erop uit zijn "ping te blokkeren" blokkeren meestal ICMP in zijn geheel en breken daarmee Path MTU Discovery en IPv6 neighbour discovery. Sta echo-request toe (eventueel rate-limited) en de error/control-berichten; drop de rest.

Beschermen deze regels mij tegen DDoS-aanvallen?

Deels, en het is belangrijk om precies te zijn over welk deel. Een default-deny ruleset verkleint het aanvalsoppervlak (rommelverkeer gericht op gesloten poorten sterft goedkoop) en rate limits verzachten kleine connection floods. Maar geen enkele regel op de host helpt zodra een aanval je uplink verzadigt; de packets hebben de kabel achter je regels dan al gepasseerd. Volumetrische aanvallen worden upstream gestopt, of helemaal niet, en daarom zet ons netwerk permanente DDoS-mitigatie en een self-service firewall aan de rand van het netwerk vóór je poort.

Ik heb een firewall toegepast en er brak iets. Hoe debug ik dat?

Controleer eerst het drop-log: journalctl -k | grep "input drop" (met de logregel uit de baseline). Verschijnt het geblokkeerde verkeer daar, dan mis je een allow-regel. Noteer de poort en het protocol uit de logregel. Verschijnt het niet, dan is de firewall niet je probleem; kijk naar de service-binding (ss -tlnp) en bevestig, voor IPv6-bereikbare hosts, dat je dezelfde adresfamilie hebt getest die faalt.

Uitrollen op Serverside

Op onze dedicated servers is de on-host ruleset uit deze gids een van twee firewallagen: elke server krijgt ook een self-service firewall aan de rand van het netwerk, zodat verkeer naar poorten die je nooit bedient al upstream wordt gedropt voordat het je machine raakt, naast permanente DDoS-mitigatie op ons ASN 55285-netwerk. En mocht een firewallwijziging je ooit toch buitensluiten, dan betekent de inbegrepen KVM-over-IP-consoletoegang dat herstel minuten kost, geen supportticket. Provisioning duurt minder dan een minuut, voor Ubuntu, Debian, AlmaLinux/Rocky, RHEL en meer.

Volgende in deze reeks: je regeltooling kiezen in iptables vs nftables, het bredere dreigingsbeeld in DDoS-aanvallen uitgelegd, en achterhalen wat je server daadwerkelijk raakt in een DDoS vastleggen en analyseren met Wireshark.

Jesse Schokker

Geschreven door

Jesse Schokker

Co-founder & CTO, Serverside.com

Jesse is the co-founder and CTO of Serverside.com, where he leads the engineering behind the company's bare-metal cloud: from the ASN 55285 backbone to the core automation that drives day-to-day operation. He writes about dedicated servers, operating systems, and running production workloads on bare metal.