Files
stack/infra/traefik/dynamic/services.yml
kert 3a225c620f
Some checks failed
CI / lint (push) Successful in 30s
CI / notebooks-smoke (push) Successful in 1m33s
Deploy / notebooks (push) Has been skipped
Deploy / zotero (push) Has been skipped
Deploy / docs (push) Has been skipped
Deploy / api (push) Has been skipped
Deploy / llm (push) Has been skipped
Deploy / mc (push) Has been skipped
Infra CI / notebooks (push) Successful in 52s
Infra CI / zotero (push) Successful in 14s
Infra CI / docs (push) Successful in 19s
Infra CI / api (push) Successful in 58s
Infra CI / llm (push) Successful in 50s
Infra CI / mc (push) Failing after 16s
Deploy / report (push) Successful in 12s
CI / test (push) Has been cancelled
infra(traefik,gitea): rate-limit filtered project-board views per source IP and serve a robots.txt disallowing filtered views — the label-permutation crawler trap (refs #656)
2026-09-11 16:46:49 -04:00

191 lines
7.0 KiB
YAML

{{- $domain := env "DOMAIN" | default "fhirworx.io" -}}
{{- $reef := dict
"dashboard" (dict "port" "80" "theme" true "extra_hosts" (list $domain) "mw" "secure-headers")
"docs" (dict "port" "80" "theme" false "mw" "git-sso,secure-headers")
"git" (dict "port" "3000" "theme" false "mw" "secure-headers")
"notebooks" (dict "port" "2718" "theme" true "mw" "git-sso,secure-headers")
"zotero" (dict "port" "8080" "theme" true "mw" "git-sso,secure-headers")
"webdav" (dict "port" "8080" "theme" false "mw" "secure-headers")
"api" (dict "port" "8000" "theme" false "mw" "secure-headers")
"llm" (dict "port" "8000" "theme" false "mw" "git-sso,secure-headers")
"nessie" (dict "port" "19120" "theme" false "mw" "git-sso,infra-headers")
"trino" (dict "port" "8080" "theme" true "mw" "git-sso,infra-headers")
"polaris" (dict "port" "8181" "theme" false "mw" "git-sso,infra-headers")
"grafana" (dict "port" "3000" "theme" true "mw" "git-sso,secure-headers")
"prometheus" (dict "port" "9090" "theme" true "mw" "git-sso,infra-headers")
"tempo" (dict "port" "3200" "theme" true "mw" "git-sso,infra-headers")
"loki" (dict "port" "3100" "theme" false "mw" "git-sso,infra-headers")
-}}
{{- $multi := dict
"rustfs-api" (dict "container" "rustfs" "port" "9000" "subdomain" "s3" "theme" false "mw" "git-sso,infra-headers")
"rustfs-console" (dict "container" "rustfs" "port" "9001" "subdomain" "s3console" "theme" true "mw" "git-sso,infra-headers")
-}}
http:
middlewares:
secure-headers:
headers:
frameDeny: true
browserXssFilter: true
contentTypeNosniff: true
# #656: a crawler permuting project-board label filters at ~1 req/s
# (216.73.216.0/24). Per-source-IP limit on the filtered project views
# only — a person clicking filters stays well under 10/min; the crawler
# gets 429s. Pairs with infra/gitea/custom/public/robots.txt.
projects-ratelimit:
rateLimit:
average: 10
period: 1m
burst: 20
# SSO: auth-handler (nginx) wraps oauth2-proxy to convert 401 → 302.
# Same logic as corwins.media: auth_request + error_page 401 = @signin.
git-sso:
forwardAuth:
address: "http://auth-handler:4181"
trustForwardHeader: true
authResponseHeaders:
- "X-Auth-Request-User"
- "X-Auth-Request-Email"
infra-headers:
headers:
frameDeny: true
browserXssFilter: true
contentTypeNosniff: true
referrerPolicy: "strict-origin-when-cross-origin"
customResponseHeaders:
X-Robots-Tag: "noindex, nofollow"
inject-fhirworx:
plugin:
rewrite-body:
lastModified: true
rewrites:
- regex: "</head>"
replacement: '<link rel="icon" type="image/png" sizes="32x32" href="//dashboard.{{ $domain }}/fav32.png"><link rel="stylesheet" type="text/css" href="//dashboard.{{ $domain }}/fhirworx.css"></head>'
routers:
# auth.DOMAIN — oauth2-proxy public endpoints (login, callback, sign_out)
auth-host:
rule: "Host(`auth.{{ $domain }}`)"
service: oauth2-proxy
entryPoints:
- web
auth-host-tls:
rule: "Host(`auth.{{ $domain }}`)"
service: oauth2-proxy
entryPoints:
- websecure
tls: {}
# #656: filtered project-board views on git — same service, higher
# priority than the generic `git` router, rate limited per source IP.
git-projects-filter:
rule: "Host(`git.{{ $domain }}`) && PathRegexp(`^/[^/]+/[^/]+/projects(/|$)`) && QueryRegexp(`labels`, `.+`)"
priority: 1000
service: git
entryPoints:
- web
middlewares:
- projects-ratelimit
- secure-headers
git-projects-filter-tls:
rule: "Host(`git.{{ $domain }}`) && PathRegexp(`^/[^/]+/[^/]+/projects(/|$)`) && QueryRegexp(`labels`, `.+`)"
priority: 1000
service: git
entryPoints:
- websecure
tls: {}
middlewares:
- projects-ratelimit
- secure-headers
{{- range $name, $svc := $reef }}
{{ $name }}:
rule: "Host(`{{ get $svc "subdomain" | default $name }}.{{ $domain }}`){{ range get $svc "extra_hosts" | default list }} || Host(`{{ . }}`){{ end }}"
service: {{ $name }}
entryPoints:
- web
{{- $mwList := list -}}
{{- if get $svc "theme" }}{{ $mwList = append $mwList "inject-fhirworx" }}{{ end -}}
{{- $extra := get $svc "mw" | default "" -}}
{{- if ne $extra "" }}{{ range splitList "," $extra }}{{ $mwList = append $mwList (trim .) }}{{ end }}{{ end -}}
{{- if $mwList }}
middlewares:
{{- range $mwList }}
- {{ . }}
{{- end }}
{{- end }}
{{ $name }}-tls:
rule: "Host(`{{ get $svc "subdomain" | default $name }}.{{ $domain }}`){{ range get $svc "extra_hosts" | default list }} || Host(`{{ . }}`){{ end }}"
service: {{ $name }}
entryPoints:
- websecure
tls: {}
{{- if $mwList }}
middlewares:
{{- range $mwList }}
- {{ . }}
{{- end }}
{{- end }}
{{- end }}
{{- range $name, $svc := $multi }}
{{ $name }}:
rule: "Host(`{{ get $svc "subdomain" }}.{{ $domain }}`)"
service: {{ $name }}
entryPoints:
- web
{{- $mwList := list -}}
{{- if get $svc "theme" }}{{ $mwList = append $mwList "inject-fhirworx" }}{{ end -}}
{{- $extra := get $svc "mw" | default "" -}}
{{- if ne $extra "" }}{{ range splitList "," $extra }}{{ $mwList = append $mwList (trim .) }}{{ end }}{{ end -}}
{{- if $mwList }}
middlewares:
{{- range $mwList }}
- {{ . }}
{{- end }}
{{- end }}
{{ $name }}-tls:
rule: "Host(`{{ get $svc "subdomain" }}.{{ $domain }}`)"
service: {{ $name }}
entryPoints:
- websecure
tls: {}
{{- if $mwList }}
middlewares:
{{- range $mwList }}
- {{ . }}
{{- end }}
{{- end }}
{{- end }}
traefik-dashboard:
rule: "Host(`traefik.{{ $domain }}`)"
service: api@internal
entryPoints:
- web
middlewares:
- inject-fhirworx
- git-sso
- infra-headers
traefik-dashboard-tls:
rule: "Host(`traefik.{{ $domain }}`)"
service: api@internal
entryPoints:
- websecure
tls: {}
middlewares:
- inject-fhirworx
- git-sso
- infra-headers
services:
{{- range $name, $svc := $reef }}
{{ $name }}:
loadBalancer:
servers:
- url: "http://{{ $name }}:{{ get $svc "port" }}"
{{- end }}
{{- range $name, $svc := $multi }}
{{ $name }}:
loadBalancer:
servers:
- url: "http://{{ get $svc "container" }}:{{ get $svc "port" }}"
{{- end }}
oauth2-proxy:
loadBalancer:
servers:
- url: "http://oauth2-proxy:4180"