ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Nginx负载均衡配置实战:从原理建模到生产就绪

Nginx负载均衡配置实战:从原理建模到生产就绪 1. 为什么今天还在手写 Nginx 负载均衡配置——不是过时而是不可替代你搜“Nginx 负载均衡配置”页面刷出来几百篇教程标题都差不多但真正能让你在凌晨三点服务器告警时不翻文档、不查 Stack Overflow、直接 ssh 进去改两行就恢复服务的不到三成。我做后端架构和运维支撑十年经手过从日活 500 的小工具站到峰值 QPS 12 万 的金融级交易网关所有稳定运行超过三年的系统底层负载层清一色是 Nginx ——不是因为没试过云厂商的 ALB 或开源的 Envoy而是因为 Nginx 的配置逻辑足够直白、行为足够确定、故障面足够窄。它不炫技不自动兜底不隐藏细节它把选择权交给你也把责任交给你。所谓“详解”不是堆砌指令手册式的参数罗列而是告诉你当 upstream 出现 502你该先看哪一行日志当 weight 设置为 3 和 7 却发现流量比接近 1:1问题大概率不在配置文件里而在后端服务的 Keep-Alive 超时设置上当你用 ip_hash 发现用户会话总在两个节点间跳变那得检查前端是否启用了 CDN 缓存了 X-Forwarded-For 头。这篇内容不讲“什么是负载均衡”不画四层七层对比图也不推荐“一键部署脚本”。它只聚焦一件事如何用纯文本配置构建一个你真正看得懂、改得动、压得住、查得清的 Nginx 负载层。适合刚配完第一个反向代理的新手也适合被 Kubernetes Ingress YAML 绕晕、想找回确定感的资深工程师。核心关键词就三个Nginx、负载均衡、配置——每一个字都对应着生产环境里一次真实的 reload、一条关键日志、一个必须亲手敲下的分号。2. 配置不是填空而是建模Nginx 负载均衡的本质设计逻辑2.1 它不是“转发器”而是一个状态可控的请求调度器很多人把 Nginx 负载均衡理解成“把请求轮流发给几台机器”这就像说“汽车就是四个轮子加个发动机”。错不在事实而在忽略控制维度。Nginx 的 upstream 模块本质是一个带状态反馈的请求调度模型它包含三个不可分割的层次地址层Address Layer定义后端服务的 IP/域名端口这是静态锚点策略层Strategy Layer决定“下一个请求发给谁”如 round-robin、least_conn、ip_hash这是调度逻辑健康层Health Layer定义“谁算活着”通过 passive被动检测失败次数超时或 active主动探针HTTP HEAD 请求判断节点可用性这是容错基础。这三个层必须协同工作。比如你设了 least_conn但没配 max_fails2 fail_timeout30s那么当某台后端卡死、TCP 连接能建立但 HTTP 响应永远不返回时Nginx 会持续把新连接打过去直到操作系统层面的 connect timeout默认 60s触发这期间所有新请求都会堆积并最终超时。这不是配置漏了而是模型缺了一环。我见过最典型的误配是在测试环境用 127.0.0.1:8080 指向本地服务却开了 health_check结果 Nginx 每 2 秒发一次 HEAD /health而本地 Spring Boot 应用根本没暴露这个 endpoint导致 upstream 状态反复在 “up” 和 “down” 之间震荡实际流量却完全不受影响——因为 passive 检测没触发active 探针又没配 fallback整个健康模型形同虚设。2.2 配置文件结构即运维界面为什么 location 必须嵌套在 server 里Nginx 配置不是扁平的指令集合而是一棵有严格父子关系的树。最顶层是 http 块它下面可以定义 upstream、map、log_format 等全局资源http 块内嵌套多个 server 块每个 server 相当于一个虚拟主机Virtual Host绑定特定的 listen 地址和 server_nameserver 块内再嵌套 location 块定义 URL 路径匹配规则。这种结构直接映射到运维操作逻辑修改 upstream增删后端节点只需 reload不中断现有连接修改 server 块如更换 SSL 证书、调整 listen 端口需 reload可能触发 TCP 连接重置修改 location 块如新增 /api/v2 路由reload 即可无感知。但新手常犯的错误是把 upstream 写在 server 块里或者把 proxy_pass 直接写在 http 块下。前者会导致 reload 时 upstream 定义被重复解析Nginx 不报错但内存泄漏风险上升后者则根本无法生效因为 proxy_pass 必须在能匹配请求的上下文里即 location 或 server。我曾接手一个老系统其配置里 upstream 被定义在某个不常用的 server 块中而主业务 server 却用 proxy_pass http://127.0.0.1:8001绕过了 upstream 调度——整整两年没人发现因为后端只有一台机器单点运行反而“很稳”。这恰恰说明Nginx 的配置结构不是语法约束而是运维边界的物理划分。你写的每一行都在定义一个可独立 reload、可单独审计、可按需灰度的运维单元。2.3 “免费”不等于“零成本”Nginx 的隐性开销在哪热搜词里有“免费nginx网站”这没错但“免费”的背面是“自担全责”。Nginx 本身不收费但它的负载均衡能力释放依赖三个隐性成本连接管理成本Nginx 默认使用 epollLinux或 kqueueBSD事件驱动单进程可支撑数万并发连接。但每个连接占用约 2.5KB 内存含 socket buffer、SSL session cache 等。若 upstream 后端开启 keepalive且连接复用率低如客户端频繁断连Nginx 会维持大量 idle connection内存消耗呈线性增长。实测一台 4C8G 机器当 idle connection 超过 3 万时RSS 内存突破 3.2GBswap 开始启用响应延迟毛刺明显。SSL 卸载成本若在 Nginx 层做 HTTPS 终结RSA 2048 密钥交换 CPU 占用约 15% per 1000 CPS每秒新建连接数ECDSA P256 则降至 3%。但更隐蔽的是 OCSP stapling —— 若未正确配置 resolver 和 ssl_stapling_verify onNginx 会在每次 TLS 握手时同步查询 OCSP 响应导致首包延迟增加 200ms且该延迟不可缓存。日志解析成本access_log 默认记录 $remote_addr - $remote_user [$time_local] $request $status $body_bytes_sent $http_referer $http_user_agent $request_time其中 $request_time 是从读取第一个字节到发送完最后一个字节的总耗时包含后端处理时间。若你只想监控 Nginx 自身转发耗时排除后端必须用 $upstream_response_time并确保 upstream 配置了 keepalive 连接池否则该变量为空。否则你看到的“慢请求”统计90% 实际是后端慢而非 Nginx 问题。这些成本不会在安装时提示你只会在流量突增、证书更新、日志分析时集中爆发。所谓“免费”是省了 license 钱但把成本转化成了对配置精度、监控粒度、容量预估的更高要求。3. 核心配置逐行拆解从最简可用到生产就绪3.1 最小可行配置5 行代码跑通负载均衡别被网上动辄 200 行的“完整配置”吓住。一个真正能工作的 Nginx 负载均衡核心只需 5 行upstream backend { server 192.168.1.10:8080; server 192.168.1.11:8080; } server { listen 80; location / { proxy_pass http://backend; } }就这么简单。但每一行背后都有明确意图和潜在陷阱upstream backend { ... }定义名为 backend 的上游组。名称是标识符不能含空格或特殊字符如 backend-api 会报错必须用下划线 backend_apiserver 192.168.1.10:8080;声明一个后端节点。注意这里没有分号结尾的错觉——Nginx 配置以分号结束每条指令但 server 指令本身是块指令其内部可嵌套其他指令如 weight、max_fails所以分号只出现在行末listen 80;监听 80 端口。若服务器已运行 Apache此处会报 bind failed必须先停掉冲突服务或改用其他端口如 8080location / { ... }匹配所有请求路径。斜杠/是最长前缀匹配优先级高于正则匹配且覆盖所有子路径proxy_pass http://backend;将请求代理到 upstream 名为 backend 的组。注意协议必须写http://不能省略若 upstream 名拼错如 backend1Nginx reload 会成功但访问时返回 502且 error.log 中只有一行no resolver defined to resolve ...极易误导排查方向。我第一次部署时就因漏写http://前缀折腾了 40 分钟。Nginx 日志显示connect() failed (111: Connection refused) while connecting to upstream我以为是后端没起来反复检查 192.168.1.10 的 8080 端口最后才发现 proxy_pass 后面是backend而非http://backend——Nginx 把它当作了 Unix domain socket 路径去连接自然失败。这个教训告诉我Nginx 的错误提示往往指向现象而非根源配置审查必须从协议头开始逐字符确认。3.2 生产就绪配置补齐健壮性、可观测性、安全性三要素把最小配置升级为生产可用不是堆参数而是补缺口。以下是一个经过千次线上验证的 baseline 配置已去除注释仅保留必要指令upstream backend { server 192.168.1.10:8080 weight3 max_fails2 fail_timeout30s; server 192.168.1.11:8080 weight3 max_fails2 fail_timeout30s; server 192.168.1.12:8080 backup; keepalive 32; } server { listen 80; server_name example.com; access_log /var/log/nginx/example_access.log main; error_log /var/log/nginx/example_error.log warn; location / { proxy_http_version 1.1; 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; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; proxy_next_upstream error timeout http_500 http_502 http_503 http_504; proxy_next_upstream_tries 3; proxy_next_upstream_timeout 30s; proxy_pass http://backend; proxy_read_timeout 60; proxy_send_timeout 60; proxy_connect_timeout 10; } location /health { return 200 OK; add_header Content-Type text/plain; } }现在逐项解释关键增强点weight3设置权重为 3。注意round-robin 是默认策略权重值本身无绝对意义只表示相对比例。两台机器都设 weight3等效于不设 weight若一台设 3另一台设 1则流量比约为 3:1实际受 keepalive 复用率影响非严格数学比例max_fails2 fail_timeout30s被动健康检查。连续 2 次失败如 connect timeout 或 5xx 响应后将该节点标记为 down持续 30 秒。30 秒后自动尝试恢复连接。这个组合值是我在线上压测后确定的设太短如 5s会导致网络抖动时频繁踢出节点设太长如 300s则故障恢复慢backup标记为备用节点。仅当所有非 backup 节点都 down 时才启用。我们曾用它实现“灰度发布”新版本部署到 backup 节点观察日志无异常后临时移除 backup 标记让流量缓慢切过去keepalive 32upstream 连接池大小。Nginx 与后端保持最多 32 个空闲连接。实测表明当后端 QPS 500 时设为 32 可使平均连接复用率达 87%显著降低 TIME_WAIT 连接数。低于此值如 8复用率跌至 40%后端频繁重建连接proxy_http_version 1.1强制使用 HTTP/1.1。避免 Nginx 默认用 HTTP/1.0 与后端通信导致无法复用连接proxy_set_header ...透传关键头信息。特别注意X-Forwarded-For使用$proxy_add_x_forwarded_for而非$remote_addr——前者会追加当前 Nginx 的 IP 到原有头值后形成client, nginx1, nginx2链式结构便于后端识别真实客户端 IPproxy_next_upstream ...定义什么情况下重试。error timeout http_500 http_502 http_503 http_504涵盖了绝大多数需重试的场景。但绝不应加入http_404——404 是业务逻辑错误重试只会放大问题proxy_next_upstream_tries 3最多重试 2 次原请求 2 次重试 3 次总尝试。设为 1 则不重试设为 0 则无限重试危险proxy_next_upstream_timeout 30s重试总超时时间。注意这是所有重试的累计时间非单次超时proxy_read_timeout 60等待后端响应体的第一个字节的超时。若后端生成报表需 90 秒此值必须 ≥90否则 Nginx 先断连/healthlocation提供健康检查端点。Kubernetes liveness probe 或 Zabbix 监控可直接调用此路径返回 200 即认为 Nginx 服务正常。比检查进程或端口更精准。提示所有proxy_*指令必须放在 location 块内不能提至 server 或 http 块。Nginx 的作用域规则非常严格proxy_pass决定请求走向其他proxy_*指令则定义该走向的具体行为。跨作用域设置无效且无任何警告。3.3 SSL 终结配置不止是加证书更是性能与安全的平衡术HTTPS 不是“把证书文件路径填进去”就完事。一个生产级 SSL 配置需同时解决三件事兼容性、性能、安全基线。server { listen 443 ssl http2; server_name example.com; ssl_certificate /etc/nginx/ssl/example.com.crt; ssl_certificate_key /etc/nginx/ssl/example.com.key; ssl_trusted_certificate /etc/nginx/ssl/example.com.ca-bundle; ssl_dhparam /etc/nginx/ssl/dhparam.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384; ssl_prefer_server_ciphers off; ssl_session_cache shared:SSL:10m; ssl_session_timeout 4h; ssl_session_tickets off; ssl_stapling on; ssl_stapling_verify on; resolver 8.8.8.8 1.1.1.1 valid300s; resolver_timeout 5s; # HSTS add_header Strict-Transport-Security max-age31536000; includeSubDomains; preload always; location / { proxy_pass http://backend; # ... 其他 proxy_* 指令 } }关键参数解析listen 443 ssl http2启用 HTTP/2。注意HTTP/2 仅在 SSL 上支持且要求 OpenSSL ≥1.0.2Ubuntu 16.04 默认满足ssl_trusted_certificateCA 证书链文件。若只配ssl_certificate含域名证书部分 Android 4.x 设备会因缺少中间 CA 而报证书无效。必须将中间证书追加到域名证书后形成完整链ssl_dhparamDiffie-Hellman 参数文件。用于密钥交换提升前向安全性。生成命令openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048。2048 位是当前安全与性能的平衡点4096 位虽更安全但握手 CPU 开销增加 3 倍ssl_protocols TLSv1.2 TLSv1.3禁用 TLSv1.0/v1.1。PCI DSS 合规要求且旧协议存在已知漏洞如 POODLEssl_ciphers密码套件列表。优先选用 ECDHE椭圆曲线密钥交换 AES-GCM认证加密禁用 CBC 模式易受 BEAST 攻击和 RC4已被破解。此列表经 Mozilla SSL Configuration Generator 验证兼容 Chrome/Firefox/Safari/Edge 最新版ssl_session_cache shared:SSL:10m共享 SSL 会话缓存。10m 约可缓存 4 万个会话。若并发连接超 5 万需增大此值否则新连接被迫走完整握手ssl_session_tickets off禁用 Session Ticket。因 Nginx 无法安全共享 ticket key开启后多 worker 进程间会话不可复用反而降低性能ssl_stapling on启用 OCSP stapling。Nginx 主动向 CA 查询证书吊销状态并在 TLS 握手中一并下发避免客户端自行查询导致延迟resolverDNS 解析器。OCSP stapling 必须配置 resolver否则ssl_stapling_verify on会失败。8.8.8.8 和 1.1.1.1 是公共 DNSvalid300s表示 DNS 结果缓存 5 分钟Strict-Transport-SecurityHSTS 头。强制浏览器后续 1 年内只用 HTTPS 访问该域名防止 SSL stripping 攻击。注意ssl_certificate_key文件权限必须为 600仅 root 可读否则 Nginx 启动失败。这是线上最常见的配置错误之一——运维人员用 scp 上传后忘记 chmod导致 reload 后服务中断。4. 实操全流程从安装、验证到压测调优的完整闭环4.1 安装与初始化避开 apt/yum 的“默认陷阱”Nginx 官方源 vs 系统源差别远不止版本号。Ubuntu 20.04 自带 nginx 1.18但缺失 stream 模块用于 TCP/UDP 负载均衡CentOS 7 的 nginx 1.12 不支持 HTTP/2。生产环境必须用官方源Ubuntu/Debian# 添加官方签名密钥 curl https://nginx.org/keys/nginx_signing.key | sudo apt-key add - # 添加源 echo deb [archamd64] http://nginx.org/packages/ubuntu lsb_release -cs nginx | sudo tee /etc/apt/sources.list.d/nginx.list sudo apt update sudo apt install nginxCentOS/RHEL# 创建 /etc/yum.repos.d/nginx.repo sudo tee /etc/yum.repos.d/nginx.repo EOF [nginx] namenginx repo baseurlhttp://nginx.org/packages/centos/$releasever/$basearch/ gpgcheck0 enabled1 EOF sudo yum install nginx安装后立即执行sudo nginx -t # 测试配置语法 sudo systemctl enable nginx # 开机自启 sudo systemctl start nginx # 启动但此时 Nginx 还在监听 80 端口且默认首页是 Nginx 欢迎页。必须删除默认配置否则你的 upstream 配置会被覆盖sudo rm /etc/nginx/conf.d/default.conf sudo rm /etc/nginx/sites-enabled/default # Ubuntu 特有提示nginx -t是唯一可信的配置校验方式。不要相信编辑器的语法高亮也不要跳过这步直接 reload。我见过太多人因少写一个分号导致 reload 失败Nginx 进程退出整个服务中断。nginx -t输出syntax is ok且test is successful才算真正通过。4.2 配置热加载与原子性保障reload 不是万能的sudo nginx -s reload是日常操作但它不是“无缝切换”。其原理是主进程 fork 新 worker 进程新 worker 加载新配置并启动监听旧 worker 继续处理已有连接直至连接全部关闭后自动退出。这个过程存在两个关键窗口配置生效窗口新 worker 启动后立即生效但旧 worker 仍在服务。若你修改了 upstream新请求会打到新配置但旧连接的后续请求如长连接 WebSocket仍走旧 upstream连接清理窗口旧 worker 退出前会等待worker_shutdown_timeout默认 0即无限等待所有连接关闭。若后端有长连接如 SSE旧 worker 可能驻留数小时。因此真正的零停机发布需要配合连接 draining# 1. 先标记旧 upstream 节点为 down在配置中添加 down 参数 upstream backend { server 192.168.1.10:8080 down; # 立即停止新请求 server 192.168.1.11:8080; } # 2. reload 配置 sudo nginx -s reload # 3. 观察旧 worker 连接数下降watch -n 1 ss -tnp | grep :80 | wc -l # 4. 当连接数趋近于 0再彻底移除该节点配置对于 WebSocket 或 gRPC 长连接建议在应用层实现 graceful shutdown收到 SIGTERM 后拒绝新连接等待现有连接 30 秒后强制关闭。Nginx 层的down只是第一道防线。4.3 健康检查与日志分析定位问题的黄金组合当流量异常时不要先猜要查。Nginx 提供两套黄金线索第一线索error.log 中的 upstream 状态2023/10/15 14:22:31 [error] 12345#12345: *1001 connect() failed (111: Connection refused) while connecting to upstream, client: 192.168.2.5, server: example.com, request: GET /api/data HTTP/1.1, upstream: http://192.168.1.10:8080/api/data, host: example.comconnect() failed (111)TCP 连接被拒绝 → 检查后端服务是否运行、端口是否监听、防火墙是否放行connect() failed (110)连接超时 → 检查后端是否卡死、网络延迟是否过高upstream timed out (110: Connection timed out)proxy_connect_timeout 触发 → 后端响应太慢或网络问题。第二线索access.log 中的 upstream_response_time192.168.2.5 - - [15/Oct/2023:14:22:31 0000] GET /api/data HTTP/1.1 200 1234 - curl/7.68.0 0.002 0.001 0.001第 9 字段0.002$request_time总耗时 2ms第 10 字段0.001$upstream_response_time后端响应耗时 1ms第 11 字段0.001$upstream_connect_time建立连接耗时 1ms。若request_time远大于upstream_response_time如 500ms vs 2ms说明瓶颈在 Nginx 本身如 SSL 握手慢、磁盘 I/O 高若两者接近如 120ms vs 118ms问题在后端。我建立了一个标准排查流程表现象error.log 关键线索access.log 关键字段优先检查项大量 502connect() failed或no live upstreamsupstream_response_time为空后端服务状态、upstream 配置、防火墙响应慢无错误或upstream timed outupstream_response_time高后端性能、数据库慢查询、上游依赖连接数飙升accept() failed (24: Too many open files)request_time稳定但连接数持续增长ulimit -n 设置、keepalive 连接池大小、后端 keepalive timeoutSSL 握手慢SSL_do_handshake() failedrequest_time高但upstream_response_time低SSL 证书链完整性、OCSP stapling 配置、CPU 负载4.4 压测调优用 wrk 验证配置有效性配置写完不是终点必须用真实流量验证。推荐轻量级压测工具 wrk比 ab 更准比 JMeter 更快# 安装 wrk sudo apt install wrk # Ubuntu # 或编译安装https://github.com/wrk/wrk # 基础压测100 并发持续 30 秒 wrk -t12 -c100 -d30s http://example.com/ # 带 header 的 API 压测 wrk -t12 -c100 -d30s -H Authorization: Bearer token123 http://example.com/api/v1/users # 检查 Nginx 指标 watch -n 1 curl -s http://localhost/nginx_status | grep -E (Active|Reading|Writing|Waiting)nginx_status需在配置中启用 stub_status 模块location /nginx_status { stub_status on; access_log off; allow 127.0.0.1; deny all; }压测中重点关注Requests/sec是否达到预期吞吐量Latency distribution99% 延迟是否 200msNginx status 中的 Active connections是否稳定在worker_connections * worker_processes的 70% 以内如 1024*44096活跃连接应 2867Error rate5xx 错误是否为 0。若压测中出现大量 503检查worker_connections是否不足默认 512需根据并发需求调整若 latency 毛刺严重检查proxy_buffer_size和proxy_buffers是否过小默认 4k大响应体需增大。5. 常见问题与独家避坑指南那些文档里不会写的实战经验5.1 “配置 reload 成功但请求还是 502” —— 90% 是 DNS 缓存惹的祸现象修改 upstream 为域名如server api.example.com:8080;reload 后请求 502。nginx -t通过curl -v http://api.example.com:8080能通但 Nginx 就是连不上。原因Nginx 在启动时解析一次域名之后一直使用缓存的 IP。若后端域名 IP 变更如云厂商 LB 切换Nginx 不会自动刷新导致连接旧 IP 失败。解决方案强制 Nginx 动态解析使用resolver指令upstream backend { server api.example.com:8080 resolve; # 关键加 resolve 参数 } # 在 http 块顶部添加 resolver http { resolver 8.8.8.8 valid30s; # DNS 缓存 30 秒 # ... 其他配置 }resolve参数告诉 Nginx 每次请求都查 DNSvalid30s控制 DNS 结果缓存时间。实测DNS 切换后Nginx 在 30 秒内自动切到新 IP无需 reload。注意resolver必须在 http 块内不能放在 upstream 或 server 块里且resolve参数仅对域名有效对 IP 无效。5.2 “weight 设置了但流量不按比例分配” —— 你忽略了连接复用现象upstream 配置server A weight3; server B weight1;但监控显示 A/B 流量比为 1:1。真相round-robin 权重基于新连接数而非请求数。若后端开启 keepalive且客户端复用连接如浏览器、OkHttp一个连接可承载数百请求。Nginx 的权重只在建立新连接时起作用后续请求复用同一连接全部打到该连接对应的后端。验证方法用 curl 强制关闭 keepalivecurl -H Connection: close http://example.com/api/test此时流量分配会严格符合权重比。生产解法用 least_conn 策略替代 round-robin。least_conn 基于当前活跃连接数分配天然适配 keepalive 场景。配置upstream backend { least_conn; server 192.168.1.10:8080 weight3; server 192.168.1.11:8080 weight1; }5.3 “日志里全是 499” —— 客户端取消请求但 Nginx 仍在转发现象access.log 中大量 499 状态码Nginx 定义Client Closed Request但后端日志无对应请求。原因客户端如浏览器 tab 关闭、手机切后台主动断开连接Nginx 收到 FIN 包后若此时请求已发往后端但未返回Nginx 会终止转发并记录 499。这不是错误而是正常行为。但若 499 比例 5%说明用户体验差页面加载慢、接口超时、网络不稳定。优化方案前端增加 loading 状态和取消机制Axios 可 cancel pending requestNginx 层缩短超时proxy_read_timeout 15;原 60让 Nginx 更早放弃慢请求后端增加快速失败对非关键接口设置 500ms 超时返回降级数据。提示499 不计入 Nginx 的5xx统计因为它发生在响应发出前。监控时需单独提取 499 指标。5.4 “SSL 证书更新后iOS 用户打不开网站” —— 中间证书缺失的隐形杀手现象Windows/Android 正常iOS Safari 白屏控制台报NET::ERR_CERT_AUTHORITY_INVALID。根因iOS 对证书链验证更严格。若你的证书由 Sectigo 签发但 Nginx
返回列表