diff --git a/packages/super-sync-server/Caddyfile b/packages/super-sync-server/Caddyfile index 5b4b1dd5bf..2351c48782 100644 --- a/packages/super-sync-server/Caddyfile +++ b/packages/super-sync-server/Caddyfile @@ -1,3 +1,8 @@ +# NOTE: docker-compose.yml healthcheck probes the Caddy admin API at +# localhost:2019 (enabled by default in Caddy 2.x). Do NOT add a global +# `{ admin off }` block or rebind admin without also updating the healthcheck, +# or Caddy will restart-loop. + {$DOMAIN} { reverse_proxy supersync:1900 { # Allow up to 85 seconds for long-running operations diff --git a/packages/super-sync-server/docker-compose.monitoring.yml b/packages/super-sync-server/docker-compose.monitoring.yml index 0e4cfb8708..ce3fe0c948 100644 --- a/packages/super-sync-server/docker-compose.monitoring.yml +++ b/packages/super-sync-server/docker-compose.monitoring.yml @@ -1,5 +1,10 @@ # Monitoring stack for SuperSync Server # +# Attaches to the external `super-sync-server_internal` network created by +# the base docker-compose.yml — the base stack must be brought up first +# (or merged into the same `up` invocation as below). Running this file +# standalone will fail with "network not found". +# # Usage: # docker compose -f docker-compose.yml -f docker-compose.monitoring.yml up -d # @@ -23,6 +28,9 @@ services: - /var/run/docker.sock:/var/run/docker.sock:ro environment: - DOZZLE_NO_ANALYTICS=true + networks: + - internal + mem_limit: 64m # Uptime monitoring + alerts (~120MB RAM) # Provides health check monitoring and notifications @@ -34,6 +42,16 @@ services: - '127.0.0.1:3001:3001' volumes: - uptime-kuma-data:/app/data + networks: + - internal + mem_limit: 192m + +# Attach to the internal network defined in docker-compose.yml so Kuma can +# probe http://supersync:1900/health by service name (not just public URL). +networks: + internal: + external: true + name: super-sync-server_internal volumes: uptime-kuma-data: diff --git a/packages/super-sync-server/docker-compose.yml b/packages/super-sync-server/docker-compose.yml index 2d72697ea2..007ee5a3ee 100644 --- a/packages/super-sync-server/docker-compose.yml +++ b/packages/super-sync-server/docker-compose.yml @@ -18,7 +18,7 @@ services: supersync: image: ${SUPERSYNC_IMAGE:-ghcr.io/super-productivity/supersync:latest} container_name: supersync-server - restart: always + restart: unless-stopped environment: - NODE_ENV=${NODE_ENV:-production} - PORT=1900 @@ -65,7 +65,13 @@ services: - no-new-privileges:true cap_drop: - ALL - mem_limit: 1g + # 200+ WSS clients each consume an fd; Alpine default soft limit (1024) + # would be tight under reconnect bursts. + ulimits: + nofile: + soft: 65535 + hard: 65535 + mem_limit: 768m cpus: '1.0' networks: - internal @@ -74,11 +80,38 @@ services: postgres: image: postgres:16-alpine container_name: supersync-postgres - restart: always + restart: unless-stopped environment: - POSTGRES_USER=${POSTGRES_USER:-supersync} - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - POSTGRES_DB=${POSTGRES_DB:-supersync} + # Tuned for the 1.5g mem_limit. shared_buffers needs shm_size > default 64m. + # max_connections=40 keeps the worst-case sort budget (max_conn × work_mem) + # well inside the 1.5g cap; Prisma's per-instance pool is single-digit so + # 40 is generous headroom for migrations + psql + a future second replica. + command: + - postgres + - -c + - shared_buffers=384MB + - -c + - effective_cache_size=1GB + - -c + - work_mem=4MB + - -c + - maintenance_work_mem=128MB + - -c + - max_connections=40 + - -c + - random_page_cost=1.1 + - -c + # 5 min — kill leaked Prisma idle-in-tx, but well above the + # migrate-deploy.sh 30-min STEP_TIMEOUT for CONCURRENTLY index builds. + - idle_in_transaction_session_timeout=300000 + - -c + - wal_compression=on + - -c + - huge_pages=off + shm_size: 256m volumes: - postgres-data:/var/lib/postgresql/data healthcheck: @@ -93,7 +126,7 @@ services: start_period: 10s security_opt: - no-new-privileges:true - mem_limit: 1g + mem_limit: 1536m networks: internal: aliases: @@ -104,7 +137,7 @@ services: caddy: image: caddy:2.11-alpine container_name: supersync-caddy - restart: always + restart: unless-stopped ports: - '80:80' - '443:443' @@ -114,6 +147,12 @@ services: - caddy-config:/config environment: - DOMAIN=${DOMAIN} + healthcheck: + test: ['CMD', 'wget', '-q', '--spider', 'http://localhost:2019/config/'] + interval: 30s + timeout: 5s + retries: 3 + start_period: 10s networks: - internal cap_drop: @@ -133,4 +172,7 @@ volumes: networks: internal: + # Pinned name so docker-compose.monitoring.yml can attach via + # `external: true` regardless of the COMPOSE_PROJECT_NAME used. + name: super-sync-server_internal driver: bridge