Docker Nginx HTTPS 自签证书部署完整操作文档

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: *,后端无跨域配置

一、环境说明

  1. 系统:CentOS / RHEL 系列

  2. Nginx:Docker 容器运行,镜像 nginx:1.29.3

  3. 访问地址:https://10.2.16.41

  4. 需求:

    • 生成兼容新版 Chrome 浏览器自签 SSL 证书

    • Docker Nginx 加载证书提供 HTTPS 访问

    • 解决前端 CORS 跨域冲突(多层网关头重复问题)

    • 规避 ERR_SSL_KEY_USAGE_INCOMPATIBLEmultiple 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 站点完整配置

核心策略:

  1. 只拦截浏览器 OPTIONS 预检请求,本机 Nginx 直接返回跨域头,不转发上游

  2. GET/POST 正常业务请求不再新增任何跨域 header ,交由上游 test.xxx.com 网关输出跨域

  3. 避免双层网关同时输出 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)

自签证书天然不被系统信任,浏览器默认提示不安全。

  1. cert/server.crt 下载到本地 Windows 电脑

  2. 右键 → 安装证书

  3. 存储位置:本地计算机

  4. 证书库选择:受信任的根证书颁发机构

  5. 导入完成后,完全关闭所有 Chrome 窗口(后台进程全部退出),重新打开访问

注意:只刷新页面不会生效,必须彻底重启浏览器。

八、Linux 服务器内部调用相关说明

  1. curl 使用方案(推荐,无需全局导入系统证书)
bash 复制代码
# 指定证书访问,安全,不关闭SSL校验
curl --cacert /datasdb/software/nginx/cert/server.crt "https://10.2.16.41/xxx"
  1. 重要知识点:单层自签证书,CentOS update-ca-trust 经常无法识别,不建议耗费精力导入系统根证书

  2. 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 证书相关

  1. ❌不要使用旧证书!旧证书缺少 digitalSignature,Chrome 报 ERR_SSL_KEY_USAGE_INCOMPATIBLE

  2. SSL 配置内路径必须是容器内路径,不能填写宿主机路径,否则启动失败

  3. 自签证书仅限测试环境,正式对外业务必须购买正规 CA 域名证书

9.2 CORS 跨域重中之重(踩坑核心)

  1. 绝对禁止两层网关同时配置 add_header 跨域头

    本机 Nginx + 上游 sqapi 网关同时输出跨域头 → Access-Control-Allow-Origin: *,* 浏览器直接拦截

  2. 方案设计取舍:

    • 当前方案:本机拦截 OPTIONS;真实业务请求透传上游,由上游处理跨域

    • 不允许:本机所有请求统一增加跨域 header

  3. 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 入方向。

相关推荐
瞬间&永恒~2 小时前
【Docker】(四)Namespace 详解
运维·docker·容器
就改了2 小时前
Docker安装并运行Redis
redis·docker·容器
yagami_gagami4 小时前
第四届黄河流域公安院校电子物证个人赛服务器取证
linux·服务器·网络·mysql·安全·docker·llama
小挪号底迪滴4 小时前
Docker 多阶段构建实战:让 Python 镜像更小、更快、更安全
python·安全·docker
风曦Kisaki4 小时前
Kubernetes(K8s)笔记Day07: StatefulSet 有状态控制器详解与使用案例
linux·docker·云原生·容器·kubernetes
张文君5 小时前
docker registry 删除镜像
运维·docker·容器
cuiyaonan20005 小时前
some weird issues regarding docker
运维·docker·容器
zerwave5 小时前
Docker 学习:多容器网络互通——从 host 模式到自定义 bridge 网络
网络·学习·docker
難釋懷5 小时前
Nginx外置缓存-redis2-nginx-module
nginx·缓存·junit