Nginx代理PHP Docker时出现ERR_SSL_PROTOCOL_ERROR问题求助
Nginx代理HTTPS出现ERR_SSL_PROTOCOL_ERROR问题排查与解决
环境背景
搭建了动态生成PHP资源的平台:
- 2个PHP Docker容器,内部使用Apache 80端口,通过
docker-compose部署并加入nginx_default外部网络 - Nginx作为统一代理处理SSL,API通过SSH动态生成容器并添加Nginx配置
- HTTP(80端口)运行正常,但配置HTTPS(443)后出现
ERR_SSL_PROTOCOL_ERROR;目前采用301跳转而非proxy_pass(此前多location场景下proxy_pass配置异常),要求容器内不配置SSL,由Nginx统一处理。
现有配置
第一个PHP容器docker-compose.yml
version: "3.5" services: php_resource_lecturer_1: container_name: php_resource_Lecturer_1 build: context: /home/user/docker-composes/resources_php/templates/ ports: - '9531:80' volumes: - /home/user/docker-composes/ftp/data/ftp/Lecturer_1/php/html/:/var/www/html networks: default: external: true name: nginx_default
第二个PHP容器docker-compose.yml
version: "3.5" services: php_resource_student_2: container_name: php_resource_Student_2 build: context: /home/user/docker-composes/resources_php/templates/ ports: - '9532:80' volumes: - /home/user/docker-composes/ftp/data/ftp/Student_2/php/html/:/var/www/html networks: default: external: true name: nginx_default
现有Nginx配置
map $http_upgrade $connection_upgrade { default upgrade; '' close; } server { listen 80; server_name php.example.com; server_tokens off; server_name_in_redirect off; proxy_set_header Host $host:$server_port; location /.well-known/acme-challenge/ { root /var/www/certbot; } location / { return 301 https://$host$request_uri; } } server { listen 443 ssl; server_name php.example.com; server_tokens off; server_name_in_redirect off; proxy_set_header Host $host:$server_port; ssl_certificate /etc/nginx/certs/data.crt; ssl_certificate_key /etc/nginx/certs/data.key; location /.well-known/acme-challenge/ { root /var/www/certbot; } location ~/lecturer1(.*)$ { return 301 $scheme://php.example.com:9531$1; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header Connection upgrade; # WebSocket support proxy_set_header Upgrade $http_upgrade; allow all; } location ~/student2(.*)$ { return 301 $scheme://php.example.com:9532$1; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header Connection upgrade; # WebSocket support proxy_set_header Upgrade $http_upgrade; allow all; } }
问题原因
当前配置中,HTTPS请求进入Nginx后通过return 301跳转到https://php.example.com:9531$1,但宿主机9531端口映射的是容器内部的Apache HTTP服务(仅监听80端口,无SSL配置)。浏览器收到跳转指令后,尝试用HTTPS协议连接9531端口,而该端口仅提供HTTP服务,协议不匹配导致ERR_SSL_PROTOCOL_ERROR。
此前proxy_pass配置异常大概率是路径匹配或网络访问问题,而非proxy_pass本身不支持多location场景。
解决方案
核心调整
- 替换
return 301为proxy_pass,让Nginx直接将HTTPS请求转发到容器的HTTP服务,避免浏览器直接访问容器端口 - 利用Docker外部网络
nginx_default,通过容器名直接访问服务(无需暴露宿主机端口,提升安全性) - 修正
proxy_pass的路径匹配,确保请求路径正确传递到容器
修正后的Nginx配置
map $http_upgrade $connection_upgrade { default upgrade; '' close; } server { listen 80; server_name php.example.com; server_tokens off; server_name_in_redirect off; location /.well-known/acme-challenge/ { root /var/www/certbot; } location / { return 301 https://$host$request_uri; } } server { listen 443 ssl; server_name php.example.com; server_tokens off; server_name_in_redirect off; ssl_certificate /etc/nginx/certs/data.crt; ssl_certificate_key /etc/nginx/certs/data.key; location /.well-known/acme-challenge/ { root /var/www/certbot; } location ~ /lecturer1(.*)$ { proxy_pass http://php_resource_Lecturer_1$1; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; # 传递HTTPS协议给后端 proxy_set_header Connection $connection_upgrade; proxy_set_header Upgrade $http_upgrade; proxy_http_version 1.1; # 支持WebSocket allow all; } location ~ /student2(.*)$ { proxy_pass http://php_resource_Student_2$1; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; # 传递HTTPS协议给后端 proxy_set_header Connection $connection_upgrade; proxy_set_header Upgrade $http_upgrade; proxy_http_version 1.1; # 支持WebSocket allow all; } }
优化Docker容器配置(可选)
由于Nginx和PHP容器在同一个nginx_default网络中,可直接通过容器名访问服务,无需暴露宿主机端口,可删除ports配置提升安全性:
# 以第一个容器为例,第二个容器同理 version: "3.5" services: php_resource_lecturer_1: container_name: php_resource_Lecturer_1 build: context: /home/user/docker-composes/resources_php/templates/ # 移除ports配置 volumes: - /home/user/docker-composes/ftp/data/ftp/Lecturer_1/php/html/:/var/www/html networks: default: external: true name: nginx_default
关键说明
X-Forwarded-Proto:传递当前请求的协议(HTTPS)给后端容器,确保后端应用能正确识别请求协议proxy_http_version 1.1:配合WebSocket的Upgrade头,确保WebSocket连接正常- 容器名访问:Docker网络内部可直接通过容器名解析到容器IP,无需依赖宿主机端口映射,避免端口冲突
内容的提问来源于stack exchange,提问作者memek
相关产品推荐
相关产品推荐

