使用Docker/Docker Compose配置Nginx反向代理本地端口遇连接超时
问题解决:Docker Nginx反向代理HTTPS请求超时
核心问题分析
- 容器内
localhost指向错误:Docker容器里的localhost是容器自身的回环地址,不是宿主机。你配置里的proxy_pass http://localhost:3000/和upstream中的server localhost:3000,根本访问不到宿主机上运行的服务。 - Stream模块配置冲突:你在
stream块里同时加了ssl_preread on和SSL证书配置,这俩是互斥的——ssl_preread是用来做不终止SSL的TCP转发,而配置SSL证书是要终止SSL加密,这种矛盾配置直接导致Nginx无法正常处理HTTPS请求。
解决方案
步骤1:修复容器访问宿主机的地址
把配置里所有指向localhost的地址,替换成宿主机的可访问地址:
- 跨平台通用方案:用Docker内置的特殊DNS名称
host.docker.internal(Docker 18.03及以上支持),它会自动解析到宿主机IP。 - Linux替代方案:如果
host.docker.internal无效,要么手动写宿主机的内网IP(比如192.168.1.100),要么在Docker Compose里加extra_hosts: - "host.docker.internal:host-gateway"(Docker 20.10及以上支持)。
步骤2:重构Nginx配置,移除错误的Stream模块
你的后端是HTTP服务,正确做法是在http模块里配置HTTPS服务器,先终止SSL再反向代理到后端,完全不需要用stream模块做TCP转发。修改后的nginx.conf如下:
http { include /etc/nginx/mime.types; default_type application/octet-stream; # 可选:把HTTP请求重定向到HTTPS server { listen 80; server_name yyy.domain2.com xxx.domain1.com; return 301 https://$host$request_uri; } # yyy.domain2.com的HTTPS配置 server { listen 443 ssl; server_name yyy.domain2.com; chunked_transfer_encoding on; # SSL证书路径(注意容器内的路径) ssl_certificate /etc/nginx/.cert/cert.pem; ssl_certificate_key /etc/nginx/.cert/key.pem; # 优化SSL协议和加密套件 ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on; ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS"; location / { proxy_pass http://host.docker.internal:3001/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } # xxx.domain1.com的HTTPS配置 server { listen 443 ssl; server_name xxx.domain1.com; chunked_transfer_encoding on; ssl_certificate /etc/nginx/.cert/cert.pem; ssl_certificate_key /etc/nginx/.cert/key.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on; ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS"; location / { proxy_pass http://host.docker.internal:3000/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } } # 删掉原来的stream块,不需要TCP层的SNI转发
步骤3:(可选)调整Docker Compose配置(针对Linux用户)
如果Linux系统下host.docker.internal不生效,就在docker-compose.yml里加extra_hosts配置:
version: '3.7' services: proxy: image: nginx:alpine container_name: proxy ports: - '443:443' - '80:80' volumes: - ./nginx.conf:/etc/nginx/nginx.conf - ./.cert/cert.pem:/etc/nginx/.cert/cert.pem - ./.cert/key.pem:/etc/nginx/.cert/key.pem restart: 'unless-stopped' extra_hosts: - "host.docker.internal:host-gateway" # 把host.docker.internal指向宿主机网关 networks: - backend networks: backend: driver: bridge
步骤4:重启服务
修改完配置后,重启Nginx容器:
docker-compose down && docker-compose up -d
验证
访问https://xxx.domain1.com/test和https://yyy.domain2.com/test,应该能正常转发到宿主机的3000/3001端口服务。如果还是有问题,检查宿主机防火墙是否允许容器访问3000/3001端口,以及证书文件是否正确挂载到容器内。
内容的提问来源于stack exchange,提问作者Edy Bourne
相关产品推荐
相关产品推荐

