# Coolify Compose Template — TheHomelessSherlock ## Proxy & Networking Rules ### Our Setup - **Proxy**: `coolify-proxy` (Traefik v3) configured with `--providers.docker.network=proxy` - **TLS**: certresolver `letsencrypt` via HTTP challenge - **Domain routing**: configured in Coolify UI, NOT in compose labels ### Rule 1 — Every service exposed via HTTP/HTTPS must be on the `proxy` network ```yaml services: myapp: image: myimage:latest pull_policy: always networks: - internal - proxy # ← mandatory for Traefik to reach it labels: traefik.http.services.myapp.loadbalancer.server.port: "3000" # ← mandatory port label networks: internal: driver: bridge proxy: external: true # ← always external, pre-created by Coolify ``` ### Rule 2 — Internal-only services do NOT need proxy ```yaml services: mydb: image: postgres:16 networks: - internal # ← only internal, no proxy networks: internal: driver: bridge ``` ### Rule 3 — Mail-relay access via mail_internal network Services that need to send mail via the internal mail-relay must be on `mail_internal`: ```yaml services: myapp: networks: - internal - proxy - mail_internal # ← only services that need mail environment: SMTP_HOST: mail-relay # ← container name as hostname SMTP_PORT: 587 networks: mail_internal: external: true # ← pre-created: docker network create mail_internal ``` ### Rule 4 — Labels: only port + optional middleware Coolify manages routing labels automatically. Only set: ```yaml labels: # MANDATORY: tell Traefik which port your app listens on traefik.http.services.myapp.loadbalancer.server.port: "3000" # OPTIONAL: define reusable middleware (e.g. security headers, redirects) traefik.http.middlewares.myapp-headers.headers.stsSeconds: "31536000" traefik.http.middlewares.myapp-headers.headers.stsIncludeSubdomains: "true" ``` **NEVER add these** (Coolify adds them automatically based on UI config): - `traefik.enable` - `traefik.docker.network` - `traefik.http.routers.*` ### Rule 5 — pull_policy: always on main service Ensures the latest image is pulled on every deploy: ```yaml services: myapp: image: myimage:latest pull_policy: always # ← add to main/frontend service only ``` ### Rule 6 — Authentik middleware To protect a service with Authentik SSO, use the middleware defined in the authentik stack: In Coolify UI: add this label to your application under "Labels": ``` traefik.http.routers..middlewares=ths-authentik@docker ``` Or in your compose labels (will be merged with Coolify's auto-labels): ```yaml labels: traefik.http.services.myapp.loadbalancer.server.port: "3000" # The router name Coolify generates follows: https-0-- # Use Coolify UI "Labels" field to add the middleware after first deploy ``` ## Full Example — Minimal web app with DB and mail ```yaml services: myapp: image: myimage:latest pull_policy: always restart: unless-stopped depends_on: - myapp-db environment: DB_HOST: myapp-db DB_PORT: 5432 SMTP_HOST: mail-relay SMTP_PORT: 587 networks: - internal - proxy - mail_internal labels: traefik.http.services.myapp.loadbalancer.server.port: "3000" myapp-db: image: postgres:16 restart: unless-stopped environment: POSTGRES_DB: myapp POSTGRES_USER: myapp POSTGRES_PASSWORD: ${DB_PASSWORD} volumes: - /opt/myapp/db:/var/lib/postgresql/data:Z networks: - internal networks: internal: driver: bridge proxy: external: true mail_internal: external: true ``` ## Pre-created networks on the host These networks must exist before deploying stacks that use them: ```bash # Already created by Coolify: # docker network create proxy ← created as part of Coolify install # Create manually once: docker network create mail_internal ``` ## Coolify UI checklist per application 1. **Ports Exposes**: set to the app's HTTP port (must match `loadbalancer.server.port` label) 2. **Domain**: set FQDN (e.g. `myapp.sherlockhomeless.net`) 3. **Base Directory**: set to the subdirectory (e.g. `/gitea`, `/n8n`) 4. **Environment Variables**: fill from `stack.env` template