2.84 v/snac0 / examples / docker-swarm-traefik / snac_stack.yml
  1---
  2# Example of a SNAC + Traefik stack on Docker Swarm mode
  3# SNAC behind Traefik v3 reverse proxy
  4# including Let's Encrypt certificates, HTTP security headers
  5# and caching */s/* (SNAC static files) for 24h with souin.
  6#
  7# docker stack deploy -c snac_stack.yml snac
  8
  9services:
 10  traefik:
 11    image: traefik:v3
 12    hostname: '{{.Node.Hostname}}'
 13    ports:
 14      # listen on host ports without ingress network
 15      - target: 80
 16        published: 80
 17        protocol: tcp
 18        mode: host
 19      - target: 443
 20        published: 443
 21        protocol: tcp
 22        mode: host
 23      - target: 443
 24        published: 443
 25        protocol: udp   # for HTTP3
 26        mode: host
 27    networks:
 28      - proxy
 29    volumes:
 30      - /opt/docker/traefik/traefik.yml:/etc/traefik/traefik_config.yml  # main Traefik static configuration
 31      - /opt/docker/traefik/dynamic:/etc/traefik/dynamic   # for Traefik dynamic configuration files
 32      - /opt/docker/acme:/acme    # directory for certificate storage files
 33      - /opt/docker/traefik/log:/var/log
 34      - /var/run/docker.sock:/var/run/docker.sock:ro
 35      - /usr/share/zoneinfo/America/Sao_Paulo:/etc/localtime:ro  # Change this to another or comment/remove to use UTC
 36      - /etc/timezone:/etc/timezone:ro    # Comment/remove to use UTC
 37    environment:
 38      - TZ=America/Sao_Paulo  # Change it to another or comment/remove to use UTC
 39    deploy:
 40      mode: global
 41      placement:
 42        constraints:
 43          - node.role==manager
 44      labels:
 45        - traefik.enable=true
 46        - traefik.http.routers.mydashboard.rule=Host(`traefik.example.net`)   # for Traefik dashboard
 47        - traefik.http.routers.mydashboard.service=api@internal
 48        - traefik.http.routers.mydashboard.middlewares=traefik_auth,traefik_retry
 49        - traefik.http.services.mydashboard.loadbalancer.server.port=1337
 50        - traefik.http.middlewares.traefik_retry.retry.attempts=3
 51        - traefik.http.middlewares.traefik_retry.retry.initialinterval=200ms
 52        # How to generate a password hash: echo $(htpasswd -nB desired_username) | sed -e s/\\$/\\$\\$/g
 53        - traefik.http.middlewares.traefik_auth.basicauth.users=desired_username:PASTE_THE_PASSWORD_HASH_HERE
 54      resources:
 55        limits:
 56          cpus: "2"
 57          memory: 1g
 58        reservations:
 59          memory: 256m
 60
 61  snac:
 62    image: codeberg.org/daltux/snac:2.82-dev_daltux3
 63    hostname: '{{.Node.Hostname}}'
 64    restart: unless-stopped
 65    security_opt:
 66      - no-new-privileges:true
 67    volumes:
 68      - /opt/snac:/data
 69    networks:
 70      - proxy
 71    depends_on:
 72      - traefik
 73    environment:
 74      - TZ=America/Sao_Paulo   # Change this to your own or comment/remove it to use UTC.
 75    deploy:
 76      mode: replicated
 77      replicas: 1
 78      labels:
 79        - traefik.enable=true
 80        - traefik.http.services.snac.loadbalancer.server.port=8001
 81        - traefik.http.routers.snac.rule=Host(`snac.example.net`)
 82        - traefik.http.routers.snac.priority=1
 83        - traefik.http.routers.snac.middlewares=snac_headers@swarm,traefik_retry@swarm
 84        - "traefik.http.routers.snac_static.rule=Host(`snac.example.net`) && PathRegexp(`^/.+/s/.+`)"
 85        - "traefik.http.routers.snac_static.priority=2"
 86        - "traefik.http.routers.snac_static.middlewares=snac_headers@swarm,snac_cache_static@swarm,traefik_retry@swarm"
 87        - traefik.http.middlewares.snac_headers.headers.stsSeconds=31536000
 88        - traefik.http.middlewares.snac_headers.headers.stsIncludeSubdomains=false
 89        - traefik.http.middlewares.snac_headers.headers.stsPreload=false
 90        - traefik.http.middlewares.snac_headers.headers.customFrameOptionsValue=SAMEORIGIN
 91        - traefik.http.middlewares.snac_headers.headers.contentTypeNosniff=true
 92        - traefik.http.middlewares.snac_headers.headers.browserXssFilter=true
 93        - traefik.http.middlewares.snac_headers.headers.referrerPolicy=strict-origin-when-cross-origin
 94        - "traefik.http.middlewares.snac_headers.headers.contentSecurityPolicy=default-src 'self'; base-uri 'self'; script-src 'none'; style-src 'self' 'unsafe-inline'; form-action 'self'; img-src https: data:; font-src 'self'; media-src https: data:; connect-src 'none'; frame-src 'none'; frame-ancestors 'none';"
 95        - traefik.http.middlewares.snac_cache_static.plugin.souin.api.souin=true
 96        - traefik.http.middlewares.snac_cache_static.plugin.souin.log_level=info
 97        - traefik.http.middlewares.snac_cache_static.plugin.souin.default_cache.ttl=1440m
 98        - traefik.http.middlewares.snac_cache_static.plugin.souin.default_cache.allowed_http_verbs=GET,HEAD
 99        - traefik.http.middlewares.snac_cache_static.plugin.souin.default_cache.stale=1h
100        - traefik.http.middlewares.snac_cache_static.plugin.souin.default_cache.etag=true
101        - "traefik.http.middlewares.snac_cache_static.plugin.souin.default_cache.default_cache_control=public, max-age=86400"
102      resources:
103        limits:
104          cpus: "3"
105          memory: 1g
106        reservations:
107          memory: 256m
108
109networks:
110  proxy:
111    name: proxy
112    driver: overlay
113    attachable: true
114    external: true