跳至主内容

Traefik

非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

Traefik 是一个现代化的 HTTP 反向代理和负载均衡器,可简化微服务的部署。Traefik 可与您现有的基础设施组件(例如 Docker)集成,并且通常在服务添加或移除时动态配置自身。

本文档提供了 Traefik v2.x 和 Jellyfin 的完整配置方案。它包含多个文件:docker-compose.ymltraefik.toml(Traefik 静态配置)、traefik-provider.toml(基于文件的 Traefik 提供程序)、traefik.log(可选日志文件)、.env(ACME/LetsEncrypt 提供程序所需环境变量)以及 acme.json(ACME/LetsEncrypt 证书状态数据)。所有文件都应创建在同一目录中。或者,您可以修改 docker-compose.ymltraefik 服务的卷路径。虽然可以将部分 traefik.toml 配置直接写入 docker-compose.yml 的标签中,但当前方法更清晰且便于注释。

备注

请确保为 Traefik 启用基本防火墙或身份验证保护,或禁用其仪表板。否则您的仪表板可能从互联网直接访问。请特别注意 IPv6 的可访问性,即使在内网环境中,系统也可能通过 IPv6 直接暴露。有关保护仪表板的详细信息,请参阅 api-insecure

备注

Traefik 提供多种 LetsEncrypt 配置选项,支持不同验证方式。若服务器可通过 80 或 443 端口从互联网访问,可使用 HTTP-01 或 TLS-ALPN-01 验证。此时,certificatesresolvers.leresolver.acme.httpchallenge.entrypoint 必须能被 Let's Encrypt 通过 80/443 端口访问。您也可以使用 DNS-01 验证,通过支持的提供程序实现。具体配置超出本文范围。本指南通过注释/取消注释代码块同时支持 HTTP-01 和 DNS-01。除非拥有 DNS 完全控制权限,否则建议使用 HTTP-01。下方配置采用 RFC2136(通过 traefik.toml 的 certificatesresolvers.leresolver.acme.dnsChallenge 设置),相关变量在 .env 文件中作为格式参考。请根据所选 ACME 提供程序文档调整配置,或在 traefik.toml 注释中切换为 HTTP-01 配置。

下方配置创建 Traefik v2.x 实例,入口点包括:80 端口(标记为 'http')、443 端口(标记为 'https')和 9999 端口(标记为 'secure')。独立于 Jellyfin 配置的是,它会将所有 http(80 端口)流量重定向到 https(443 端口)确保数据加密。对于 Jellyfin,该配置使其在安全入口点无需路径即可访问。此配置仅作为起点,您可能需要根据实际情况调整。若需让 Jellyfin 通过默认 https 端口(无端口号)访问,只需在 docker-compose.yml 指定位置将 'secure' 改为 'https',并移除 SSLHost 参数中的 ':9999'。若需通过路径访问 Jellyfin(如 '/jellyfin'),添加 PathPrefix 并参考文档末尾的 Jellyfin 配置说明。

docker-compose.yml

services:
traefik:
container_name: traefik
image: traefik:chevrotin # the chevrotin tag refers to v2.2.x
restart: unless-stopped
volumes:
# So that Traefik can listen to the Docker events (read-only)
- /var/run/docker.sock:/var/run/docker.sock:ro
# TOML Configuration with global options
- /srv/traefik.toml:/traefik.toml
# Configuration for the file provider (needed for host networking and default TLS Options)
- /srv/traefik-provider.toml:/traefik-provider.toml
# LetsEncrypt ACME Configuration
- /srv/acme.json:/acme.json
# Log File (optional)
- /srv/traefik.log:/traefik.log
ports:
# The Web UI (enabled by --api.insecure=true in traefik.toml)
- 8080:8080
# The Available Ports (forward your router's incoming ports to the ports on the host)
- 80:80
- 443:443
- 9999:9999
env_file: .env

jellyfin:
image: jellyfin/jellyfin
container_name: 'jellyfin'
user: 1000:1000
group_add: # by id as these may not exist within the container. Needed to provide permissions to the VAAPI Devices
- '107' #render
- '44' #video
# Network mode of 'host' exposes the ports on the host. This is needed for DLNA access.
network_mode: 'host'
volumes:
- /path/to/config:/config
- /path/to/cache:/cache
# Update this configuration as desired
- /path/to/media:/media
restart: always
devices:
# VAAPI Devices
- /dev/dri/renderD128:/dev/dri/renderD128
- /dev/dri/card0:/dev/dri/card0
labels:
- 'traefik.enable=true'
## HTTP Router
#### Entry point where Jellyfin is accessible via
#### Change secure to https in the line below to have accessible without needing to specify a port and change the SSLHost option below
- 'traefik.http.routers.jellyfin.entryPoints=secure'
#### Host or Path where Jellyfin is accessible
#### Remove (or change) this rule if you'd rather have Jellyfin accessible at a PathPrefix URI
- 'traefik.http.routers.jellyfin.rule=Host(`HOST_NAME.DOMAIN_NAME`)' # OPTIONAL: && PathPrefix(`/jellyfin`)
#### Enable TLS with the ACME/LetsEncrypt resolver for HOSTNAME.DOMAIN_NAME
- 'traefik.http.routers.jellyfin.tls=true'
- 'traefik.http.routers.jellyfin.tls.certResolver=leresolver'
- 'traefik.http.routers.jellyfin.tls.domains=HOSTNAME.DOMAIN_NAME'
## Middleware
- 'traefik.http.routers.jellyfin.middlewares=jellyfin-mw'
#### The customResponseHeaders option lists the Header names and values to apply to the response.
- 'traefik.http.middlewares.jellyfin-mw.headers.customResponseHeaders.X-Robots-Tag=noindex,nofollow,nosnippet,noarchive,notranslate,noimageindex'
#### The sslRedirect is set to true, then only allow https requests.
- 'traefik.http.middlewares.jellyfin-mw.headers.SSLRedirect=true'
#### The sslHost option is the host name that is used to redirect http requests to https.
#### This is the exact URL that will be redirected to, so you can remove the :9999 port if using default SSL port
- 'traefik.http.middlewares.jellyfin-mw.headers.SSLHost=HOST_NAME.DOMAIN_NAME:9999'
#### Set sslForceHost to true and set SSLHost to forced requests to use SSLHost even the ones that are already using SSL.
#### Note that this uses SSLHost verbatim, so add the port to SSLHost if you are using an alternate port.
- 'traefik.http.middlewares.jellyfin-mw.headers.SSLForceHost=true'
#### The stsSeconds is the max-age of the Strict-Transport-Security header. If set to 0, would NOT include the header.
- 'traefik.http.middlewares.jellyfin-mw.headers.STSSeconds=315360000'
#### The stsIncludeSubdomains is set to true, the includeSubDomains directive will be
#### appended to the Strict-Transport-Security header.
- 'traefik.http.middlewares.jellyfin-mw.headers.STSIncludeSubdomains=true'
#### Set stsPreload to true to have the preload flag appended to the Strict-Transport-Security header.
- 'traefik.http.middlewares.jellyfin-mw.headers.STSPreload=true'
#### Set forceSTSHeader to true, to add the STS header even when the connection is HTTP.
- 'traefik.http.middlewares.jellyfin-mw.headers.forceSTSHeader=true'
#### Set frameDeny to true to add the X-Frame-Options header with the value of DENY.
- 'traefik.http.middlewares.jellyfin-mw.headers.frameDeny=true'
#### Set contentTypeNosniff to true to add the X-Content-Type-Options header with the value nosniff.
- 'traefik.http.middlewares.jellyfin-mw.headers.contentTypeNosniff=true'
#### Set browserXssFilter to true to add the X-XSS-Protection header with the value 1; mode=block.
- 'traefik.http.middlewares.jellyfin-mw.headers.customresponseheaders.X-XSS-PROTECTION=1'
#### The customFrameOptionsValue allows the X-Frame-Options header value to be set with a custom value. This
#### overrides the FrameDeny option.
- "traefik.http.middlewares.jellyfin-mw.headers.customFrameOptionsValue='allow-from https://DOMAIN_NAME'"
## HTTP Service
# We define the port here as a port is required, but note that the service is pointing to the service defined in @file
- 'traefik.http.routers.jellyfin.service=jellyfin-svc@file'
- 'traefik.http.services.jellyfin-svc.loadBalancer.server.port=8096'
- 'traefik.http.services.jellyfin-svc.loadBalancer.passHostHeader=true'
## Redirection of HTTP on port 9999 to HTTPS on port 9999 (consistent protocol)
- 'traefik.http.routers.jellyfin-insecure.entryPoints=secure'
- 'traefik.http.routers.jellyfin-insecure.rule=Host(`HOST_NAME.DOMAIN_NAME`)' # OPTIONAL: && PathPrefix(`/jellyfin`)
- 'traefik.http.routers.jellyfin-insecure.middlewares=jellyfin-insecure-mw'
- 'traefik.http.middlewares.jellyfin-insecure-mw.redirectscheme.scheme=https'
- 'traefik.http.middlewares.jellyfin-insecure-mw.redirectscheme.port=9999' # remove if you are using a default port
- 'traefik.http.middlewares.jellyfin-insecure-mw.redirectscheme.permanent=false'
- 'traefik.http.routers.jellyfin-insecure.service=noop@internal'
注意

TOML 文件不支持环境变量,所有值必须硬编码。

traefik.toml

[log]
# By default, the level is set to ERROR. Alternative logging levels
# are DEBUG, PANIC, FATAL, ERROR, WARN, and INFO.
level = "DEBUG"
filePath = "/traefik.log"

[docker]
# Defines a default docker network to use for connections to all
# containers. This option can be overridden on a container basis
# with the traefik.docker.network label.
network = "traefik"

# Expose containers by default through Traefik. If set to false,
# containers that don't have a traefik.enable=true label will be
# ignored from the resulting routing configuration.
exposedbydefault = false

[api]
# Enable the API in insecure mode, which means that the API will be
# available directly on the entryPoint named traefik. If the entryPoint
# named traefik is not configured, it will be automatically created on
# port 8080.
insecure = true

[providers]
# Connection to docker host system (docker.sock)
# Attach labels to your containers and let Traefik do the rest!
# Traefik works with both Docker (standalone) Engine and Docker Swarm Mode.
# See: https://docs.traefik.io/providers/docker/
[providers.docker]
# Traefik requires access to the docker socket to get its dynamic
# configuration.
endpoint = "unix:///var/run/docker.sock"
[providers.file]
filename = "/traefik-provider.toml"


# EntryPoints are the network entry points into Traefik. They define
# the port which will receive the packets, and whether to listen for
# TCP or UDP.
# See: https://docs.traefik.io/routing/entrypoints/
# NOTE: If a TLS section (i.e. any of its fields) is defined in your docker-compose.yml file,
# then the default configuration does not apply at all.
[entryPoints]
# Standard HTTP redirects to HTTPS
[entryPoints.http]
address = ":80"
[entryPoints.http.http]
[entryPoints.http.http.redirections]
[entryPoints.http.http.redirections.entrypoint]
to = "https"
scheme = "https"
# Standard HTTPS
[entryPoints.https]
address = ":443"
[entryPoints.https.http.tls]
certResolver = "leresolver"
[[entryPoints.https.http.tls.domains]]
main = "HOST_NAME.DOMAIN_NAME"
# SANS are any other hostnames which Traefik should obtain a certificate for.
# If you are using DNS for LetsEncrypt, you can set a wildcard.
# Include all possible hostnames of this server.
#sans = ["*.DOMAIN_NAME"]
# Alternate HTTPS Port (for services - accepts both HTTP and HTTP by not defining a TLS configuration here)
[entryPoints.secure]
address = ":9999"

# Enable ACME (Let's Encrypt): automatic SSL.
[certificatesresolvers.leresolver.acme]
email = "YOU@DOMAIN_NAME"
storage = "acme.json"
# Use HTTP-01 ACME challenge
#[certificateresolvers.leresolver.acme.httpChallenge]
# entryPoint = "http"
# Use a DNS-01 ACME challenge rather than HTTP-01 challenge.
# Mandatory for wildcard certificate generation.
[certificatesresolvers.leresolver.acme.dnsChallenge]
# Update this to your provider of choice and then ensure necessary variables are in the .env file to support it.
provider = "rfc2136"
delayBeforeCheck = 0
# A DNS server used to check whether the DNS is set up correctly before
# making the ACME request. Ideally a DNS server that isn't going to cache an old entry.
resolvers = ["8.8.8.8:53"]

[retry]

由于 Traefik 存在一个特殊限制,当使用 network_mode=host 时无法动态路由到容器。我们已在 traefik-provider.toml 中创建了指向 Docker 主机的静态路由 (192.168.1.xx:8096)。使用主机网络模式(如本文档所示)或 macvlan 是支持 DLNA 或 HdHomeRun 的必要条件,这样才能利用多播网络。traefik-provider.toml 定义了 jellyfin-svc@file 服务,我们在 docker-compose.yml 文件中将路由器指向该服务。由于无法在 docker-compose.yml 中设置 URL,因此我们在外部配置了此服务。请务必将下方 IP 地址更新为本地网络中的主机 IP 地址(本例中为 192.168.1.xx)。

traefik-provider.toml

[http]
[http.services]
[http.services.jellyfin-svc]
[[http.services.jellyfin-svc.loadBalancer.servers]]
url = "http://192.168.1.xx:8096"
# Set secure options by disabling insecure older TLS/SSL versions
# and insecure ciphers. SNIStrict disabled leaves TLS1.0 open.
# If you have problems with older clients, you can may need to relax
# these minimums. This configuration will give you an A+ SSL security
# score supporting TLS1.2 and TLS1.3
[tls.options]
[tls.options.default]
sniStrict = true
minVersion = "VersionTLS12"
curvePreferences = [
"secp521r1",
"secp384r1"
]
cipherSuites = [
"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",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"
]
[tls.options.mintls13]
minVersion = "VersionTLS13"

.env

RFC2136_NAMESERVER=...
RFC2136_TSIG_ALGORITHM=hmac-sha512.
RFC2136_TSIG_KEY=...
RFC2136_TSIG_SECRET=...

最后创建空的 acme.json 和 traefik.log 文件,用于处理证书和日志记录

touch acme.json traefik.log
chmod 600 acme.json traefik.log
注意

整个配置中使用了 DOMAIN_NAME(例如:example.com)和 HOST_NAME(例如:servername)。请将其替换为你的服务器名称。HOST_NAME.DOMAIN_NAME 指代机器本身(例如:servername.example.com)。别忘了将 traefik.toml 中的 YOU@DOMAIN_NAME 更新为你的电子邮件地址。Let's Encrypt 不要求有效邮箱,但无效邮件地址可能被标记为伪造。

启动 Traefik 和 Jellyfin 服务。

docker compose up -d

如果设置了 PathPrefix(例如 /jellyfin),需要配置 Jellyfin 识别该路径。启动服务后,直接访问 Jellyfin(通过主机 IP 的 8096 端口),在 控制面板 / 高级 / 网络 中将 "基础 URL" 修改为对应的路径(如配置中使用了 /jellyfin)。之后,建议创建防火墙规则阻止通过主机 8096 端口直接访问 Jellyfin,或确保该端口无法从互联网访问。

恭喜!你的 Traefik 2.x 和 Jellyfin 服务栈(希望)已正常运行!请检查日志文件或运行时不加 '-d' 参数来排查可能出现的错误,特别是与 Let's Encrypt 配置相关的问题。