{
  "id": "01a108b9-5dd0-742b-ad9c-c35a5c398679",
  "title": "Cloudflare CDN 源站防护配置",
  "slug": "jkckuiu16qdzy8l",
  "editDate": "2026-10-12T09:42:39.921944332Z",
  "createDate": "2026-10-07T18:14:19.514087299Z",
  "tags": [
    "技术"
  ],
  "summary": "本文详细介绍 Cloudflare CDN 源站防护配置方案，结合 1Panel、Docker 与 OpenResty，实现橙云代理、AOP 双向 TLS 认证及真实 IP 识别，并涵盖证书生成、Nginx 配置、防火墙限制与故障排查，帮助站长提升源站安全性。",
  "coverImage": "/post-images/jkckuiu16qdzy8l/cover-4219e268fae5.webp",
  "shareImage": "/post-images/jkckuiu16qdzy8l/cover-4219e268fae5.jpg",
  "html": "<p>为了提升源站安全性，防止公网恶意扫描，很多站长会开启 Cloudflare 橙云代理，并配合 Authenticated Origin Pulls (AOP) 实现源站的 mTLS 校验。但在 1Panel Docker OpenResty 环境下，如何优雅地将 <strong>CA 信任、客户端验证、Cloudflare 真实 IP 识别 </strong>揉进一份<strong> nginx.conf </strong>中，且不破坏原有的 1Panel 站点与 WAF 配置？</p><p>这篇文章记录了我的完整配置过程。适用流量链路如下：</p><p>访客 → Cloudflare 橙云代理 → 1Panel Docker OpenResty HTTPS → 后端应用</p><h2 id=\"heading-核心概念与准备工作-0\">核心概念与准备工作</h2><h3 id=\"heading-什么是橙云代理与源站防护-1\">什么是橙云代理与源站防护</h3><div class=\"halo-table-wrapper\"><table><tbody><tr><th><p>设置</p></th><th><p>配置位置</p></th><th><p>作用</p></th></tr><tr><td><p>Proxied（橙云）</p></td><td><p>Cloudflare DNS</p></td><td><p>让访客优先经 Cloudflare 访问网站，默认隐藏源站 IP 地址</p></td></tr><tr><td><p>完全加密</p></td><td><p>Cloudflare SSL/TLS</p></td><td><p>验证源站的网站服务端证书（必须是存在且有效的证书）</p></td></tr><tr><td><p>区域级 AOP 与源站 mTLS 校验</p></td><td><p>Cloudflare 与 OpenResty 两端</p></td><td><p>Cloudflare 出示专用客户端证书，源站验证后才接受请求</p></td></tr></tbody></table></div><blockquote><p><strong>特别说明：</strong></p><ul><li><p>这里的“源站防护”指上述设置配合公网入口限制，没有一个设置可以替代所有步骤。</p></li><li><p>AOP 证明连接方持有受信任客户端私钥；它本身不校验 HTTP Host 与 Cloudflare Zone 的绑定，所以不可以替代服务器本身的防火墙。</p></li><li><p>AOP 配置完成后，务必在云服务器安全组把 HTTPS 端口只开放给 CF 的官方 IP 段。另外，测试阶段不适合一开始就把 Nginx 的验证强制设为 <strong>On</strong>，先用 <strong>Optional</strong>，不然容易导致业务宕机。</p></li></ul></blockquote><h3 id=\"heading-实施顺序-2\">实施顺序</h3><p>鉴于配置步骤略微复杂，建议按照下方的步骤，进行配置：</p><ul><li><p>在 DNS 设置中将网站记录开启橙云代理</p></li><li><p>在 SSL/TLS → 概述 中，加密模式设为 完全 (严格)</p></li><li><p>在 1Panel 网站设置中已配好有效的 HTTPS 服务端证书（Let's Encrypt 或 Cloudflare Origin CA 均可，AOP 证书不替代服务端证书）</p></li><li><p>在信任的管理机生成 区域级 AOP 证书，并导入源站服务器</p></li><li><p>源站 1Panel/OpenResty 全局配置加载 区域级 AOP 证书（调试阶段请使用 Optional 选项，后续确认无误可手动切换为 On）</p></li><li><p>开启 Cloudflare 区域级 AOP 开关，确认有无报错</p></li><li><p>确认无误，全局配置区域级 AOP 证书，收紧服务器防火墙</p></li></ul><h2 id=\"heading-实施指南-3\">实施指南</h2><h3 id=\"heading-前置准备-4\">前置准备</h3><p>1. 打开域名控制台，进入 DNS，将网站记录设置为 <strong>Proxied／已代理</strong>，即橙云。</p><figure class=\"post-figure\"><img src=\"/post-images/jkckuiu16qdzy8l/img-1-164693862191.webp\" alt=\"图1 开启橙云代理\" width=\"1590\" height=\"366\" decoding=\"async\" class=\"zoom-image\" tabindex=\"0\" role=\"button\" data-gallery-index=\"0\" aria-label=\"查看大图：图1 开启橙云代理\"><figcaption class=\"image-caption\">图1 开启橙云代理</figcaption></figure><p>2. 进入 <code>SSL/TLS</code><strong> → </strong><code>概述</code>，将加密模式设为 <code>完全（严格）</code>。</p><figure class=\"post-figure\"><img src=\"/post-images/jkckuiu16qdzy8l/img-2-35ea86bb5fb9.webp\" width=\"1920\" height=\"690\" decoding=\"async\" class=\"zoom-image\" tabindex=\"0\" role=\"button\" data-gallery-index=\"1\" alt=\"图2 修改加密模式\" aria-label=\"查看大图：图2 修改加密模式\"><figcaption class=\"image-caption\">图2 修改加密模式</figcaption></figure><p>3. 确认 1Panel 网站已启用 HTTPS，使用域名匹配且有效的服务端证书。现有 <code>Cloudflare Origin CA 服务端证书</code> 或 <code>Let's Encrypt</code> 仍需保留；AOP 客户端证书不替代它。</p><blockquote><p><strong>特别说明：</strong></p><ul><li><p>Cloudflare Origin CA 服务器证书，无法脱离 Cloudflare 平台使用，不被现代浏览器信任</p></li><li><p>Let's Encrypt 证书，免费证书，可直接在 1Panel 面板公开申请并使用（需添加 DNS 账户 API 和 ACME 账号验证）</p></li></ul></blockquote><figure class=\"post-figure\"><img src=\"/post-images/jkckuiu16qdzy8l/img-3-124cb4c9c807.webp\" width=\"1920\" height=\"693\" decoding=\"async\" class=\"zoom-image\" tabindex=\"0\" role=\"button\" data-gallery-index=\"2\" alt=\"图3 创建 Cloudflare 源站证书\" aria-label=\"查看大图：图3 创建 Cloudflare 源站证书\"><figcaption class=\"image-caption\">图3 创建 Cloudflare 源站证书</figcaption></figure><figure class=\"post-figure\"><img src=\"/post-images/jkckuiu16qdzy8l/img-4-a0cd1093de81.webp\" width=\"1920\" height=\"393\" decoding=\"async\" class=\"zoom-image\" tabindex=\"0\" role=\"button\" data-gallery-index=\"3\" alt=\"图4 申请 Let's Encrypt 证书\" aria-label=\"查看大图：图4 申请 Let's Encrypt 证书\"><figcaption class=\"image-caption\">图4 申请 Let's Encrypt 证书</figcaption></figure><p>4. 进入 <strong>SSL/TLS → Origin Server → Authenticated Origin Pulls</strong>，检查当前配置<strong> </strong>(相关生成教程见后文)。</p><blockquote><p><strong>特别说明：</strong></p><ul><li><p>不要把 <strong>全局 AOP </strong>开关当成 <strong>区域级 AOP</strong>，两者互相独立</p></li><li><p>若当前已配置 按主机名 AOP，则它对指定主机名生效。优先级高于区域级 AOP 配置，应检查其是否使用其他证书</p></li><li><p>SSL/TLS 加密的 关闭 (不安全)/ 灵活 模式不适用 AOP</p></li><li><p>Cloudflare Tunnel 也不适用此部署方式</p></li><li><p>我这里为了方便，直接签发了完整的 15 年证书。如果为了安全，应把客户端有效期设置为短日期，后续使用 CA 根证书进行更新</p></li></ul></blockquote><h3 id=\"heading-生成自定义-aop-证书-5\">生成自定义 AOP 证书</h3><p>在安全管理主机的 Bash 终端执行，先准备 OpenSSL 和 Python 3。</p><p>每次执行都会新建目录，并不会覆盖现有密钥。将下面代码中的 <code>example.com</code> 替换为实际要部署的目标根域名。</p><p>生成过程中 CA 私钥会要求设置口令（提示 Enter PEM pass phrase）；客户端私钥使用无口令 PEM 供 Cloudflare 使用。</p><p>Enter pass phrase for rootca.key，这个是需要输入两次之前设置的密码，不是再设置一个新密码。</p><div class=\"code-block\"><button type=\"button\" class=\"copy-btn\" aria-label=\"复制代码\">复制</button><pre><code class=\"language-shellscript hljs\">umask 077\nAOP_WORK=<span class=\"hljs-string\">\"$HOME/cf-zone-aop-$(date +%Y%m%d-%H%M%S)\"</span>\nmkdir <span class=\"hljs-string\">\"$AOP_WORK\"</span>\ncd <span class=\"hljs-string\">\"$AOP_WORK\"</span>\n<span class=\"hljs-comment\"># 将 example.com 替换为目标 Zone 的域名。</span>\nAOP_ZONE='example.com'\n<span class=\"hljs-comment\"># 按日历计算：客户端 15 年，CA 在客户端到期月份后再延长一个月。</span>\n<span class=\"hljs-comment\"># 处理闰年；遇到目标月没有该日时，取该月最后一天。</span>\nVALIDITY_DAYS=<span class=\"hljs-variable\">$(python3 - &lt;&lt;'PYDATES'\nfrom datetime import datetime, timezone\nimport calendar\ntoday = datetime.now(timezone.utc)</span>.date()\nclient_year = today.year + 15\nclient_end = today.replace(\nyear=client_year,\nday=min(today.day, calendar.monthrange(client_year, today.month)[1]),\n)\nca_year = client_end.year + (client_end.month == 12)\nca_month = client_end.month % 12 + 1\nca_end = client_end.replace(\nyear=ca_year, month=ca_month,\nday=min(client_end.day, calendar.monthrange(ca_year, ca_month)[1]),\n)\nprint((client_end - today).days, (ca_end - today).days)\nPYDATES\n) || { echo '有效期计算失败，停止'; exit 1; }\nread -r CLIENT_DAYS CA_DAYS &lt;&lt;&lt; <span class=\"hljs-string\">\"$VALIDITY_DAYS\"</span>\nprintf '客户端有效期 %s 天；CA 有效期 %s 天\\n' <span class=\"hljs-string\">\"$CLIENT_DAYS\"</span> <span class=\"hljs-string\">\"$CA_DAYS\"</span>\ncat &gt; rootca.cnf &lt;&lt;EOF\n[req]\nprompt = no\ndistinguished_name = dn\nx509_extensions = v3_ca\n[dn]\nCN = ${AOP_ZONE} Dedicated AOP Root CA\n[v3_ca]\nbasicConstraints = critical,CA:TRUE,pathlen:0\nkeyUsage = critical,keyCertSign,cRLSign\nsubjectKeyIdentifier = hash\nauthorityKeyIdentifier = keyid:always\nEOF\nopenssl genrsa -aes256 -out rootca.key 4096\nopenssl req -x509 -new -sha256 -days <span class=\"hljs-string\">\"$CA_DAYS\"</span> \\\n-key rootca.key -out rootca.crt -config rootca.cnf\nopenssl genrsa -out aop-client.key 4096\nopenssl req -new -sha256 -key aop-client.key \\\n-out aop-client.csr -subj <span class=\"hljs-string\">\"/CN=${AOP_ZONE} Cloudflare AOP Client\"</span>\ncat &gt; client.ext &lt;&lt;'EOF'\nbasicConstraints = critical,CA:FALSE\nkeyUsage = critical,digitalSignature\nextendedKeyUsage = clientAuth\nsubjectKeyIdentifier = hash\nauthorityKeyIdentifier = keyid,issuer\nEOF\nopenssl x509 -req -sha256 -days <span class=\"hljs-string\">\"$CLIENT_DAYS\"</span> \\\n-in aop-client.csr -CA rootca.crt -CAkey rootca.key \\\n-CAcreateserial -out aop-client.crt -extfile client.ext\nopenssl verify -purpose sslclient -CAfile rootca.crt aop-client.crt\nopenssl x509 -in aop-client.crt -noout -subject -issuer -dates\nopenssl x509 -in rootca.crt -noout -fingerprint -sha256</code></pre></div><p>执行以下命令，检查客户端证书和私钥匹配，两条哈希应相同：</p><div class=\"code-block\"><button type=\"button\" class=\"copy-btn\" aria-label=\"复制代码\">复制</button><pre><code class=\"language-shellscript hljs\">openssl x509 -<span class=\"hljs-keyword\">in</span> aop-client.crt -pubkey -noout | openssl pkey -pubin -outform DER | openssl dgst -sha256\nopenssl pkey -<span class=\"hljs-keyword\">in</span> aop-client.<span class=\"hljs-keyword\">key</span> -pubout -outform DER | openssl dgst -sha256</code></pre></div><h3 id=\"heading-将证书导入-cloudflare-aop-6\">将证书导入 Cloudflare AOP</h3><p>进入目标域名的 <code>SSL/TLS</code> → <code>原服务器</code> → <code>Authenticated Origin Pulls</code> →<code> 区域级 AOP</code> → <code>上传证书</code>，上传上一步生成的相关证书文件。</p><p>相关证书文件的用途说明见下表</p><div class=\"halo-table-wrapper\"><table><tbody><tr><th><p>文件</p></th><th><p>导入位置</p></th><th><p>用途</p></th></tr><tr><td><p>aop-client.crt</p></td><td><p>Cloudflare Zone-level Certificate</p></td><td><p>回源客户端叶证书</p></td></tr><tr><td><p>aop-client.key</p></td><td><p>Cloudflare Zone-level Private key</p></td><td><p>回源客户端私钥</p></td></tr><tr><td><p>rootca.crt</p></td><td><p>源站持久化目录，命名 ca.crt</p></td><td><p>验证客户端证书的 CA 公钥</p></td></tr><tr><td><p>rootca.key</p></td><td><p>加密，脱机离线保存</p></td><td><p>后续签发和续期客户端证书使用，不放入 OpenResty</p></td></tr></tbody></table></div><figure class=\"post-figure\"><img src=\"/post-images/jkckuiu16qdzy8l/img-5-898fcf460913.webp\" width=\"1083\" height=\"685\" decoding=\"async\" class=\"zoom-image\" tabindex=\"0\" role=\"button\" data-gallery-index=\"4\" alt=\"图5 上传区域级 AOP 证书\" aria-label=\"查看大图：图5 上传区域级 AOP 证书\"><figcaption class=\"image-caption\">图5 上传区域级 AOP 证书</figcaption></figure><h3 id=\"heading-查看当前容器信息-7\">查看当前容器信息</h3><p>以下命令在 <strong>源站宿主机</strong> 的 Bash 终端执行，需 Docker 管理权限。容器名、路径均需替换。</p><div class=\"code-block\"><button type=\"button\" class=\"copy-btn\" aria-label=\"复制代码\">复制</button><pre><code class=\"language-shellscript hljs\"><span class=\"hljs-comment\"># 查看当前的 Docker 容器信息</span>\ndocker ps --<span class=\"hljs-keyword\">format</span> <span class=\"hljs-string\">'table {{.Names}}\\t{{.Image}}\\t{{.Ports}}'</span>\n\n<span class=\"hljs-comment\"># 设置变量</span>\n<span class=\"hljs-comment\"># 设置变量 'OR_CONTAINER' 为 OpenResty 容器名称</span>\nOR_CONTAINER=<span class=\"hljs-string\">'替换为实际OpenResty容器名'</span>\n<span class=\"hljs-comment\"># 设置变量 'NGINX_BIN' 为 容器内部 NGINX 程序的路径</span>\nNGINX_BIN=<span class=\"hljs-string\">'/usr/local/openresty/nginx/sbin/nginx'</span>\n\n<span class=\"hljs-comment\"># 查看容器网络模式</span>\ndocker inspect <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$OR_CONTAINER</span>\"</span> --<span class=\"hljs-keyword\">format</span> <span class=\"hljs-string\">'{{.HostConfig.NetworkMode}}'</span>\n<span class=\"hljs-comment\"># 查看目录和文件挂载</span>\ndocker inspect <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$OR_CONTAINER</span>\"</span> --<span class=\"hljs-keyword\">format</span> <span class=\"hljs-string\">'{{range .Mounts}}{{println .Type .Source \"-&gt;\" .Destination \"RW=\" .RW}}{{end}}'</span>\n<span class=\"hljs-comment\"># 查看容器启动命令</span>\ndocker inspect <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$OR_CONTAINER</span>\"</span> --<span class=\"hljs-keyword\">format</span> <span class=\"hljs-string\">'{{json .Config.Entrypoint}} {{json .Config.Cmd}}'</span>\n<span class=\"hljs-comment\"># 查看 NGINX 版本和编译参数</span>\ndocker <span class=\"hljs-keyword\">exec</span> <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$OR_CONTAINER</span>\"</span> <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$NGINX_BIN</span>\"</span> -V</code></pre></div><h3 id=\"heading-持久化挂载配置文件-8\">持久化挂载配置文件</h3><p>这里按照挂载整个 conf 目录进行操作，如若只单独挂载 nginx.conf 文件，则需要在容器的编排文件中添加添加一条只读映射</p><div class=\"code-block\"><button type=\"button\" class=\"copy-btn\" aria-label=\"复制代码\">复制</button><pre><code class=\"language-shellscript hljs\">OR_CONF_HOST=<span class=\"hljs-string\">'/替换为实际宿主机conf目录'</span>\n<span class=\"hljs-built_in\">test</span> -f <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$OR_CONF_HOST</span>/nginx.conf\"</span> || { <span class=\"hljs-built_in\">echo</span> <span class=\"hljs-string\">'配置路径错误，停止'</span>; <span class=\"hljs-built_in\">exit</span> 1; }\n<span class=\"hljs-comment\"># 备份放在 conf 目录之外，避免备份自身</span>\nBACKUP_DIR=<span class=\"hljs-string\">\"/root/openresty-aop-backup-<span class=\"hljs-subst\">$(date +%Y%m%d-%H%M%S)</span>\"</span>\n<span class=\"hljs-built_in\">mkdir</span> -m 700 <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$BACKUP_DIR</span>\"</span>\n<span class=\"hljs-built_in\">cp</span> -a <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$OR_CONF_HOST</span>/nginx.conf\"</span> <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$BACKUP_DIR</span>/nginx.conf\"</span>\ntar -C <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$OR_CONF_HOST</span>\"</span> -czf <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$BACKUP_DIR</span>/conf-before-aop.tar.gz\"</span> .\ndocker <span class=\"hljs-built_in\">exec</span> <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$OR_CONTAINER</span>\"</span> <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$NGINX_BIN</span>\"</span> -T &gt; <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$BACKUP_DIR</span>/nginx-before-aop.txt\"</span> 2&gt;&amp;1\n<span class=\"hljs-built_in\">printf</span> <span class=\"hljs-string\">'备份位置：%s\\n'</span> <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$BACKUP_DIR</span>\"</span></code></pre></div><h3 id=\"heading-导入-ca-公钥证书-9\">导入 CA 公钥证书</h3><p>如果证书在其他管理主机生成，先安全传输 <code>rootca.crt</code> 到源站宿主机。</p><div class=\"code-block\"><button type=\"button\" class=\"copy-btn\" aria-label=\"复制代码\">复制</button><pre><code class=\"language-shellscript hljs\">ROOTCA_SOURCE=<span class=\"hljs-string\">'/替换为源站宿主机上的rootca.crt路径'</span>\ninstall -m 0644 <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$ROOTCA_SOURCE</span>\"</span> <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$OR_CONF_HOST</span>/ca.crt\"</span>\n<span class=\"hljs-comment\"># 两次输出的 SHA-256 指纹应相同</span>\nopenssl x509 -<span class=\"hljs-keyword\">in</span> <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$ROOTCA_SOURCE</span>\"</span> -noout -fingerprint -sha256\ndocker <span class=\"hljs-built_in\">exec</span> <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$OR_CONTAINER</span>\"</span> <span class=\"hljs-built_in\">cat</span> /usr/local/openresty/nginx/conf/ca.crt \\\n| openssl x509 -noout -fingerprint -sha256</code></pre></div><h3 id=\"heading-配置-1panel-openresty-10\">配置 1Panel OpenResty</h3><p>在 1Panel 网站列表上方的 <code>OpenResty 设置</code> → <code>配置修改</code> 中编辑当前生效主配置，或编辑已确认的宿主机 nginx.conf；选择一种方式完成同一次修改。不要点击“恢复默认配置”，该按钮会覆盖自定义内容。</p><p><strong>首次粘贴前：只把下方 </strong><code>ssl_verify_client on;</code><strong> 改为 </strong><code>ssl_verify_client optional;</code><strong>。验收成功后改回 on。</strong></p><div class=\"code-block\"><button type=\"button\" class=\"copy-btn\" aria-label=\"复制代码\">复制</button><pre><code class=\"language-nginx hljs\"><span class=\"hljs-comment\"># Worker 运行用户及进程数</span>\nuser root;\nworker_processes auto;\n\n<span class=\"hljs-comment\"># 错误日志：同时输出到文件和标准输出</span>\nerror_log /var/log/nginx/error.log notice;\nerror_log /dev/stdout notice;\npid /var/run/nginx.pid;\n\n<span class=\"hljs-comment\"># 单个 worker 可打开的文件描述符上限</span>\nworker_rlimit_nofile 51200;\n\n<span class=\"hljs-comment\"># 加载动态模块</span>\ninclude /usr/local/openresty/nginx/conf/modules-enabled/*.conf;\n\nevents {\n    <span class=\"hljs-comment\"># Linux 事件模型</span>\n    use epoll;\n    <span class=\"hljs-comment\"># 单个 worker 的最大连接数（包含上游连接）</span>\n    worker_connections 5120;\n    <span class=\"hljs-comment\"># 一次接受所有待处理的新连接</span>\n    multi_accept on;\n}\n\nhttp {\n    <span class=\"hljs-comment\"># MIME 类型及默认响应类型</span>\n    include mime.types;\n    default_type application/octet-stream;\n\n    <span class=\"hljs-comment\"># Cloudflare 可信代理 IPv4 网段：部署前及后续定期核对官方列表</span>\n    set_real_ip_from 103.21.244.0/22;\n    set_real_ip_from 103.22.200.0/22;\n    set_real_ip_from 103.31.4.0/22;\n    set_real_ip_from 104.16.0.0/13;\n    set_real_ip_from 104.24.0.0/14;\n    set_real_ip_from 108.162.192.0/18;\n    set_real_ip_from 131.0.72.0/22;\n    set_real_ip_from 141.101.64.0/18;\n    set_real_ip_from 162.158.0.0/15;\n    set_real_ip_from 172.64.0.0/13;\n    set_real_ip_from 173.245.48.0/20;\n    set_real_ip_from 188.114.96.0/20;\n    set_real_ip_from 190.93.240.0/20;\n    set_real_ip_from 197.234.240.0/22;\n    set_real_ip_from 198.41.128.0/17;\n\n    <span class=\"hljs-comment\"># Cloudflare 可信代理 IPv6 网段</span>\n    set_real_ip_from 2400:cb00::/32;\n    set_real_ip_from 2606:4700::/32;\n    set_real_ip_from 2803:f800::/32;\n    set_real_ip_from 2405:b500::/32;\n    set_real_ip_from 2405:8100::/32;\n    set_real_ip_from 2a06:98c0::/29;\n    set_real_ip_from 2c0f:f248::/32;\n\n    <span class=\"hljs-comment\"># 仅对可信代理提供的请求头执行真实 IP 替换</span>\n    real_ip_header CF-Connecting-IP;\n    real_ip_recursive on;\n\n    <span class=\"hljs-comment\"># remote_addr：替换后的客户端 IP；realip_remote_addr：原始连接对端 IP</span>\n    <span class=\"hljs-comment\"># ssl_client_verify：客户端证书验证结果；cfip：原始 CF-Connecting-IP 头</span>\n    log_format main\n        <span class=\"hljs-string\">'$remote_addr - $remote_user [$time_local] \"$request\" '</span>\n        <span class=\"hljs-string\">'$status $body_bytes_sent \"$http_referer\" '</span>\n        <span class=\"hljs-string\">'\"$http_user_agent\" \"$http_x_forwarded_for\"'</span>\n        <span class=\"hljs-string\">' peer=$realip_remote_addr aop=$ssl_client_verify'</span>\n        <span class=\"hljs-string\">' cfip=\"$http_cf_connecting_ip\"'</span>;\n\n    <span class=\"hljs-comment\"># HTTP 访问日志</span>\n    access_log /var/log/nginx/access.log main;\n    access_log /dev/stdout main;\n\n    <span class=\"hljs-comment\"># 隐藏响应头和错误页中的版本号</span>\n    server_tokens off;\n\n    <span class=\"hljs-comment\"># 文件发送及 TCP 参数</span>\n    sendfile on;\n    tcp_nopush on;\n    tcp_nodelay on;\n\n    <span class=\"hljs-comment\"># 虚拟主机名称哈希桶及客户端请求缓冲参数</span>\n    server_names_hash_bucket_size 512;\n    client_header_buffer_size 32k;\n    client_max_body_size 50m;\n\n    <span class=\"hljs-comment\"># Keepalive 空闲超时（秒）及单个连接的请求数上限</span>\n    keepalive_timeout 60;\n    keepalive_requests 5000;\n\n    <span class=\"hljs-comment\"># Gzip 压缩：最小响应长度、缓冲区、最低请求协议版本及压缩等级</span>\n    gzip on;\n    gzip_min_length 1k;\n    gzip_buffers 4 16k;\n    gzip_http_version 1.1;\n    gzip_comp_level 5;\n\n    <span class=\"hljs-comment\"># 额外允许压缩的 MIME 类型（text/html 默认包含）</span>\n    gzip_types\n        text/plain\n        text/css\n        text/xml\n        text/javascript\n        application/json\n        application/ld+json\n        application/javascript\n        application/x-javascript\n        application/xml\n        application/xhtml+xml\n        application/rss+xml\n        application/atom+xml\n        application/wasm\n        image/svg+xml\n        font/ttf\n        font/otf;\n\n    <span class=\"hljs-comment\"># 添加 Vary: Accept-Encoding，并允许压缩带 Via 头的代理请求响应</span>\n    gzip_vary on;\n    gzip_proxied any;\n\n    <span class=\"hljs-comment\"># 连接限制共享内存区域；实际限制需在子配置中使用 limit_conn 设置</span>\n    limit_conn_zone <span class=\"hljs-variable\">$binary_remote_addr</span> zone=perip:10m;\n    limit_conn_zone <span class=\"hljs-variable\">$server_name</span> zone=perserver:10m;\n\n    <span class=\"hljs-comment\"># HTTPS 虚拟主机默认客户端证书校验策略，server 可显式覆盖</span>\n    <span class=\"hljs-comment\"># CA 文件用于验证客户端证书；当前 on 表示强制校验</span>\n    <span class=\"hljs-comment\"># 首次部署若需观察，可先用 optional，确认日志为 SUCCESS 后再用 on</span>\n    ssl_client_certificate /usr/local/openresty/nginx/conf/ca.crt;\n    ssl_verify_client on;\n    ssl_verify_depth 2;\n\n    <span class=\"hljs-comment\"># HTTP 虚拟主机及其他子配置</span>\n    include /usr/local/openresty/nginx/conf/http.d/*.conf;\n    include /usr/local/openresty/nginx/conf/conf.d/*.conf;\n    include /usr/local/openresty/nginx/conf/default/*.conf;\n\n    <span class=\"hljs-comment\"># 1Panel WAF 配置</span>\n    include /usr/local/openresty/1pwaf/data/conf/waf.conf;\n}\n\nstream {\n    <span class=\"hljs-comment\"># TCP / UDP 会话日志：对端地址、协议、状态、流量及会话时长</span>\n    log_format streamlog\n        <span class=\"hljs-string\">'$remote_addr[$time_local] '</span>\n        <span class=\"hljs-string\">'$protocol $status $bytes_sent $bytes_received '</span>\n        <span class=\"hljs-string\">'$session_time'</span>;\n\n    access_log /var/log/nginx/stream-access.log streamlog;\n    access_log /dev/stdout streamlog;\n\n    <span class=\"hljs-comment\"># TCP / UDP 代理子配置</span>\n    include /usr/local/openresty/nginx/conf/stream.d/*.conf;\n}</code></pre></div><h3 id=\"heading-验证配置并启用-11\">验证配置并启用</h3><p>保存部署时按照 <code>ssl_verify_client optional</code> 进行配置，语法检查成功后重载配置。</p><div class=\"code-block\"><button type=\"button\" class=\"copy-btn\" aria-label=\"复制代码\">复制</button><pre><code class=\"language-shellscript hljs\">docker <span class=\"hljs-built_in\">exec</span> <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$OR_CONTAINER</span>\"</span> <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$NGINX_BIN</span>\"</span> -t &amp;&amp; \\\ndocker <span class=\"hljs-built_in\">exec</span> <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$OR_CONTAINER</span>\"</span> <span class=\"hljs-string\">\"<span class=\"hljs-variable\">$NGINX_BIN</span>\"</span> -s reload</code></pre></div><p>在 Cloudflare 开启 区域级 AOP，并观察相关日志，确认相关配置生效后，修改为为 <code>ssl_verify_client on，后续进行强制校验。</code></p><h2 id=\"heading-收尾阶段-12\">收尾阶段</h2><h3 id=\"heading-收敛防火墙入口-13\">收敛防火墙入口</h3><ul><li><p>源站 HTTPS 回源端口只允许 Cloudflare 官方 IPv4 和 IPv6 网段进入（非必要情况关闭 HTTP-80 端口公开访问，HTTPS 只保留443端口）</p></li><li><p>优先在云安全组或上游防火墙限制；规则必须覆盖 Docker 实际发布端口与 IPv6，不能只看宿主机表面规则</p></li><li><p>后端应用端口借助 OpenResty 进行代理访问，避免 Docker 将其直接发布到公网</p></li><li><p>1Panel 管理端口与 SSH 单独限制管理来源（例如：1.2.3.4/32）</p></li><li><p>nginx.conf 中的 <code>set_real_ip_from</code> 只是头信息信任配置，不是防火墙放行规则</p></li><li><p>AOP 在这里保护 HTTP 层的 HTTPS 站点，不保护明文 HTTP、stream 转发或独立管理端口</p></li></ul><h3 id=\"heading-错误排查-14\">错误排查</h3><div class=\"halo-table-wrapper\"><table><tbody><tr><th><p>现象</p></th><th><p>优先检查</p></th></tr><tr><td><p>CA 文件不存在</p></td><td><p>是否正确配置持久化挂载，容器路径是否正确</p></td></tr><tr><td><p>unknown directive real_ip_header</p></td><td><p>是否编译 Real IP 模块</p></td></tr><tr><td><p>缺少客户端证书</p></td><td><p>Cloudflare Zone 开关、实际 TLS 入口</p></td></tr><tr><td><p>客户端证书验证失败</p></td><td><p>CA 匹配、有效期、clientAuth 扩展</p></td></tr><tr><td><p>525 或 526</p></td><td><p>分别检查 TLS 握手与网站服务端证书，不能一律归因于 AOP</p></td></tr><tr><td><p>第一列仍为 Cloudflare IP</p></td><td><p>官方网段、头是否存在、server 覆盖、模块状态</p></td></tr><tr><td><p>其他网站或探活失效</p></td><td><p>http 层 AOP 默认策略影响范围</p></td></tr></tbody></table></div><p></p>",
  "toc": [
    {
      "id": "heading-核心概念与准备工作-0",
      "text": "核心概念与准备工作",
      "level": 2
    },
    {
      "id": "heading-什么是橙云代理与源站防护-1",
      "text": "什么是橙云代理与源站防护",
      "level": 3
    },
    {
      "id": "heading-实施顺序-2",
      "text": "实施顺序",
      "level": 3
    },
    {
      "id": "heading-实施指南-3",
      "text": "实施指南",
      "level": 2
    },
    {
      "id": "heading-前置准备-4",
      "text": "前置准备",
      "level": 3
    },
    {
      "id": "heading-生成自定义-aop-证书-5",
      "text": "生成自定义 AOP 证书",
      "level": 3
    },
    {
      "id": "heading-将证书导入-cloudflare-aop-6",
      "text": "将证书导入 Cloudflare AOP",
      "level": 3
    },
    {
      "id": "heading-查看当前容器信息-7",
      "text": "查看当前容器信息",
      "level": 3
    },
    {
      "id": "heading-持久化挂载配置文件-8",
      "text": "持久化挂载配置文件",
      "level": 3
    },
    {
      "id": "heading-导入-ca-公钥证书-9",
      "text": "导入 CA 公钥证书",
      "level": 3
    },
    {
      "id": "heading-配置-1panel-openresty-10",
      "text": "配置 1Panel OpenResty",
      "level": 3
    },
    {
      "id": "heading-验证配置并启用-11",
      "text": "验证配置并启用",
      "level": 3
    },
    {
      "id": "heading-收尾阶段-12",
      "text": "收尾阶段",
      "level": 2
    },
    {
      "id": "heading-收敛防火墙入口-13",
      "text": "收敛防火墙入口",
      "level": 3
    },
    {
      "id": "heading-错误排查-14",
      "text": "错误排查",
      "level": 3
    }
  ],
  "images": [
    {
      "src": "/post-images/jkckuiu16qdzy8l/img-1-164693862191.webp",
      "alt": "图1 开启橙云代理"
    },
    {
      "src": "/post-images/jkckuiu16qdzy8l/img-2-35ea86bb5fb9.webp",
      "alt": "图2 修改加密模式"
    },
    {
      "src": "/post-images/jkckuiu16qdzy8l/img-3-124cb4c9c807.webp",
      "alt": "图3 创建 Cloudflare 源站证书"
    },
    {
      "src": "/post-images/jkckuiu16qdzy8l/img-4-a0cd1093de81.webp",
      "alt": "图4 申请 Let's Encrypt 证书"
    },
    {
      "src": "/post-images/jkckuiu16qdzy8l/img-5-898fcf460913.webp",
      "alt": "图5 上传区域级 AOP 证书"
    }
  ],
  "wordCount": 3620,
  "readingMinutes": 15,
  "searchText": "cloudflare cdn 源站防护配置 本文详细介绍 cloudflare cdn 源站防护配置方案,结合 1panel、docker 与 openresty,实现橙云代理、aop 双向 tls 认证及真实 ip 识别,并涵盖证书生成、nginx 配置、防火墙限制与故障排查,帮助站长提升源站安全性。 技术 为了提升源站安全性,防止公网恶意扫描,很多站长会开启 cloudflare 橙云代理,并配合 authenticated origin pulls (aop) 实现源站的 mtls 校验。但在 1panel docker openresty 环境下,如何优雅地将 ca 信任、客户端验证、cloudflare 真实 ip 识别 揉进一份 nginx.conf 中,且不破坏原有的 1panel 站点与 waf 配置?这篇文章记录了我的完整配置过程。适用流量链路如下:访客 → cloudflare 橙云代理 → 1panel docker openresty https → 后端应用核心概念与准备工作什么是橙云代理与源站防护设置配置位置作用proxied(橙云)cloudflare dns让访客优先经 cloudflare 访问网站,默认隐藏源站 ip 地址完全加密cloudflare ssl/tls验证源站的网站服务端证书(必须是存在且有效的证书)区域级 aop 与源站 mtls 校验cloudflare 与 openresty 两端cloudflare 出示专用客户端证书,源站验证后才接受请求特别说明:这里的“源站防护”指上述设置配合公网入口限制,没有一个设置可以替代所有步骤。aop 证明连接方持有受信任客户端私钥;它本身不校验 http host 与 cloudflare zone 的绑定,所以不可以替代服务器本身的防火墙。aop 配置完成后,务必在云服务器安全组把 https 端口只开放给 cf 的官方 ip 段。另外,测试阶段不适合一开始就把 nginx 的验证强制设为 on,先用 optional,不然容易导致业务宕机。实施顺序鉴于配置步骤略微复杂,建议按照下方的步骤,进行配置:在 dns 设置中将网站记录开启橙云代理在 ssl/tls → 概述 中,加密模式设为 完全 (严格)在 1panel 网站设置中已配好有效的 https 服务端证书(let's encrypt 或 cloudflare origin ca 均可,aop 证书不替代服务端证书)在信任的管理机生成 区域级 aop 证书,并导入源站服务器源站 1panel/openresty 全局配置加载 区域级 aop 证书(调试阶段请使用 optional 选项,后续确认无误可手动切换为 on)开启 cloudflare 区域级 aop 开关,确认有无报错确认无误,全局配置区域级 aop 证书,收紧服务器防火墙实施指南前置准备1. 打开域名控制台,进入 dns,将网站记录设置为 proxied/已代理,即橙云。图1 开启橙云代理2. 进入 ssl/tls → 概述,将加密模式设为 完全(严格)。图2 修改加密模式3. 确认 1panel 网站已启用 https,使用域名匹配且有效的服务端证书。现有 cloudflare origin ca 服务端证书 或 let's encrypt 仍需保留;aop 客户端证书不替代它。特别说明:cloudflare origin ca 服务器证书,无法脱离 cloudflare 平台使用,不被现代浏览器信任let's encrypt 证书,免费证书,可直接在 1panel 面板公开申请并使用(需添加 dns 账户 api 和 acme 账号验证)图3 创建 cloudflare 源站证书图4 申请 let's encrypt 证书4. 进入 ssl/tls → origin server → authenticated origin pulls,检查当前配置 (相关生成教程见后文)。特别说明:不要把 全局 aop 开关当成 区域级 aop,两者互相独立若当前已配置 按主机名 aop,则它对指定主机名生效。优先级高于区域级 aop 配置,应检查其是否使用其他证书ssl/tls 加密的 关闭 (不安全)/ 灵活 模式不适用 aopcloudflare tunnel 也不适用此部署方式我这里为了方便,直接签发了完整的 15 年证书。如果为了安全,应把客户端有效期设置为短日期,后续使用 ca 根证书进行更新生成自定义 aop 证书在安全管理主机的 bash 终端执行,先准备 openssl 和 python 3。每次执行都会新建目录,并不会覆盖现有密钥。将下面代码中的 example.com 替换为实际要部署的目标根域名。生成过程中 ca 私钥会要求设置口令(提示 enter pem pass phrase);客户端私钥使用无口令 pem 供 cloudflare 使用。enter pass phrase for rootca.key,这个是需要输入两次之前设置的密码,不是再设置一个新密码。umask 077 aop_work=\"$home/cf-zone-aop-$(date +%y%m%d-%h%m%s)\" mkdir \"$aop_work\" cd \"$aop_work\" # 将 example.com 替换为目标 zone 的域名。 aop_zone='example.com' # 按日历计算:客户端 15 年,ca 在客户端到期月份后再延长一个月。 # 处理闰年;遇到目标月没有该日时,取该月最后一天。 validity_days=$(python3 - <<'pydates' from datetime import datetime, timezone import calendar today = datetime.now(timezone.utc).date() client_year = today.year + 15 client_end = today.replace( year=client_year, day=min(today.day, calendar.monthrange(client_year, today.month)[1]), ) ca_year = client_end.year + (client_end.month == 12) ca_month = client_end.month % 12 + 1 ca_end = client_end.replace( year=ca_year, month=ca_month, day=min(client_end.day, calendar.monthrange(ca_year, ca_month)[1]), ) print((client_end - today).days, (ca_end - today).days) pydates ) || { echo '有效期计算失败,停止'; exit 1; } read -r client_days ca_days <<< \"$validity_days\" printf '客户端有效期 %s 天;ca 有效期 %s 天\\n' \"$client_days\" \"$ca_days\" cat > rootca.cnf <<eof [req] prompt = no distinguished_name = dn x509_extensions = v3_ca [dn] cn = ${aop_zone} dedicated aop root ca [v3_ca] basicconstraints = critical,ca:true,pathlen:0 keyusage = critical,keycertsign,crlsign subjectkeyidentifier = hash authoritykeyidentifier = keyid:always eof openssl genrsa -aes256 -out rootca.key 4096 openssl req -x509 -new -sha256 -days \"$ca_days\" \\ -key rootca.key -out rootca.crt -config rootca.cnf openssl genrsa -out aop-client.key 4096 openssl req -new -sha256 -key aop-client.key \\ -out aop-client.csr -subj \"/cn=${aop_zone} cloudflare aop client\" cat > client.ext <<'eof' basicconstraints = critical,ca:false keyusage = critical,digitalsignature extendedkeyusage = clientauth subjectkeyidentifier = hash authoritykeyidentifier = keyid,issuer eof openssl x509 -req -sha256 -days \"$client_days\" \\ -in aop-client.csr -ca rootca.crt -cakey rootca.key \\ -cacreateserial -out aop-client.crt -extfile client.ext openssl verify -purpose sslclient -cafile rootca.crt aop-client.crt openssl x509 -in aop-client.crt -noout -subject -issuer -dates openssl x509 -in rootca.crt -noout -fingerprint -sha256执行以下命令,检查客户端证书和私钥匹配,两条哈希应相同:openssl x509 -in aop-client.crt -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 openssl pkey -in aop-client.key -pubout -outform der | openssl dgst -sha256将证书导入 cloudflare aop进入目标域名的 ssl/tls → 原服务器 → authenticated origin pulls → 区域级 aop → 上传证书,上传上一步生成的相关证书文件。相关证书文件的用途说明见下表文件导入位置用途aop-client.crtcloudflare zone-level certificate回源客户端叶证书aop-client.keycloudflare zone-level private key回源客户端私钥rootca.crt源站持久化目录,命名 ca.crt验证客户端证书的 ca 公钥rootca.key加密,脱机离线保存后续签发和续期客户端证书使用,不放入 openresty图5 上传区域级 aop 证书查看当前容器信息以下命令在 源站宿主机 的 bash 终端执行,需 docker 管理权限。容器名、路径均需替换。# 查看当前的 docker 容器信息 docker ps --format 'table {{.names}}\\t{{.image}}\\t{{.ports}}' # 设置变量 # 设置变量 'or_container' 为 openresty 容器名称 or_container='替换为实际openresty容器名' # 设置变量 'nginx_bin' 为 容器内部 nginx 程序的路径 nginx_bin='/usr/local/openresty/nginx/sbin/nginx' # 查看容器网络模式 docker inspect \"$or_container\" --format '{{.hostconfig.networkmode}}' # 查看目录和文件挂载 docker inspect \"$or_container\" --format '{{range .mounts}}{{println .type .source \"->\" .destination \"rw=\" .rw}}{{end}}' # 查看容器启动命令 docker inspect \"$or_container\" --format '{{json .config.entrypoint}} {{json .config.cmd}}' # 查看 nginx 版本和编译参数 docker exec \"$or_container\" \"$nginx_bin\" -v持久化挂载配置文件这里按照挂载整个 conf 目录进行操作,如若只单独挂载 nginx.conf 文件,则需要在容器的编排文件中添加添加一条只读映射or_conf_host='/替换为实际宿主机conf目录' test -f \"$or_conf_host/nginx.conf\" || { echo '配置路径错误,停止'; exit 1; } # 备份放在 conf 目录之外,避免备份自身 backup_dir=\"/root/openresty-aop-backup-$(date +%y%m%d-%h%m%s)\" mkdir -m 700 \"$backup_dir\" cp -a \"$or_conf_host/nginx.conf\" \"$backup_dir/nginx.conf\" tar -c \"$or_conf_host\" -czf \"$backup_dir/conf-before-aop.tar.gz\" . docker exec \"$or_container\" \"$nginx_bin\" -t > \"$backup_dir/nginx-before-aop.txt\" 2>&1 printf '备份位置:%s\\n' \"$backup_dir\"导入 ca 公钥证书如果证书在其他管理主机生成,先安全传输 rootca.crt 到源站宿主机。rootca_source='/替换为源站宿主机上的rootca.crt路径' install -m 0644 \"$rootca_source\" \"$or_conf_host/ca.crt\" # 两次输出的 sha-256 指纹应相同 openssl x509 -in \"$rootca_source\" -noout -fingerprint -sha256 docker exec \"$or_container\" cat /usr/local/openresty/nginx/conf/ca.crt \\ | openssl x509 -noout -fingerprint -sha256配置 1panel openresty在 1panel 网站列表上方的 openresty 设置 → 配置修改 中编辑当前生效主配置,或编辑已确认的宿主机 nginx.conf;选择一种方式完成同一次修改。不要点击“恢复默认配置”,该按钮会覆盖自定义内容。首次粘贴前:只把下方 ssl_verify_client on; 改为 ssl_verify_client optional;。验收成功后改回 on。# worker 运行用户及进程数 user root; worker_processes auto; # 错误日志:同时输出到文件和标准输出 error_log /var/log/nginx/error.log notice; error_log /dev/stdout notice; pid /var/run/nginx.pid; # 单个 worker 可打开的文件描述符上限 worker_rlimit_nofile 51200; # 加载动态模块 include /usr/local/openresty/nginx/conf/modules-enabled/*.conf; events { # linux 事件模型 use epoll; # 单个 worker 的最大连接数(包含上游连接) worker_connections 5120; # 一次接受所有待处理的新连接 multi_accept on; } http { # mime 类型及默认响应类型 include mime.types; default_type application/octet-stream; # cloudflare 可信代理 ipv4 网段:部署前及后续定期核对官方列表 set_real_ip_from 103.21.244.0/22; set_real_ip_from 103.22.200.0/22; set_real_ip_from 103.31.4.0/22; set_real_ip_from 104.16.0.0/13; set_real_ip_from 104.24.0.0/14; set_real_ip_from 108.162.192.0/18; set_real_ip_from 131.0.72.0/22; set_real_ip_from 141.101.64.0/18; set_real_ip_from 162.158.0.0/15; set_real_ip_from 172.64.0.0/13; set_real_ip_from 173.245.48.0/20; set_real_ip_from 188.114.96.0/20; set_real_ip_from 190.93.240.0/20; set_real_ip_from 197.234.240.0/22; set_real_ip_from 198.41.128.0/17; # cloudflare 可信代理 ipv6 网段 set_real_ip_from 2400:cb00::/32; set_real_ip_from 2606:4700::/32; set_real_ip_from 2803:f800::/32; set_real_ip_from 2405:b500::/32; set_real_ip_from 2405:8100::/32; set_real_ip_from 2a06:98c0::/29; set_real_ip_from 2c0f:f248::/32; # 仅对可信代理提供的请求头执行真实 ip 替换 real_ip_header cf-connecting-ip; real_ip_recursive on; # remote_addr:替换后的客户端 ip;realip_remote_addr:原始连接对端 ip # ssl_client_verify:客户端证书验证结果;cfip:原始 cf-connecting-ip 头 log_format main '$remote_addr - $remote_user [$time_local] \"$request\" ' '$status $body_bytes_sent \"$http_referer\" ' '\"$http_user_agent\" \"$http_x_forwarded_for\"' ' peer=$realip_remote_addr aop=$ssl_client_verify' ' cfip=\"$http_cf_connecting_ip\"'; # http 访问日志 access_log /var/log/nginx/access.log main; access_log /dev/stdout main; # 隐藏响应头和错误页中的版本号 server_tokens off; # 文件发送及 tcp 参数 sendfile on; tcp_nopush on; tcp_nodelay on; # 虚拟主机名称哈希桶及客户端请求缓冲参数 server_names_hash_bucket_size 512; client_header_buffer_size 32k; client_max_body_size 50m; # keepalive 空闲超时(秒)及单个连接的请求数上限 keepalive_timeout 60; keepalive_requests 5000; # gzip 压缩:最小响应长度、缓冲区、最低请求协议版本及压缩等级 gzip on; gzip_min_length 1k; gzip_buffers 4 16k; gzip_http_version 1.1; gzip_comp_level 5; # 额外允许压缩的 mime 类型(text/html 默认包含) gzip_types text/plain text/css text/xml text/javascript application/json application/ld+json application/javascript application/x-javascript application/xml application/xhtml+xml application/rss+xml application/atom+xml application/wasm image/svg+xml font/ttf font/otf; # 添加 vary: accept-encoding,并允许压缩带 via 头的代理请求响应 gzip_vary on; gzip_proxied any; # 连接限制共享内存区域;实际限制需在子配置中使用 limit_conn 设置 limit_conn_zone $binary_remote_addr zone=perip:10m; limit_conn_zone $server_name zone=perserver:10m; # https 虚拟主机默认客户端证书校验策略,server 可显式覆盖 # ca 文件用于验证客户端证书;当前 on 表示强制校验 # 首次部署若需观察,可先用 optional,确认日志为 success 后再用 on ssl_client_certificate /usr/local/openresty/nginx/conf/ca.crt; ssl_verify_client on; ssl_verify_depth 2; # http 虚拟主机及其他子配置 include /usr/local/openresty/nginx/conf/http.d/*.conf; include /usr/local/openresty/nginx/conf/conf.d/*.conf; include /usr/local/openresty/nginx/conf/default/*.conf; # 1panel waf 配置 include /usr/local/openresty/1pwaf/data/conf/waf.conf; } stream { # tcp / udp 会话日志:对端地址、协议、状态、流量及会话时长 log_format streamlog '$remote_addr[$time_local] ' '$protocol $status $bytes_sent $bytes_received ' '$session_time'; access_log /var/log/nginx/stream-access.log streamlog; access_log /dev/stdout streamlog; # tcp / udp 代理子配置 include /usr/local/openresty/nginx/conf/stream.d/*.conf; }验证配置并启用保存部署时按照 ssl_verify_client optional 进行配置,语法检查成功后重载配置。docker exec \"$or_container\" \"$nginx_bin\" -t && \\ docker exec \"$or_container\" \"$nginx_bin\" -s reload在 cloudflare 开启 区域级 aop,并观察相关日志,确认相关配置生效后,修改为为 ssl_verify_client on,后续进行强制校验。收尾阶段收敛防火墙入口源站 https 回源端口只允许 cloudflare 官方 ipv4 和 ipv6 网段进入(非必要情况关闭 http-80 端口公开访问,https 只保留443端口)优先在云安全组或上游防火墙限制;规则必须覆盖 docker 实际发布端口与 ipv6,不能只看宿主机表面规则后端应用端口借助 openresty 进行代理访问,避免 docker 将其直接发布到公网1panel 管理端口与 ssh 单独限制管理来源(例如:1.2.3.4/32)nginx.conf 中的 set_real_ip_from 只是头信息信任配置,不是防火墙放行规则aop 在这里保护 http 层的 https 站点,不保护明文 http、stream 转发或独立管理端口错误排查现象优先检查ca 文件不存在是否正确配置持久化挂载,容器路径是否正确unknown directive real_ip_header是否编译 real ip 模块缺少客户端证书cloudflare zone 开关、实际 tls 入口客户端证书验证失败ca 匹配、有效期、clientauth 扩展525 或 526分别检查 tls 握手与网站服务端证书,不能一律归因于 aop第一列仍为 cloudflare ip官方网段、头是否存在、server 覆盖、模块状态其他网站或探活失效http 层 aop 默认策略影响范围",
  "dataSource": "halo",
  "sourceVersion": "c0477100568e841a47a09ac423aa34fec46c420e24a3560d1131ecebbad7c962",
  "syncSchemaVersion": 9
}