上一篇 下一篇 分享链接 返回 返回顶部

用开源组件搭一套“私有版 Cloudflare”:边缘网关部署实战与源码分享

发布人:慈云数据-客服中心 发布时间:23小时前 阅读量:4

Cloudflare 私有化部署方案|附源码

说明:Cloudflare 本身是商业化的全球边缘网络与安全平台,无法直接“私有化部署 Cloudflare 官方服务”。本文所说的“Cloudflare 私有化部署方案”,指的是在企业自有机房、私有云或公有云 VPC 内,使用开源组件搭建一套具备类似能力的边缘访问网关平台,实现反向代理、HTTPS 证书管理、WAF 防护、访问控制、限流、缓存、日志审计、监控告警等能力。


一、为什么需要“私有化版 Cloudflare”

很多企业在业务上云或对外提供服务时,会使用 Cloudflare、Akamai、Fastly 等边缘安全与加速平台。这类平台通常具备以下能力:

  • CDN 缓存与静态资源加速;
  • HTTPS 自动证书管理;
  • DDoS 缓解与基础安全防护;
  • Web Application Firewall,简称 WAF;
  • 反向代理与源站隐藏;
  • 访问控制、身份认证、零信任访问;
  • Bot 防护、限速、IP 黑白名单;
  • 日志分析、请求追踪、监控告警。

但在一些场景下,企业并不适合完全依赖第三方边缘平台,例如:

  1. 数据合规要求高
    金融、政务、医疗、军工等行业,可能要求流量、日志、证书、用户数据都必须在企业可控环境内处理。

  2. 内网系统无法暴露公网
    例如办公系统、内部管理后台、运维平台、研发系统等,只允许通过 VPN、专线或零信任网关访问。

  3. 希望掌控完整架构
    一些企业不希望安全策略、访问日志、WAF 规则完全依赖第三方平台。

  4. 成本可控诉求
    当请求量、带宽或安全功能规模较大时,商业边缘平台费用可能持续增长。

  5. 私有云与混合云架构需求
    企业可能同时拥有 IDC、Kubernetes、公有云、边缘节点,需要统一接入、统一防护和统一观测。

因此,搭建一套“私有化 Cloudflare 替代方案”具有现实意义。


二、总体架构设计

本文推荐的私有化方案基于开源组件实现,核心架构如下:

用户浏览器 / API 客户端
        |
        | HTTPS
        v
边缘入口层 Edge Gateway
Nginx / OpenResty / Envoy / Traefik
        |
        | WAF / 限流 / 鉴权 / 缓存
        v
安全控制层 Security Layer
ModSecurity / Coraza / Lua Script / OPA
        |
        | 反向代理
        v
业务服务层 Origin Services
Kubernetes / VM / Docker / Bare Metal
        |
        v
日志与监控层 Observability
Prometheus / Grafana / Loki / ELK

在这个架构中,各模块的职责如下:

模块 推荐组件 主要作用
入口网关 Nginx、OpenResty、Envoy、Traefik 统一接收外部请求、TLS 终止、反向代理
证书管理 Certbot、acme.sh、step-ca 自动签发与续期 HTTPS 证书
WAF 防护 ModSecurity、OWASP CRS、Coraza SQL 注入、XSS、恶意请求拦截
缓存加速 Nginx proxy_cache、Varnish 静态资源缓存、减轻源站压力
限流控制 Nginx limit_req、Lua、Envoy Rate Limit 防刷、防爆破、防接口滥用
身份认证 Authelia、Keycloak、OAuth2 Proxy 登录保护、SSO、MFA
零信任访问 WireGuard、Tailscale、Teleport 内部服务安全访问
日志分析 Loki、ELK、Vector、Fluent Bit 请求日志采集、检索、分析
监控告警 Prometheus、Grafana、Alertmanager 指标监控、服务告警
容器编排 Docker Compose、Kubernetes 服务部署与弹性扩缩

三、核心能力拆解

1. 反向代理与源站隐藏

Cloudflare 的基础能力之一是代理用户请求,并将请求转发到真实源站。源站 IP 不直接暴露,可以降低被直接攻击的风险。

私有化部署时,可以使用 Nginx 或 OpenResty 作为统一入口,将不同域名转发到不同内部服务:

server {
    listen 443 ssl http2;
    server_name app.example.com;

    ssl_certificate     /etc/nginx/certs/app.example.com/fullchain.pem;
    ssl_certificate_key /etc/nginx/certs/app.example.com/privkey.pem;

    location / {
        proxy_pass http://app_backend;
        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;
    }
}

upstream app_backend {
    server 10.0.1.10:8080;
    server 10.0.1.11:8080;
}

通过这种方式,用户只访问网关地址,真实业务服务仅允许来自网关的访问。


2. HTTPS 自动证书管理

如果系统对公网开放,可以通过 Let’s Encrypt 签发免费证书。对于完全内网环境,可以使用自建 CA,例如 step-ca

公网证书可以使用 acme.sh

curl https://get.acme.sh | sh

~/.acme.sh/acme.sh --issue \
  -d app.example.com \
  --webroot /var/www/html

~/.acme.sh/acme.sh --install-cert -d app.example.com \
  --key-file       /etc/nginx/certs/app.example.com/privkey.pem \
  --fullchain-file /etc/nginx/certs/app.example.com/fullchain.pem \
  --reloadcmd     "docker exec edge-nginx nginx -s reload"

在企业内网中,可以使用私有 CA 给内部系统签发证书,保证通信加密,同时避免证书数据流出企业环境。


3. WAF Web 应用防火墙

Cloudflare 的安全能力里,WAF 是非常关键的一环。私有化方案可以选择:

  • ModSecurity;
  • OWASP Core Rule Set;
  • Coraza WAF;
  • OpenResty Lua 自定义规则。

其中,ModSecurity + OWASP CRS 是较成熟的组合。它可以防护常见 Web 攻击,例如:

  • SQL 注入;
  • XSS 跨站脚本;
  • 路径穿越;
  • 命令注入;
  • 恶意 User-Agent;
  • 扫描器行为;
  • 异常参数长度。

Nginx 中开启 ModSecurity 的示例:

server {
    listen 443 ssl http2;
    server_name app.example.com;

    modsecurity on;
    modsecurity_rules_file /etc/nginx/modsec/main.conf;

    location / {
        proxy_pass http://app_backend;
    }
}

main.conf 示例:

Include /etc/nginx/modsec/modsecurity.conf
Include /etc/nginx/modsec/owasp-crs/crs-setup.conf
Include /etc/nginx/modsec/owasp-crs/rules/*.conf

需要注意的是,WAF 不是“开箱即用就一定安全”。实际生产环境中,应先使用检测模式观察误报情况,再逐步切换到阻断模式。


4. 请求限流与防刷

对于登录接口、短信接口、支付接口、搜索接口等高风险 API,需要限制访问频率。

Nginx 原生支持限流:

http {
    limit_req_zone $binary_remote_addr zone=perip:10m rate=10r/s;

    server {
        listen 443 ssl http2;
        server_name api.example.com;

        location /login {
            limit_req zone=perip burst=20 nodelay;
            proxy_pass http://api_backend;
        }
    }
}

上面的配置表示:

  • 每个 IP 平均每秒最多 10 个请求;
  • 突发请求最多允许 20 个;
  • 超过限制后返回 503 或自定义错误码。

如果要实现更复杂的限流策略,比如按照用户 ID、Token、租户 ID 限流,可以使用 OpenResty + Redis。

Lua 示例:

local redis = require "resty.redis"
local red = redis:new()
red:set_timeout(1000)

local ok, err = red:connect("redis", 6379)
if not ok then
    ngx.log(ngx.ERR, "redis connect failed: ", err)
    return ngx.exit(500)
end

local key = "rate:" .. ngx.var.binary_remote_addr
local current = red:incr(key)

if current == 1 then
    red:expire(key, 60)
end

if current > 100 then
    ngx.status = 429
    ngx.say("Too Many Requests")
    return ngx.exit(429)
end

该脚本表示:同一个 IP 在 60 秒内最多访问 100 次,超过后返回 429 Too Many Requests


5. 静态资源缓存

Cloudflare 的另一个常用功能是 CDN 缓存。私有化环境下,虽然无法天然具备全球边缘节点,但可以在企业 IDC、区域机房或云上部署多个边缘节点,实现区域级缓存。

Nginx 缓存配置示例:

proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=edge_cache:100m
                 max_size=10g inactive=60m use_temp_path=off;

server {
    listen 443 ssl http2;
    server_name static.example.com;

    location / {
        proxy_cache edge_cache;
        proxy_cache_valid 200 302 10m;
        proxy_cache_valid 404 1m;

        add_header X-Cache-Status $upstream_cache_status;

        proxy_pass http://static_backend;
    }
}

缓存命中后,用户请求无需再回源,能够显著降低后端压力。


四、部署方案选择

方案一:Docker Compose 部署

适用于中小型企业、测试环境、内部系统网关。

优点:

  • 部署简单;
  • 维护成本低;
  • 适合快速验证;
  • 便于迁移。

缺点:

  • 高可用能力有限;
  • 扩容需要额外设计;
  • 对大规模流量支持有限。

方案二:Kubernetes 部署

适用于中大型企业和生产级系统。

优点:

  • 支持弹性扩缩容;
  • 可结合 Ingress Controller;
  • 支持服务发现;
  • 高可用能力强;
  • 易于接入 Prometheus、Grafana 等云原生监控体系。

缺点:

  • 部署和运维复杂度较高;
  • 需要专业平台团队维护;
  • 初期建设成本较高。

方案三:多边缘节点部署

适用于多地域访问、跨区域办公、混合云业务。

典型架构:

北京 Edge Node
上海 Edge Node
广州 Edge Node
新加坡 Edge Node
        |
        v
中心控制面 / 配置中心 / 日志中心

每个边缘节点独立承载访问流量,配置由中心控制面统一下发。DNS 根据地域或健康检查结果,将用户解析到最近或最可用节点。


五、完整 Docker Compose 源码

下面给出一个可运行的简化版私有化边缘网关方案,包含:

  • Nginx 反向代理;
  • Redis 限流依赖;
  • Prometheus 监控;
  • Grafana 可视化;
  • 示例后端服务。

目录结构如下:

private-cloudflare/
├── docker-compose.yml
├── nginx/
│   ├── nginx.conf
│   ├── conf.d/
│   │   └── app.conf
│   └── lua/
│       └── rate_limit.lua
├── app/
│   ├── Dockerfile
│   └── server.py
└── prometheus/
    └── prometheus.yml

1. docker-compose.yml

version: "3.8"

services:
  edge-nginx:
    image: openresty/openresty:1.25.3.1-0-alpine
    container_name: edge-nginx
    ports:
      - "80:80"
    volumes:
      - ./nginx/nginx.conf:/usr/local/openresty/nginx/conf/nginx.conf:ro
      - ./nginx/conf.d:/etc/nginx/conf.d:ro
      - ./nginx/lua:/etc/nginx/lua:ro
    depends_on:
      - app
      - redis
    networks:
      - edge-net

  app:
    build:
      context: ./app
    container_name: demo-app
    networks:
      - edge-net

  redis:
    image: redis:7-alpine
    container_name: edge-redis
    networks:
      - edge-net

  prometheus:
    image: prom/prometheus:v2.52.0
    container_name: edge-prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
    networks:
      - edge-net

  grafana:
    image: grafana/grafana:10.4.2
    container_name: edge-grafana
    ports:
      - "3000:3000"
    networks:
      - edge-net

networks:
  edge-net:
    driver: bridge

2. nginx/nginx.conf

worker_processes auto;

events {
    worker_connections 4096;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    lua_package_path "/usr/local/openresty/lualib/?.lua;;";

    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for" '
                    'rt=$request_time uct="$upstream_connect_time" '
                    'uht="$upstream_header_time" urt="$upstream_response_time"';

    access_log /dev/stdout main;
    error_log  /dev/stderr warn;

    sendfile on;
    keepalive_timeout 65;

    include /etc/nginx/conf.d/*.conf;
}

3. nginx/conf.d/app.conf

upstream app_backend {
    server app:8080;
}

proxy_cache_path /tmp/nginx_cache levels=1:2 keys_zone=edge_cache:10m
                 max_size=500m inactive=30m use_temp_path=off;

server {
    listen 80;
    server_name _;

    location /health {
        return 200 "edge gateway ok\n";
    }

    location /api/ {
        access_by_lua_file /etc/nginx/lua/rate_limit.lua;

        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_pass http://app_backend;
    }

    location /static/ {
        proxy_cache edge_cache;
        proxy_cache_valid 200 10m;
        add_header X-Cache-Status $upstream_cache_status;

        proxy_pass http://app_backend;
    }

    location / {
        proxy_pass http://app_backend;
    }
}

4. nginx/lua/rate_limit.lua

local redis = require "resty.redis"

local red = redis:new()
red:set_timeout(1000)

local ok, err = red:connect("redis", 6379)
if not ok then
    ngx.log(ngx.ERR, "failed to connect redis: ", err)
    return ngx.exit(500)
end

local ip = ngx.var.remote_addr or "unknown"
local key = "rate_limit:" .. ip

local current, err = red:incr(key)
if not current then
    ngx.log(ngx.ERR, "redis incr failed: ", err)
    return ngx.exit(500)
end

if current == 1 then
    red:expire(key, 60)
end

if current > 60 then
    ngx.status = 429
    ngx.say("Too Many Requests")
    return ngx.exit(429)
end

local ok, err = red:set_keepalive(10000, 100)
if not ok then
    ngx.log(ngx.WARN, "failed to set redis keepalive: ", err)
end

5. app/Dockerfile

FROM python:3.12-alpine

WORKDIR /app

COPY server.py /app/server.py

EXPOSE 8080

CMD ["python", "server.py"]

6. app/server.py

from http.server import BaseHTTPRequestHandler, HTTPServer
import json
import time

class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path.startswith("/api/"):
            self.response_json({
                "path": self.path,
                "message": "Hello from private Cloudflare-like gateway",
                "timestamp": int(time.time())
            })
        elif self.path.startswith("/static/"):
            self.send_response(200)
            self.send_header("Content-Type", "text/plain; charset=utf-8")
            self.end_headers()
            self.wfile.write(b"static resource from origin server")
        else:
            self.send_response(200)
            self.send_header("Content-Type", "text/html; charset=utf-8")
            self.end_headers()
            self.wfile.write("""
            
              Private Edge Gateway
              
                

Private Cloudflare-like Gateway

Reverse proxy, rate limit and cache are enabled.

""".encode("utf-8")) def response_json(self, data): body = json.dumps(data, ensure_ascii=False).encode("utf-8") self.send_response(200) self.send_header("Content-Type", "application/json; charset=utf-8") self.send_header("Content-Length", str(len(body))) self.end_headers() self.wfile.write(body) if __name__ == "__main__": server = HTTPServer(("0.0.0.0", 8080), Handler) print("demo app listening on :8080") server.serve_forever()

7. prometheus/prometheus.yml

global:
  scrape_interval: 15s

scrape_configs:
  - job_name: "prometheus"
    static_configs:
      - targets: ["localhost:9090"]

六、启动与测试

进入项目目录后执行:

docker compose up -d --build

查看服务状态:

docker compose ps

测试网关健康检查:

curl http://localhost/health

访问 API:

curl http://localhost/api/user

测试缓存:

curl -I http://localhost/static/logo.png

返回头中可以看到:

X-Cache-Status: MISS

再次请求可能变为:

X-Cache-Status: HIT

测试限流:

for i in {1..100}; do curl -s http://localhost/api/test; done

超过限制后,将返回:

Too Many Requests

七、生产环境增强建议

上面的源码是一个最小可运行版本,适合用于学习和验证。如果要用于生产环境,建议进一步增强以下能力。

1. 高可用部署

至少部署两台以上边缘网关节点,并通过负载均衡器进行流量分发。

常见方案:

  • LVS + Keepalived;
  • HAProxy;
  • 云厂商 SLB / CLB;
  • Kubernetes Ingress;
  • Anycast 网络。

2. 完整 HTTPS 支持

生产环境必须启用 HTTPS,并使用安全 TLS 配置:

ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;

同时建议开启:

  • HSTS;
  • OCSP Stapling;
  • 自动证书续期;
  • 证书过期告警。

3. WAF 规则调优

WAF 上线建议分三步:

  1. 观察模式:只记录不拦截;
  2. 灰度阻断:对部分域名或路径启用阻断;
  3. 全面启用:稳定后扩大范围。

同时,应为正常业务接口设置例外规则,避免误杀。

4. 日志集中化

边缘网关会产生大量访问日志和安全日志,建议统一采集到日志平台。

可选组件:

  • Filebeat;
  • Fluent Bit;
  • Vector;
  • Logstash;
  • Loki;
  • Elasticsearch。

日志字段建议包含:

  • 请求时间;
  • 客户端 IP;
  • 请求方法;
  • URI;
  • 状态码;
  • 响应耗时;
  • User-Agent;
  • Referer;
  • 上游服务;
  • WAF 命中规则;
  • 请求 ID。

5. 请求追踪

建议在网关层生成统一请求 ID:

proxy_set_header X-Request-ID $request_id;
add_header X-Request-ID $request_id;

这样可以从网关日志、业务日志、链路追踪系统中关联同一次请求。

6. 管理后台

如果企业内部有多个业务域名和团队,建议开发一个管理后台,用于配置:

  • 域名;
  • 源站地址;
  • 缓存策略;
  • 限流策略;
  • IP 黑白名单;
  • WAF 开关;
  • TLS 证书;
  • 访问日志;
  • 告警规则。

配置变更后,可以通过 GitOps、配置中心或消息队列下发到边缘节点。


八、与 Cloudflare 的差异

私有化方案可以实现许多类似能力,但也必须正视差异:

能力 Cloudflare 私有化方案
全球 CDN 全球边缘节点 需要自建多地域节点
DDoS 防护 大规模骨干网络清洗 依赖运营商、云清洗或自建清洗
WAF 商业规则持续更新 需要自行维护规则
Bot 防护 高级行为分析 需要额外开发或购买
零信任访问 成熟产品化 可用开源组件组合
运维成本 平台托管 企业自行维护
可控性 较低 较高
合规性 取决于服务区域 可完全内部可控

所以,私有化方案并不是简单“复制 Cloudflare”,而是根据企业需求,在可控性、安全性、成本和运维复杂度之间做取舍。


九、推荐落地路线

如果企业计划建设私有化边缘网关,可以按照以下路线推进:

第一阶段:基础网关

目标是实现统一入口。

建设内容:

  • Nginx / OpenResty 反向代理;
  • HTTPS 证书;
  • 访问日志;
  • 基础限流;
  • 健康检查;
  • 源站隐藏。

第二阶段:安全防护

目标是提升 Web 安全能力。

建设内容:

  • WAF;
  • IP 黑白名单;
  • 登录接口限流;
  • 敏感路径保护;
  • 安全响应头;
  • 请求体大小限制;
  • 异常流量告警。

第三阶段:可观测性

目标是让系统可监控、可审计、可追踪。

建设内容:

  • Prometheus 指标;
  • Grafana 仪表盘;
  • Loki / ELK 日志检索;
  • Alertmanager 告警;
  • 请求 ID;
  • 安全事件报表。

第四阶段:平台化

目标是降低运维成本。

建设内容:

  • 配置管理后台;
  • 多租户权限;
  • 策略模板;
  • 自动发布;
  • 灰度变更;
  • 审批流;
  • 审计日志。

第五阶段:多地域边缘

目标是支持高可用和区域加速。

建设内容:

  • 多机房边缘节点;
  • 智能 DNS;
  • 健康检查;
  • 配置中心;
  • 日志回传;
  • 灾备切换。

十、总结

Cloudflare 是成熟的全球边缘安全网络,无法直接私有化部署。但企业可以使用开源技术栈,构建一套“Cloudflare-like”的私有化边缘网关平台。

本文提供的方案以 OpenResty / Nginx 为核心,结合 Redis、缓存、限流、日志、监控等能力,实现了一个最小可运行的私有化网关原型。进一步结合 ModSecurity、OWASP CRS、Keycloak、Authelia、Prometheus、Grafana、Loki、Kubernetes 等组件后,可以逐步演进为生产级边缘安全平台。

最终是否选择私有化方案,取决于企业的业务规模、合规要求、安全等级、运维能力和成本预算。如果企业重视可控性、数据安全和内网访问治理,私有化边缘网关是一条非常值得投入的路线。

目录结构
全文