Symptom: Docker refused to bind :::$PORT on a fresh, provably free
port — a known stuck-IPv6-reservation bug on shared Docker hosts.
Fixes the root cause by only asking Docker to bind the IPv4 loopback.
- docker-compose.prod.yml
postgres/redis: !override ports: []
(not reachable from host; intra-compose calls still work)
api/frontend: !override 127.0.0.1:$PORT:$INTERNAL_PORT
(Apache is the only caller; reaches them via loopback)
- deploy.sh is_port_free: probe IPv4 loopback only. The old IPv6 bind
check was correct in principle but rejected usable ports on this host
because stale :::PORT reservations don't collide with an IPv4-only
bind.
Security upgrade too: postgres, redis, api are no longer exposed to
the server's public interface.
49 lines
1.5 KiB
YAML
49 lines
1.5 KiB
YAML
# Production overrides for docker-compose.yml.
|
|
# Use: docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
|
|
#
|
|
# Differences from the dev compose file:
|
|
# - Frontend is built with the `prod` target (nginx serving dist/)
|
|
# - No dev volume mounts for hot-reload
|
|
# - Frontend listens on port 80 internally; host port still configurable
|
|
# - Build args for VITE_API_URL and VITE_BASE_PATH come from .env
|
|
|
|
name: hp-studios-ai-content-agent
|
|
|
|
# Production binds all host ports to 127.0.0.1 only — Apache is the only
|
|
# caller and reaches the containers via loopback. This also sidesteps a
|
|
# recurring Docker IPv6 "port already allocated" bug on shared hosts where
|
|
# stale reservations on :::PORT block fresh binds.
|
|
#
|
|
# Postgres + Redis don't need host publication at all in prod; intra-service
|
|
# calls use the internal compose network.
|
|
|
|
services:
|
|
postgres:
|
|
ports: !override []
|
|
|
|
redis:
|
|
ports: !override []
|
|
|
|
api:
|
|
volumes:
|
|
- ./data:/app/data
|
|
# Prod uvicorn: no --reload, controlled concurrency
|
|
command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 2
|
|
ports: !override
|
|
- "127.0.0.1:${API_HOST_PORT}:8000"
|
|
|
|
worker:
|
|
volumes:
|
|
- ./data:/app/data
|
|
|
|
frontend:
|
|
build:
|
|
context: ./frontend
|
|
dockerfile: Dockerfile
|
|
target: prod
|
|
args:
|
|
VITE_API_URL: ${VITE_API_URL}
|
|
VITE_BASE_PATH: ${VITE_BASE_PATH}
|
|
ports: !override
|
|
- "127.0.0.1:${FRONTEND_HOST_PORT}:80"
|
|
volumes: []
|