Traefik 1.7中OPTIONS请求返回502错误问题求助
问题场景
在Ubuntu系统上,使用Docker容器中的Traefik 1.7代理本地Icecast服务器:
- 手动访问
radio.localhost.traefik.me时,所有CORS头均正常返回 - 从
gsr.localhost.traefik.me跨域访问时,OPTIONS请求始终返回502错误,Traefik日志显示'502 Bad Gateway' caused by: EOF
相关日志与配置
Traefik调试日志
everse-proxy | time="2022-11-11T21:08:01Z" level=debug msg="vulcand/oxy/forward/http: begin ServeHttp on request" Request="{\"Method\":\"OPTIONS\",\"URL\":{\"Scheme\":\"http\",\"Opaque\":\"\",\"User\":null,\"Host\":\"10.10.1.8:8000\",\"Path\":\"\",\"RawPath\":\"\",\"ForceQuery\":false,\"RawQuery\":\"\",\"Fragment\":\"\",\"RawFragment\":\"\"},\"Proto\":\"HTTP/2.0\",\"ProtoMajor\":2,\"ProtoMinor\":0,\"Header\":{\"Accept\":[\"*/*\"],\"Accept-Encoding\":[\"gzip, deflate, br\"],\"Accept-Language\":[\"en-US,en;q=0.9,nl;q=0.8\"],\"Access-Control-Request-Headers\":[\"icy-metadata\"],\"Access-Control-Request-Method\":[\"GET\"],\"Cache-Control\":[\"no-cache\"],\"Origin\":[\"https://gsr.localhost.traefik.me\"],\"Pragma\":[\"no-cache\"],\"Referer\":[\"https://gsr.localhost.traefik.me/\"],\"Sec-Fetch-Dest\":[\"empty\"],\"Sec-Fetch-Mode\":[\"cors\"],\"Sec-Fetch-Site\":[\"same-site\"],\"User-Agent\":[\"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36\"]},\"ContentLength\":0,\"TransferEncoding\":null,\"Host\":\"radio.localhost.traefik.me\",\"Form\":null,\"PostForm\":null,\"MultipartForm\":null,\"Trailer\":null,\"RemoteAddr\":\"127.0.0.1:53784\",\"RequestURI\":\"/radio\",\"TLS\":null}" reverse-proxy | time="2022-11-11T21:08:01Z" level=debug msg="Upstream ResponseWriter of type *pipelining.writerWithoutCloseNotify does not implement http.CloseNotifier. Returning dummy channel." reverse-proxy | time="2022-11-11T21:08:01Z" level=debug msg="'502 Bad Gateway' caused by: EOF" reverse-proxy | time="2022-11-11T21:08:01Z" level=debug msg="vulcand/oxy/forward/http: Round trip: http://10.10.1.8:8000, code: 502, Length: 11, duration: 5.960359ms tls:version: 303, tls:resume:true, tls:csuite:c02f, tls:server:radio.localhost.traefik.me"
docker-compose.yml
version: "3.1" networks: db_default: external: true services: reverse-proxy: container_name: reverse-proxy image: traefik:v1.7-alpine # The official Traefik docker image network_mode: "host" command: --api --docker # Enables the web UI and tells Traefik to listen to docker volumes: - ./docker:/certs:ro - ./docker/traefik.toml:/etc/traefik/traefik.toml - /var/run/docker.sock:/var/run/docker.sock # So that Traefik can listen to the Docker events gsr2: container_name: gsrdev2 build: docker volumes: - .bash_history:/root/.bash_history - ./:/var/www - ./log:/tmp/audit environment: #PHP_IDE_CONFIG: "serverName=gsr2.localhost.xip.io" XDEBUG_CONFIG: "start_with_request=yes" labels: - traefik.enable=true - "traefik.frontend.rule=Host:gsr.localhost.traefik.me" networks: - db_default icecast2: image: pltnk/icecast2 container_name: icecast2 expose: - 8000 volumes: - ./icecast.xml:/etc/icecast2/icecast.xml - ./log:/var/log/icecast2 - ./docker/bundle.pem:/etc/icecast2/bundle.pem labels: - traefik.enable=true - "traefik.frontend.rule=Host:radio.localhost.traefik.me" networks: - db_default
traefik.toml
defaultEntryPoints = ["http","https"] loglevel="DEBUG" [api] dashboard = false [entryPoints] [entryPoints.http] address = ":80" #[entryPoints.http.redirect] # regex = "^http://(www.)*(.*)" # replacement = "https://$2" # permanent = true [entryPoints.https] address = ":443" [entryPoints.https.tls] [[entryPoints.https.tls.certificates]] certFile = "/certs/cert.pem" keyFile = "/certs/key.pem" [docker] endpoint = "unix:///var/run/docker.sock" domain = "localhost.traefik.me" watch = true exposedbydefault = false network = "proxy"
Icecast HTTP头配置
<http-headers> <header name="Access-Control-Allow-Origin" value="*" /> <header name="Vary" value="Origin" /> <header name="Access-Control-Allow-Methods" value="GET, OPTIONS, PUT, POST" /> <header name="Access-Control-Allow-Headers" value="Content-Type, Icy-Metadata" /> <header name="Access-Control-Expose-Headers" value="Icy-MetaInt, Icy-Br, Icy-Description, Icy-Genre, Icy-Name, Ice-Audio-Info, Icy-Url, Icy-Sr, Icy-Vbr, Icy-Pub" /> </http-headers>
解决方案
1. 修正Traefik的Docker网络匹配
traefik.toml中[docker]段的network = "proxy"与icecast使用的db_default网络不匹配,导致Traefik无法正确解析Icecast容器的网络地址。修改traefik.toml:
[docker] endpoint = "unix:///var/run/docker.sock" domain = "localhost.traefik.me" watch = true exposedbydefault = false network = "db_default" # 改为icecast所在的外部网络
2. 让Traefik直接处理OPTIONS请求
部分Icecast版本对OPTIONS请求的处理存在兼容性问题,配置Traefik前端规则,直接返回CORS响应,无需转发到Icecast后端:
更新docker-compose.yml中icecast2的labels:
icecast2: # ... 其他配置不变 labels: - traefik.enable=true - "traefik.frontend.rule=Host:radio.localhost.traefik.me" - "traefik.frontend.headers.customResponseHeaders=Access-Control-Allow-Origin:*" - "traefik.frontend.headers.accessControlAllowMethods=GET,OPTIONS,PUT,POST" - "traefik.frontend.headers.accessControlAllowHeaders=Content-Type,Icy-Metadata" - "traefik.frontend.headers.accessControlExposeHeaders=Icy-MetaInt,Icy-Br,Icy-Description,Icy-Genre,Icy-Name,Ice-Audio-Info,Icy-Url,Icy-Sr,Icy-Vbr,Icy-Pub" - "traefik.frontend.headers.accessControlMaxAge=3600" - "traefik.frontend.passHostHeader=true"
此配置会让Traefik拦截OPTIONS请求,直接返回符合要求的CORS头,避免转发到Icecast产生EOF错误。
3. 验证Icecast容器的可达性(可选)
在主机或Traefik容器中测试Icecast服务的可达性,确认是否是后端服务本身的问题:
# 获取Icecast容器IP docker inspect icecast2 | grep -oP '"IPAddress": "\K[^"]+' # 发送OPTIONS请求测试 curl -X OPTIONS http://<icecast-ip>:8000/radio -H "Origin: https://gsr.localhost.traefik.me" -H "Access-Control-Request-Method: GET" -v
如果Icecast无响应或返回错误,说明后端不处理该路径的OPTIONS请求,优先使用方案2解决。
4. 调整Traefik网络模式(可选)
若Traefik使用host模式存在网络冲突,可改为加入db_default网络并配置端口映射:
更新docker-compose.yml中reverse-proxy的配置:
reverse-proxy: container_name: reverse-proxy image: traefik:v1.7-alpine # 移除network_mode: "host" ports: - "80:80" - "443:443" command: --api --docker volumes: - ./docker:/certs:ro - ./docker/traefik.toml:/etc/traefik/traefik.toml - /var/run/docker.sock:/var/run/docker.sock networks: - db_default # 加入icecast所在网络
同时确保traefik.toml中的network = "db_default"配置正确。
内容的提问来源于stack exchange,提问作者Oli
相关产品推荐
相关产品推荐

