SSD Nodes Learn Hosting plans →
Gidsen Matt ConnorDoor Matt Connor · Bijgewerkt 2026-08-28

wg-easy installeren met Docker Compose

Installeer WireGuard met de wg-easy webinterface via Docker Compose. Leer hoe u NET_ADMIN en sysctls configureert voor een werkende VPN en QR-codes voor mobiele apparaten.

Wat u bouwt

wg-easy is WireGuard met een webinterface, draaiend als één Docker container. Het beheert de WireGuard-interface voor u en voegt een browser-UI toe voor het aanmaken van clients. Elke client die u aanmaakt krijgt een configuratiebestand en een QR-code, waardoor een telefoon verbinding maakt met de VPN door de camera op het scherm te richten.

De tunnel zelf is standaard WireGuard. De kernelmodule verplaatst de pakketten, waardoor de doorvoer gelijk is aan een handmatig opgezette configuratie. Wat u wint is de levenscyclus van de client: peers toevoegen, uitschakelen en verwijderen zonder via SSH een configuratiebestand te hoeven bewerken. Wat u opgeeft is de directe controle over die configuratie, wat het onderwerp is van de handmatige WireGuard-installatie op een VPS.

U heeft een KVM VPS nodig met een publiek IPv4-adres, Docker Engine met de Compose-plugin en root-toegang. Containervirtualisatie die de host-kernel deelt, zoals OpenVZ of LXC, kan de WireGuard-module meestal niet laden, waardoor de container de interface niet kan opstarten.

Versie 15 heeft de instellingen verplaatst uit de environment

De meeste handleidingen die u zult vinden, zijn geschreven voor wg-easy 14, waarbij u WG_HOST instelde op uw serveradres en PASSWORD_HASH op een bcrypt-hash van het beheerderswachtwoord, beide als omgevingsvariabelen. Versie 15 is een herschreven versie. De officiële migratienotities vermelden duidelijk dat v15 niet dezelfde omgevingsvariabelen gebruikt als v14 en dat de meeste daarvan zijn verplaatst naar het beheerderspaneel in de web-UI.

WG_HOST en PASSWORD_HASH doen daarom niets meer. Als u een oud compose-bestand kopieert, start de container, negeert deze regels en vraagt u vervolgens om een beheerdersaccount aan te maken in de browser. Dat is geen bug. Het is de nieuwe installatieprocedure.

Sinds juli 2026 is de major-tag die u moet vastzetten 15. Zet de major-versie vast in plaats van latest te gebruiken, omdat een major-upgrade het configuratieformaat op de schijf wijzigt en niet probleemloos kan worden teruggedraaid.

Het compose-bestand

Maak een map aan voor de stack en schrijf het officiële compose-bestand hierin. Dit is het upstream-bestand, ongewijzigd.

sudo mkdir -p /etc/docker/containers/wg-easy
sudo curl -o /etc/docker/containers/wg-easy/docker-compose.yml \
  https://raw.githubusercontent.com/wg-easy/wg-easy/master/docker-compose.yml

De inhoud ziet er als volgt uit:

volumes:
  etc_wireguard:

services:
  wg-easy:
    image: ghcr.io/wg-easy/wg-easy:15
    container_name: wg-easy
    networks:
      wg:
        ipv4_address: 10.42.42.42
        ipv6_address: fdcc:ad94:bacf:61a3::2a
    volumes:
      - etc_wireguard:/etc/wireguard
      - /lib/modules:/lib/modules:ro
    ports:
      - "51820:51820/udp"
      - "51821:51821/tcp"
    restart: unless-stopped
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    sysctls:
      - net.ipv4.ip_forward=1
      - net.ipv4.conf.all.src_valid_mark=1
      - net.ipv6.conf.all.disable_ipv6=0
      - net.ipv6.conf.all.forwarding=1
      - net.ipv6.conf.default.forwarding=1

networks:
  wg:
    driver: bridge
    enable_ipv6: true
    ipam:
      driver: default
      config:
        - subnet: 10.42.42.0/24
        - subnet: fdcc:ad94:bacf:61a3::/64

etc_wireguard is een named volume dat de server-key en elke client die u aanmaakt bevat. Maak een back-up van dit volume, anders raakt u bij een rebuild al uw peers kwijt. Als u deze bestanden liever op het host-bestandssysteem ziet, vervang dit dan door een bind mount. Lees eerst het verschil tussen bind mounts en named volumes voordat u dit doet, omdat de permissies zich anders gedragen.

Waarom NET_ADMIN, SYS_MODULE en de sysctls nodig zijn

Een container mag standaard de netwerkstack niet aanpassen; elk van deze regels heft een specifieke blokkade op.

NET_ADMIN stelt de container in staat om de wg0-interface aan te maken, een adres toe te wijzen en routes te schrijven. Zonder deze optie start de container wel, maar crasht deze bij het initialiseren van de interface, omdat ip link add wg0 type wireguard de foutmelding Operation not permitted teruggeeft.

SYS_MODULE in combinatie met de read-only /lib/modules-mount zorgt ervoor dat de container de WireGuard-kernelmodule kan laden als de host deze nog niet heeft geladen. De module bevindt zich in de host-kernel en niet in de image zelf, waardoor de host-directory zichtbaar moet zijn. Bij een moderne kernel is de module meestal ingebouwd; u kunt dit controleren met sudo modprobe wireguard && echo ok op de host.

net.ipv4.ip_forward=1 zorgt ervoor dat de kernel pakketten doorstuurt die niet voor de machine zelf bestemd zijn. Zonder deze instelling maakt een client verbinding en slaagt de handshake, maar wordt elk pakket naar het internet geweigerd. Hierdoor treedt een time-out op in ping 1.1.1.1, terwijl de VPN-verbinding als actief wordt weergegeven.

net.ipv4.conf.all.src_valid_mark=1 is de instelling die vaak voor verrassing zorgt. WireGuard markeert zijn eigen uitgaande pakketten zodat deze niet terug de tunnel in worden gerouteerd. Strict reverse path filtering ziet een pakket waarvan het bronadres niet overeenkomt met de verwachte route en weigert dit. Deze sysctl instrueert de kernel om gemarkeerde pakketten te accepteren, wat voorkomt dat een volledige tunnel zichzelf blokkeert.

Start de service en maak het beheerdersaccount aan

cd /etc/docker/containers/wg-easy
sudo docker compose up -d
sudo docker compose logs -f

Gebruik docker compose up en docker compose down, niet start en stop. De upstream-ontwikkelaars waarschuwen dat start op een container die met andere instellingen is aangemaakt, het netwerk in een inconsistente staat achterlaat. Als u wilt dat de stack na een herstart terugkeert, dekt restart: unless-stopped dit al af, en het opstartgedrag van compose-services legt uit wat dat beleid wel en niet garandeert.

De web-UI luistert op TCP 51821. Bij het eerste bezoek ziet u een configuratiepagina waar u het beheerdersaccount aanmaakt en het hostadres bevestigt dat clients zullen gebruiken om de server te bereiken. Dat hostadres komt in de Endpoint-regel van elke clientconfiguratie terecht, dus het moet het publieke IP-adres of de DNS-naam van de VPS zijn. Als dit onjuist is, verwijst de QR-code die u aan een telefoon geeft naar een onbereikbare locatie en zal de handshake nooit voltooien.

Nog een punt over die poort: wg-easy 15 weigert platte HTTP tenzij u INSECURE=true instelt. Het bereiken via HTTPS met een niet-vertrouwd certificaat, of het beëindigen van TLS bij een reverse proxy voor de service, is beide in orde. Het bereiken via http:// met de standaardinstellingen is dat niet.

Stel de UI-poort niet bloot aan het internet

Het compose-bestand publiceert 51821 op elke interface. Dit is een inlogpagina voor een systeem dat uw netwerkverkeer kan routeren en deze mag niet openstaan voor de buitenwereld. Het publiceren van een poort in Docker schrijft regels naar de DOCKER-chain, die vóór ufw wordt geëvalueerd; een ufw deny-regel sluit de poort daarom niet af. Deze valkuil is belangrijk om te begrijpen, en waarom Docker gepubliceerde poorten ufw negeren behandelt dit volledig.

De eenvoudige oplossing is om de UI aan loopback te binden en deze te benaderen via een SSH-tunnel:

    ports:
      - "51820:51820/udp"
      - "127.0.0.1:51821:51821/tcp"
    environment:
      - INSECURE=true

Voer vervolgens vanaf uw laptop het volgende uit:

ssh -L 51821:127.0.0.1:51821 youruser@your.server.address

Open http://127.0.0.1:51821 in de browser op uw laptop. Het verkeer wordt versleuteld door SSH, de poort reageert op niemand anders en INSECURE=true is hier veilig omdat de ongecodeerde HTTP-stap de loopback-interface nooit verlaat.

Open UDP 51820 en controleer beide firewalls

WireGuard zelf heeft UDP 51820 nodig dat bereikbaar is vanaf het internet. Docker publiceert deze poort, maar veel providers plaatsen een aparte netwerkfirewall voor de VPS waar Docker geen weet van heeft. Open de poort op beide locaties. Als u de host-firewall beheert met ufw, is de basis ufw-regels voor een VPS een snellere methode dan het handmatig schrijven van nftables.

Controleer of de container daadwerkelijk luistert:

sudo ss -ulnp | grep 51820

U hoort een luisterende UDP-socket te zien. Als er niets op die regel staat, betekent dit dat de container de interface nooit heeft opgestart, en sudo docker compose logs wg-easy zal de reden hiervoor aangeven.

Een client aanmaken en scannen met een telefoon

Maak in de UI een client aan en geef deze een naam die u later herkent, zoals het apparaat waarvoor deze bedoeld is. wg-easy wijst het eerstvolgende vrije tunneladres toe en genereert het sleutelpaar voor u. Elke clientrij biedt een QR-code en een downloadbaar .conf-bestand.

Installeer de officiële WireGuard-app op de telefoon, kies voor het toevoegen van een tunnel via een QR-code en richt de camera op de code op uw scherm. De tunnel verschijnt met de naam die u heeft ingevoerd. Schakel deze in; de clientrij in de UI begint nu overdrachtstellers en een recente handshake-tijd weer te geven. Zodra een telefoon verbonden is met de tunnel, kan deze services bereiken die u nooit op internet heeft gepubliceerd. Zo kan een telefoon overal vandaan foto's uploaden naar een zelfgehoste fotoserver, zonder dat die server ook maar één poort open heeft staan naar de buitenwereld. Dezelfde methode werkt voor media, en een Jellyfin-bibliotheek die is ingericht als een videotheek uit de jaren 90 is prettig om doorheen te bladeren vanuit een hotelkamer, terwijl deze net zo privé blijft als op uw eigen LAN. Waarschuwingen werken via dezelfde tunnel de andere kant op, aangezien een zelfgehoste ntfy-server een bericht naar die telefoon kan pushen op het moment dat een back-upjob mislukt, zonder ooit een verzoek vanaf het openbare internet te beantwoorden.

Een client die geen handshake toont nadat u deze heeft ingeschakeld, bereikt de server niet. Dit wijst op UDP 51820, hetzij bij de firewall van de provider, hetzij bij het endpoint-adres dat in de configuratie is vastgelegd. Een client die wel een handshake toont maar geen werkend internet heeft, wijst op problemen met forwarding of DNS.

Download op een desktop het .conf-bestand en importeer dit in de WireGuard-client in plaats van het opnieuw in te typen. De privésleutel in dat bestand wordt eenmalig gegenereerd en getoond. Behandel dit bestand zoals u een SSH-privésleutel behandelt.

Wanneer de UI niet meer volstaat

wg-easy is de juiste tool zolang uw peers uit mensen en telefoons bestaan. De UI is sneller dan het bewerken van configuratiebestanden en het intrekken van de toegang voor een verloren telefoon kost slechts één klik.

U zult tegen de grenzen aanlopen wanneer u functionaliteit wenst die niet in de UI is opgenomen. Site-to-site routing, waarbij de AllowedIPs van een peer een volledig extern subnet beslaat in plaats van één enkel adres, is meestal de eerste barrière. Split tunnels met routingregels per peer, of een configuratie die door uw provisioning-tool wordt gegenereerd, zijn de volgende stappen. Op dat punt is een handmatige configuratie niet moeilijker, maar simpelweg anders, en de standaard WireGuard-handleiding toont dezelfde tunnel opgebouwd vanuit wg0.conf. Als u liever helemaal geen control plane meer beheert, behandelt WireGuard vergeleken met Tailscale de beheerde optie. Of dat een goede ruil is, hangt af van wat de coördinatieserver daadwerkelijk kan bereiken, en het vertrouwensmodel van Tailscale is het lezen waard voordat u uw netwerk aan hen toevertrouwt. Kosten zijn meestal de volgende vraag, en wat het gratis abonnement van Tailscale daadwerkelijk dekt is voldoende zodat een huishouden of een klein team er niets voor betaalt. Voorbij dat punt telt de facturatie gebruikers in plaats van apparaten, wat een andere kostenstructuur is dan een VPS waar u al voor betaalt, dus wat Tailscale kost zodra u het gratis abonnement ontgroeit is het getal om te controleren voordat u een team migreert. De volledige tunnel die u zojuist heeft gebouwd heeft daar een direct equivalent, aangezien het adverteren van de VPS als een Tailscale exit node u dezelfde route naar buiten via de server oplevert, goedgekeurd in de beheerconsole in plaats van geschreven in elke clientconfiguratie. De subnet-barrière heeft ook een equivalent, omdat het adverteren van een volledig privénetwerk vanaf de VPS dat netwerk beschikbaar stelt aan elk apparaat in de tailnet zonder de bewerkingen per peer in AllowedIPs die u wegduwden bij de UI. Als u dat dashboard en de automatische mesh-routing wilt, maar niet de coördinatieserver van iemand anders, houdt het draaien van uw eigen NetBird-server op een VPS de control plane op hardware die u zelf bezit, ten koste van de DNS- en TLS-configuratie waar wg-easy nooit om vroeg.

Als de compose-syntax hierboven het onbekende deel was in plaats van het WireGuard-gedeelte, legt Docker Compose basics op een VPS het bestandsformaat en de dagelijkse commando's uit.

FAQ

Waarom negeert wg-easy mijn WG_HOST en PASSWORD_HASH?

Deze variabelen hoorden bij wg-easy 14. Versie 15 is een herschreven versie, waarbij de ontwikkelaars bijna alle configuratie hebben verplaatst naar het beheerderspaneel in de webinterface. De container leest beide variabelen niet; deze start normaal op en vraagt u bij het eerste bezoek om een beheerdersaccount aan te maken. Stel het hostadres voor clients in op die configuratiepagina.

Heb ik SYS_MODULE nodig als mijn kernel al over WireGuard beschikt?

Nee. SYS_MODULE en de /lib/modules-mount zijn aanwezig zodat de container de module kan laden wanneer de host dit nog niet heeft gedaan. Op een host waar sudo modprobe wireguard al slaagt, wordt deze capability niet gebruikt. Het verwijderen ervan is een verstandige stap voor hardening, en NET_ADMIN is in beide gevallen nog steeds vereist.

De client maakt verbinding, maar er is geen internet. Wat is er mis?

Een handshake zonder netwerkverkeer wijst bijna altijd op een probleem met forwarding. Controleer of net.ipv4.ip_forward=1 en net.ipv4.conf.all.src_valid_mark=1 nog in het compose-bestand staan, aangezien deze bij handmatige aanpassingen vaak verloren gaan. Als forwarding is ingeschakeld, controleer dan de DNS-server die de client heeft ontvangen. Een tunnel die al het verkeer door de VPN stuurt maar verwijst naar een DNS-server die niet langer bereikbaar is, gedraagt zich in een browser als een verbroken verbinding.

Hoe maak ik een back-up van mijn clients?

Alles bevindt zich in het etc_wireguard named volume, in een wg0.json-bestand. De interface bevat ook een back-upknop die dezelfde gegevens exporteert. Kopieer dat bestand naar een locatie buiten de server voordat u een upgrade uitvoert. Herstellen gebeurt door het bestand te uploaden tijdens de configuratiestap van een nieuwe container.

Kan ik wg-easy achter een reverse proxy draaien?

Ja. Plaats de proxy voor TCP 51821, beëindig daar de TLS-verbinding en stel INSECURE=true in op de container zodat deze de ongecodeerde HTTP-stap vanaf de proxy accepteert. Houd UDP 51820 direct gepubliceerd, omdat het VPN-verkeer via UDP verloopt en niet door een HTTP-proxy kan worden afgehandeld.