Docker in productie op een VPS: wat er misgaat en hoe je het oplost
Docker werkt op je laptop. Op een publieke VPS omzeilt het firewalls, vult het de schijf met logs, draait alles als root en heeft geen updatestrategie. Dit zijn de 8 problemen die je moet oplossen.
Je hebt Docker op je VPS geïnstalleerd. Je hebt docker compose up gedraaid. Je applicatie is live. Klaar, toch?
Niet helemaal. Op je laptop scant niemand je poorten, is er schijfruimte genoeg en doet beveiliging er nauwelijks toe. Op een VPS die aan het internet hangt, werken de standaardinstellingen van Docker actief tegen je.
Deze pagina behandelt de 8 problemen die je zult tegenkomen en linkt naar een speciale handleiding voor elk probleem. Scan de pagina, vind wat van toepassing is op jouw server, volg de uitgebreide handleiding.
Vereisten
Deze handleiding gaat ervan uit dat je de Docker-basis al kent. Als je je kennis moet bijspijkeren:
- Docker-commando's en -concepten
- Multi-service-applicaties met Compose
Alle commando's en output in dit artikel zijn getest op Debian 12 en Ubuntu 24.04 met Docker Engine 29.x en Compose v2 (versie 5.x).
Wat gaat er mis als je Docker op een publieke VPS draait?
Acht dingen gaan mis als je Docker van ontwikkeling naar een publieke VPS verplaatst: je firewall werkt niet meer, containers draaien als root met volledige toegang tot de host, logs vullen je schijf zonder rotatie, containernetwerken conflicteren met het hostnetwerk, services hebben geen resourcelimieten of health checks, volumes hebben geen backupstrategie, poorten zijn blootgesteld zonder TLS en container-images worden verouderd zonder updateplan. Dit zijn allemaal Docker-standaardinstellingen. Elk van deze zal je problemen geven in productie.
Snel overzicht voordat we in de details duiken:
| # | Probleem | Diagnostisch commando | Risico |
|---|---|---|---|
| 1 | Firewall-omzeiling | sudo iptables -L DOCKER-USER -n |
Kritiek |
| 2 | Root-containers | docker info --format '{{.SecurityOptions}}' |
Kritiek |
| 3 | Schijf vol door logs | du -sh /var/lib/docker/containers/*/*-json.log |
Hoog |
| 4 | Netwerkconflicten | docker network ls |
Gemiddeld |
| 5 | Geen resourcelimieten | docker stats --no-stream |
Hoog |
| 6 | Geen volume-backups | docker volume ls |
Hoog |
| 7 | Geen reverse proxy / TLS | ss -tlnp | grep -E ':80|:443' |
Kritiek |
| 8 | Verouderde images | docker compose images |
Gemiddeld |
Voer deze commando's nu uit op je server. Als een uitvoer je verrast, lees dan het bijbehorende onderdeel hieronder.
Omzeilt Docker je firewall?
Ja. Docker manipuleert iptables direct en voegt regels in de nat- en filter-tabellen in die worden geëvalueerd voordat UFW of firewalld het verkeer ziet. Als je een poort publiceert met -p 8080:80, staat die poort open voor het hele internet, zelfs als je UFW-regels deny incoming zeggen.
Controleer of dit op jou van toepassing is:
sudo iptables -L DOCKER-USER -n -v
Als de uitvoer een lege chain toont of alleen een onvoorwaardelijke RETURN-regel zonder filtering, staat elke gepubliceerde poort wagenwijd open.
De oorzaak: pakketten bestemd voor Docker-containers gaan door de FORWARD-chain en de DOCKER-chain. UFW werkt op de INPUT-chain. De twee ontmoeten elkaar nooit.
De eenvoudigste directe oplossing is om gepubliceerde poorten alleen aan 127.0.0.1 te binden:
ports:
- "127.0.0.1:8080:80"
Dit maakt de poort alleen toegankelijk vanuit de host zelf. Combineer het met een reverse proxy om extern verkeer af te handelen.
Voor een complete doorloop van de DOCKER-USER chain fix, UFW-integratie en nftables-configuratie.
Is Docker als root draaien gevaarlijk op een VPS?
Standaard draait de Docker-daemon als root en draaien containers als root binnen hun namespaces. Als een aanvaller uit een container ontsnapt, landt hij als root op de host. Op een publieke VPS is dit een directe weg naar volledige servercompromittering.
Controleer je huidige configuratie:
docker info --format '{{.SecurityOptions}}'
Zoek naar name=rootless in de uitvoer. Als het er niet staat, draait je daemon als root.
Controleer ook of je containers intern als root draaien:
docker ps -q | xargs -I {} docker exec {} id
Als je uid=0(root) ziet bij de meeste containers, draaien ze als root binnenin de container. Een image dat USER appuser instelt in zijn Dockerfile toont in plaats daarvan een non-root uid.
Je hebt drie verdedigingslagen:
- Rootless-modus draait de hele Docker-daemon onder een non-root gebruiker. Zelfs een container-ontsnapping landt als een onbevoegde gebruiker op de host.
- Seccomp-profielen beperken welke syscalls containers mogen gebruiken. Docker levert een standaardprofiel dat ongeveer 44 gevaarlijke syscalls blokkeert, maar je kunt het verder aanscherpen.
- AppArmor / SELinux voegt verplichte toegangscontrole toe bovenop al het andere.
Volledige configuratie voor rootless Docker, aangepaste seccomp-profielen en no-new-privileges.
Waarom vullen Docker-containers je schijf?
De standaard logdriver van Docker is json-file zonder groottelimiet en zonder rotatie. Elke regel die je applicatie naar stdout schrijft, wordt opgeslagen in /var/lib/docker/containers/<id>/<id>-json.log. Een drukke webapplicatie kan in dagen gigabytes aan logs genereren.
Controleer hoeveel ruimte logs momenteel innemen:
sudo du -sh /var/lib/docker/containers/*/*-json.log 2>/dev/null | sort -rh | head -5
Op een VPS die al een paar weken draait zonder logrotatie, kun je output als deze zien:
4.2G /var/lib/docker/containers/a1b2c3.../a1b2c3...-json.log
1.8G /var/lib/docker/containers/d4e5f6.../d4e5f6...-json.log
256M /var/lib/docker/containers/g7h8i9.../g7h8i9...-json.log
Logs zijn niet de enige schijfverbruiker. Controleer het totale Docker-schijfgebruik:
docker system df
Typische uitvoer op een server met 5 services:
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 12 5 4.2GB 2.8GB (66%)
Containers 8 5 52MB 12MB (23%)
Local Volumes 6 4 1.1GB 245MB (22%)
Build Cache 18 0 890MB 890MB (100%)
Die build cache is 100% terug te winnen. Die 7 ongebruikte images nemen 2,8 GB in. Op een 40 GB VPS-schijf loopt dat snel op.
De oplossing bestaat uit twee delen: logrotatie configureren in /etc/docker/daemon.json en periodieke opschoning van ongebruikte images en build cache instellen.
Volledige logrotatie-configuratie, schijfmonitoring en geautomatiseerde opschoning:
Hoe werkt Docker-netwerk op een enkele VPS?
Docker maakt zijn eigen bridge-netwerk (172.17.0.0/16 standaard) en beheert container-IP's intern. Op een VPS kan dit conflicteren met je hostnetwerk, je VPN-subnetten of andere services.
Bekijk welke netwerken Docker heeft aangemaakt:
docker network ls
NETWORK ID NAME DRIVER SCOPE
a1b2c3d4e5f6 bridge bridge local
f6e5d4c3b2a1 host host local
9i8h7g6f5e4d none null local
Elke docker compose up maakt een extra netwerk aan. Na een paar projecten heb je misschien een dozijn netwerken met overlappende subnetten.
Belangrijke beslissingen voor VPS-netwerken:
- Bridge-modus (standaard): containers krijgen interne IP's, poorten worden gepubliceerd via iptables. Werkt voor de meeste setups. Voegt een NAT-laag toe.
- Host-modus: containers delen de netwerkstack van de host direct. Geen NAT-overhead, maar geen poortisolatie. Nuttig voor prestatie-gevoelige services.
- Aangepaste bridge-netwerken: containers op hetzelfde aangepaste netwerk kunnen elkaar bereiken via containernaam. Dit is wat Compose automatisch aanmaakt.
Het belangrijke punt op een VPS: definieer je subnetten expliciet in docker-compose.yml in plaats van Docker te laten kiezen. Dit voorkomt conflicten met de interne netwerken van je hostingprovider.
Uitgebreide handleiding over bridge vs host, aangepaste subnetten en inter-container DNS:
Wat gebeurt er zonder resourcelimieten en health checks?
Zonder geheugenlimieten zal een enkele container met een geheugenlek al het beschikbare RAM verbruiken, de Linux OOM killer activeren en niet-gerelateerde containers of zelfs de SSH-daemon laten crashen. Zonder health checks heeft Docker geen manier om te weten dat een container defect is. Hij blijft "running" terwijl hij fouten retourneert.
Controleer of je containers limieten hebben ingesteld:
docker stats --no-stream --format "table {{.Name}}\t{{.MemUsage}}\t{{.MemPerc}}\t{{.CPUPerc}}"
Als de kolom MEM % waarden toont maar je nooit limieten hebt ingesteld, zijn die percentages berekend ten opzichte van het totale host-RAM. Een container die 45% toont, gebruikt 45% van het gehele VPS-geheugen, en niets houdt hem tegen om meer te nemen.
De minimale productieconfiguratie in je docker-compose.yml:
services:
app:
deploy:
resources:
limits:
memory: 512M
cpus: "1.0"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
restart: unless-stopped
Het beleid restart: unless-stopped herstart automatisch gecrashte containers maar respecteert handmatige stops. De healthcheck laat Docker ongezonde containers markeren en herstarten op basis van het aantal pogingen.
Volledige handleiding over Compose-resourcelimieten, healthcheck-patronen en herstartbeleid:
Hoe maak je een backup van Docker-volumes?
Docker-volumes bewaren data buiten containers. Als een volume wordt verwijderd of beschadigd raakt, is je database, geüploade bestanden of configuratie weg. Docker heeft geen ingebouwd backupmechanisme voor volumes.
Maak een lijst van je volumes en hun grootte:
docker system df -v | grep -A 100 "Local Volumes space usage"
Of controleer individuele volume-mountpoints:
docker volume ls -q | xargs -I {} docker volume inspect {} --format '{{.Name}}: {{.Mountpoint}}'
De mountpoints staan standaard onder /var/lib/docker/volumes/. Je kunt ze back-uppen met standaard Linux-tools, maar je moet de container eerst stoppen of pauzeren om inconsistente snapshots te voorkomen. Voor databases is een bestandssysteemkopie van een draaiende database geen betrouwbare backup. Je hebt eerst een dump nodig.
Backupstrategieën, herstelprocedures en geautomatiseerde planning:
Hoe stel je Docker-services bloot met TLS?
Poorten direct publiceren met -p 443:443 op elke container schaalt niet voorbij één service. Je hebt een reverse proxy nodig die TLS termineert, verkeer naar de juiste container routeert en certificaatvernieuwing afhandelt.
Controleer wat er momenteel luistert op je VPS:
ss -tlnp | grep -E ':80|:443'
Als je ziet dat je applicatiecontainers direct aan poort 80 of 443 gebonden zijn, zijn ze zonder proxylaag blootgesteld. Dit betekent dat elke service zijn eigen certificaatbeheer nodig heeft, en je kunt niet meerdere domeinen op één VPS hosten.
Drie reverse proxy-opties domineren het Docker-ecosysteem:
| Proxy | Auto-discovery | Automatisch TLS | Configuratiestijl |
|---|---|---|---|
| Traefik | Ja (Docker-labels) | Let's Encrypt ingebouwd | Labels + YAML |
| Caddy | Via plugin | Standaard automatisch | Caddyfile |
| Nginx Proxy Manager | Docker-socket | Let's Encrypt UI | Web-GUI |
Traefik is de meest voorkomende keuze voor Docker-native setups omdat het containerlabels leest en automatisch routingregels genereert. Geen configuratiebestanden om bij te werken als je een service toevoegt.
Vergelijking, installatiehandleidingen en TLS-configuratie voor elke optie:
Wat is de updatestrategie voor Docker-containers op een VPS?
Docker-images updaten zichzelf niet. Als je postgres:16 draait en er een beveiligingspatch uitkomt in postgres:16.4, blijft je container de oude image draaien totdat je expliciet pullt en de container opnieuw aanmaakt.
Controleer welke images je services gebruiken:
docker compose images
Vergelijk de image-digests met de laatste beschikbare versies:
docker compose pull --dry-run 2>&1
Als een image als "pulled" verschijnt in de dry-run uitvoer, is je draaiende versie verouderd.
De belangrijke beslissingen:
- Pin image-tags: gebruik nooit
:latestin productie. Gebruik specifieke versietags zoalspostgres:16.4of zelfs SHA-digests. - Geplande pulls: draai
docker compose pull && docker compose up -dop een schema, maar test updates eerst in een stagingomgeving. - Herstart zonder downtime: gebruik health checks en
docker compose up -d --no-deps <service>om één service tegelijk bij te werken. - Image-scanning: tools zoals Trivy scannen je images op bekende CVE's vóór deployment.
Updatestrategieën, image-pinning-patronen en deployment zonder downtime:
Heb je Kubernetes nodig om Docker in productie te draaien?
Nee. Docker Compose is een productie-klaar deploymenttool voor single-server workloads. Kubernetes lost multi-node orchestratie, automatisch schalen en self-healing over een cluster op. Als je applicatie op één VPS draait, geeft Compose je alles wat je nodig hebt zonder de operationele overhead van Kubernetes.
Waar Compose werkt:
- Een enkele VPS met 3-15 containers
- Statische of voorspelbare verkeerspatronen
- Klein team zonder toegewijde platform-engineers
- Services die seconden downtime tijdens updates tolereren
Waar je Compose ontgroeit:
- Meerdere servers nodig voor hoge beschikbaarheid
- Auto-scaling op basis van verkeerspieken
- Complexe service meshes met honderden microservices
- Zero-downtime-vereisten met blue-green deployments over nodes
De lichtgewicht middenweg is K3s, een afgeslankt Kubernetes dat op een enkele VPS draait met ongeveer 512 MB RAM-overhead. Maar voor de meeste hobbyprojecten, SaaS-MVP's en kleine productieapplicaties is Compose het juiste gereedschap.
Hoeveel RAM heeft een VPS nodig voor Docker in productie?
Een VPS die Docker in productie draait heeft minimaal 4 GB RAM nodig voor 3-5 containers. De Docker-daemon zelf gebruikt ongeveer 100-200 MB. Elke container voegt zijn eigen geheugengebruik toe. Zonder geheugenlimieten kan een enkele misdragende container alles opslokken.
| VPS-grootte | Containers | Geschikt voor |
|---|---|---|
| 4 GB RAM | 3-5 lichtgewicht | Blog, API, database, Redis |
| 8 GB RAM | 5-10 gemengd | SaaS-MVP, meerdere services, monitoringstack |
| 16 GB RAM | 10-20 | Meerdere projecten, CI-runners, zwaardere databases |
| 32 GB RAM | 20+ | AI-inferentie, grote databases, buildservers |
Opslag is net zo belangrijk als RAM. Docker-images, volumes, logs en build cache stapelen zich op. Plan minstens 40 GB NVMe-opslag in en stel de monitoring beschreven in in vanaf dag één.
CPU is zelden het knelpunt voor gecontaineriseerde webservices. 4 vCPU's verwerken de meeste workloads. Uitzonderingen: videotranscodering, AI-inferentie en buildservers.
Voor een VPS met NVMe-opslag gedimensioneerd voor Docker-productieworkloads, zie de Virtua Cloud VPS-plannen.
Productiechecklist
Controleer elk punt voordat je met Docker op een VPS in productie gaat:
- Firewallregels blokkeren alle door Docker gepubliceerde poorten behalve via de reverse proxy
- Containers draaien waar mogelijk als non-root gebruikers
- Docker-daemon draait in rootless-modus of containers gebruiken seccomp + no-new-privileges
- Logrotatie is geconfigureerd in
/etc/docker/daemon.json -
docker system prunedraait op schema (wekelijkse cron) - Elke service heeft geheugen- en CPU-limieten in
docker-compose.yml - Elke service heeft een health check
- Herstartbeleid is ingesteld (
unless-stoppedofon-failure) - Volumes met belangrijke data hebben geautomatiseerde backups
- Een reverse proxy handelt TLS-terminatie en certificaatvernieuwing af
- Image-tags zijn vastgezet op specifieke versies, niet
:latest - Je hebt een geteste updateprocedure voor het pullen van nieuwe images
-
journalctl -u dockerendocker logs <container>werken en je weet waar je moet kijken
Als je niet elk vakje kunt aanvinken, werk dan door de artikelen gelinkt in elke sectie hierboven.
Copyright 2026 Virtua.Cloud. Alle rechten voorbehouden. Deze inhoud is een origineel werk van het Virtua.Cloud-team. Reproductie, herpublicatie of herdistributie zonder schriftelijke toestemming is verboden.