Naar de inhoud
Actuele kortingscode:10% kortingGebruiken bij je bestelling

Docker en Docker Compose op een VPS: installatie en je eerste applicatie

Je installeert Docker vanuit de officiële repository, start WordPress met MariaDB via Docker Compose en leert containers beheren, updaten, back-uppen en met de firewall beschermen.

  • gevorderd
  • ~25 min
  • Bijgewerkt op 1-10-2026

Docker draait applicaties in geïsoleerde containers die alles wat ze nodig hebben met zich meebrengen. We installeren het vanuit de officiële repository, starten via Docker Compose WordPress met een database en lopen het beheer, de updates, de firewall en de back-ups door.

Wat je nodig hebt

  • Een VPS bij StormHost met Ubuntu 24.04 of Debian 13
  • Een SSH-verbinding als root (handleiding)
  • Voor WordPress met HTTPS een domein dat naar de VPS verwijst
  • Ongeveer 25 minuten

Hoe het werkt#

BegripWat het is
ImageEen kant-en-klaar sjabloon van een applicatie: systeembibliotheken, het programma en de instellingen ervan. Je downloadt het uit een registry, meestal Docker Hub (bijvoorbeeld wordpress, mariadb).
ContainerEen draaiende instantie van een image. Hij heeft een eigen bestandssysteem en netwerk, maar deelt de kernel met de VPS. Een container kun je op elk moment verwijderen en opnieuw aanmaken vanuit hetzelfde image.
VolumePermanente opslag voor gegevens buiten de container. Gegevens in een volume overleven het verwijderen en het updaten van de container. Alles wat bewaard moet blijven, moet in een volume staan.
PoortEen container heeft een eigen netwerk. Om hem van buitenaf bereikbaar te maken, wordt zijn poort “gepubliceerd” op een poort van de VPS.
Docker ComposeEen tool die op basis van één bestand compose.yaml een hele applicatie start die uit meerdere containers bestaat (bijvoorbeeld een website en een database).

Installatie#

Installeer Docker vanuit de officiële repository van Docker. Het pakket docker.io uit de repository van de distributie is meestal ouder en botst met de officiële pakketten.

Verwijder eerst eventuele conflicterende pakketten. Op een schone VPS vindt het commando niets, dat is in orde.

Ubuntu 24.04

bash
apt remove $(dpkg --get-selections docker.io docker-compose docker-compose-v2 docker-doc docker-buildx podman-docker containerd runc | cut -f1)

Debian 13

bash
apt remove $(dpkg --get-selections docker.io docker-compose docker-doc docker-buildx podman-docker containerd runc | cut -f1)
  • dpkg --get-selections … – toont welke van de genoemde pakketten geïnstalleerd zijn.
  • | cut -f1 – laat van de uitvoer alleen de pakketnamen over.
  • apt remove $(…) – verwijdert ze. De gegevens in /var/lib/docker blijven staan.

Voeg daarna de repository van Docker toe en installeer Docker:

Ubuntu 24.04

bash
apt update
apt -y install ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
apt update
apt -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Debian 13

bash
apt update
apt -y install ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/debian
Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
apt update
apt -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Wat de afzonderlijke regels doen:

CommandoWat het doet
apt -y install ca-certificates curlCertificaten voor HTTPS en een downloadprogramma.
install -m 0755 -d /etc/apt/keyringsMaakt een map aan voor de ondertekeningssleutels van repository's, met de rechten 0755.
curl -fsSL …/gpg -o /etc/apt/keyrings/docker.ascDownloadt de ondertekeningssleutel van Docker. -f = bij een HTTP-fout met een fout stoppen, -s = stil, -S = fouten tonen, -L = omleidingen volgen.
chmod a+r …/docker.ascIedereen mag de sleutel lezen (apt leest hem als een andere gebruiker).
tee /etc/apt/sources.list.d/docker.sources <<EOF … EOFSchrijft de beschrijving van de repository naar een bestand.
Types: debEen repository met binaire pakketten.
URIs:Het adres van de repository voor jouw systeem.
Suites: $(…)De codenaam van het systeem (noble voor Ubuntu 24.04, trixie voor Debian 13), wordt vanzelf ingevuld.
Components: stableAlleen stabiele releases.
Architectures: $(dpkg --print-architecture)De processorarchitectuur (amd64).
Signed-By:Pakketten moeten met deze sleutel ondertekend zijn, anders weigert apt ze.
apt -y install docker-ce …Installeert Docker Engine (docker-ce), de opdrachtregel (docker-ce-cli), de runtime voor containers (containerd.io), het bouwen van images (docker-buildx-plugin) en Compose (docker-compose-plugin).

Docker start na de installatie vanzelf en start voortaan automatisch mee met de VPS. Controleer de installatie:

bash
docker run --rm hello-world
docker compose version
  • docker run --rm hello-world – downloadt een testimage en start het; --rm verwijdert de container zodra hij klaar is. Je ziet Hello from Docker!.
  • docker compose version – toont de versie van Compose, bijvoorbeeld Docker Compose version v5.…. Na versie 2 is Compose meteen naar nummer 5 gegaan, oudere installaties tonen daarom v2.…. De commando's in deze handleiding werken in beide.

De groep docker = rootrechten

Wie in de groep docker zit, kan containers starten met toegang tot de hele schijf van de VPS en heeft dus in feite rootrechten. Voeg alleen mensen aan de groep toe aan wie je ook root zou geven. Werk je als root, dan heb je de groep niet nodig.

Eerste applicatie: WordPress met MariaDB#

Project en wachtwoorden#

  1. Maak de projectmap aan en ga erheen:

    bash
    mkdir -p /opt/wordpress
    cd /opt/wordpress

    De naam van de map (wordpress) wordt de naam van het Compose-project en het voorvoegsel van de namen van containers en volumes.

  2. Maak een bestand met wachtwoorden aan met nano .env. Genereer de wachtwoorden in de wachtwoordgenerator (alleen letters en cijfers):

    /opt/wordpress/.envini
    DB_PASSWORD=<DATABASE_PASSWORD>
    DB_ROOT_PASSWORD=<DATABASE_ROOT_PASSWORD>
    • DB_PASSWORD – het wachtwoord van de databasegebruiker van WordPress.
    • DB_ROOT_PASSWORD – het wachtwoord van de gebruiker root binnen de databasecontainer (voor back-ups en beheer).
  3. Zorg dat alleen root het bestand kan lezen:

    bash
    chmod 600 .env

Het bestand compose.yaml#

Maak met nano compose.yaml een bestand aan met deze inhoud:

/opt/wordpress/compose.yamlYAML
services:
  db:
    image: mariadb:lts
    restart: unless-stopped
    environment:
      MARIADB_DATABASE: wordpress
      MARIADB_USER: wordpress
      MARIADB_PASSWORD: ${DB_PASSWORD}
      MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
    volumes:
      - db_data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
      start_period: 10s
      interval: 10s
      timeout: 5s
      retries: 3

  wordpress:
    image: wordpress:latest
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
    ports:
      - "127.0.0.1:8080:80"
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: ${DB_PASSWORD}
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - wp_data:/var/www/html

volumes:
  db_data:
  wp_data:

Regel voor regel:

RegelWat het doet
services:De lijst met containers van de applicatie. De naam van de service (db, wordpress) dient ook als naam in het netwerk van het project.
image: mariadb:ltsHet officiële image van MariaDB, de tag lts = de nieuwste versie met langdurige ondersteuning.
restart: unless-stoppedDe container start na een crash en na een herstart van de VPS opnieuw, tenzij je hem zelf hebt gestopt.
MARIADB_DATABASE, MARIADB_USER, MARIADB_PASSWORDMaakt bij de eerste start de database en een gebruiker met wachtwoord aan.
MARIADB_ROOT_PASSWORDHet wachtwoord van de root van de database, wordt bij de eerste start ingesteld.
${DB_PASSWORD}De waarde wordt ingevuld vanuit het bestand .env in dezelfde map. Zo staan de wachtwoorden niet rechtstreeks in compose.yaml.
volumes: - db_data:/var/lib/mysqlDe gegevens van de database worden opgeslagen in het volume db_data, zodat ze een update van de container overleven.
healthcheck:Docker controleert elke 10 s met het script healthcheck.sh uit het image van MariaDB of de database verbindingen accepteert en geïnitialiseerd is.
depends_on: db: condition: service_healthyWordPress start pas op het moment dat de database gereed is.
image: wordpress:latestHet officiële image van WordPress (Apache + PHP).
ports: - "127.0.0.1:8080:80"Poort 80 van de container is bereikbaar op poort 8080 van de VPS, maar alleen vanaf de VPS zelf (127.0.0.1). Van buitenaf is hij alleen via Nginx te bereiken.
WORDPRESS_DB_HOST: dbHet adres van de database: de naam van de service db in het netwerk van het project.
WORDPRESS_DB_USER, …_PASSWORD, …_NAMEDe inloggegevens voor de database; ze moeten overeenkomen met de waarden bij de service db.
volumes: - wp_data:/var/www/htmlDe bestanden van WordPress (plugins, thema's, geüploade afbeeldingen) staan in het volume wp_data.
volumes: aan het eindDe declaratie van de benoemde volumes die het project gebruikt.

Starten#

bash
docker compose up -d
docker compose ps
  • docker compose up -d – downloadt de images, maakt het netwerk, de volumes en de containers aan en start ze op de achtergrond (-d, detached).
  • docker compose ps – toont de containers van het project en hun status. Bij db zie je healthy, bij wordpress Up.

Controle vanaf de VPS: curl -I http://127.0.0.1:8080 geeft de headers van het antwoord van WordPress terug (een omleiding naar de installatie).

De variabelen MARIADB_* gelden alleen bij de eerste start

De database wordt aangemaakt bij de eerste start met een leeg volume. Wijzig je het wachtwoord later in .env, dan verandert het wachtwoord in de database niet. Wijzig het wachtwoord in de database met het commando ALTER USER (zie MariaDB op een VPS) en pas daarna in .env.

Bereikbaar maken via Nginx en HTTPS#

WordPress luistert nu alleen op 127.0.0.1:8080. Je maakt het bereikbaar via Nginx als reverse proxy volgens de handleiding Nginx en HTTPS: gebruik in de configuratie proxy_pass http://127.0.0.1:8080; en je domein, bijvoorbeeld blog.example.cz, en vraag daarna een certificaat aan met certbot --nginx -d blog.example.cz.

Het image van WordPress herkent HTTPS zelf aan de header X-Forwarded-Proto, die Nginx volgens de handleiding meestuurt. Open tot slot https://blog.example.cz en rond de installatie van WordPress af in je browser.

Containers beheren#

Voer de commando's docker compose uit in de projectmap (cd /opt/wordpress).

CommandoWat het doet
docker compose psDe status van de containers van het project.
docker compose logs -fDe logs van alle services; -f = doorlopend volgen (stoppen met Ctrl+C). Alleen één service: docker compose logs -f wordpress.
docker compose restartHerstart de containers.
docker compose stop / startStopt / start de containers, verwijdert niets.
docker compose up -dMaakt na een wijziging van compose.yaml alleen de gewijzigde containers opnieuw aan.
docker compose downStopt en verwijdert de containers en het netwerk. De volumes met gegevens blijven staan.
docker compose exec db mariadb -uroot -pVoert een commando uit binnen een draaiende container (hier de console van MariaDB).
docker compose configControleert compose.yaml en toont het met de ingevulde waarden uit .env (let op, ook de wachtwoorden worden getoond).

Updaten naar nieuwe versies van de images:

bash
docker compose pull
docker compose up -d
docker image prune -f
  • docker compose pull – downloadt nieuwe versies van de images.
  • docker compose up -d – maakt de containers waarvoor een nieuwer image is opnieuw aan. De gegevens in de volumes blijven staan.
  • docker image prune -f – verwijdert oude images die niet meer worden gebruikt; -f zonder bevestiging.

docker compose down -v verwijdert gegevens

De optie -v bij docker compose down verwijdert ook de volumes van het project, dus de database en de bestanden van WordPress. Dit is niet terug te draaien. Gebruik de optie alleen als je de applicatie helemaal wilt verwijderen en een back-up hebt.

Mogelijke waarden voor restart::

WaardeWanneer de container opnieuw start
noNooit (standaard).
alwaysAltijd, ook als je hem handmatig hebt gestopt (na een herstart van Docker of de VPS).
on-failureAlleen als hij met een fout eindigt.
unless-stoppedAltijd, behalve als je hem zelf hebt gestopt. Aanbevolen voor services.

Poorten en firewall#

Docker publiceert de poorten van containers met eigen firewallregels die UFW omzeilen. Een poort die als 8080:80 is gepubliceerd, is bereikbaar vanaf internet, ook als je hem in UFW niet toestaat. De handleiding UFW-firewall legt dit uitgebreid uit.

Notatie in ports:Wie de poort kan bereiken
"8080:80"Iedereen op internet, ongeacht UFW.
"127.0.0.1:8080:80"Alleen processen op de VPS (bijvoorbeeld Nginx). Aanbevolen voor websites achter Nginx.
zonder ports:Alleen de andere containers in hetzelfde netwerk van het project (meestal een database).

Publiceer een database en andere interne services helemaal niet. Poorten die openbaar moeten zijn (bijvoorbeeld een gameserver in een container), beperk je met de firewall in je klantaccount (handleiding). Die staat vóór de VPS en Docker kan hem niet omzeilen.

Schijfruimte opruimen#

Images, gestopte containers en logs nemen na verloop van tijd veel ruimte in.

bash
docker system df
docker system prune
  • docker system df – hoeveel ruimte de images, containers, volumes en cache innemen.
  • docker system prune – verwijdert na bevestiging gestopte containers, ongebruikte netwerken, images zonder naam en de buildcache. Volumes met gegevens verwijdert het zonder de optie --volumes niet.

Voorzichtig met het verwijderen van volumes en met -a

docker system prune --volumes verwijdert ook ongebruikte anonieme volumes (zonder naam, ze ontstaan bijvoorbeeld bij docker run zonder -v). Stonden daarin gegevens van een container die op dat moment verwijderd of gestopt is, dan zijn ze weg. docker volume prune -a verwijdert ook benoemde volumes zoals wordpress_db_data als geen enkele container ze gebruikt, bijvoorbeeld na docker compose down. docker system prune -a verwijdert alle images die door geen enkele container worden gebruikt. Lees vóór het bevestigen wat het commando aangeeft te gaan verwijderen.

De logs van containers worden standaard niet geroteerd en kunnen de schijf vullen. Stel de driver local in, die oude logs zelf verwijdert (standaard bewaart hij hoogstens 5 bestanden van 20 MB per container). Maak met nano /etc/docker/daemon.json een bestand aan met de inhoud hieronder. Bestaat het bestand al, overschrijf het dan niet, maar voeg er alleen de regel "log-driver" aan toe (items gescheiden door een komma):

/etc/docker/daemon.jsonJSON
{
  "log-driver": "local"
}

Herstart daarna Docker (systemctl restart docker) en maak de containers opnieuw aan (docker compose up -d --force-recreate). De instelling geldt alleen voor nieuw aangemaakte containers.

Back-ups#

Maak een back-up van de volumes, niet van de containers. Een container maak je opnieuw aan vanuit het image, de gegevens niet.

  1. Maak een map voor de back-ups aan: mkdir -p /root/zalohy.

  2. Maak een back-up van de database met een export (consistenter dan een kopie van de bestanden):

    bash
    cd /opt/wordpress
    docker compose exec -T db sh -c 'exec mariadb-dump --single-transaction --all-databases -uroot -p"$MARIADB_ROOT_PASSWORD"' > /root/zalohy/wp-db-$(date +%F).sql
    • docker compose exec -T db – voert een commando uit in de container db; -T schakelt de terminal uit, zodat de uitvoer naar een bestand kan worden omgeleid.
    • sh -c '…' – het commando wordt uitgevoerd in de shell van de container, waar de variabele $MARIADB_ROOT_PASSWORD is ingesteld.
    • mariadb-dump --single-transaction --all-databases – een export van alle databases zonder vergrendeling.
    • > /root/zalohy/… – de uitvoer wordt op de VPS opgeslagen, buiten de container.
  3. Maak een back-up van de bestanden van WordPress door het volume in te pakken:

    bash
    docker run --rm -v wordpress_wp_data:/data:ro -v /root/zalohy:/backup alpine tar czf /backup/wp-files-$(date +%F).tar.gz -C /data .
    • docker run --rm – start een eenmalige container die na afloop wordt verwijderd.
    • -v wordpress_wp_data:/data:ro – koppelt het volume wp_data van het project wordpress alleen-lezen (ro).
    • -v /root/zalohy:/backup – koppelt de back-upmap van de VPS.
    • alpine tar czf … -C /data . – pakt in het kleine image Alpine de inhoud van het volume in een archief in.

    De exacte namen van de volumes toont docker volume ls.

Het automatisch starten van back-ups met cron en het overzetten ervan naar een plek buiten de VPS staat beschreven in de handleiding Back-ups op een VPS.

Controle#

  • docker compose ps toont beide containers als draaiend en de database als healthy.
  • https://blog.example.cz toont WordPress met een slotje in de adresbalk.
  • Na een herstart van de VPS (reboot) starten de containers vanzelf.
  • Vanaf een andere computer kun je geen verbinding maken met http://<VPS_IP_ADDRESS>:8080 (de poort staat alleen op 127.0.0.1).

Als iets niet werkt#

permission denied while trying to connect to the Docker daemon socket#

Je bent geen root en je gebruiker zit niet in de groep docker. Voer het commando uit met sudo, of log in als root.

Bind for 127.0.0.1:8080 failed: port is already allocated of address already in use#

Poort 8080 wordt al gebruikt door een andere container (eerste melding) of door een ander programma op de VPS (tweede melding). Zoek uit welk (ss -tlnp | grep 8080, docker ps) en kies in compose.yaml een andere poort, bijvoorbeeld 127.0.0.1:8081:80. Pas daarna ook proxy_pass in Nginx aan.

WordPress meldt “Error establishing a database connection”#

De database is nog niet gereed of de inloggegevens kloppen niet. Bekijk de log van de database (docker compose logs db). Heb je het wachtwoord in .env pas na de eerste start gewijzigd, dan heeft de database nog steeds het oude wachtwoord (zie de waarschuwing in het hoofdstuk Starten).

De container blijft in de status Restarting#

De applicatie in de container crasht meteen na het starten. De oorzaak vind je in de log: docker compose logs --tail 50 <SERVICE_NAME>.

toomanyrequests: You have reached your unauthenticated pull rate limit#

Docker Hub beperkt het downloaden van images zonder in te loggen tot 100 per 6 uur vanaf één IP-adres. Wacht even, of log in met je Docker Hub-account: docker login.

no space left on device#

De schijf is vol. Zoek uit wat de ruimte inneemt (docker system df, df -h) en ruim op volgens het hoofdstuk Schijfruimte opruimen. Kom je echt ruimte tekort, verhoog dan het RAM op het tabblad Pakket wijzigen, de schijf groeit mee met het geheugen.

Samenvatting

  • Installeer Docker vanuit de officiële repository download.docker.com, niet het pakket docker.io.
  • Gegevens horen in volumes; containers kun je op elk moment verwijderen en opnieuw aanmaken.
  • Publiceer websites op 127.0.0.1 en maak ze bereikbaar via Nginx met HTTPS; anders omzeilt Docker UFW.
  • Updaten: docker compose pull en docker compose up -d.
  • docker compose down -v en prune --volumes verwijderen gegevens, maak regelmatig een back-up van de volumes.

Was deze handleiding nuttig?

Geldt voor

  • Ubuntu 24.04
  • Debian 13
  • Docker Engine
  • Docker Compose v2 en nieuwer

Diensten

Fout in de handleiding melden

Zoeken in de handleidingen