Docker容器内Daphne+Supervisor部署Django应用无法访问问题
问题:Docker容器内用Supervisor管理多Daphne进程导致Nginx 502错误
此前通过多容器部署单进程Daphne可正常访问,改为单容器内用Supervisor管理多Daphne进程后,日志显示应用运行正常,但无法通过浏览器访问。更新后发现:容器内执行curl localhost:8000可正常访问,但容器内外用容器IP访问均失败,Nginx返回:
502 Bad Gateway nginx/1.18.0
现有配置
Supervisord配置
[supervisord] nodaemon=true [supervisorctl] [fcgi-program:asgi] User=root # TCP socket used by Nginx backend upstream socket=tcp://localhost:8000 # Directory where your site's project files are located directory=/app # Each process needs to have a separate socket file, so we use process_num # Make sure to update "mysite.asgi" to match your project name command= /usr/local/bin/daphne -u /run/daphne/daphne%(process_num)d.sock --endpoint fd:fileno=0 --access-log - --proxy-headers WBT.asgi:application # Number of processes to startup, roughly the number of CPUs you have numprocs=4 # Give each process a unique name so they can be told apart process_name=asgi%(process_num)d # Automatically start and recover processes autostart=true autorestart=true # Choose where you want your log to go stdout_logfile=/home/appuser/supervisor_log.log redirect_stderr=true
Nginx配置
upstream django_daphne{ hash $remote_addr consistent; server django_daphne_1:8000; server django_daphne_2:8000; server django_daphne_3:8000; } server { server_name xxx.yyy.zzz.khmm; listen 80; client_max_body_size 64M; location = /favicon.ico { access_log off; log_not_found off; } location / { proxy_pass http://django_daphne; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; #Websocket support proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } location /api/ { proxy_pass http://api_app:8888; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
问题原因
核心矛盾在于Supervisord配置与Daphne启动命令的通信方式不匹配:
- Supervisord的
[fcgi-program:asgi]配置了socket=tcp://localhost:8000,这会让Supervisord在容器的127.0.0.1:8000监听FastCGI请求,再转发给Daphne进程。但这个监听仅绑定本地回环地址,容器外部(包括Nginx容器)无法访问。 - Daphne命令中使用了
--endpoint fd:fileno=0,这意味着Daphne通过Supervisord提供的文件描述符接收请求,而非直接监听TCP端口或Unix套接字对外提供服务。容器内curl localhost:8000能通是因为请求发给了Supervisord的本地监听端口,再被转发给Daphne。
修复方案
方案1:让Daphne直接监听TCP端口(容器间通信友好)
这种方案不需要依赖Supervisord的FCGI转发,让每个Daphne进程直接监听容器的所有IP,方便Nginx容器通过网络访问。
修改Supervisord配置:
- 删除
[fcgi-program:asgi]下的socket=tcp://localhost:8000(FCGI配置对ASGI的Daphne无用) - 调整Daphne启动命令,让每个进程监听不同的TCP端口,绑定容器的0.0.0.0(允许外部访问):
[fcgi-program:asgi] # 其他配置保留 command= /usr/local/bin/daphne -b 0.0.0.0 -p 800%(process_num)d --access-log - --proxy-headers WBT.asgi:application numprocs=4 process_name=asgi%(process_num)d(
800%(process_num)d会生成8000、8001、8002、8003四个端口)- 删除
更新Nginx的upstream配置,指向Daphne容器的四个端口(替换
django_daphne_container为你的容器服务名):upstream django_daphne{ hash $remote_addr consistent; server django_daphne_container:8000; server django_daphne_container:8001; server django_daphne_container:8002; server django_daphne_container:8003; }
方案2:使用Unix套接字(性能更优)
Unix套接字比TCP端口性能更好,适合同一宿主机的容器间通信,需要通过共享卷让Nginx容器访问Daphne的套接字文件。
在docker-compose中添加共享卷:
services: django_daphne: volumes: - daphne_sockets:/run/daphne nginx: volumes: - daphne_sockets:/run/daphne volumes: daphne_sockets:修改Supervisord配置:
- 删除
[fcgi-program:asgi]下的socket=tcp://localhost:8000 - 调整Daphne命令,去掉
--endpoint fd:fileno=0,让它直接监听Unix套接字:
[fcgi-program:asgi] # 其他配置保留 command= /usr/local/bin/daphne -u /run/daphne/daphne%(process_num)d.sock --access-log - --proxy-headers WBT.asgi:application- 删除
更新Nginx的upstream配置,指向共享卷中的Unix套接字:
upstream django_daphne{ hash $remote_addr consistent; server unix:/run/daphne/daphne0.sock; server unix:/run/daphne/daphne1.sock; server unix:/run/daphne/daphne2.sock; server unix:/run/daphne/daphne3.sock; }
验证步骤
- 重启Supervisord服务(或重启Daphne容器)
- 重启Nginx容器
- 在Nginx容器内执行
curl http://django_daphne验证连通性,或直接通过浏览器访问域名测试
内容的提问来源于stack exchange,提问作者MijatTomić
相关产品推荐
相关产品推荐

