From ffa563f354a64d6a471411a837ff2aabf8165365 Mon Sep 17 00:00:00 2001 From: f-amine Date: Thu, 18 Jun 2026 13:49:37 +0100 Subject: [PATCH] fix(deploy): no host ports; route apps via dokploy-network (Traefik) Publishing 3000/3001/3002 to the host collides with other apps sharing the VPS ("Bind for 0.0.0.0:3000 failed: port is already allocated"). Dokploy's Traefik routes by domain over its shared network, so host ports are unnecessary and harmful here. - drop `ports:` from web/marketing/admin; add `expose:` instead - web/marketing/admin join external `dokploy-network` (Traefik) + a private `internal` network for db/redis access - postgres/redis/migrate/backup stay on `internal` only - doc note on the networking model + how to rename the proxy network Co-Authored-By: Claude Opus 4.8 (1M context) --- docker-compose.prod.yml | 42 ++++++++++++++++++++++++++++++----- docs/deploy/production-env.md | 8 +++++++ 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index e9e3a12..994f5d5 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -27,6 +27,8 @@ services: POSTGRES_DB: ${POSTGRES_DB:-vibestack} volumes: - pgdata:/var/lib/postgresql/data + networks: + - internal healthcheck: test: ["CMD", "pg_isready", "-U", "${POSTGRES_USER:-postgres}"] interval: 10s @@ -39,6 +41,8 @@ services: command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD} volumes: - redisdata:/data + networks: + - internal healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s @@ -57,6 +61,8 @@ services: postgres: condition: service_healthy env_file: .env + networks: + - internal web: build: @@ -75,8 +81,14 @@ services: migrate: condition: service_completed_successfully env_file: .env - ports: - - "3001:3001" + # No host port: Traefik (Dokploy) routes to the container over + # dokploy-network using the port set in the Domain config. Publishing + # to the host would collide with other apps sharing this VPS. + expose: + - "3001" + networks: + - internal + - dokploy-network healthcheck: test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:3001/api/health || exit 1"] interval: 30s @@ -94,8 +106,11 @@ services: APP_PORT: 3000 restart: unless-stopped env_file: .env - ports: - - "3000:3000" + expose: + - "3000" + networks: + - internal + - dokploy-network healthcheck: test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:3000/api/health || exit 1"] interval: 30s @@ -120,8 +135,11 @@ services: migrate: condition: service_completed_successfully env_file: .env - ports: - - "3002:3002" + expose: + - "3002" + networks: + - internal + - dokploy-network healthcheck: test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:3002/api/health || exit 1"] interval: 30s @@ -136,6 +154,8 @@ services: postgres: condition: service_healthy env_file: .env + networks: + - internal volumes: - ./scripts/backup-r2.sh:/usr/local/bin/backup-r2.sh:ro entrypoint: @@ -146,6 +166,16 @@ services: echo "0 3 * * * /usr/local/bin/backup-r2.sh >> /var/log/backup.log 2>&1" | crontab - crond -f -l 2 +networks: + # Private network for app <-> postgres/redis traffic. + internal: + driver: bridge + # Dokploy's shared Traefik network. Must already exist on the host + # (created by the Dokploy install). web/marketing/admin join it so the + # reverse proxy can route the domains to them — no host ports needed. + dokploy-network: + external: true + volumes: pgdata: redisdata: diff --git a/docs/deploy/production-env.md b/docs/deploy/production-env.md index 8de5211..3601264 100644 --- a/docs/deploy/production-env.md +++ b/docs/deploy/production-env.md @@ -26,6 +26,14 @@ reports unconfigured features as `"disabled"` and still returns HTTP 200. session cookie is host-only and admin redirect-loops. Leave it unset for single-host or local dev. +**Networking / shared VPS:** the apps publish **no host ports** — Traefik +routes the domains to the containers over the external `dokploy-network` +(created by the Dokploy install) using the container port you set in each +service's Domain config (web 3001, marketing 3000, admin 3002). This is what +lets the stack share a VPS with other apps without port collisions. If your +Dokploy proxy network isn't named `dokploy-network`, rename it in the +`networks:` block of `docker-compose.prod.yml`. + ## Required — app refuses to boot without these | Variable | Used by | Notes |