用开源组件搭一套“私有版 Cloudflare”:边缘网关部署实战与源码分享
Cloudflare 私有化部署方案|附源码
说明:Cloudflare 本身是商业化的全球边缘网络与安全平台,无法直接“私有化部署 Cloudflare 官方服务”。本文所说的“Cloudflare 私有化部署方案”,指的是在企业自有机房、私有云或公有云 VPC 内,使用开源组件搭建一套具备类似能力的边缘访问网关平台,实现反向代理、HTTPS 证书管理、WAF 防护、访问控制、限流、缓存、日志审计、监控告警等能力。
一、为什么需要“私有化版 Cloudflare”
很多企业在业务上云或对外提供服务时,会使用 Cloudflare、Akamai、Fastly 等边缘安全与加速平台。这类平台通常具备以下能力:
- CDN 缓存与静态资源加速;
- HTTPS 自动证书管理;
- DDoS 缓解与基础安全防护;
- Web Application Firewall,简称 WAF;
- 反向代理与源站隐藏;
- 访问控制、身份认证、零信任访问;
- Bot 防护、限速、IP 黑白名单;
- 日志分析、请求追踪、监控告警。
但在一些场景下,企业并不适合完全依赖第三方边缘平台,例如:
-
数据合规要求高
金融、政务、医疗、军工等行业,可能要求流量、日志、证书、用户数据都必须在企业可控环境内处理。 -
内网系统无法暴露公网
例如办公系统、内部管理后台、运维平台、研发系统等,只允许通过 VPN、专线或零信任网关访问。 -
希望掌控完整架构
一些企业不希望安全策略、访问日志、WAF 规则完全依赖第三方平台。 -
成本可控诉求
当请求量、带宽或安全功能规模较大时,商业边缘平台费用可能持续增长。 -
私有云与混合云架构需求
企业可能同时拥有 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 上线建议分三步:
- 观察模式:只记录不拦截;
- 灰度阻断:对部分域名或路径启用阻断;
- 全面启用:稳定后扩大范围。
同时,应为正常业务接口设置例外规则,避免误杀。
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 等组件后,可以逐步演进为生产级边缘安全平台。
最终是否选择私有化方案,取决于企业的业务规模、合规要求、安全等级、运维能力和成本预算。如果企业重视可控性、数据安全和内网访问治理,私有化边缘网关是一条非常值得投入的路线。