# ============================================ # ProxCenter Community Edition — Docker Swarm Stack # ============================================ # Deploy (do NOT run until volumes/secrets exist): # set -a; . ./proxcenter.env; set +a # docker stack deploy -c proxcenter-compose.yml proxcenter # # Alternative if you prefer to render with docker compose first: # docker compose --env-file proxcenter.env -f proxcenter-compose.yml config \ # | docker stack deploy -c - proxcenter # # Prerequisites — create external volumes before first deploy: # docker volume create proxcenter_data # docker volume create postgres_data # # Named volumes in Swarm are node-local by default. Both services are # pinned to a labeled node so proxcenter_data and postgres_data stay on # the same host. Label the intended primary Swarm node before deploying: # docker node update --label-add proxcenter.storage=true # If you use a distributed volume driver (NFS/Longhorn/etc.), remove or # change the placement constraints. # # Optional: use Docker Secrets instead of env vars for sensitive values. # Create secrets before deploying, then uncomment the secrets: blocks: # printf 'your-app-secret' | docker secret create app_secret - # printf 'your-nextauth-secret' | docker secret create nextauth_secret - # Then in the frontend service, swap the APP_SECRET / NEXTAUTH_SECRET # env vars for APP_SECRET_FILE / NEXTAUTH_SECRET_FILE and uncomment # the secrets: section on the service and at the bottom of this file. # ============================================ services: # ======================================== # Frontend (Next.js + WebSocket Proxy) # ======================================== frontend: image: ghcr.io/adminsyspro/proxcenter-frontend:${VERSION:-latest} ports: - "3020:3000" environment: - NODE_ENV=production # Build the Postgres connection string from individual vars so # POSTGRES_PASSWORD only needs to be set once (not duplicated in DATABASE_URL). - DATABASE_URL=postgresql://${POSTGRES_USER:-proxcenter}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-proxcenter}?schema=public - APP_SECRET=${APP_SECRET} - NEXTAUTH_SECRET=${NEXTAUTH_SECRET} - NEXTAUTH_URL=${NEXTAUTH_URL:-http://localhost:3000} - APP_URL=${APP_URL:-http://localhost:3000} # Docker Secrets alternative — comment out APP_SECRET / NEXTAUTH_SECRET above # and uncomment these if you prefer file-based secrets: # - APP_SECRET_FILE=/run/secrets/app_secret # - NEXTAUTH_SECRET_FILE=/run/secrets/nextauth_secret volumes: - ${DockerData}/proxcenter/frontend_data:/app/data # secrets: # - app_secret # - nextauth_secret networks: - proxcenter # depends_on is intentionally omitted: it is ignored by docker stack deploy. # Swarm relies on healthcheck + restart_policy to handle startup ordering. healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3000/api/health"] interval: 30s timeout: 10s retries: 3 start_period: 30s deploy: replicas: 1 placement: constraints: # Keep the node-local proxcenter_data volume on the intended primary node. - node.platform.os == linux restart_policy: condition: on-failure delay: 5s max_attempts: 5 window: 120s update_config: parallelism: 1 delay: 10s order: start-first failure_action: rollback rollback_config: parallelism: 1 delay: 5s # ======================================== # Postgres (application database) # ======================================== postgres: image: postgres:16-alpine # Run as the postgres UID/GID used by postgres:16-alpine so the NFS-backed # data directory can be owned by 70:70 on TrueNAS and avoid startup chown failures. user: "70:70" environment: - POSTGRES_USER=${POSTGRES_USER:-proxcenter} - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - POSTGRES_DB=${POSTGRES_DB:-proxcenter} - POSTGRES_INITDB_ARGS=--encoding=UTF8 --locale=C # Use a child directory under the NFS bind mount so Postgres does not # need to chmod the NFS mount root during initdb. - PGDATA=/var/lib/postgresql/data/pgdata volumes: - ${DockerData}/proxcenter/postgres_data:/var/lib/postgresql/data # Port is intentionally not published. Postgres is reachable only # over the internal overlay network. Uncomment to expose for debugging: # ports: # - "127.0.0.1:5432:5432" networks: - proxcenter healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-proxcenter} -d ${POSTGRES_DB:-proxcenter}"] interval: 10s timeout: 5s retries: 5 start_period: 20s deploy: replicas: 1 restart_policy: condition: on-failure delay: 5s max_attempts: 5 window: 120s update_config: parallelism: 1 delay: 10s # stop-first so the old container releases its data dir before the new one starts order: stop-first failure_action: rollback rollback_config: parallelism: 1 delay: 5s placement: constraints: # Keep the node-local postgres_data volume on the intended primary node. - node.platform.os == linux # ======================================== # Networks # ======================================== networks: proxcenter: driver: overlay attachable: true # ======================================== # Volumes (must be created externally) # ======================================== # docker volume create proxcenter_data # docker volume create postgres_data volumes: proxcenter_data: external: true postgres_data: external: true # ======================================== # Secrets (uncomment after creating them) # ======================================== # printf 'your-app-secret' | docker secret create app_secret - # printf 'your-nextauth-secret' | docker secret create nextauth_secret - # # secrets: # app_secret: # external: true # nextauth_secret: # external: true