services: traefik: image: traefik:v3.7.16 restart: unless-stopped command: - --providers.docker=true - --providers.docker.exposedbydefault=false - --providers.docker.network=proxy - --entrypoints.web.address=:80 - --entrypoints.web.http.redirections.entrypoint.to=websecure - --entrypoints.web.http.redirections.entrypoint.scheme=https - --entrypoints.web.http.redirections.entrypoint.permanent=true - --entrypoints.websecure.address=:443 - --entrypoints.websecure.http.tls.certresolver=letsencrypt - --certificatesresolvers.letsencrypt.acme.email=${ACME_EMAIL} - --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json - --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web - --ping=true - --log.format=json ports: - "80:80" - "443:443" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - letsencrypt:/letsencrypt networks: [proxy] healthcheck: test: ["CMD", "traefik", "healthcheck", "--ping"] start_period: 30s start_interval: 1s interval: 10s timeout: 3s retries: 3 security_opt: - no-new-privileges:true labels: - traefik.enable=true - traefik.http.middlewares.hsts.headers.stsSeconds=31536000 - traefik.http.middlewares.security-headers.headers.frameDeny=true - traefik.http.middlewares.security-headers.headers.contentTypeNosniff=true - traefik.http.middlewares.security-headers.headers.referrerPolicy=strict-origin-when-cross-origin - traefik.http.middlewares.admin-ratelimit.ratelimit.average=2 - traefik.http.middlewares.admin-ratelimit.ratelimit.burst=10 - traefik.http.middlewares.admin-ratelimit.ratelimit.period=1s - traefik.http.middlewares.admin-ratelimit.ratelimit.sourcecriterion.ipstrategy.depth=1 migrate: networks: - db - backend serve: environment: ALISTEN_PUBLIC_URL: https://${ALISTEN_DOMAIN} STORAGE_PUBLIC_URL: ${STORAGE_PUBLIC_URL} networks: - backend - db - proxy labels: - traefik.enable=true - traefik.http.services.serve.loadbalancer.server.port=8080 - traefik.http.routers.serve.rule=Host(`${ALISTEN_DOMAIN}`) && (PathPrefix(`/api/`) || Path(`/ws`) || PathPrefix(`/media/`)) - traefik.http.routers.serve.entrypoints=websecure - traefik.http.routers.serve.middlewares=hsts,security-headers@docker - traefik.http.routers.serve.service=serve - traefik.http.routers.admin.rule=Host(`${ALISTEN_DOMAIN}`) && PathPrefix(`/api/admin/`) - traefik.http.routers.admin.entrypoints=websecure - traefik.http.routers.admin.priority=100 - traefik.http.routers.admin.middlewares=hsts,security-headers,admin-ratelimit@docker - traefik.http.routers.admin.service=serve - traefik.http.services.serve.loadbalancer.healthcheck.path=/readyz - traefik.http.services.serve.loadbalancer.healthcheck.port=9090 - traefik.http.services.serve.loadbalancer.healthcheck.interval=1s - traefik.http.services.serve.loadbalancer.healthcheck.timeout=1s worker: networks: - backend - db web: ports: !reset [] environment: !reset {} networks: - proxy labels: - traefik.enable=true - traefik.http.routers.web.rule=Host(`${ALISTEN_DOMAIN}`) - traefik.http.routers.web.entrypoints=websecure - traefik.http.routers.web.middlewares=hsts,security-headers@docker - traefik.http.services.web.loadbalancer.server.port=8080 postgres: networks: - db redis: networks: - db rustfs: networks: - proxy - backend labels: - traefik.enable=true - traefik.http.routers.storage.rule=Host(`${STORAGE_DOMAIN}`) && PathPrefix(`/${STORAGE_BUCKET_NAME}/link/`) && (Method(`GET`) || Method(`HEAD`)) - traefik.http.routers.storage.entrypoints=websecure - traefik.http.routers.storage.middlewares=storage-headers,hsts@docker - traefik.http.middlewares.storage-headers.headers.contentsecuritypolicy=sandbox; default-src 'none' - traefik.http.middlewares.storage-headers.headers.contenttypenosniff=true - traefik.http.services.storage.loadbalancer.server.port=9000 networks: proxy: name: proxy backend: name: alisten-backend db: name: alisten-db volumes: letsencrypt: