Veel selfhosted applicaties worden aangeboden als Docker-container. Met Docker Compose kun je zo’n applicatie netjes beheren vanuit een compose-bestand.
In deze guide installeren we Docker Engine en Docker Compose op Debian of Ubuntu. Daarna maken we een simpele teststack, zodat je meteen begrijpt hoe een compose-bestand is opgebouwd.
Doel
Na deze guide heb je:
- Docker Engine geïnstalleerd
- Docker Compose geïnstalleerd
- gecontroleerd of Docker werkt
- een normale gebruiker toegevoegd aan de docker-groep
- een duidelijke mappenstructuur voor Docker Compose-stacks
- een eerste simpele compose-stack getest
- basisbegrip van poorten en volumes in Docker Compose
Voor wie is deze guide?
Deze guide is bedoeld voor mensen die een Debian- of Ubuntu-server gebruiken voor selfhosting.
Dit kan bijvoorbeeld zijn:
- een VM
- een Proxmox LXC
- een bare-metal server
- een VPS
- een mini-pc met Debian of Ubuntu Server
Let op bij Proxmox LXC
Docker in een Proxmox LXC kan prima werken, maar je container moet daar wel geschikt voor zijn.
In Proxmox heb je meestal minimaal nodig:
nesting=1
Voor sommige situaties ook:
keyctl=1
Op de Proxmox-host kun je dat bijvoorbeeld instellen met:
pct set 105 -features nesting=1,keyctl=1
Daarna de container herstarten:
pct reboot 105
Vervang 105 door het ID van jouw LXC.
Als pct reboot niet werkt omdat de container niet netjes reageert, kun je de container stoppen en daarna opnieuw starten:
pct stop 105
pct start 105
Als je net begint en zo min mogelijk gedoe wilt, kun je Docker ook in een gewone VM draaien. Dat is iets zwaarder, maar vaak voorspelbaarder.
Stap 1: Oude Docker-pakketten verwijderen
Soms staan er oude of distro-eigen Docker-pakketten op het systeem. Die kunnen conflicteren met de officiële Docker-pakketten.
Verwijder oude of conflicterende pakketten:
sudo apt remove -y docker docker-engine docker.io docker-compose docker-doc podman-docker containerd runc
Het is niet erg als sommige pakketten niet geïnstalleerd zijn. Dan meldt apt gewoon dat er niets te verwijderen is.
Let op: bestaande Docker-data in /var/lib/docker wordt hiermee niet automatisch verwijderd. Als je al een bestaande Docker-installatie had, denk dan goed na voordat je data opruimt.
Stap 2: Basisbenodigdheden installeren
Werk eerst je pakketlijst bij:
sudo apt update
Installeer daarna de benodigde pakketten:
sudo apt install -y ca-certificates curl gnupg lsb-release
Stap 3: Docker GPG-key toevoegen
Maak de keyring-map aan:
sudo install -m 0755 -d /etc/apt/keyrings
Debian
Voor Debian:
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
Ubuntu
Voor Ubuntu:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
Zet de rechten goed:
sudo chmod a+r /etc/apt/keyrings/docker.gpg
Stap 4: Docker repository toevoegen
Nu voeg je de officiële Docker apt-repository toe.
Debian
Voor Debian:
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Ubuntu
Voor Ubuntu:
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Werk daarna de pakketlijst opnieuw bij:
sudo apt update
Stap 5: Docker en Docker Compose installeren
Installeer Docker Engine, containerd, Buildx en de Compose-plugin:
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Controleer of Docker draait:
sudo systemctl status docker
Als Docker niet draait, start hem dan:
sudo systemctl enable --now docker
Stap 6: Installatie testen
Test Docker met:
sudo docker run hello-world
Als alles goed werkt, downloadt Docker een testimage en krijg je een melding dat de installatie werkt.
Controleer de Docker-versie:
docker --version
Controleer Docker Compose:
docker compose version
Als docker compose version werkt, is Docker Compose correct geïnstalleerd.
Stap 7: Gebruiker toevoegen aan de docker-groep
Standaard moet je Docker-commando’s met sudo uitvoeren.
Wil je Docker gebruiken zonder steeds sudo te typen, voeg je gebruiker dan toe aan de docker-groep.
Voor de huidige gebruiker:
sudo usermod -aG docker $USER
Of voor een specifieke gebruiker, bijvoorbeeld moofz:
sudo usermod -aG docker moofz
Log daarna uit en opnieuw in.
Of activeer de groep tijdelijk met:
newgrp docker
Test daarna:
docker ps
Als je geen foutmelding krijgt, werkt het.
Let op: gebruikers in de docker-groep hebben praktisch root-achtige rechten op het systeem. Voeg dus niet zomaar elke gebruiker toe aan deze groep.
Stap 8: Mappenstructuur kiezen
In deze guide gebruiken we /opt/stacks als basis voor Docker Compose-stacks.
/opt is volgens de Linux Filesystem Hierarchy Standard bedoeld voor optionele of third-party applicatiesoftware. Dat past goed bij selfhosted Docker-applicaties, omdat je die meestal zelf installeert en beheert.
We gebruiken daarbinnen de map stacks, zodat duidelijk is dat hier Docker Compose-stacks staan.
Voorbeelden:
/opt/stacks/nginx-proxy-manager
/opt/stacks/uptime-kuma
/opt/stacks/vaultwarden
Een stack bevat vaak meer dan alleen een compose-bestand, bijvoorbeeld:
- compose.yml
- .env
- data/
- config/
Je mag natuurlijk ook een andere map gebruiken, zoals /opt/compose, /srv/docker of /srv/stacks. Het belangrijkste is dat je consequent bent en weet waar je configuratie en data staan.
Voor beginners is dit een nette standaard:
/opt/stacks/<appnaam>
Stap 9: Mappenstructuur maken
Maak de basisdirectory aan:
sudo mkdir -p /opt/stacks
Geef je gebruiker rechten:
sudo chown -R $USER:$USER /opt/stacks
Of specifiek voor gebruiker moofz:
sudo chown -R moofz:moofz /opt/stacks
Daarna kun je per applicatie een eigen map maken.
Voorbeeld:
mkdir -p /opt/stacks/uptime-kuma
Of later:
mkdir -p /opt/stacks/nginx-proxy-manager
Mijn voorkeur is één map per compose-stack.
Bijvoorbeeld:
/opt/stacks/nginx-proxy-manager
/opt/stacks/uptime-kuma
/opt/stacks/mealie
/opt/stacks/vaultwarden
Zo blijft het overzichtelijk.
Stap 10: Eerste simpele compose-test
We maken nu een kleine teststack met Nginx. Dit is niet bedoeld als productie-webserver, maar puur om te testen of Docker Compose werkt.
Maak een testmap:
mkdir -p /opt/stacks/hello
Ga naar de map:
cd /opt/stacks/hello
Maak een compose-bestand:
nano compose.yml
Plaats hierin deze inhoud:
services:
nginx:
image: nginx:alpine
container_name: test-nginx
restart: unless-stopped
ports:
- "8080:80"
volumes:
- ./data:/usr/share/nginx/html
Sla het bestand op.
Maak daarna de map aan die we als volume gebruiken:
mkdir -p data
Maak een simpele testpagina:
echo "<h1>Docker Compose werkt!</h1>" > data/index.html
Start de container:
docker compose up -d
Controleer of hij draait:
docker ps
Open daarna in je browser:
http://IP-VAN-DE-SERVER:8080
Als alles goed werkt, zie je:
Docker Compose werkt!
Wat betekent dit compose-bestand?
Het bestand compose.yml beschrijft welke container Docker moet starten en hoe die container gekoppeld wordt aan je systeem.
services
services:
Onder services zet je één of meerdere containers die samen een stack vormen.
In dit voorbeeld hebben we maar één service:
nginx:
De naam nginx is de servicenaam binnen Docker Compose. Die mag je zelf kiezen.
image
image: nginx:alpine
Dit vertelt Docker welke image gebruikt moet worden.
In dit geval gebruiken we:
nginx:alpine
Dat is een lichte Nginx-container gebaseerd op Alpine Linux.
container_name
container_name: test-nginx
Hiermee geef je de container een vaste naam.
Daardoor zie je in docker ps duidelijk:
test-nginx
Zonder container_name maakt Docker Compose zelf een naam op basis van de map en servicenaam.
restart
restart: unless-stopped
Dit zorgt ervoor dat de container automatisch opnieuw start na een reboot of crash.
unless-stopped betekent: start automatisch opnieuw, behalve als je de container bewust zelf hebt gestopt.
Voor selfhosted services is dit meestal een handige instelling.
ports
ports:
- "8080:80"
Dit koppelt een poort op de host aan een poort binnen de container.
De notatie is:
HOSTPOORT:CONTAINERPOORT
In dit voorbeeld:
8080:80
Dat betekent:
- poort 8080 op je server
- gaat naar poort 80 binnen de Docker-container
Nginx luistert binnen de container op poort 80.
Maar vanaf je netwerk bezoek je:
http://IP-VAN-DE-SERVER:8080
Dus:
server:8080 → container:80
Een ander voorbeeld:
3001:3001
Dan wordt poort 3001 op de host gekoppeld aan poort 3001 binnen de container.
Bij een reverse proxy zoals Nginx Proxy Manager gebruik je vaak:
80:80
443:443
81:81
Omdat die poorten direct op de host beschikbaar moeten zijn.
volumes
volumes:
- ./data:/usr/share/nginx/html
Volumes koppelen een map op de host aan een map binnen de container.
De notatie is:
PAD-OP-HOST:PAD-IN-CONTAINER
In dit voorbeeld:
./data:/usr/share/nginx/html
Dat betekent:
- ./data is de map op de host
- /usr/share/nginx/html is de map binnen de container
Omdat we in /opt/stacks/hello staan, betekent ./data eigenlijk:
/opt/stacks/hello/data
Nginx gebruikt binnen de container deze map voor de websitebestanden:
/usr/share/nginx/html
Daardoor wordt onze hostmap:
/opt/stacks/hello/data
zichtbaar binnen de container als:
/usr/share/nginx/html
Als we op de host dit bestand maken:
/opt/stacks/hello/data/index.html
dan ziet Nginx dat binnen de container als:
/usr/share/nginx/html/index.html
Daarom verschijnt onze testpagina in de browser.
Waarom zijn volumes belangrijk?
Containers zijn vervangbaar. Je kunt een container stoppen, verwijderen en opnieuw maken.
Maar je data wil je behouden.
Daarom zet je belangrijke data meestal buiten de container, in volumes of bind mounts.
Voorbeelden:
./data:/app/data
./config:/config
/mnt/media:/media
/opt/stacks/app/config:/config
Links staat de hostkant. Rechts staat de containerkant.
Bijvoorbeeld:
/mnt/media:/media
betekent:
- op de host staat media in /mnt/media
- binnen de container is die media zichtbaar als /media
Relatief of absoluut pad?
In compose-bestanden kun je relatieve of absolute paden gebruiken.
Voorbeeld relatief:
./data:/app/data
Dit betekent: de map data naast je compose-bestand.
Voorbeeld absoluut:
/opt/stacks/uptime-kuma/data:/app/data
Dit wijst naar een exacte locatie op de host.
Voor beginners is relatief vaak overzichtelijk:
./data:/app/data
Dan blijft alles netjes binnen de map van de stack.
De testcontainer stoppen
Als je klaar bent met testen, kun je de container stoppen en verwijderen met:
docker compose down
De map data blijft gewoon bestaan op de host.
Wil je de testmap helemaal opruimen?
Ga dan eerst uit de map:
cd /opt/stacks
Verwijder daarna de testmap:
rm -rf hello
Let op met rm -rf. Controleer altijd goed welk pad je verwijdert.
Stap 11: Basiscommando’s
Handige Docker Compose-commando’s:
docker compose up -d
Start de stack op de achtergrond.
docker compose down
Stopt en verwijdert de containers van deze stack. Data in volumes blijft bestaan als je volumes goed hebt ingesteld.
docker compose logs -f
Bekijk live logs.
docker compose pull
Download nieuwe images.
docker compose up -d
Past updates toe na een pull.
docker ps
Toont draaiende containers.
docker ps -a
Toont alle containers, ook gestopte.
Stap 12: Updates uitvoeren
Docker zelf update je via apt:
sudo apt update
sudo apt upgrade
Containers update je per stack meestal zo:
cd /opt/stacks/naam-van-stack
docker compose pull
docker compose up -d
Ruim oude ongebruikte images af en toe op:
docker image prune
Let op: gebruik niet blind agressieve cleanup-commando’s als je niet weet wat ze verwijderen.
Stap 13: Firewall
Als je UFW gebruikt, moet je poorten toestaan die je nodig hebt.
Voor SSH:
sudo ufw allow OpenSSH
Voor een testservice op poort 8080:
sudo ufw allow 8080/tcp
Voor een reverse proxy zoals Nginx Proxy Manager heb je meestal nodig:
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
Zet alleen open wat je echt nodig hebt.
Veelgemaakte fouten
Het oude docker-compose commando gebruiken
Veel oude guides gebruiken:
docker-compose up -d
Bij moderne installaties gebruik je meestal:
docker compose up -d
Dus met een spatie.
Als docker-compose niet werkt, probeer dan docker compose.
Controleer met:
docker compose version
Geen volumes gebruiken
Zonder volumes kan data verdwijnen als je containers opnieuw maakt.
Volumes verkeerd om zetten
Bij volumes is de volgorde:
hostpad:containerpad
Dus bijvoorbeeld:
./data:/app/data
Links is de host. Rechts is binnen de container.
Als je dit omdraait, werkt je applicatie niet zoals verwacht of schrijf je data op een verkeerde plek.
Poorten verkeerd om zetten
Bij poorten is de volgorde:
hostpoort:containerpoort
Dus bijvoorbeeld:
8080:80
Links is de poort op je server. Rechts is de poort binnen Docker.
Alles in één map zetten
Dat wordt snel rommelig. Gebruik liever één map per stack.
Geen backups maken
Docker maakt beheer makkelijk, maar backups moet je nog steeds zelf regelen.
Backup minimaal:
- compose-bestanden
- configuratiebestanden
- data-volumes
- databases op applicatieniveau als dat nodig is
Containers als vervanging zien voor security
Docker is handig, maar geen magische beveiligingslaag. Houd containers up-to-date en publiceer niet zomaar alles op internet.
Docker in LXC zonder nesting
Als Docker in een Proxmox LXC vreemd doet, controleer dan of nesting aanstaat.
Te veel vertrouwen op latest
Veel compose-voorbeelden gebruiken images met de tag latest.
Dat is makkelijk, maar kan onverwachte updates geven. Voor belangrijke services kun je beter een specifieke versie gebruiken of updates bewust uitvoeren.
Checklist
Controleer na installatie:
- docker --version werkt
- docker compose version werkt
- docker run hello-world werkt
- je gebruiker kan Docker gebruiken
- /opt/stacks bestaat
- je weet waar je compose-bestanden staan
- je begrijpt het verschil tussen hostpoort en containerpoort
- je begrijpt het verschil tussen hostpad en containerpad
- je hebt nagedacht over backups
- je opent alleen noodzakelijke poorten
Samenvatting
Docker en Docker Compose zijn een goede basis voor veel selfhosted applicaties.
De belangrijkste punten:
- gebruik de officiële Docker repository
- gebruik Compose met docker compose
- maak een duidelijke mappenstructuur
- /opt/stacks is een nette plek voor selfhosted compose-stacks
- gebruik volumes voor data
- onthoud bij poorten: hostpoort:containerpoort
- onthoud bij volumes: hostpad:containerpad
- update bewust
- maak backups
- publiceer services pas als je begrijpt wat je openzet
Vanaf hier kun je verder met bijvoorbeeld Nginx Proxy Manager, Uptime Kuma, Mealie, Vaultwarden of andere selfhosted services.