 Autor: [Adam Nadolny](/autorzy/adam-nadolny) Ekspert DevOps i infrastruktury · Zweryfikowano Kwiecień 2026

1.  [Strona główna](/) ›
2.  [Baza wiedzy](/baza-wiedzy/) ›
3.  Docker Compose w produkcji

# Docker Compose w produkcji — best practices

Opublikowano: 9 kwietnia 2026 · Kategoria: VPS / Docker

Docker Compose świetnie sprawdza się w developmencie. Ale produkcja ma inne wymagania: trwałe dane, izolacja sieci, bezpieczne sekrety, automatyczny restart po awarii. Oto kompletny przewodnik jak skonfigurować Compose na VPS tak, żeby nie budzić się w nocy z alertem.

## Pełny docker-compose.yml dla produkcji

Przykładowy stack: aplikacja Node.js + PostgreSQL + Nginx reverse proxy:

services:
  # Baza danych
  db:
    image: postgres:16-alpine
    restart: unless-stopped
    env\_file: .env          # Ładuje zmienne z pliku .env
    environment:
      POSTGRES\_DB: ${DB\_NAME}
      POSTGRES\_USER: ${DB\_USER}
      POSTGRES\_PASSWORD: ${DB\_PASSWORD}
    volumes:
      - db\_data:/var/lib/postgresql/data   # Named volume — persystentne dane
    networks:
      - backend
    healthcheck:
      test: \["CMD-SHELL", "pg\_isready -U ${DB\_USER} -d ${DB\_NAME}"\]
      interval: 10s
      timeout: 5s
      retries: 5
      start\_period: 30s

  # Aplikacja
  app:
    image: myapp:latest
    restart: unless-stopped
    env\_file: .env
    environment:
      DATABASE\_URL: postgresql://${DB\_USER}:${DB\_PASSWORD}@db:5432/${DB\_NAME}
      NODE\_ENV: production
    networks:
      - backend
      - frontend
    depends\_on:
      db:
        condition: service\_healthy   # Czeka aż DB jest gotowa
    healthcheck:
      test: \["CMD", "wget", "-qO-", "http://localhost:3000/health"\]
      interval: 30s
      timeout: 10s
      retries: 3
    deploy:
      resources:
        limits:
          memory: 512m      # Limit RAM
          cpus: '0.5'       # Limit CPU

  # Reverse proxy
  nginx:
    image: nginx:alpine
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro    # Bind mount — config
      - ./nginx/certs:/etc/nginx/certs:ro              # Certyfikaty SSL
      - nginx\_cache:/var/cache/nginx                   # Named volume — cache
    networks:
      - frontend
    depends\_on:
      - app

volumes:
  db\_data:
    driver: local
  nginx\_cache:
    driver: local

networks:
  backend:
    driver: bridge
    internal: true    # Brak dostępu z zewnątrz — tylko między serwisami
  frontend:
    driver: bridge

## Plik .env — bezpieczne sekrety

Plik `.env` trzyma wrażliwe dane. Nigdy nie commituj go do gita:

\# .env (dodaj do .gitignore!)
DB\_NAME=myapp\_prod
DB\_USER=myapp
DB\_PASSWORD=super\_secret\_password\_here
SECRET\_KEY=32\_char\_random\_string\_here
REDIS\_URL=redis://redis:6379

# Uprawnienia — tylko właściciel może czytać
chmod 600 .env

\# .env.example (commituj — szablon bez wartości)
DB\_NAME=
DB\_USER=
DB\_PASSWORD=
SECRET\_KEY=
REDIS\_URL=

## Healthchecks — automatyczna detekcja awarii

Healthchecks pozwalają Compose (i Docker) wiedzieć czy kontener naprawdę działa, a nie tylko że proces się uruchomił. Stany kontenera: `starting` → `healthy` lub `unhealthy`. Przy `unhealthy` można automatycznie zrestartować.

Parametr

Opis

Wartość domyślna

`interval`

Co ile sprawdzać

30s

`timeout`

Czas oczekiwania na odpowiedź

30s

`retries`

Ile nieudanych prób = unhealthy

3

`start_period`

Grace period przy starcie (błędy nie liczą się)

0s

## Deploy i aktualizacje

\# Podstawowe komendy produkcyjne

# Uruchom w tle
docker compose up -d

# Sprawdź stan
docker compose ps
docker compose logs -f app

# Aktualizacja aplikacji (pobierz nowy obraz + restart)
docker compose pull app
docker compose up -d app    # Zatrzymuje i startuje tylko zmieniony serwis

# Pełna aktualizacja wszystkich serwisów
docker compose pull
docker compose up -d

# Zatrzymaj bez usuwania danych
docker compose stop

# Usuń kontenery (dane w volumes są bezpieczne)
docker compose down

# NIEBEZPIECZNE: usuń kontenery + volumes (utrata danych!)
docker compose down -v

## Backup named volumes

\# Backup named volume do pliku tar
docker run --rm \\
  -v myapp\_db\_data:/data \\
  -v ${PWD}/backups:/backup \\
  alpine tar czf /backup/db\_data\_$(date +%Y%m%d).tar.gz -C /data .

# Restore z backupu
docker run --rm \\
  -v myapp\_db\_data:/data \\
  -v ${PWD}/backups:/backup \\
  alpine tar xzf /backup/db\_data\_20260409.tar.gz -C /data

## Traefik zamiast Nginx — automatyczne SSL

Traefik to nowoczesna alternatywa dla Nginx jako reverse proxy w środowisku Docker. Automatycznie wykrywa kontenery i wystawia certyfikaty Let's Encrypt bez konfiguracji ręcznej:

services:
  traefik:
    image: traefik:v3
    restart: unless-stopped
    command:
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.letsencrypt.acme.email=admin@example.com"
      - "--certificatesresolvers.letsencrypt.acme.storage=/certs/acme.json"
      - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - traefik\_certs:/certs
    networks:
      - frontend

  app:
    image: myapp:latest
    restart: unless-stopped
    networks:
      - frontend
      - backend
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.app.rule=Host(\`example.com\`)"
      - "traefik.http.routers.app.tls.certresolver=letsencrypt"
      - "traefik.http.services.app.loadbalancer.server.port=3000"

volumes:
  traefik\_certs:

networks:
  frontend:
  backend:
    internal: true

## Best practices — lista kontrolna

-   **restart: unless-stopped** na wszystkich serwisach produkcyjnych — kontenery restartują po restarcie hosta.
-   **Limity zasobów** — bez `deploy.resources.limits` jeden serwis może zagłodzić pozostałe z pamięci.
-   **Internal networks** — baza danych nie powinna mieć dostępu do internetu. Użyj `internal: true`.
-   **Read-only bind mounts** — dodaj `:ro` dla plików konfiguracyjnych (Nginx, certyfikaty).
-   **Pinuj wersje obrazów** — `postgres:16-alpine` zamiast `postgres:latest`. Unikasz niespodzianek po auto-update.
-   **Logowanie** — ustaw `logging.driver: json-file` z `max-size` i `max-file` żeby logi nie zapełniły dysku.

## Najczęstsze pytania

Czy Docker Compose nadaje się do produkcji? +

Tak, dla pojedynczego VPS lub małego klastra Docker Compose jest bardzo dobrym wyborem. Jest prostszy niż Kubernetes, ma mniejszy overhead i wystarczy dla zdecydowanej większości aplikacji webowych. Kubernetes warto rozważyć przy potrzebie automatycznego skalowania horyzontalnego (dziesiątki/setki nodów) lub gdy masz dedykowany DevOps team. Dla startupu lub aplikacji do kilku tysięcy użytkowników Compose + VPS to często najlepsza opcja.

Jak bezpiecznie przechowywać sekrety w Docker Compose? +

Najlepsza praktyka: plik .env z sekretami (w .gitignore), ładowany przez Compose jako env\_file. Nigdy nie hardcoduj haseł w docker-compose.yml — ten plik idzie do gita. Dla zaawansowanego podejścia: Docker Secrets (dla Swarm) lub zewnętrzny vault (HashiCorp Vault, AWS Secrets Manager). Na VPS produkcyjnym ustaw restrykcyjne uprawnienia: chmod 600 .env.

Jak wykonać rolling update bez przestoju w Docker Compose? +

Docker Compose (nie Swarm) nie ma wbudowanego rolling update. Strategie: (1) Blue-Green: odpal nową wersję na innym porcie, przestaw proxy (Nginx/Traefik), zatrzymaj starą. (2) Traefik jako reverse proxy z automatycznym service discovery — wykrywa nowe kontenery i przełącza ruch. (3) Dla Docker Swarm: deploy.update\_config z parallelism=1 i delay. Najprostszy pattern dla Compose: najpierw docker compose pull, potem docker compose up -d (Compose zatrzyma i uruchomi zmienione serwisy z minimalnym przestojem).

Jaka jest różnica między named volumes a bind mounts? +

Named volumes (volumes: db\_data:) są zarządzane przez Docker, przechowywane w /var/lib/docker/volumes/. Łatwiejsze w backupie (docker run --volumes-from), przenośne, działają lepiej na Linuksie (brak overhead filesystemu). Bind mounts (./data:/app/data) mapują katalog hosta bezpośrednio. Lepsze do developmentu (hot reload kodu), do konfiguracji na produkcji. W produkcji: named volumes dla danych (bazy, przesyłki), bind mounts dla plików konfiguracyjnych i certyfikatów.

## Sprawdź oferty pasujące do tego scenariusza

Poniżej masz szybkie przejścia do ofert i stron z kodami rabatowymi tam, gdzie są dostępne.

Contabo

VPS z dużym RAM — idealny dla Docker Compose z wieloma serwisami

Docker VPS

[Aktywuj rabat →](/out/contabo)

#Reklama · link partnerski

[Zobacz kod rabatowy →](/kody-rabatowe/contabo)

Mikrus

Tani VPS do nauki Docker Compose i testowania stacków

Tani VPS

[Aktywuj rabat →](/out/mikrus)

#Reklama · link partnerski

[Zobacz kod rabatowy →](/kody-rabatowe/mikrus)

## Powiązane strony

-   [Docker na VPS — instalacja i konfiguracja](/baza-wiedzy/docker-na-vps)
-   [Terraform — zarządzanie VPS jako kod](/baza-wiedzy/terraform-vps-infrastruktura)
-   [Nginx — konfiguracja virtual hostów](/baza-wiedzy/nginx-vhost-konfiguracja)
-   [Rsync — kopia zapasowa VPS](/baza-wiedzy/rsync-kopia-zapasowa-vps)
-   [Wszystkie artykuły](/baza-wiedzy/)