Swarm Start Guide
This guide explains how to start and operate the gmod stack with Docker Swarm.
Prerequisites
- Docker Engine installed
- A valid
.envat repository root - Logged in to GHCR if images are private (
docker login ghcr.io)
1. Initialize Swarm (once)
docker swarm init
If Swarm is already initialized, Docker will tell you and you can continue.
2. Deploy the Stack
From repository root:
docker stack deploy -c docker-stack.swarm.yml --with-registry-auth --prune gmod
What this does:
- creates/updates services in
docker-stack.swarm.yml - applies rolling updates (
parallelism: 1,start-first) - runs
prisma-migrateservice to executeprisma db pushwith retries api,websocket, anddiscordnow wait for MariaDB schema readiness (userstable) before starting
3. Check Health
docker stack services gmod
Expected target replicas:
gmod_api:2/2gmod_websocket:2/2gmod_discord:2/2gmod_mariadb:1/1gmod_redis:1/1gmod_mongo:1/1gmod_minio:1/1gmod_traefik:1/1
Traefik dashboard:
# Direct port (no host rule): http://<SERVER_IP>:8080/dashboard/
# API endpoint: http://<SERVER_IP>:8080/api/overview
Host-rule access is still available on port 80 with TRAEFIK_DASHBOARD_HOST (default traefik.localhost).
Migration logs:
docker service logs -f gmod_prisma-migrate
Live logs (all services in stack):
docker service logs -f --timestamps --tail 50 $(docker stack services gmod --format '{{.Name}}')
Live logs (apps only: api, websocket, discord):
docker service logs -f --timestamps --tail 50 $(docker stack services gmod --format '{{.Name}}' | grep -E '^gmod_(api|websocket|discord)$')
Live logs with container prefix (apps only, no rg required):
zsh -lc '
trap "kill 0" INT TERM EXIT
for c in $(docker ps --filter label=com.docker.stack.namespace=gmod --format "{{.Names}}" | grep -E "gmod_(api|websocket|discord)"); do
docker logs -f --tail 50 "$c" 2>&1 | sed -u "s/^/[$c] /" &
done
wait
'
One service at a time:
docker service logs -f --tail 100 gmod_api
docker service logs -f --tail 100 gmod_websocket
docker service logs -f --tail 100 gmod_discord
docker service logs -f --tail 100 gmod_mariadb
docker service logs -f --tail 100 gmod_prisma-migrate
Service/task details:
docker service ps gmod_api
docker service ps gmod_websocket
docker service ps gmod_discord
docker service ps gmod_mariadb
4. Update the Stack
After changing images or stack config:
docker stack deploy -c docker-stack.swarm.yml --with-registry-auth --prune gmod
5. Rollback a Service
docker service rollback gmod_api
docker service rollback gmod_websocket
docker service rollback gmod_discord
6. Stop Everything (Swarm)
docker stack rm gmod
7. Production FQDN (Cloudflare Tunnel)
In Swarm, app services are behind Traefik. Do not route Cloudflare directly to 53136 or 53139.
Set production hosts in .env:
API_HOST=api.your-domain.com
WS_HOST=ws.your-domain.com
TRAEFIK_DASHBOARD_HOST=traefik.your-domain.com
Deploy/redeploy:
docker stack deploy -c docker-stack.swarm.yml --with-registry-auth --prune gmod
Cloudflare Tunnel example (config.yml):
ingress:
- hostname: api.your-domain.com
service: http://localhost:80
- hostname: ws.your-domain.com
service: http://localhost:80
- hostname: traefik.your-domain.com
service: http://localhost:80
- service: http_status:404
Local-only defaults like api.localhost and ws.localhost are intended for local testing, not production DNS.
Troubleshooting
table does not exist
Schema is missing in MariaDB. Check migration service logs:
docker service logs --tail 200 gmod_prisma-migrate
Then redeploy stack:
docker stack deploy -c docker-stack.swarm.yml --with-registry-auth --prune gmod
Note:
- In Swarm, startup order is not strictly enforced.
- A first
P1001ingmod_prisma-migratecan happen while MariaDB is still booting. - With current stack config, migration retries and app startup waits handle this automatically.
Too many connections
- avoid running Compose and Swarm for this project at the same time
- current stack enforces
MARIA_CONNECTION_LIMIT=10in app services - check MariaDB load/logs:
docker service logs --tail 200 gmod_mariadb
Leftover Compose containers
If old Compose containers still run:
docker compose -p gmod-integration-monorepo -f docker-compose.prod.yml down --remove-orphans
MariaDB env names (MARIA_* vs MARIADB_*)
You can keep your existing MARIA_* variables.
- App services (
api/websocket/discord) useMARIA_* - MariaDB service now supports both:
- if
MARIADB_*is set, it is used - if not, Swarm/Compose fallback automatically to
MARIA_*