Docker Nginx HTTPS 自签证书部署完整操作文档
适用场景:
服务器:10.2.16.41,Docker 部署 Nginx,前端本地 http://127.0.0.1:8090 调用 HTTPS 接口;
流量链路:前端 → 本机 Nginx (10.2.161.41(10.2.161.41)) → 反向代理上游 https://test.xxx.com
上游test.xxx.com网关已配置跨域
Access-Control-Allow-Origin: *,后端无跨域配置
一、环境说明
-
系统:CentOS / RHEL 系列
-
Nginx:Docker 容器运行,镜像 nginx:1.29.3
-
访问地址:
https://10.2.16.41 -
需求:
-
生成兼容新版 Chrome 浏览器自签 SSL 证书
-
Docker Nginx 加载证书提供 HTTPS 访问
-
解决前端 CORS 跨域冲突(多层网关头重复问题)
-
规避
ERR_SSL_KEY_USAGE_INCOMPATIBLE、multiple values *,*等经典报错
-
二、步骤 1:生成兼容浏览器的自签 SSL 证书
2.1 目录准备
进入 docker-compose 工作目录,创建证书文件夹
bash
cd /datasdb/software/nginx
mkdir cert
cd cert
2.2 创建证书配置文件 ssl.conf
ini
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
C = CN
ST = Hubei
L = Wuhan
O = TestDev
OU = DevTeam
CN = 10.2.16.41
[v3_req]
# 完整密钥用途,解决Chrome ERR_SSL_KEY_USAGE_INCOMPATIBLE
keyUsage = digitalSignature, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
IP.1 = 10.2.16.41
2.3 OpenSSL 生成证书(有效期 10 年)
bash
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
-keyout server.key -out server.crt \
-config ssl.conf
执行完成后 cert 目录产出两个核心文件:
-
server.crt证书公钥 -
server.key私钥
⚠️旧证书全部删除,必须使用这份配置重新生成,否则新版 Chrome SSL 策略拦截
三、步骤 2:docker-compose.yaml 配置
文件路径:/datasdb/software/nginx/docker-compose.yaml
yaml
version: '3'
services:
nginx:
restart: always
container_name: nginx
image: nginx:1.29.3
ports:
- "80:80"
- "443:443"
volumes:
- "./nginx.conf:/etc/nginx/nginx.conf"
- "./conf.d:/etc/nginx/conf.d"
- "./cert:/etc/nginx/cert" # 证书挂载,容器内路径固定 /etc/nginx/cert
- "./logs:/var/log/nginx"
- "./conf.d2:/etc/nginx/conf.d2"
user: root
network_mode: bridge
关键说明:
宿主机 ./cert 映射容器 /etc/nginx/cert
Nginx 配置内证书路径必须填写容器内路径,不能填写宿主机物理路径!
四、步骤 3:Nginx 站点完整配置
核心策略:
只拦截浏览器 OPTIONS 预检请求,本机 Nginx 直接返回跨域头,不转发上游
GET/POST 正常业务请求不再新增任何跨域 header ,交由上游
test.xxx.com网关输出跨域避免双层网关同时输出
Access-Control-Allow-Origin,杜绝*,*重复头报错
nginx
server {
listen 443 ssl;
server_name 10.2.16.41;
# 容器内证书路径(重要!不要写宿主机路径)
ssl_certificate /etc/nginx/cert/server.crt;
ssl_certificate_key /etc/nginx/cert/server.key;
# SSL协议优化
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
# =========跨域核心配置=========
# 仅OPTIONS预检请求由本地Nginx直接响应,不代理上游
# 这里下游Nginx如果有配置,这里也不要配置
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin * always;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS,PUT,DELETE always;
add_header Access-Control-Allow-Headers x-yss-jwt-token,Content-Type always;
return 204;
}
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# 【严禁】在此处额外增加任何Access-Control-Allow-Origin头!
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# 引入反向代理规则(转发至test.xxx.com)
include /etc/nginx/conf.d2/server.location;
}
# 80端口配置(保持原有业务配置不变)
server {
server_name localhost;
listen 80 default;
limit_req zone=mylimit burst=200 nodelay;
limit_conn perip 200;
limit_conn perserver 200;
include /etc/nginx/conf.d2/server.location;
}
五、步骤 4:启动 / 重启 Nginx 服务
bash
# 进入工作目录
cd /datasdb/software/nginx
# 停止旧容器
docker-compose down
# 启动
docker-compose up -d
# 校验Nginx配置语法(必执行!)
docker exec -it nginx nginx -t
# 平滑重载(后续修改配置只用这条)
docker exec -it nginx nginx -s reload
六、步骤 5:连通性验证命令
6.1 测试 OPTIONS 预检请求(模拟浏览器跨域预检)
bash
curl -v -X OPTIONS 'https://10.2.16.41/test_csyx/scg/yst-qztynl/dzqz/getOrderSummaryPage' \
-H "Origin: http://127.0.0.1:8090" \
-H "Access-Control-Request-Method: GET" \
-H "Access-Control-Request-Headers: x-yss-jwt-token"
✅预期结果:
HTTP 204 No Content,响应头存在跨域相关 header
6.2 测试正常业务 GET 接口
bash
curl -v -k "https://10.2.16.41/test_csyx/scg/yst-qztynl/dzqz/getOrderSummaryPage?orderStatus=CREATED&pageNum=1&pageSize=10&project=1" -H "x-yss-jwt-token=填写真实token"
✅预期:\\ 仅出现一条 Access-Control-Allow-Origin: \\*
七、前端浏览器自签证书消除不安全警告(Windows)
自签证书天然不被系统信任,浏览器默认提示不安全。
-
将
cert/server.crt下载到本地 Windows 电脑 -
右键 → 安装证书
-
存储位置:本地计算机
-
证书库选择:受信任的根证书颁发机构
-
导入完成后,完全关闭所有 Chrome 窗口(后台进程全部退出),重新打开访问
注意:只刷新页面不会生效,必须彻底重启浏览器。
八、Linux 服务器内部调用相关说明
- curl 使用方案(推荐,无需全局导入系统证书)
bash
# 指定证书访问,安全,不关闭SSL校验
curl --cacert /datasdb/software/nginx/cert/server.crt "https://10.2.16.41/xxx"
-
重要知识点:单层自签证书,CentOS
update-ca-trust经常无法识别,不建议耗费精力导入系统根证书。 -
Java 后端调用:系统证书库和 JDK 证书库隔离,如需 Java 信任证书,单独导入 JDK cacerts。
bash
keytool -importcert \
-alias cert-10.2.16.41 \
-file /datasdb/software/nginx/cert/server.crt \
-keystore $JAVA_HOME/lib/security/cacerts \
-storepass changeit
九、重点注意事项 & 常见故障清单
9.1 证书相关
-
❌不要使用旧证书!旧证书缺少
digitalSignature,Chrome 报ERR_SSL_KEY_USAGE_INCOMPATIBLE -
SSL 配置内路径必须是容器内路径,不能填写宿主机路径,否则启动失败
-
自签证书仅限测试环境,正式对外业务必须购买正规 CA 域名证书
9.2 CORS 跨域重中之重(踩坑核心)
-
绝对禁止两层网关同时配置 add_header 跨域头
本机 Nginx + 上游 sqapi 网关同时输出跨域头 →
Access-Control-Allow-Origin: *,*浏览器直接拦截 -
方案设计取舍:
-
当前方案:本机拦截 OPTIONS;真实业务请求透传上游,由上游处理跨域
-
不允许:本机所有请求统一增加跨域 header
-
-
x-yss-jwt-token属于自定义请求头,跨域配置必须显式声明,不能直接全部用*
9.3 Shell curl 坑
GET 请求 URL 包含&,必须使用英文双引号包裹地址,否则 shell 截断参数
bash
# 错误
curl https://xxx?a=1&b=2
# 正确
curl "https://xxx?a=1&b=2"
9.4 报错快速自查表
| 报错信息 | 解决方案 |
|---|---|
| net::ERR_SSL_KEY_USAGE_INCOMPATIBLE | 使用本文 ssl.conf 重新生成证书 |
| multiple values ',' | 删除一层网关的跨域 add_header |
| No 'Access-Control-Allow-Origin' header | OPTIONS 预检没有返回跨域头,使用文档内 nginx 配置 |
| SSL certificate problem: self signed certificate | curl 增加--cacert参数,或浏览器导入证书 |
| curl: Connection refused | 检查宿主机防火墙、安全组开放 443 端口 |
9.5 防火墙提醒
宿主机 firewalld 放行 443 端口
bash
firewall-cmd --add-port=443/tcp --permanent
firewall-cmd --reload
云服务器额外在服务商安全组开放 443 入方向。