# ============================================================================= # CUSTOMER STACK TEMPLATE — Gitea + PostgreSQL # ============================================================================= # This is the Docker Swarm stack deployed for each paying customer. # It defines what product/service they receive when they subscribe. # # PRODUCT: Gitea — a self-hosted Git service, backed by PostgreSQL. # Each customer gets their own isolated instance at their subdomain. # # Structure: # web — the application, exposed via Traefik behind Authelia auth # db — PostgreSQL, internal only (backend network, never exposed) # # To sell a different product: replace the `web` image, update the port # in the Traefik loadbalancer label, and adjust `db` env/image as needed. # # Template variables (injected at deploy time by swarm/client.go): # {{.ID}} - customer's username (unique resource naming) # {{.Subdomain}} - customer's subdomain (same as ID by default) # {{.Domain}} - base domain (e.g. bc.a250.ca) # {{.TraefikNetwork}} - Traefik overlay network name # # Each customer gets their stack at: https://{{.Subdomain}}.{{.Domain}} # Access is restricted to the owning user via Authelia forward-auth. # ============================================================================= services: web: image: gitea/gitea:1-rootless environment: GITEA__database__DB_TYPE: postgres GITEA__database__HOST: db:5432 GITEA__database__NAME: gitea GITEA__database__USER: gitea GITEA__database__PASSWD: gitea GITEA__server__DOMAIN: "{{.Subdomain}}.{{.Domain}}" GITEA__server__ROOT_URL: "https://{{.Subdomain}}.{{.Domain}}" GITEA__server__HTTP_PORT: "3000" volumes: - gitea_data:/var/lib/gitea networks: - traefik_net - backend deploy: replicas: 1 labels: traefik.enable: "true" traefik.docker.network: "atlas_{{.TraefikNetwork}}" traefik.http.routers.customer-{{.ID}}-web.rule: "Host(`{{.Subdomain}}.{{.Domain}}`)" traefik.http.routers.customer-{{.ID}}-web.entrypoints: "websecure" traefik.http.routers.customer-{{.ID}}-web.tls: "true" traefik.http.routers.customer-{{.ID}}-web.middlewares: "authelia-auth@swarm" traefik.http.services.customer-{{.ID}}-web.loadbalancer.server.port: "3000" restart_policy: condition: on-failure db: image: postgres:16-alpine environment: POSTGRES_DB: gitea POSTGRES_USER: gitea POSTGRES_PASSWORD: gitea volumes: - db_data:/var/lib/postgresql/data networks: - backend deploy: replicas: 1 restart_policy: condition: on-failure networks: traefik_net: external: true name: "atlas_{{.TraefikNetwork}}" backend: driver: overlay volumes: gitea_data: driver: local db_data: driver: local