UFW-firewall instellen zonder uzelf buiten te sluiten
De juiste volgorde bij het opbouwen van UFW, IPv6-regels, nftables als backend, rate limiting met ufw limit en de weg terug via de console als het toch misgaat.
Een pakketfilter is op een rootserver geen luxe, maar basisuitrusting. UFW (Uncomplicated Firewall) maakt dat aangenaam eenvoudig, maar heeft één eigenschap die elk jaar duizenden beheerders uit hun eigen server sluit: het commando dat de firewall scherpstelt, is hetzelfde commando dat de lopende SSH-sessie kan afkappen. Deze handleiding laat zien in welke volgorde dat niet gebeurt en, bijna nog belangrijker, hoe u weer binnenkomt als het toch misgaat.
Alle informatie geldt voor Debian 13 (trixie), Debian 12 (bookworm), Ubuntu 24.04 LTS en Ubuntu 22.04 LTS. De commando's zijn geschreven voor gebruik als root. Werkt u als gewone gebruiker, zet dan voor elk commando sudo.
Waarom de volgorde alles bepaalt
De klassieke fout gaat zo: iemand zet eerst het standaardbeleid op "al het inkomende verkeer verwerpen", schakelt de firewall in en wil daarna rustig de SSH-regel toevoegen. Precies daartussen ligt het tijdvenster waarin de server ophoudt bereikbaar te zijn.
De reden dat deze fout zo vaak onopgemerkt blijft, is verraderlijker dan de fout zelf. UFW levert in /etc/ufw/before.rules een regel mee die al bestaande verbindingen doorlaat:
-A ufw-before-input -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
Uw huidige SSH-sessie is zo'n bestaande verbinding. Die overleeft het inschakelen van de firewall dus ook wanneer er helemaal geen SSH-regel bestaat. De prompt blijft staan, alles lijkt in orde. Pas de volgende verbindingspoging, doorgaans uw login de volgende ochtend, loopt in een timeout. Daarom geldt: zolang de firewall niet met een tweede, vers opgebouwde sessie is geverifieerd, verlaat u de eerste sessie niet.
Vuistregel: eerst toestaan, dan verwerpen, dan inschakelen, dan controleren met een tweede sessie, en pas daarna de eerste sessie sluiten.
Vóór het eerste commando: noodtoegang en inventarisatie
Zorg dat twee dingen duidelijk zijn voordat u ook maar iets aan de pakketfiltering verandert.
1. Hoe komt u zonder SSH op de server?
Bij de KVM-rootservers en dedicated servers van KernelHost vindt u de VNC-console rechtstreeks in het klantenpaneel. Die console hangt niet aan de netwerkstack van het gastsysteem, maar aan de virtualisatielaag of aan de netwerkaansluiting zelf. Een firewallregel binnen het gastsysteem kan hem daarom niet blokkeren. Log vooraf één keer via die console in en controleer of u het rootwachtwoord kent. Een noodtoegang die u pas tijdens het incident voor het eerst uitprobeert, is geen noodtoegang.
2. Wat luistert er eigenlijk op deze server?
Regels voor diensten die niet bestaan, zijn onschuldig. Een dienst die u over het hoofd hebt gezien, kost u de toegang of een storing. Verschaf uzelf eerst een overzicht:
ss -lntup
De kolom Local Address:Port maakt daarbij een net onderscheid tussen 0.0.0.0:22 (alleen IPv4), [::]:22 (IPv6 en via de dual-stack-socket meestal ook IPv4) en 127.0.0.1:3306 (alleen lokaal, heeft geen firewallregel nodig). Alles wat aan 127.0.0.1 of ::1 gebonden is, hoeft u niet open te zetten.
Extra belangrijk is de werkelijke SSH-poort. Niet gokken, opzoeken. Het commando heeft leesrechten op de hostkeys nodig en draait dus als root of met sudo:
sudo sshd -T | grep -i "^port "
Een detail dat veel handleidingen weglaten: op Ubuntu 24.04 start de SSH-dienst via socketactivering met ssh.socket, niet met ssh.service. Daar meldt systemctl is-enabled ssh.socket een enabled en ssh.service een disabled. Op Debian 12, Debian 13 en Ubuntu 22.04 is het precies andersom, daar geldt de klassieke permanent draaiende dienst.
Het gevolg is voor dit onderwerp onaangenaam concreet: op Ubuntu 24.04 is de poort die sshd -T meldt niet per se de poort waarop werkelijk wordt geluisterd. Doorslaggevend is daar ListenStream in /lib/systemd/system/ssh.socket of in een aanvullend bestand onder /etc/systemd/system/ssh.socket.d/. Wie zijn SSH-poort heeft gewijzigd en op sshd -T vertrouwt, zet in UFW het verkeerde poortnummer open en sluit zichzelf bij de volgende login buiten. Op alle vier de systemen is alleen de blik op het proces dat werkelijk luistert betrouwbaar:
sudo ss -lntp | grep sshd
3. De dodemansknop
Leg voor het geval er iets misgaat, nog vóór de riskante wijziging, een tijdschakelaar aan die de firewall na tien minuten vanzelf weer uitschakelt:
nohup sh -c 'sleep 600; ufw disable' >/dev/null 2>&1 &
Werkt alles naar behoren, breek hem dan af:
pkill -f 'sleep 600; ufw disable'
De pkill raakt alleen het omsluitende shellproces. De sleep loopt als weesproces door en eindigt zonder gevolgen, want er is niemand meer over die daarna ufw disable zou kunnen aanroepen.
De volgorde die u niet buitensluit
Op Debian is UFW meestal niet voorgeïnstalleerd, op Ubuntu Server doorgaans wel. Installeren kan in geen geval kwaad:
apt-get update
apt-get install -y ufw
ufw version
Nu de volgorde, en wel precies zo:
ufw allow 22/tcp comment 'SSH'
ufw default deny incoming
ufw default allow outgoing
ufw --force enable
Vier opmerkingen daarbij:
- De toestemmingsregel staat vóór al het andere. UFW neemt regels ook in inactieve toestand aan en bewaart ze in
/etc/ufw/user.rules. Bij het inschakelen zijn ze er meteen. - In plaats van
22/tcpkunt u een applicatieprofiel gebruiken, bijvoorbeeldufw allow OpenSSH. Vertrouw daar echter niet blind op: de profielen komen niet van UFW zelf, maar uit de geïnstalleerde pakketten. Op Ubuntu is/etc/ufw/applications.d/zonder geïnstalleerde diensten leeg,ufw app listgeeft daar alleen de kopAvailable applications:en geen enkele regel terug. Op Debian levert het ufw-pakket zelf al zo'n 38 profielen mee, daar heet het SSH-profielSSH. Het profielOpenSSHkomt op beide distributies uit het pakketopenssh-server, op servers dus het normale geval. Bij een afwijkende SSH-poort slaat het profiel sowieso de plank mis. Welke profielen uw systeem kent, laatufw app listzien; de poortgebaseerde schrijfwijzeufw allow 22/tcpwerkt daarentegen op alle vier de systemen identiek en is daarom de betrouwbaardere keuze. ufw enablevraagt interactief na:Command may disrupt existing ssh connections. Proceed with operation (y|n)?. Gebruik in scripts en in Ansible-rollenufw --force enable, anders blijft de uitvoering hangen.- Het commentaar achter
commentduikt op inufw status. Anders weet u over een half jaar niet meer waarvoor poort 8443 openstaat.
Verdere diensten komen daarna aan de beurt, bijvoorbeeld een webserver:
ufw allow 80/tcp comment 'HTTP'
ufw allow 443/tcp comment 'HTTPS'
En pas nu opent u een tweede terminal en logt u opnieuw in. Pas als die login lukt, is de klus geklaard.
IPv6: de tweede adresfamilie die iedereen vergeet
Elke moderne server heeft IPv6, meestal zonder dat iemand dat actief heeft ingericht. Wie alleen aan IPv4 denkt, houdt uiteindelijk een firewall over die precies de helft van het verkeer regelt en de andere helft doorlaat. Controleer eerst of er wel globale IPv6-adressen zijn geconfigureerd:
ip -6 addr show scope global
Het goede nieuws: op alle vier de hier behandelde distributies staat in /etc/default/ufw standaard IPV6=yes. UFW onderhoudt dan bij elke IPv4-regel parallel een IPv6-regel. Verifiëren in plaats van vertrouwen:
grep '^IPV6' /etc/default/ufw
Een tweede, harder bewijs is het standaardbeleid van de IPv6-chain zelf:
ip6tables -L INPUT -n
In de eerste regel moet Chain INPUT (policy DROP) staan. Staat er policy ACCEPT en daaronder geen ufw-chains, dan staat uw server via IPv6 volledig open, hoe goed de IPv4-regels er ook uitzien.
Twee valkuilen:
- Een wijziging aan
IPV6in/etc/default/ufwwerkt niet door viaufw reload. Daarvoor isufw disablegevolgd doorufw enablenodig. Precies in dat gat hebt u kortstondig geen firewall, doe dat dus niet zomaar tussendoor op een blootgesteld systeem. - Wie ICMPv6 zonder onderscheid blokkeert, sloopt zijn eigen connectiviteit. Neighbor Discovery en "Packet too big" zijn bij IPv6 niet optioneel, maar onderdeel van het protocol. UFW staat de noodzakelijke types al toe in
/etc/ufw/before6.rules. Kom aan dat bestand alleen als u precies weet wat u doet.
Is een poortgebaseerde regel in beide adresfamilies correct aangelegd, dan meldt UFW bij het toevoegen twee regels: Rule added en Rule added (v6). Ontbreekt de tweede regel, dan ontbreekt de halve bescherming. Een uitzondering vormen bronbeperkte regels: bij ufw allow from 203.0.113.10 to any port 22 proto tcp verschijnt alleen Rule added, en dat klopt ook, want bij een IPv4-bronadres bestaat geen IPv6-tegenhanger.
Wat UFW werkelijk wegschrijft: nftables als backend
Hierover circuleert veel halve kennis. De situatie op Debian 12, Debian 13, Ubuntu 22.04 en Ubuntu 24.04 is uniform: UFW spreekt nog steeds de iptables-syntaxis, maar het commando iptables is op alle vier de systemen de compatibiliteitstool iptables-nft. De regels belanden dus in het nftables-subsysteem van de kernel. Het bewijs in één regel:
iptables -V
De uitvoer eindigt met (nf_tables). Staat er (legacy), dan werkt uw systeem met het oude backend. Dat functioneert wel, maar het leidt ertoe dat regels uit twee werelden naast elkaar in de kernel liggen en elkaar overlappen. Welke variant is ingesteld, laat update-alternatives --display iptables zien.
Vanaf de nftables-kant bekeken ziet dat er zo uit. Belangrijk daarbij: kijk pas na het inschakelen van de firewall:
apt-get install -y nftables
nft list tables
Zolang UFW niet actief is, bestaat de tabel namelijk helemaal niet: iptables-nft maakt hem pas aan zodra er werkelijk regels worden geladen, dus op zijn vroegst met ufw --force enable. Daarvóór blijft nft list tables leeg en breekt een nft list table ip filter af met Error: No such file or directory. Dat is geen defect, maar de verwachte toestand. Pas als in de lijst table ip filter en table ip6 filter opduiken, loont het om erin te kijken:
nft list table ip filter
De uitvoer begint met de regel Warning: table ip filter is managed by iptables-nft, do not touch!, en die is letterlijk bedoeld: bekijken mag, met de hand wijzigen niet. Daaronder vindt u chains als ufw-before-input, ufw-user-input en ufw-after-input. Dit is het punt waarop het belangrijkste conflict zichtbaar wordt: meng UFW niet met handgeschreven nft-regels. Een nft flush ruleset wist alle UFW-regels uit de kernel zonder dat UFW daar iets van merkt. ufw status meldt daarna nog altijd Status: active, terwijl er feitelijk geen enkele regel meer werkt. Dat is een van de vervelendste foutbronnen die er zijn, omdat het gereedschap waarmee u controleert tegen u liegt. De weg terug:
ufw reload
Controleer daarom na elke ingreep met andere firewalltools (Docker, Kubernetes, VPN-software, iptables-persistent) niet de UFW-status, maar de werkelijke regelset in de kernel.
ufw limit tegen brute force, en waar het ophoudt
Voor SSH biedt UFW een vorm van rate limiting:
ufw limit 22/tcp comment 'SSH rate limit'
De semantiek staat helder in de handleiding: verbindingen worden gewoon toegestaan, maar verworpen zodra één enkel bron-IP binnen 30 seconden zes of meer nieuwe verbindingen opbouwt. Die waarden liggen vast en zijn via de UFW-interface niet te wijzigen. Onder de motorkap werkt dit met de module recent, zichtbaar in iptables -S. Voor IPv6 legt UFW een gelijkwaardige regel aan, mits de kernelmodule beschikbaar is, en dat is op alle vier de distributies het geval.
Hebt u eerder al ufw allow 22/tcp gezet, dan ontstaat nu een tweede regel. De oude moet weg, anders grijpt die als eerste in en heeft de begrenzing geen effect:
ufw status numbered
ufw delete allow 22/tcp
Verwijdert u in plaats daarvan via het nummer (ufw delete 3), houd dan rekening met twee eigenaardigheden. Ten eerste nummert ufw status numbered IPv4- en IPv6-regels doorlopend in één enkele lijst, en na elke verwijdering schuiven alle volgende nummers op. Verwijder daarom altijd maar één regel tegelijk, laat de lijst daarna opnieuw tonen, of werk van het hoogste nummer naar beneden. Ten tweede vraagt UFW daarbij interactief na: Proceed with operation (y|n)?.
En nu de eerlijke duiding die in de meeste handleidingen ontbreekt:
- Tegen gedistribueerde aanvallen helpt het niet. De telling loopt per bron-IP. Een botnet met duizend adressen doet vijf pogingen per adres en blijft daarmee onder de drempel.
- Het treft uw eigen automatismen. Een back-upscript met veel losse
rsync-aanroepen, een Ansible-run met meerdere forks of een CI-taak kan tegen dezelfde grens aanlopen. Dan sluit u niet de aanvaller buiten, maar uw eigen deploymentpipeline. Voor zulke bronnen zet u er beter een expliciete uitzondering vóór, bijvoorbeeldufw allow from 203.0.113.10 to any port 22 proto tcpmet het echte adres van uw buildserver. - Het vervangt geen nette SSH-configuratie. De effectiefste stap tegen het raden van wachtwoorden is wachtwoorden uitschakelen:
PasswordAuthentication noin/etc/ssh/sshd_configof in een bestand onder/etc/ssh/sshd_config.d/. Wie geen wachtwoorden accepteert, kan ze ook niet laten raden. Aanvullend is fail2ban zinvol, dat in tegenstelling totufw limitop logregels reageert en langer blokkeert.
Waaraan u ziet dat het werkelijk gelukt is
"Het commando liep zonder fouten door" is geen bewijs. Vier controles die werkelijk iets zeggen:
Ten eerste de algehele toestand.
ufw status verbose
Verwacht wordt uitvoer in deze vorm:
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
To Action From
-- ------ ----
22/tcp LIMIT IN Anywhere
22/tcp (v6) LIMIT IN Anywhere (v6)
Doorslaggevend is de tweede regel met de toevoeging (v6). Zonder die regel ontbreekt de IPv6-dekking.
Ten tweede de herstart. Een firewall die een reboot niet overleeft, is waardeloos.
systemctl is-enabled ufw
Het antwoord moet enabled zijn. En start de server daarna ook werkelijk één keer opnieuw op en log in. Dat is de enige test die de vraag echt beantwoordt.
Ten derde de blik van buitenaf. Controleer vanaf een andere host of een bewust niet opengezette poort werkelijk dicht is, bijvoorbeeld met nc -zv UW-IP 3306. Belangrijk: een test vanaf localhost bewijst helemaal niets, want verkeer via de loopback-interface laat UFW principieel door.
Ten vierde de logs. Hier zit een echt verschil tussen de distributies. Met de standaardinstelling low logt UFW geblokkeerde pakketten via het kernellog. Op Ubuntu 22.04 en 24.04 is rsyslog aanwezig en belanden de meldingen ook in /var/log/ufw.log. Op Debian 12 en zeker op Debian 13 ontbreekt rsyslog in minimale installaties, daar bestaat dat bestand simpelweg niet. De weg die overal werkt:
journalctl -k -n 50
U zoekt naar regels die met [UFW BLOCK] beginnen. Wilt u meer zien, zet het niveau dan hoger (ufw logging medium) en daarna weer terug op ufw logging low. Op een server met publieksverkeer vult het hogere niveau de schijf sneller dan u denkt.
Foutmeldingen letterlijk
ERROR: problem running ufw-init: de meest voorkomende oorzaak is een conflict met een tweede firewalltool, meestal nftables.service of iptables-persistent, of een vermenging van het legacy- en het nft-backend. Controleer iptables -V en schakel concurrerende diensten uit. UFW levert daarnaast een controlescript mee dat de kernelvereisten stuk voor stuk nagaat en meldt welke module-eis niet wordt gehaald.
ERROR: Could not find a profile matching 'OpenSSH': het applicatieprofiel ontbreekt, omdat openssh-server niet is geïnstalleerd of het bestand onder /etc/ufw/applications.d/ is verwijderd. Op Ubuntu is die map zonder geïnstalleerde diensten sowieso leeg. Gebruik in plaats daarvan het poortnummer.
ERROR: Bad port: meestal een typefout of een dienstnaam die /etc/services niet kent. Poortnummers zijn altijd eenduidig.
Skipping adding existing rule of Skipping adding existing rule (v6): geen foutmelding, maar de mededeling dat de regel er al is. Denkt u een regel te hebben gewijzigd terwijl die ongewijzigd blijft, dan is dit de reden.
ERROR: Invalid position '0': bij het verwijderen en invoegen telt UFW vanaf 1, niet vanaf 0. De nummers komen uit ufw status numbered en schuiven na elke verwijdering op. Verwijder daarom altijd van het hoogste nummer naar beneden.
WARN: Rules updated but not applied: de regel staat in de configuratie, maar de firewall is inactief. Er ontbreekt een ufw enable.
Distributieverschillen in één oogopslag
- Debian 13 (trixie): UFW zelf installeren. Backend nf_tables.
IPV6=yesstandaard. rsyslog ontbreekt in minimale installaties, logs dus viajournalctl -k. SSH viassh.service. - Debian 12 (bookworm): UFW zelf installeren. Backend nf_tables.
IPV6=yesstandaard. rsyslog afhankelijk van de installatievariant aanwezig,/var/log/ufw.logdus niet gegarandeerd. SSH viassh.service. - Ubuntu 24.04 LTS: UFW aanwezig op de serverimages, maar inactief. Backend nf_tables.
IPV6=yesstandaard./var/log/ufw.logaanwezig. SSH via socketactivering metssh.socket, controleer de luisterende poort daarom altijd metsudo ss -lntp | grep sshden niet metsshd -T. - Ubuntu 22.04 LTS: UFW aanwezig op de serverimages, maar inactief. Backend nf_tables.
IPV6=yesstandaard./var/log/ufw.logaanwezig. SSH viassh.service.
Wat op alle vier de systemen hetzelfde is: UFW is na de installatie altijd inactief. Niemand zet uw firewall stiekem aan, en niemand zet hem stiekem uit.
Docker omzeilt UFW
Draait er Docker op de server, dan geldt een belangrijke beperking: gepubliceerde containerpoorten negeren uw UFW-regels. Docker legt eigen chains aan en werkt met doeladresvertaling, waardoor de pakketten langs de UFW-chains in INPUT heen lopen. Een docker run -p 8080:80 is dus van buitenaf bereikbaar, ook al toont ufw status een keurig "deny incoming".
De eenvoudigste en robuustste tegenmaatregel is om niet op alle adressen te publiceren, maar alleen lokaal, en de toegang via een reverse proxy te laten lopen:
docker run -d -p 127.0.0.1:8080:80 nginx
In een Compose-bestand komt dat overeen met de poortopgave "127.0.0.1:8080:80". Als alternatief kunt u UFW met eigen regels inhaken in de door Docker gereserveerde chain DOCKER-USER. Dat werkt, maar het vraagt veel onderhoud en moet bij elke Docker-update opnieuw worden gecontroleerd. De binding aan 127.0.0.1 lost het probleem bij de wortel op.
Als u toch buitengesloten bent
Het is gebeurd, SSH reageert niet meer. Op volgorde:
- Niet herstarten. Een reboot helpt niet, want UFW is als systemd-service ingeschakeld en herstelt zijn regels bij het opstarten. De server komt net zo gesloten terug als hij is afgesloten.
- Open de VNC-console in het klantenpaneel en log daar in als root.
- Schakel de firewall uit:
ufw disable. Daarmee bent u weer binnen, maar ook weer onbeschermd. - Zoek de oorzaak, gok niet. Bekijk
ufw status numbereden de werkelijke SSH-poort uitss -lntup. In negen van de tien gevallen is de oorzaak een van deze drie: er is nooit een toestemmingsregel voor SSH geweest, de regel staat op poort 22 terwijl sshd op een andere poort luistert, of de vrijgave was beperkt tot een IP-adres dat uw verbinding inmiddels niet meer heeft (dynamische adrestoewijzing bij de internetaansluiting). - Corrigeer en schakel opnieuw in, dit keer in de juiste volgorde en met een actieve dodemansknop.
Wilt u de regelset volledig resetten, dan is er ufw reset. Belangrijk om te weten: dat commando deactiveert de firewall en legt back-ups van de bestaande regelbestanden onder /etc/ufw/ neer, met een tijdstempel in de bestandsnaam. U kunt bij twijfel dus nalezen wat er eerder gold. Voer het nooit uit over een SSH-verbinding zonder dat de console ernaast openstaat.
Een verstandige uitgangsconfiguratie
Voor een typische webserver ziet de volledige reeks er zo uit:
apt-get update
apt-get install -y ufw
ufw default deny incoming
ufw default allow outgoing
ufw limit 22/tcp comment 'SSH rate limit'
ufw allow 80/tcp comment 'HTTP'
ufw allow 443/tcp comment 'HTTPS'
ufw --force enable
ufw status verbose
Let erop dat hier weliswaar default deny incoming vóór de SSH-regel staat, maar dat het inschakelen helemaal aan het einde gebeurt. Zolang UFW inactief is, richt het standaardbeleid geen schade aan. Kritiek is uitsluitend de toestand op het moment van enable, en op dat moment staat de SSH-regel er allang in.
Wie daarnaast beheertoegangen alleen vanuit het eigen netwerk bereikbaar wil maken, werkt met bronbeperkte regels volgens het patroon ufw allow from 203.0.113.0/24 to any port 22 proto tcp. Nog netter is het om beheerdiensten helemaal niet in het open netwerk te zetten, maar via een VPN te ontsluiten. Een WireGuard-instantie staat op elk van de vier systemen binnen enkele minuten, en vervangt een hele stapel firewalluitzonderingen door één enkele open UDP-poort.
En tot slot de nuance die u voor ogen moet houden: UFW filtert op de server zelf. Tegen volumetrische aanvallen die de uplink verzadigen helpt dat principieel niet, want de pakketten hebben de lijn al doorlopen wanneer uw kernel ze verwerpt. Daarvoor is filtering in het netwerk ervóór nodig. Bij KernelHost doet de voorgeschakelde infrastructuur in het datacenter maincubes in Frankfurt am Main dat met Arbor-realtimefiltering. Uw lokale firewall en de netwerkbescherming lossen twee verschillende problemen op, en u hebt ze allebei nodig.
Veelgestelde vragen
Word ik door "ufw enable" meteen buitengesloten uit mijn lopende SSH-sessie?
Moet ik IPv6 in UFW apart activeren?
Gebruikt UFW iptables of nftables?
Wat doet ufw limit precies?
Ik kom niet meer via SSH op de server. Helpt een herstart?
Waarom zijn mijn Docker-containers ondanks een actieve UFW-firewall van buitenaf bereikbaar?
Waarom bestaat /var/log/ufw.log op mijn Debian-server niet?
2026 KernelHost GmbH. Alle rechten voorbehouden. Deze handleiding is auteursrechtelijk beschermd. Publicatie op andere websites, geheel, gedeeltelijk of in bewerkte vorm, is zonder onze schriftelijke toestemming niet toegestaan. Citeren met bronvermelding en link is uitdrukkelijk welkom.

