Metainformationen zur Seite
Dies ist eine alte Version des Dokuments!
Traefik
- URL
- https://traefik.smns-bw.org/
- User
- smns-tr
- Passwort
- ••••••••••
- Production
- hetzner:/opt/traefik/
├── traefik
│ ├── configfiles
│ │ ├── {{:server:config.yml|config.yml}}
│ │ ├── {{:server:middleware-chains.yml|middleware-chains.yml}}
│ │ ├── {{:server:middlewares.yml|middlewares.yml}}
│ │ ├── {{:server:tls-opts.yml|tls-opts.yml}}
│ ├── docker-compose.yml
│ ├── .env
│ ├── traefik.log
│ ├── traefik.yml
│ ├── access.log
In .env steht die URL traefik.smns-bw.org sowie die Zugangsdaten für diese Seite für docker-compose.yml
In die einzelnen docker-compose.yml Files der Container kommt dann sowas (Beispiel Sammlungskatalog):
labels:
- "traefik.http.routers.webportal.rule=Host(`${URL}`)"
- "traefik.http.routers.webportal.entrypoints=https"
- "traefik.http.routers.webportal.tls=true"
- "traefik.http.routers.webportal.tls.certresolver=leresolver"
- "traefik.http.routers.webportal.middlewares=secure-collections@file"
- "traefik.http.services.webportal.loadbalancer.server.port=6543"
- "traefik.http.services.webportal.loadbalancer.sticky=true"
- "traefik.http.services.webportal.loadbalancer.sticky.cookie.name=collections.smns-bw.org"
- "traefik.http.services.webportal.loadbalancer.sticky.cookie.httpOnly=true"
- "traefik.http.services.webportal.loadbalancer.sticky.cookie.secure=true"
- "traefik.docker.network=proxy"
Damit der Docker.sock nicht nach außen exposed ist, ist zusammen mit Traefik ein docker-socket aufgesetzt, der von hier stammt: https://github.com/wollomatic/socket-proxy
[1] docker-compose.yml show
services:
traefik:
container_name: traefik
image: „traefik:latest“
restart: always
# read_only: true
command:
- –configfile=/traefik.yml
mem_limit: 2G
cpus: 0.75
ports:
- „80:80“
- „443:443“
volumes:
- „./acme.json:/acme.json“
- „./traefik.yml:/traefik.yml:ro“
- „./configfiles:/configfiles:ro“
# - „.logs/traefik.log:/traefik.log“
# - „.logs/access.log:/access.log“
- „./logs:/logs:rw“
depends_on:
- „dockerproxy“
security_opt:
- „no-new-privileges:true“
networks:
- „proxy“
- „docker-proxynet“
labels:
- „traefik.http.routers.traefik.entrypoints=https“
- „traefik.http.routers.traefik.rule=Host(`traefik.smns-bw.org`)“
- „traefik.http.routers.traefik.tls=true“
- „traefik.http.routers.traefik.tls.certresolver=leresolver“
# API service
- „traefik.http.routers.traefik.service=api@internal“
- „traefik.http.routers.traefik.middlewares=secure-traefik@file“
- „traefik.http.services.traefik.loadbalancer.sticky=true“
- „traefik.http.services.traefik.loadbalancer.sticky.cookie.httpOnly=true“
- „traefik.http.services.traefik.loadbalancer.sticky.cookie.secure=true“
healthcheck:
test: [„CMD“, „wget“, „–spider“, „http://localhost:8082/ping“]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
dockerproxy:
build:
context: .
container_name: socket-proxy
command:
- '-loglevel=DEBUG'
- '-allowfrom=traefik,172.31.0.1'
- '-listenip=0.0.0.0'
- '-allowGET=/v1\..{1,2}/(version|containers/.*|events.*)'
- '-shutdowngracetime=5'
restart: unless-stopped
user: „65534:998“
read_only: true
mem_limit: 64M
cap_drop:
- ALL
security_opt:
- no-new-privileges
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- „proxy“
- „docker-proxynet“
healthcheck:
test: [ „CMD“, „nc“, „-z“, „localhost“, „2375“ ]
interval: 1m
timeout: 3s
retries: 3
error-pages-webportal:
container_name: error-webportal
image: nginx:alpine
restart: always
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./mime.types:/etc/nginx/mime.types
- ./error-pages-webportal:/usr/share/nginx/html:ro
labels:
- „traefik.http.routers.error-pages-webportal.entrypoints=https“
- „traefik.http.routers.error-pages-webportal.tls=true“
- „traefik.http.routers.error-pages-webportal.tls.certresolver=leresolver“
- „traefik.http.routers.error-pages-webportal.rule=Host(`error-webportal.smns-bw.org`)“
# - „traefik.http.routers.error-pages-webportal.middlewares=secure-global@file“
- „traefik.http.services.error-pages-webportal.loadbalancer.sticky=true“
- „traefik.http.services.error-pages-webportal.loadbalancer.sticky.cookie.httpOnly=true“
- „traefik.http.services.error-pages-webportal.loadbalancer.sticky.cookie.secure=true“
- „traefik.http.services.error-pages-webportal.loadbalancer.server.port=80“
networks:
- „proxy“
healthcheck:
test: [„CMD“, „curl“, „-f“, „http://localhost/healthz.html“]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
networks:
proxy:
external: true
docker-proxynet:
driver: bridge
internal: true
entryPoints:
http:
address: „:80“
http:
redirections:
entryPoint:
to: ':443'
scheme: https
https:
address: „:443“
# http3:
# advertisedPort: 443
postgres:
address: „:5434“
ssh:
address: „:666“
healthcheck:
address: „:8082“
log:
level: INFO
filePath: „/logs/traefik.log“
format: json
accessLog:
filePath: „/logs/access.log“
bufferingSize: 100
api: {}
ping:
entryPoint: healthcheck
providers:
docker:
# endpoint: „tcp://socket-proxy:2375“
endpoint: „tcp://dockerproxy:2375“
# endpoint: „unix:///var/run/docker.sock“
watch: true
network: proxy
# exposedByDefault: false
file:
directory: „/configfiles“
watch: true
certificatesResolvers:
leresolver:
acme:
email: „it@smns-bw.org“
storage: „/acme.json“
caServer: „https://acme-v02.api.letsencrypt.org/directory“
tlsChallenge: {}
experimental:
plugins:
traefik-plugin-cookie-path-prefix:
moduleName: „github.com/SchmitzDan/traefik-plugin-cookie-path-prefix“
version: „v0.0.3“
http:
routers:
webmin:
entryPoints:
- „https“
rule: Host(`webmin.smns-bw.org`)
service: webmin
middlewares:
- „secure-webmin“
tls:
certResolver: leresolver
options: tls-opts
traefik:
rule: Host(`traefik.smns-bw.org`)
service: cookies
smns_stats:
rule: Host(`statistics.smns-bw.org`)
# rule: „PathPrefix(`/statistics`)“
service: smns_stats
entryPoints:
- „https“
middlewares:
- „secure-collections“
tls:
certResolver: leresolver
options: tls-opts
services:
webmin:
loadBalancer:
servers:
- url: „http://172.18.0.1:10000/“
passHostHeader: true
sticky:
cookie:
secure: true
httpOnly: true
sameSite: lax
smns_stats:
loadBalancer:
servers:
- url: „http://172.18.0.1:8050“
passHostHeader: true
cookies:
loadBalancer:
sticky:
cookie:
secure: true
httpOnly: true
sameSite: lax
http:
middlewares:
secure-global:
chain:
middlewares:
- „security-headers“
- „CSP-global“
secure-traefik:
chain:
middlewares:
- „security-headers“
- „CSP-global“
- „traefik-auth“
secure-idservice:
chain:
middlewares:
- „security-headers“
- „CSP-idservice“
secure-biocase:
chain:
middlewares:
- „security-headers“
- „CSP-biocase“
secure-webmin:
chain:
middlewares:
- „security-headers“
- „CSP-webmin“
secure-prestashop:
chain:
middlewares:
- „security-headers“
- „CSP-prestashop“
secure-ent:
chain:
middlewares:
- „security-headers“
- „CSP-ent“
secure-collections:
chain:
middlewares:
- „security-headers-collection“
- „CSP-collections“
- „webportal-errors“
secure-digiphyll:
chain:
middlewares:
- „security-headers-allowframes“
- „CSP-digiphyll“
secure-dokuwiki:
chain:
middlewares:
- „security-headers-h5p“
- „CSP-dokuwiki“
secure-geometroidea:
chain:
middlewares:
- „security-headers“
- „CSP-geometroidea“
secure-h5p:
chain:
middlewares:
- „security-headers-allowframes“
- „CSP-h5p“
secure-awstats:
chain:
middlewares:
- „security-headers“
- „CSP-awstats“
secure-librechat:
chain:
middlewares:
- „security-headers-librechat“
- „CSP-librechat“
secure-pictures:
chain:
middlewares:
- „security-headers-allowframes“
- „CSP-global“
http:
middlewares:
default-whitelist:
ipWhiteList:
sourceRange:
- „127.0.0.1/32“
- „172.19.0.0/24“
traefik-auth:
basicAuth:
users:
- „smns-tr:$2y$10$mUF04Rf7852wnP5xGxewte1hW4X/LcEN2c7of5xPOEyzbAXGVrEAi“
security-headers-noindex:
headers:
accessControlAllowMethods:
- GET
- OPTIONS
- PUT
accessControlMaxAge: 100
addVaryHeader: true
customResponseHeaders:
X-Robots-Tag: „none,noarchive,nosnippet,notranslate,noimageindex“
X-Forwarded-Proto: „https“
Server: „“
x-powered-by: „“
customRequestHeaders:
X-Forwarded-Proto: „https“
Cache-Control: public
customFrameOptionsValue: SAMEORIGIN
sslProxyHeaders:
X-Forwarded-Proto: „https“
sslRedirect: true
referrerPolicy: „same-origin“
hostsProxyHeaders:
- „X-Forwarded-Host“
contentTypeNosniff: true
browserXssFilter: true
forceSTSHeader: true
stsSeconds: 31536000
stsPreload: false
permissionsPolicy: fullscreen=(self „https://smns-bw.org“), geolocation=*, midi=(), camera=(), usb=(), magnetometer=(), accelerometer=(), vr=(), speaker=(), ambient-light-sensor=(), gyroscope=(), microphone=(), payment=()
frameDeny: true
security-headers:
headers:
accessControlMaxAge: 100
addVaryHeader: true
customResponseHeaders:
X-Robots-Tag: „index, follow“
X-Forwarded-Proto: „https“
Server: „“
accessControlAllowMethods:
- GET
- OPTIONS
- PUT
accessControlAllowHeaders: „*“
X-Powered-By: „“
customRequestHeaders:
X-Forwarded-Proto: „https“
Cache-Control: public
customFrameOptionsValue: „ALLOW-FROM https://smns-bw.org“
sslProxyHeaders:
X-Forwarded-Proto: „https“
sslRedirect: true
referrerPolicy: „same-origin“
hostsProxyHeaders:
- „X-Forwarded-Host“
contentTypeNosniff: true
browserXssFilter: true
forceSTSHeader: true
stsSeconds: 31536000
stsPreload: false
permissionsPolicy: fullscreen=(self „https://smns-bw.org“), geolocation=*, midi=(), camera=(), usb=(), magnetometer=(), accelerometer=(), vr=(), speaker=(), ambient-light-sensor=(), gyroscope=(), microphone=(), payment=()
frameDeny: true
security-headers-allowframes:
headers:
accessControlMaxAge: 100
addVaryHeader: true
customResponseHeaders:
X-Robots-Tag: „index, follow“
accessControlAllowMethods:
- GET
- OPTIONS
- PUT
X-Forwarded-Proto: „https“
Server: „“
X-Powered-By: „“
customRequestHeaders:
X-Forwarded-Proto: „https“
Cache-Control: public
CustomFrameOptionsValue: „ALLOW-FROM https://smns-bw.org“
sslProxyHeaders:
X-Forwarded-Proto: „https“
sslRedirect: true
referrerPolicy: „same-origin“
hostsProxyHeaders:
- „X-Forwarded-Host“
contentTypeNosniff: true
browserXssFilter: true
forceSTSHeader: true
stsIncludeSubdomains: true
stsSeconds: 63072000
stsPreload: false
permissionsPolicy: fullscreen=(self „https://smns-bw.org“), geolocation=*, midi=(), camera=(), usb=(), magnetometer=(), accelerometer=(), vr=(), speaker=(), ambient-light-sensor=(), gyroscope=(), microphone=(), payment=()
security-headers-collection:
headers:
addVaryHeader: true
customResponseHeaders:
X-Robots-Tag: „index, follow“
X-Forwarded-Proto: „https“
Server: „“
accessControlAllowMethods:
- GET
- OPTIONS
- PUT
accessControlAllowHeaders: „*“
accessControlAllowOriginList:
- https://pydeepzoom.smns-bw.org
- https://pictures.smns-bw.org
accessControlMaxAge: 100
# customFrameOptionsValue: „ALLOW-FROM https://pictures.smns-bw.org“
customRequestHeaders:
X-Forwarded-Proto: „https“
Cache-Control: public
sslProxyHeaders:
X-Forwarded-Proto: „https“
sslRedirect: true
referrerPolicy: „same-origin“
hostsProxyHeaders:
- „X-Forwarded-Host“
contentTypeNosniff: true
browserXssFilter: true
forceSTSHeader: true
stsIncludeSubdomains: true
stsSeconds: 63072000
stsPreload: false
permissionsPolicy: fullscreen=(self „https://smns-bw.org“), geolocation=*, midi=(), camera=(), usb=(), magnetometer=(), accelerometer=(), vr=(), speaker=(), ambient-light-sensor=(), gyroscope=(), microphone=(), payment=()
# x-frame-options: ALLOW-FROM https://pictures.smns-bw.org
security-headers-librechat:
headers:
accessControlAllowMethods:
- GET
- OPTIONS
- PUT
accessControlMaxAge: 100
addVaryHeader: true
customResponseHeaders:
X-Robots-Tag: „none,noarchive,nosnippet,notranslate,noimageindex“
X-Forwarded-Proto: „https“
server: „“
x-powered-by: „“
customRequestHeaders:
X-Forwarded-Proto: „https“
Cache-Control: public
customFrameOptionsValue: SAMEORIGIN
sslProxyHeaders:
X-Forwarded-Proto: „https“
sslRedirect: true
referrerPolicy: „same-origin“
hostsProxyHeaders:
- „X-Forwarded-Host“
contentTypeNosniff: true
browserXssFilter: true
forceSTSHeader: true
# stsIncludeSubdomains: true
# stsSeconds: 63072000
stsPreload: false
permissionsPolicy: fullscreen=(self „https://smns-bw.org“), geolocation=*, midi=(), camera=(), usb=(), magnetometer=(), accelerometer=(), vr=(), ambient-light-sensor=(), gyroscope=(), payment=()
frameDeny: true
security-headers-h5p:
headers:
accessControlAllowMethods:
- GET
- OPTIONS
- PUT
accessControlMaxAge: 100
addVaryHeader: true
customResponseHeaders:
X-Robots-Tag: „none,noarchive,nosnippet,notranslate,noimageindex“
X-Forwarded-Proto: „https“
server: „“
customRequestHeaders:
X-Forwarded-Proto: „https“
Cache-Control: public
customFrameOptionsValue: SAMEORIGIN
sslProxyHeaders:
X-Forwarded-Proto: „https“
sslRedirect: true
referrerPolicy: „same-origin“
hostsProxyHeaders:
- „X-Forwarded-Host“
contentTypeNosniff: true
browserXssFilter: true
forceSTSHeader: true
stsIncludeSubdomains: true
stsSeconds: 63072000
stsPreload: false
permissionsPolicy: fullscreen=(self „https://smns-bw.org“), geolocation=*, midi=(), camera=(), usb=(), magnetometer=(), accelerometer=(), vr=(), speaker=(), ambient-light-sensor=(), gyroscope=(), microphone=(), payment=()
frameDeny: false
CSP-global:
headers:
contentSecurityPolicy: >
default-src 'self' 'unsafe-inline' 'unsafe-eval' *.smns-bw.org; frame-ancestors 'self' *.smns-bw.org;
frame-src *.smns-bw.org; base-uri 'self';
form-action 'self'; img-src 'self' data:;
connect-src 'self'; font-src 'self';
style-src 'self' 'unsafe-inline';
script-src 'self' 'unsafe-inline' 'unsafe-eval' *.smns-bw.org;
CSP-dokuwiki:
headers:
contentSecurityPolicy: >
default-src 'self' 'unsafe-inline' 'unsafe-eval' *.smns-bw.org;
frame-ancestors 'self' *.smns-bw.org;
frame-src *.smns-bw.org *.google.com;
base-uri 'self';
form-action 'self';
img-src 'self' https://www.dokuwiki.org https://www.gravatar.com data:;
connect-src 'self';
font-src 'self';
style-src 'self' 'unsafe-inline';
script-src 'self' 'unsafe-inline' 'unsafe-eval' *.smns-bw.org;
CSP-idservice:
headers:
contentSecurityPolicy: >
default-src 'self' 'unsafe-inline' 'unsafe-eval' *.smns-bw.org;
frame-ancestors 'self' *.smns-bw.org; frame-src *.smns-bw.org;
base-uri 'self';
form-action 'self';
img-src 'self' https://physalia.evolution.uni-bonn.de data:;
connect-src 'self';
font-src 'self';
style-src 'self' 'unsafe-inline';
script-src 'self' 'unsafe-inline' 'unsafe-eval' *.smns-bw.org https://physalia.evolution.uni-bonn.de;
CSP-librechat:
headers:
contentSecurityPolicy: >
default-src 'self' 'unsafe-inline' 'unsafe-eval' *.smns-bw.org;
frame-ancestors 'self' *.smns-bw.org;
frame-src *.smns-bw.org;
base-uri 'self';
form-action 'self';
img-src 'self' blob: data:;
connect-src 'self';
font-src 'self';
style-src 'self' 'unsafe-inline';
script-src 'self' 'unsafe-inline' 'unsafe-eval' *.smns-bw.org;
CSP-awstats:
headers:
contentSecurityPolicy: >
default-src 'self' 'unsafe-inline' 'unsafe-eval' *.smns-bw.org;
frame-ancestors 'self' *.smns-bw.org;
frame-src *.smns-bw.org;
base-uri 'self';
form-action 'self';
img-src 'self' https://chart.googleapis.com;
connect-src 'self' https://www.gstatic.com/charts/;
font-src 'self';
style-src 'self' 'unsafe-inline';
style-src-elem https://www.gstatic.com/charts/ 'unsafe-inline';
script-src 'self' 'unsafe-inline' 'unsafe-eval' *.smns-bw.org;
script-src-elem https://www.google.com/jsapi https://www.gstatic.com/charts/ 'unsafe-inline' 'unsafe-eval';
CSP-h5p:
headers:
contentSecurityPolicy: >
default-src 'self' 'unsafe-inline' 'unsafe-eval' *.smns-bw.org;
frame-ancestors https://www.naturkundemuseum-bw.de;
frame-src *.smns-bw.org;
base-uri 'self';
form-action 'self';
img-src 'self' data:;
connect-src 'self';
font-src 'self';
style-src 'self' 'unsafe-inline';
script-src 'self' 'unsafe-inline' 'unsafe-eval' *.smns-bw.org;
CSP-biocase:
headers:
contentSecurityPolicy: >
default-src 'self' 'unsafe-inline' 'unsafe-eval' *.smns-bw.org;
frame-ancestors 'self' *.smns-bw.org;
frame-src *.smns-bw.org;
base-uri 'self';
form-action 'self';
img-src 'self' https://unpkg.com/ https://*.tile.osm.org data:;
connect-src 'self';
font-src 'self';
style-src 'self' 'unsafe-inline' https://unpkg.com/leaflet@1.3.3/dist/leaflet.css;
script-src 'self' 'unsafe-inline' 'unsafe-eval' *.smns-bw.org https://unpkg.com/leaflet@1.3.3/dist/leaflet.js https://code.jquery.com/jquery-1.7.min.js;
CSP-prestashop:
headers:
contentSecurityPolicy: >
default-src 'self' 'unsafe-inline' 'unsafe-eval' *.smns-bw.org;
frame-ancestors 'self' *.smns-bw.org;
frame-src *.smns-bw.org;
base-uri 'self';
form-action 'self';
img-src 'self' data:;
connect-src 'self';
font-src 'self';
style-src 'self' 'unsafe-inline';
style-src-elem https://market.smns-bw.org/;
script-src 'self' 'unsafe-inline' 'unsafe-eval' https://market.smns-bw.org/;
CSP-webmin:
headers:
contentSecurityPolicy: >
default-src 'self' 'unsafe-inline' 'unsafe-eval' *.smns-bw.org;
img-src 'self' data:;
font-src 'self' *.smns-bw.org data:;
CSP-collections:
headers:
contentSecurityPolicy: >
default-src 'none';
frame-ancestors 'self' *.smns-bw.org pictures.smns-bw.org;
frame-src *.smns-bw.org;
base-uri 'self';
form-action 'self';
style-src 'self' 'unsafe-inline' *.smns-bw.org https://cloud.ccm19.de;
connect-src 'self' https://cloud.ccm19.de https://matomo.naturkundemuseum-bw.de/;
font-src 'self' *.smns-bw.org;
img-src 'self' data *.smns-bw.org https://a.tile.openstreetmap.org https://b.tile.openstreetmap.org https://c.tile.openstreetmap.org https://cloud.ccm19.de data:;
script-src 'self' 'unsafe-inline' 'unsafe-eval' https://pydeepzoom.smns-bw.org https://matomo.naturkundemuseum-bw.de https://cloud.ccm19.de;
CSP-ent:
headers:
contentSecurityPolicy: >
default-src 'none';
base-uri 'self';
form-action 'self';
style-src-elem https://ent.smns-bw.org/static/css/ 'unsafe-inline';
connect-src 'self' 'unsafe-inline' https://matomo.naturkundemuseum-bw.de;
script-src-elem 'self' 'unsafe-inline' 'unsafe-eval' https://matomo.naturkundemuseum-bw.de https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js https://openseadragon.github.io/openseadragon/openseadragon.js;
img-src 'self' https://openseadragon.github.io/openseadragon/images/;
CSP-digiphyll:
headers:
contentSecurityPolicy: >
default-src 'self' 'unsafe-inline' 'unsafe-eval' *.smns-bw.org;
frame-ancestors 'self' *.smns-bw.org;
frame-src *.smns-bw.org https://144.41.33.40/;
base-uri 'self';
form-action 'self';
img-src 'self' https://a.tile.openstreetmap.org https://b.tile.openstreetmap.org https://c.tile.openstreetmap.org https://unpkg.com/ data:;
connect-src 'self';
font-src 'self' data:;
style-src 'self' 'unsafe-inline' data:;
script-src 'self' 'unsafe-inline' 'unsafe-eval' *.smns-bw.org https://mathjax.rstudio.com/latest/ http://144.41.33.40/ data:;
CSP-geometroidea:
headers:
contentSecurityPolicy: >
default-src 'self';
style-src 'self' 'unsafe-inline' 'unsafe-eval' *.smns-bw.org https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css https://fonts.googleapis.com/css2;
font-src 'self' https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/webfonts/ https://fonts.gstatic.com/s/nunito/v25/;
img-src 'self' data:;
my-traefik-plugin-cookie-path-prefix:
plugin:
traefik-plugin-cookie-path-prefix:
prefix: smns
webportal-errors:
errors:
status:
- „404-503“
service: error-pages-webportal@docker
query: „/{status}.html“
# another-service-errors:
# errors:
# status:
# - „404-503“
# service: error-pages-another-service
# query: „/error-pages-another-service/{status}.html“
tls:
options:
tls-opts:
minVersion: VersionTLS12
cipherSuites:
- „TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256“
- „TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256“
- „TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384“
- „TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384“
- „TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305“
- „TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305“
curvePreferences:
- CurveP521
- CurveP384
# sniStrict: true
Traefik v3 Healthcheck (Docker)
Overview
This page describes how to set up a robust Docker healthcheck for Traefik v3.x.
It covers recent Traefik changes, the “gotchas” with TLS, and provides full configuration (compose and YAML) for reliable service monitoring.
Why Do I Need a Special Healthcheck for Traefik 3?
- As of Traefik 3, the /ping endpoint (Traefik's native health endpoint) can only be bound to a non-TLS (HTTP/plaintext) entrypoint.
- Any attempt to bind /ping to a TLS entrypoint (e.g., :443) causes it to be unavailable and will not log an error!
- Many guides and blog posts referencing Traefik 2.x are now out of date.
- Docker healthchecks are only updated when containers are recreated.
Step-by-Step Setup
1. Add a dedicated HTTP (non-TLS) entrypoint for health
Add this to your traefik.yml:
entryPoints: healthcheck: address: ":8082" ping: entryPoint: healthcheck
- Use any unused high port (8082 is common and outside process-bound port ranges).
- Do not enable TLS or configure HTTP redirection for this entrypoint.
2. Update ''docker-compose.yml'' healthcheck section
healthcheck: test: [ "CMD", "wget", "--spider", "http://localhost:8082/ping" ] interval: 30s timeout: 5s retries: 3 start_period: 10s
3. Recreate the container (!important)
After editing the healthcheck, you must remove and recreate the container to apply the updated check.
docker compose down docker compose up -d
or for just the traefik service:
docker compose rm traefik docker compose up -d traefik
4. Confirm it's working
- Check status with:
docker inspect traefik | grep Health -A 10
- Look for:
„Status“: „healthy“- The test pointing at
http://localhost:8082/ping
- You can also exec into the container:
wget --spider http://localhost:8082/ping
- and expect “remote file exists” or HTTP 200.
Troubleshooting
- If you see
'404 Not Found' or status staysunhealthy, check:- The entryPoint in ping and traefik.yml matches (healthcheck)
- Logs for ping endpoint registration (grep -i ping <traefik.log>)
- Healthcheck in the running container is updated (see
docker inspect)
- If the healthcheck is still using the old endpoint (e.g., port 443), the container must be removed and recreated.
FAQ
- Q: Why not use /ping on :443?
- A: Traefik 3.x forbids it; /ping only works on a non-TLS (HTTP) entrypoint.
- Q: Do I need to expose port 8082 externally?
- A: No; healthchecks run inside the container.
- Q: Can I combine ping and redirect on the same entrypoint?
- A: No; keep your healthcheck entrypoint plain.
References
Authored for SMNS IT by Chattie and AI Programmer — date