Natrag na blog
Kolovoz 19, 2026Vodiči

Kako raspoređivati aplikacije s Docker Compose na VPS

Praktičan produkcijski vodič za Docker Compose v2 na Ubuntu: instalacija mehanizma, Compose datoteka s mrežama i volumenima, tajne, obrnuti proxy ispred, ažuriranja bez panike i sigurnosne kopije imenovanih volumena.

Kako raspoređivati aplikacije s Docker Compose na VPS

Docker Compose uobičajen je način da na jednom VPS vodite mali stog: web aplikacija, baza, Redis predmemorija i obrnuti proxy u jednoj YAML datoteci. To nije Kubernetes. Nećete dobiti failover na više čvorova. Dobit ćete ponovljivo, pregledivo postavljanje koje za minute podignete na novom Hiddence VPS — upravo ono što većini sporednih projekata i malih proizvoda treba.

Ovaj članak pretpostavlja da želite nešto bliže produkciji od docker run u petak navečer. Instalirat ćemo Docker Engine i Compose dodatak, napraviti korisnika za raspoređivanje bez root u svakodnevici, napisati Compose datoteku s healthcheckovima i politikom restarta, tajne držati izvan Gita, na internet objaviti samo portove obrnutog proxyja i opisati rutinu ažuriranja i kopije. Primjer stoga je tipična web aplikacija plus PostgreSQL plus Caddy, ali isti obrazac radi za Node, PHP, Python ili skup radnika.

Zašto Compose na jednom VPS još ima smisla

Ljudi skaču na Kubernetes jer je moderno, pa vikend provedu nad YAML-om za jedan web. Compose ostaje čitljiv. Verzionirate datoteku, dokumentirate varijable okruženja i možete vidjeti diff izmjene prije primjene. Izolacija je dovoljna: kompromitirani kontejner aplikacije ne bi trebao držati UNIX utičnicu baze ako ste koristili mreže i korisnike s najmanjim privilegijama. Limiti resursa sprječavaju jedno curenje memorije da zamrzne cijeli VPS.

  • Jedna datoteka opisuje cijeli stog
  • Imenovani volumeni prežive ponovno stvaranje kontejnera
  • Unutarnje Docker mreže drže Postgres izvan javnog interneta
  • restart: unless-stopped pokriva većinu ponovnih pokretanja
  • Lako se kopira na drugi VPS kada prvi postane tjesan

Zahtjevi

Koristite VPS s dovoljno RAM za aplikaciju plus Postgres. Plan od 2 GB realističan je minimum za aplikaciju + bazu + proxy. Pretpostavlja se Ubuntu 24.04. Ne instalirajte Docker iz slučajnog Snap-a bez čitanja što radi s cgroups; koraci ispod koriste službeni Docker apt repozitorij.

  • Ubuntu 22.04/24.04, root ili sudo
  • Preporučeno 2 GB RAM (1 GB samo za sićušne stogove bez Postgres)
  • Domena koja pokazuje na VPS ako želite automatski HTTPS
  • Git ili drugi način da kopirate projekt na poslužitelj

Korak 1. Instalirajte Docker Engine i Compose v2

Compose v2 dodatak je koji se poziva kao docker compose (s razmakom), ne stari python binarni docker-compose. Instalirajte oba iz Docker repozitorija da dobivate aktualne sigurnosne zakrpe.

bash
ssh root@YOUR_VPS_IP
apt update && apt -y install ca-certificates curl gnupg
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

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null

apt update
apt -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

docker version
docker compose version

Korak 2. Korisnik za raspoređivanje i raspored direktorija

Compose kao root radi, ali namjenski korisnik u grupi docker čišći je. Projekt stavite u /opt ili /srv, ne u /root, da su kopije i dopuštenja očita. Nikad ne dajte svijetu pisanje u direktorij s .env.

bash
adduser --disabled-password --gecos '' deploy
usermod -aG docker deploy
mkdir -p /srv/app
chown deploy:deploy /srv/app
chmod 750 /srv/app

# Log in as deploy for the rest of the file editing:
# su - deploy
# cd /srv/app

Korak 3. Napišite Compose datoteku s produkcijskom pameti

Datoteka ispod predložak je. Zamijenite image aplikacije svojim. Postgres nije objavljen na 0.0.0.0:5432 — van ide samo Caddy na 80 i 443. Healthcheckovi sprječavaju obrnuti proxy da šalje promet aplikaciji koja još migrira bazu. Pričvrstite oznake imagea; latest je kako dolaze iznenadna pucanja.

bash
# /srv/app/compose.yaml
services:
  caddy:
    image: caddy:2.8-alpine
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
      - caddy_config:/config
    depends_on:
      app:
        condition: service_healthy

  app:
    image: ghcr.io/example/webapp:1.4.2
    restart: unless-stopped
    env_file: .env
    environment:
      DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}
    depends_on:
      db:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-fsS", "http://127.0.0.1:8000/health"]
      interval: 10s
      timeout: 3s
      retries: 10
    networks:
      - frontend
      - backend

  db:
    image: postgres:16-alpine
    restart: unless-stopped
    env_file: .env
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
      interval: 10s
      timeout: 5s
      retries: 10
    networks:
      - backend

networks:
  frontend: {}
  backend: {}

volumes:
  pgdata:
  caddy_data:
  caddy_config:

Korak 4. Tajne, .env i Caddyfile

Lozinke stavite u .env na poslužitelju, chmod 600, i nikad ne commitajte tu datoteku. Generirajte lozinke s openssl rand -base64 32. Caddyfile treba samo obrnuto proksirati na ime usluge aplikacije u Docker mreži.

bash
# /srv/app/.env (permissions 600)
POSTGRES_USER=app
POSTGRES_PASSWORD=change-me-long-random
POSTGRES_DB=app
# plus any APP_SECRET / NEXTAUTH_SECRET your image needs

# /srv/app/Caddyfile
app.example.com {
    encode gzip
    reverse_proxy app:8000
}

chmod 600 /srv/app/.env
cd /srv/app
docker compose up -d
docker compose ps
docker compose logs -f --tail=100

Korak 5. Vatrozid, zapisnici i limiti resursa

UFW treba dopustiti samo 22, 80 i 443. Docker ponekad zaobiđe UFW za objavljene portove; ako treba strogi vatrozid na hostu, pogledajte aktualnu interakciju Docker + UFW za vaš Ubuntu ili objavite portove samo na 127.0.0.1 i stavite Caddy na host. Postavite limite memorije u Compose da Postgres ne pojede VPS.

bash
ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable

# Optional in compose.yaml under app or db:
#    deploy:
#      resources:
#        limits:
#          memory: 512M

# Logs (do not let json-file grow forever):
# { "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } }
# in /etc/docker/daemon.json then: systemctl restart docker

Korak 6. Ažuriranja i vraćanja

Dosadno ažuriranje koje radi: povucite nove imagee, up -d, gledajte healthcheckove, držite prethodnu oznaku u gitu da se vratite. Ne radite docker compose down na produkcijskoj bazi osim ako namjeravate prestati primati promet. down -v briše volumene — to je brisanje, ne restart.

bash
cd /srv/app
git pull   # if the Compose file lives in git

# Change the image tag in compose.yaml, then:
docker compose pull
docker compose up -d
docker compose ps

# Rollback: set the old tag, pull, up -d again
# NEVER: docker compose down -v   # this deletes named volumes

Napravite sigurnosne kopije imenovanih volumena

Snimka VPS dobra je. Logički dump Postgresa bolji je ako vraćate na drugo računalo. Zakažite to cronom. Jednom testirajte vraćanje, inače nemate kopije — imate datoteke za koje se nadate da su kopije.

bash
# Postgres dump while the db container is running:
docker compose exec -T db pg_dump -U app app | gzip > /var/backups/app-$(date +%F).sql.gz

# Copy off-box
# scp /var/backups/app-*.sql.gz backup-host:~

# Restore sketch (maintenance window):
# gunzip -c app-2026-08-19.sql.gz | docker compose exec -T db psql -U app app

Rješavanje problema

Čitajte docker compose ps i docker compose logs usluga. Neuspjesi povlačenja imagea obično su limiti ghcr/Docker Hub ili privatni image bez prijave. 502 od Caddyja znači da aplikacija nije zdrava ili je hostname proxyja pogrešan (iz Caddy kontejnera koristite ime Compose usluge, ne localhost). Pogreške dopuštenja na volumenima često znače da image radi kao uid 1000 dok je direktorij na hostu root.

  • compose: command not found — instalirali ste staro ime binarne datoteke; koristite docker compose
  • port is already allocated — nešto drugo drži 80/443 (Apache, Nginx, drugi Caddy)
  • database connection refused — aplikacija je krenula prije nego što je Postgres spreman; healthcheck + depends_on s condition
  • disk pun — docker system df, zatim oprezan prune neiskorištenih imagea
  • permission denied na docker.sock — korisnik nije u grupi docker ili treba nova sesija prijave

Sigurnost

Ne objavljujte portove baze. Ne uključujte privileged: true. Ne montirajte /var/run/docker.sock u kontejner aplikacije osim ako namjerno pišete upravitelj kontejnera. Držite mehanizam ažurnim. Skenirajte vlastite imagee ako ih gradite. .env na disku i dalje je tajna datoteka — ograničite tko može ssh na kutiju.

  • Nema javnih 5432 / 3306 / 6379
  • Pričvrstite digest imagea ili barem nepromjenjive oznake
  • chmod 600 .env
  • Unattended-upgrades host OS-a i dalje vrijede
  • Jedan Compose projekt po aplikaciji smanjuje radijus oštećenja

Savjeti

  • compose.yaml u gitu; .env.example bez pravih tajni
  • Profili za opcionalne radnike (docker compose --profile workers up -d)
  • Gledajte docker stats kada dimenzionirate VPS
  • Bind mount izvornog koda nije produkcijski obrazac — ispecite image
  • Kada stog poraste na nekoliko VPS, tek tada gledajte orkestraciju — ne ranije

Produkcijskiji Compose na jednom VPS je: službeni Docker paketi, zaključan .env, YAML koji ne objavljuje bazu, healthcheckovi, obrnuti proxy na 80/443, UFW, oznake imagea na koje se možete vratiti i dumpovi Postgresa koje ste barem jednom vratili. Počnite od predloška u ovom članku, zamijenite image aplikacije i docker compose down -v tretirajte kao destruktivnu naredbu s istim poštovanjem kao rm -rf.