Πίσω στο blog
Αύγουστος 19, 2026Οδηγοί

Πώς να αναπτύξετε εφαρμογές με Docker Compose σε ένα VPS

Πρακτικός οδηγός παραγωγής για Docker Compose v2 σε Ubuntu: εγκαταστήστε τη μηχανή, γράψτε αρχείο Compose με δίκτυα και τόμους, διαχειριστείτε μυστικά, βάλτε αντίστροφο διαμεσολαβητή μπροστά, ενημερώστε με ήρεμες κυκλοφορίες και δημιουργήστε αντίγραφα ασφαλείας επώνυμων τόμων.

Πώς να αναπτύξετε εφαρμογές με Docker Compose σε ένα VPS

Το Docker Compose είναι ο συνηθισμένος τρόπος να τρέξετε μικρή στοίβα σε ένα VPS: εφαρμογή ιστού, βάση δεδομένων, προσωρινή μνήμη Redis και αντίστροφος διαμεσολαβητής, περιγραμμένα σε ένα αρχείο YAML. Δεν είναι Kubernetes. Δεν θα πάρετε εναλλαγή πολλαπλών κόμβων. Θα πάρετε επαναλήψιμη, ελέγξιμη ρύθμιση που μπορείτε να ξαναδημιουργήσετε σε νέο VPS Hiddence σε λεπτά — ακριβώς αυτό που χρειάζονται τα περισσότερα παράλληλα έργα και μικρά προϊόντα.

Αυτό το άρθρο υποθέτει ότι θέλετε κάτι πιο κοντά στην παραγωγή από docker run ένα βράδυ Παρασκευής. Θα εγκαταστήσουμε Docker Engine και το πρόσθετο Compose, θα δημιουργήσουμε χρήστη ανάπτυξης χωρίς root, θα γράψουμε αρχείο Compose με healthcheck και πολιτικές επανεκκίνησης, θα κρατήσουμε μυστικά εκτός Git, θα δημοσιεύσουμε μόνο τις θύρες του αντίστροφου διαμεσολαβητή στο διαδίκτυο και θα ορίσουμε ρουτίνα ενημέρωσης και αντιγράφων ασφαλείας. Η στοίβα παραδείγματος είναι τυπική εφαρμογή ιστού συν PostgreSQL συν Caddy, αλλά το ίδιο μοτίβο λειτουργεί για Node, PHP, Python ή σωρό εργατών.

Γιατί το Compose σε ένα VPS εξακολουθεί να έχει νόημα

Οι άνθρωποι πηδάνε στο Kubernetes επειδή είναι της μόδας και μετά περνούν το σαββατοκύριακο σε YAML για έναν ιστότοπο. Το Compose μένει αναγνώσιμο. Εκδίδετε το αρχείο, τεκμηριώνετε μεταβλητές περιβάλλοντος και μπορείτε να συγκρίνετε μια αλλαγή πριν την εφαρμόσετε. Η απομόνωση είναι αρκετή: ένα παραβιασμένο κοντέινερ εφαρμογής δεν πρέπει να κρατά το UNIX socket της βάσης αν χρησιμοποιήσατε δίκτυα και χρήστες ελάχιστων προνομίων. Τα όρια πόρων σταματούν μια διαρροή μνήμης από το να παγώσει όλο το VPS.

  • Ένα αρχείο περιγράφει όλη τη στοίβα
  • Οι επώνυμοι τόμοι επιβιώνουν την αναδημιουργία κοντέινερ
  • Τα εσωτερικά δίκτυα Docker κρατούν την Postgres εκτός του δημόσιου διαδικτύου
  • restart: unless-stopped καλύπτει τις περισσότερες επανεκκινήσεις
  • Εύκολο να αντιγραφεί σε δεύτερο VPS όταν ξεπεράσετε το πρώτο

Απαιτήσεις

Χρησιμοποιήστε VPS με αρκετή RAM για την εφαρμογή συν Postgres. Πλάνο 2 GB είναι ρεαλιστικό ελάχιστο για εφαρμογή + βάση + διαμεσολαβητή. Υποτίθεται Ubuntu 24.04. Μην εγκαταστήσετε Docker από τυχαίο Snap χωρίς να διαβάσετε τι κάνει στα cgroups· τα παρακάτω βήματα χρησιμοποιούν το επίσημο αποθετήριο apt της Docker.

  • Ubuntu 22.04/24.04, root ή sudo
  • Συνιστώνται 2 GB RAM (1 GB μόνο για μικροσκοπικές στοίβες χωρίς Postgres)
  • Τομέας που δείχνει στο VPS αν θέλετε αυτόματο HTTPS
  • Git ή άλλος τρόπος να αντιγράψετε το έργο στον διακομιστή

Βήμα 1: Εγκαταστήστε Docker Engine και Compose v2

Το Compose v2 είναι πρόσθετο που καλείται ως docker compose (με κενό), όχι το παλιό δυαδικό docker-compose της Python. Εγκαταστήστε και τα δύο από το αποθετήριο Docker ώστε να παίρνετε τρέχουσες ενημερώσεις ασφαλείας.

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

Βήμα 2: Χρήστης ανάπτυξης και διάταξη καταλόγων

Η εκτέλεση Compose ως root λειτουργεί, αλλά αφιερωμένος χρήστης με μέλος στην ομάδα docker είναι καθαρότερος. Βάλτε το έργο στο /opt ή /srv, όχι στο /root, ώστε αντίγραφα ασφαλείας και δικαιώματα να είναι προφανή. Μην κάνετε ποτέ εγγράψιμο από όλους τον κατάλογο που περιέχει .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

Βήμα 3: Γράψτε αρχείο Compose με νοοτροπία παραγωγής

Το παρακάτω αρχείο είναι πρότυπο. Αντικαταστήστε την εικόνα εφαρμογής με τη δική σας. Η Postgres δεν δημοσιεύεται στο 0.0.0.0:5432 — μόνο το Caddy δημοσιεύεται στις 80 και 443. Τα healthcheck σταματούν έναν αντίστροφο διαμεσολαβητή από το να στέλνει κίνηση σε εφαρμογή που ακόμη μεταφέρει τη βάση. Καρφιτσώστε ετικέτες εικόνων· το latest είναι πώς συμβαίνουν ξαφνικά σπασίματα.

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:

Βήμα 4: Μυστικά, .env και Caddyfile

Βάλτε κωδικούς στο .env στον διακομιστή, chmod 600, και μην κάνετε ποτέ commit αυτό το αρχείο. Δημιουργήστε κωδικούς με openssl rand -base64 32. Το Caddyfile χρειάζεται μόνο να κάνει αντίστροφο διαμεσολαβητή στο όνομα υπηρεσίας της εφαρμογής στο δίκτυο Docker.

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

Βήμα 5: Τείχος προστασίας, αρχεία καταγραφής και όρια πόρων

Το UFW πρέπει να επιτρέπει μόνο 22, 80 και 443. Το Docker μερικές φορές παρακάμπτει το UFW για δημοσιευμένες θύρες· αν χρειάζεστε αυστηρό τείχος προστασίας κεντρικού, κοιτάξτε την τρέχουσα αλληλεπίδραση Docker + UFW για την έκδοση Ubuntu σας ή δημοσιεύστε θύρες μόνο στο 127.0.0.1 και βάλτε Caddy κεντρικού μπροστά. Ορίστε όρια μνήμης στο Compose ώστε η Postgres να μην μπορεί να φάει το 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

Βήμα 6: Ενημερώσεις και επαναφορές

Η βαρετή ενημέρωση που λειτουργεί: τραβήξτε νέες εικόνες, up -d, παρακολουθήστε healthcheck, κρατήστε την προηγούμενη ετικέτα στο git ώστε να μπορείτε να καρφιτσώσετε πίσω. Μην κάνετε docker compose down σε βάση παραγωγής εκτός αν σκοπεύετε να σταματήσετε να δέχεστε κίνηση. Το down -v διαγράφει τόμους — αυτό είναι σκούπισμα, όχι επανεκκίνηση.

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

Αντίγραφα ασφαλείας επώνυμων τόμων

Ένα στιγμιότυπο VPS είναι καλό. Ένα λογικό dump Postgres είναι καλύτερο αν χρειάζεται να επαναφέρετε σε άλλο μηχάνημα. Προγραμματίστε το με cron. Δοκιμάστε μία επαναφορά μία φορά, αλλιώς δεν έχετε αντίγραφα ασφαλείας — έχετε αρχεία που ελπίζετε ότι είναι αντίγραφα ασφαλείας.

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

Αντιμετώπιση προβλημάτων

Διαβάστε docker compose ps και docker compose logs service. Αποτυχίες έλξης εικόνας είναι συνήθως όρια ρυθμού ghcr/docker hub ή ιδιωτική εικόνα χωρίς σύνδεση. 502 από Caddy σημαίνει ότι η εφαρμογή δεν είναι healthy ή το όνομα κεντρικού διαμεσολαβητή είναι λάθος (χρησιμοποιήστε το όνομα υπηρεσίας Compose, όχι localhost, από μέσα στο κοντέινερ Caddy). Σφάλματα δικαιωμάτων σε τόμους συχνά σημαίνουν ότι η εικόνα τρέχει ως uid 1000 ενώ ο κατάλογος κεντρικού είναι root.

  • compose: command not found — εγκαταστήσατε το παλιό όνομα δυαδικού· χρησιμοποιήστε docker compose
  • port is already allocated — κάτι άλλο κατέχει 80/443 (Apache, Nginx, άλλο Caddy)
  • database connection refused — η εφαρμογή ξεκίνησε πριν είναι έτοιμη η Postgres· χρησιμοποιήστε healthcheck + depends_on condition
  • disk full — docker system df, μετά prune αχρησιμοποίητες εικόνες προσεκτικά
  • permission denied on docker.sock — ο χρήστης δεν είναι στην ομάδα docker ή χρειάζεστε νέα συνεδρία σύνδεσης

Ασφάλεια

Μην δημοσιεύετε θύρες βάσης δεδομένων. Μην τρέχετε privileged: true. Μην προσαρτάτε /var/run/docker.sock σε κοντέινερ εφαρμογής εκτός αν γράφετε σκόπιμα διαχειριστή κοντέινερ. Κρατήστε τη μηχανή ενημερωμένη. Σαρώστε τις δικές σας εικόνες αν τις χτίζετε. Το .env στον δίσκο είναι ακόμη μυστικό αρχείο — περιορίστε ποιος μπορεί να κάνει ssh στο κουτί.

  • Χωρίς δημόσιο 5432 / 3306 / 6379
  • Καρφιτσώστε digest εικόνων ή τουλάχιστον αμετάβλητες ετικέτες
  • chmod 600 .env
  • Τα Unattended-upgrades για το OS του κεντρικού εξακολουθούν να έχουν σημασία
  • Ένα έργο Compose ανά εφαρμογή κρατά την ακτίνα έκρηξης μικρότερη

Συμβουλές

  • Βάλτε compose.yaml στο git· κρατήστε .env.example χωρίς πραγματικά μυστικά
  • Χρησιμοποιήστε προφίλ για προαιρετικούς εργάτες (docker compose --profile workers up -d)
  • Παρακολουθήστε docker stats όταν διαστασιολογείτε το VPS
  • Για bind mounts πηγαίου κώδικα αυτό δεν είναι το μοτίβο παραγωγής — ψήστε μια εικόνα
  • Αν η στοίβα μεγαλώσει σε πολλά VPS, τότε κοιτάξτε ενορχήστρωση — όχι πριν

Μια σχεδόν παραγωγική ρύθμιση Compose σε ένα VPS είναι: επίσημα πακέτα Docker, κλειδωμένο .env, αρχείο YAML που δεν δημοσιεύει τη βάση, healthcheck, αντίστροφος διαμεσολαβητής στις 80/443, UFW, ετικέτες εικόνων που μπορείτε να επαναφέρετε και dump Postgres που έχετε πραγματικά επαναφέρει μία φορά. Ξεκινήστε από το πρότυπο αυτού του άρθρου, αντικαταστήστε την εικόνα εφαρμογής και αντιμετωπίστε το docker compose down -v ως καταστροφική εντολή με τον ίδιο σεβασμό όπως το rm -rf.