SSD Nodes Learn 8GB RAM — $66/jaar
Gidsen Matt ConnorDoor Matt Connor · Bijgewerkt 2026-08-02

Docker Compose-netwerken: DNS, host-modus en poorten

Leer hoe het standaard bridge-netwerk werkt, waarom DNS via servicenaam werkt, wanneer host-modus zinvol is en waarom een gepubliceerde poort UFW kan omzeilen.

Wat Compose bouwt voordat uw applicatie start

Docker Compose-netwerken beginnen met één regel: docker compose up maakt een privénetwerk voor het project, koppelt elke service eraan en zorgt ervoor dat die services elkaar via hun servicenaam kunnen bereiken. U hoeft daarvoor geen enkele regel met networks: te schrijven. De meeste verwarring over netwerken in Compose ontstaat doordat niet bekend is dat dit standaard al aanwezig is.

Hier is een klein bestand. Sla het op als compose.yaml in een map met de naam shop.

services:
  web:
    image: nginx:1.27
    ports:
      - "8080:80"
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: example

Start het project en bekijk wat Docker heeft aangemaakt:

docker compose up -d
docker network ls

De lijst bevat nu een netwerk met de naam shop_default. Compose noemt het <project>_default en de projectnaam is standaard de naam van de map in kleine letters. U kunt deze overschrijven met docker compose -p myproject up -d of met een name: myproject op het hoogste niveau in het bestand. Het stuurprogramma is bridge, een virtuele switch binnen de host. Elke container krijgt een adres op een privésubnet en uitgaand verkeer wordt onderweg naar buiten vertaald naar het adres van de host.

docker compose down verwijdert dat netwerk weer. Daarom kan een achtergebleven container uit een oud project een netwerk behouden: Docker weigert dit met error while removing network: network shop_default has active endpoints. De oplossing is de container die nog aan het netwerk is gekoppeld, te stoppen of te verwijderen.

Als Compose nieuw voor u is, kunt u het beste eerst De indeling van Compose-bestanden en opdrachten voor de levenscyclus lezen, omdat al het onderstaande ervan uitgaat dat u een project kunt starten en stoppen.

DNS op servicenamen is het onderdeel dat beginners missen

Op elk door de gebruiker gedefinieerd netwerk voert Docker een ingebouwde DNS-server uit die elke container ziet op 127.0.0.11. Deze server zet servicenamen om in de huidige containeradressen. Daarom bereikt web de database via de hostnaam db op poort 5432, zonder enige configuratie.

docker compose exec web getent hosts db

Dit geeft een regel zoals 172.18.0.2 db. Als er niets wordt weergegeven, bevinden de twee services zich niet op hetzelfde netwerk.

De fout die bijna iedereen één keer maakt, is localhost gebruiken in de configuratie van de applicatie. Binnen een container verwijst localhost naar die container, niet naar de host en niet naar de andere service. Postgres-clients rapporteren dit duidelijk:

could not connect to server: Connection refused
	Is the server running on host "localhost" (127.0.0.1) and accepting
	TCP connections on port 5432?

De connection string moet postgresql://postgres:example@db:5432/postgres zijn. Het hostgedeelte is de servicenaam.

Twee details die later tijd besparen. Namen worden omgezet naar wat er op dat moment actief is. Daarom geeft docker compose up -d --scale web=3 één naam met drie adressen. Een client die DNS voor altijd cachet, blijft dan aan een niet meer actieve container gekoppeld. Bovendien biedt het legacy-netwerk bridge, dat door een gewone docker run zonder --network wordt gebruikt, helemaal geen naamomzetting. Daarom komt advies over containerlinks uit 2016 niet overeen met wat u ziet.

U hebt ports: niet nodig om twee services te verbinden

ports: publiceert een containerpoort op de host. Deze optie is bedoeld voor netwerkverkeer dat van buiten Docker binnenkomt. Dit heeft niets te maken met verkeer tussen services. Dat verkeer werkt al over het volledige poortbereik op het projectnetwerk.

De ports: - "5432:5432" die veel mensen aan hun databaseservice toevoegen, heeft daarom geen nut en veroorzaakt wel echte schade: hierdoor wordt Postgres beschikbaar op de openbare interface van de server. Verwijder deze optie. Als u de service vanaf uw laptop bereikbaar wilt maken voor een migratie, bindt u deze met "127.0.0.1:5432:5432" aan loopback en gebruikt u een SSH-tunnel. Het verschil tussen een listening socket, een gepubliceerde poort en een firewallregel wordt beschreven in hoe poorten en listening services werken in Linux.

expose: dient onder Compose alleen als documentatie. Deze optie opent niets, omdat er niets was afgesloten tussen containers op hetzelfde netwerk.

Wanneer network_mode host de juiste keuze is en wat dit kost

In host-modus gebruikt het proces de netwerkinterfaces van de host rechtstreeks. De eigen netwerknamespace van de container wordt niet gebruikt.

services:
  probe:
    image: alpine:3.20
    network_mode: host
    command: sleep infinity

Daar zijn geldige redenen voor. Een proces dat broadcast- of multicastverkeer op het lokale netwerk moet kunnen zien, zoals apparaatdetectie voor een mediaserver of een hub voor huisautomatisering, kan dit niet achter een bridge zien. De bridge stuurt dat verkeer namelijk niet door naar de container. Een monitoringagent die de tellers van de interfaces van de host uitleest, heeft de interfaces van de host nodig. Ook slaat u de stap voor adresvertaling over. Dat is relevant bij hoge pakketfrequenties.

De nadelen zijn specifiek.

ports: werkt niet meer. Docker waarschuwt dat gepubliceerde poorten worden genegeerd bij host-netwerkmodus. De container maakt verbinding met de poort waarop het proces zelf luistert. Twee containers in host-modus die poort 8080 willen gebruiken, veroorzaken een conflict. De tweede container stopt met bind: address already in use.

Naamresolutie op basis van servicenaam werkt niet meer, in beide richtingen. De container maakt geen deel uit van het projectnetwerk en kan db daarom niet resolven. De andere services kunnen de container evenmin resolven. De container kan deze services alleen bereiken via poorten die op de host zijn gepubliceerd, meestal op 127.0.0.1.

De isolatie is verdwenen. Een proces dat binnen een container in host-modus aan 0.0.0.0 bindt, luistert op elke interface van uw server, ook op de publieke interface. Dit werkt precies zoals bij een pakket dat met apt is geïnstalleerd. Daar staat tegenover dat dit verkeer de normale inkomende route volgt. UFW-regels zijn er daarom wel op van toepassing. Dat geldt niet voor gepubliceerde poorten.

Host-modus is een functie van Linux Docker Engine. Docker Desktop ondersteunt deze modus pas vanaf versie 4.34 en alleen nadat u deze hebt ingeschakeld. Daarnaast kunnen containers geen binding maken met IP-adressen van de host en worden alleen TCP en UDP verwerkt. Als een deel van uw team Linux-servers gebruikt en een ander deel Docker Desktop, kan hetzelfde bestand zich anders gedragen.

Gebruik host-modus wanneer u de interfaces van de host nodig hebt. Gebruik deze modus niet om een verbindingsprobleem op te lossen. Meestal vervangt u daarmee het ene probleem door een moeilijker probleem.

Twee Compose-projecten verbinden met een extern netwerk

Een netwerk dat door één project is gemaakt, is niet zichtbaar voor een ander project. Daarom kan een reverse proxy in proxy/compose.yaml geen toegang krijgen tot een app in app/compose.yaml, zelfs niet op dezelfde server. De oplossing is een netwerk dat geen van beide projecten beheert.

Maak het netwerk één keer handmatig aan:

docker network create edge

Declareer het vervolgens als extern netwerk in elk project. De proxyzijde:

services:
  proxy:
    image: traefik:v3.1
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - edge

networks:
  edge:
    name: edge
    external: true

De applicatiezijde:

services:
  app:
    image: nginx:1.27
    networks:
      - edge
      - internal
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: example
    networks:
      - internal

networks:
  edge:
    name: edge
    external: true
  internal:

external: true geeft Compose de opdracht om verbinding te maken met een bestaand netwerk in plaats van er een te maken, en om het netwerk op docker compose down te laten staan. De afzonderlijke sleutel name: is belangrijker dan het lijkt: zonder deze sleutel zoekt Compose naar een netwerk dat exact edge heet. Met deze sleutel kunt u het netwerk in uw bestand een andere naam geven dan op de host.

Als het netwerk niet bestaat, weigert Compose te starten en meldt het dat het netwerk als extern is gedeclareerd maar niet kon worden gevonden. Maak het eerst aan.

Let op wat het applicatiebestand met internal doet. De database bevindt zich alleen op dat projectspecifieke netwerk. De proxy kan de database daardoor niet bereiken; alleen app kan dat. Als u internal: true onder een netwerk toevoegt, wordt de route van de database naar de buitenwereld volledig verwijderd. Dat is een goede standaardinstelling voor een database. Houd wel rekening met één gevolg voordat u deze instelt: een container op een intern netwerk kan niets downloaden. Een entrypoint dat bij het opstarten apt-get update of pip install uitvoert, blijft daarom wachten en mislukt vervolgens met een time-out.

Zie meerdere apps achter één Traefik-instantie uitvoeren voor een volledige uitgewerkte configuratie met routeringsregels en certificaten.

Gepubliceerde poorten omzeilen UFW

Dit is het onderdeel van Compose-netwerken dat tot een beveiligingsincident leidt. U publiceert een poort, controleert dat UFW actief is en alles behalve SSH weigert, maar de service is nog steeds bereikbaar vanaf het internet.

sudo ufw status
curl http://203.0.113.10:8080

UFW geeft aan dat de poort is geblokkeerd. De curl retourneert de pagina toch. Er is niets defect. Docker schrijft zijn eigen adresvertalings- en forwardingregels rechtstreeks naar iptables. Verkeer naar een gepubliceerde containerpoort wordt doorgestuurd naar de container in plaats van te worden afgeleverd bij de host. Het passeert daardoor nooit de keten die UFW beheert voor lokaal bestemd verkeer. De regels van Docker worden bovendien vóór de regels van UFW gecontroleerd.

De korte oplossing is om alleen te publiceren waar dat nodig is:

    ports:
      - "127.0.0.1:8080:80"

Hiermee bindt u de hostzijde aan loopback. De poort is daardoor bereikbaar vanaf de server zelf en via een SSH-tunnel, maar nergens anders vandaan. Plaats het openbare toegangspunt achter een reverse proxy die 80 en 443 bewust publiceert. De volledige uitleg, inclusief de DOCKER-USER-keten voor gevallen waarin u een gepubliceerde poort moet filteren, staat in waarom Docker rechtstreeks langs UFW publiceert en hoe u dit oplost.

In vier opdrachten debuggen

Begin met nagaan op welk netwerk elke container daadwerkelijk is aangesloten:

docker network inspect shop_default

Het blok Containers vermeldt elke gekoppelde container met zijn adres. Een service die niet in deze lijst staat, bevindt zich op een ander netwerk, gebruikt de hostmodus of is niet actief.

Test de naamresolutie vanuit een tijdelijke container die op hetzelfde netwerk is aangesloten. Zo hebt u geen hulpprogramma's in uw eigen images nodig:

docker run --rm --network shop_default busybox nslookup db
docker run --rm --network shop_default busybox nc -zv db 5432

Als nslookup mislukt, ligt het probleem bij de naamresolutie of het netwerklidmaatschap. Als nslookup slaagt terwijl nc mislukt, draait de service wel, maar luistert deze niet op die poort. Of de service luistert binnen de eigen container op 127.0.0.1 in plaats van op 0.0.0.0. Dit komt vaak voor bij ontwikkelservers. U lost dit op in het bindadres van de applicatie, niet in Docker.

Er is nog een fout die op een Docker-probleem lijkt. Als containers met elkaar kunnen communiceren, maar geen machine op uw kantoor- of VPN-netwerk kunnen bereiken, overlapt het Docker-subnet waarschijnlijk met dat netwerk. Docker wijst standaard adressen toe vanaf 172.17.0.0/16. Verplaats de pool in /etc/docker/daemon.json:

{
  "default-address-pools": [
    { "base": "10.200.0.0/16", "size": 24 }
  ]
}

Voer daarna sudo systemctl restart docker uit en maak de betrokken netwerken opnieuw aan. Een bestaand netwerk behoudt namelijk het subnet waarmee het is aangemaakt.

FAQ

Waarom kunnen mijn containers elkaar niet bereiken via de servicenaam?

Ze bevinden zich niet op hetzelfde netwerk. Compose plaatst elke service automatisch op <project>_default, maar zodra u een lijst networks: aan een service toevoegt, wordt die lijst de volledige verzameling netwerken voor die service en wordt het standaardnetwerk niet meer impliciet toegevoegd. Voer docker network inspect <network> uit en controleer of beide containers in het blok Containers staan. Controleer ook of geen van beide services network_mode: host gebruikt, omdat een container in hostmodus geen Docker-netwerk gebruikt en servicenamen niet kan oplossen.

Moet ik poorten publiceren zodat de ene service de andere kan bereiken?

Nee. Op een Compose-netwerk is elke poort van elke container bereikbaar voor andere containers op dat netwerk. ports: is alleen bedoeld om een container bereikbaar te maken voor verkeer van buiten Docker, en expose: dient als documentatie. Het publiceren van een databasepoort is een veelvoorkomende en riskante gewoonte, omdat de database daardoor op de publieke interface van uw server beschikbaar wordt.

Wat is het verschil tussen bridge- en host-netwerken?

Bridge geeft de container een eigen netwerknamespace en adres op een virtuele switch, met automatische naamresolutie tussen containers en vertaald uitgaand verkeer. Host geeft de container rechtstreeks de netwerkstack van de host: geen afzonderlijk adres, geen resolutie via servicenaam, geen poortpublicatie en geen isolatie van andere listeners op de host. Bridge is de standaard en de juiste keuze, tenzij het proces de interfaces van de host nodig heeft.

Hoe verbind ik containers uit twee verschillende Compose-bestanden?

Maak een gedeeld netwerk met docker network create edge. Declareer het vervolgens in beide bestanden met external: true en koppel de services die met elkaar moeten communiceren eraan. Compose maakt dit netwerk niet aan en verwijdert het ook niet. Als u de aanmaakstap overslaat, weigert Compose te starten en meldt het dat het netwerk als extern is gedeclareerd maar niet is gevonden.

Waarom is mijn container vanaf internet bereikbaar terwijl UFW de poort blokkeert?

Omdat een gepubliceerde poort wordt verwerkt door de forwardingregels die Docker aan iptables toevoegt. Deze regels worden vóór de regels van UFW geëvalueerd, en doorgestuurd verkeer gaat bovendien niet door de keten die UFW filtert. Bind de hostzijde aan loopback met "127.0.0.1:8080:80" en plaats alles wat publiek toegankelijk moet zijn achter een reverse proxy op poorten 80 en 443.