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

用开源组件搭一套“私有版 Cloudflare”:网关、WAF、缓存与源码实战

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

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

说明:严格来说,Cloudflare 本身是一个全球化的 SaaS / 边缘网络平台,并不提供“官方私有化部署版”。因此,本文所说的“Cloudflare 私有化部署方案”,并不是把 Cloudflare 原厂服务部署到自己的服务器上,而是基于开源组件,构建一套具备 CDN 加速、反向代理、HTTPS、WAF、安全访问控制、缓存、日志监控、源站隐藏 等能力的私有化替代方案。


一、为什么需要 Cloudflare 私有化部署方案?

Cloudflare 是很多网站和业务系统常用的前置安全与加速平台,常见能力包括:

  • DNS 解析;
  • CDN 静态资源加速;
  • HTTPS 证书托管;
  • WAF Web 应用防火墙;
  • DDoS 缓解;
  • 反向代理;
  • Bot 防护;
  • Zero Trust 访问控制;
  • 边缘缓存;
  • 访问日志与安全分析。

对于中小型业务来说,Cloudflare 的托管方式非常方便。但在某些场景下,企业可能希望构建一套可私有化部署的替代方案。

常见原因包括:

  1. 数据合规要求
    某些行业对数据流转、访问日志、用户 IP、请求内容有严格要求,不希望流量经过第三方平台。

  2. 内网系统访问控制
    企业内部系统可能部署在私有云、IDC 或 Kubernetes 集群内,需要通过统一入口进行安全访问。

  3. 源站隐藏与安全隔离
    不希望源站 IP 暴露在公网,需要通过网关层统一代理访问。

  4. 可控性更强
    希望自定义缓存策略、限流策略、WAF 规则、认证逻辑、日志采集方式。

  5. 成本与架构自主性
    对于大流量业务,长期依赖商业 CDN 可能成本较高,私有化方案可以按需扩展。


二、方案目标

本文设计的私有化方案,将实现类似 Cloudflare 的部分核心能力。

目标能力

能力 实现方式
反向代理 Nginx / OpenResty
HTTPS Caddy / Nginx + Certbot
缓存加速 Nginx Proxy Cache
WAF ModSecurity + OWASP CRS
访问限流 Nginx limit_req
IP 黑白名单 Nginx / OpenResty
安全 Header Nginx 配置
日志采集 Filebeat / Prometheus / Grafana
容器化部署 Docker Compose
多源站转发 Nginx upstream
健康检查 Nginx upstream + Docker healthcheck
简易管理接口 Node.js API 示例

三、整体架构设计

整体架构如下:

用户浏览器
   |
   | HTTPS
   v
私有化边缘网关
Nginx / OpenResty / Caddy
   |
   | WAF / 限流 / 缓存 / 日志
   v
业务源站服务
Web / API / 静态资源 / Kubernetes Service

如果部署在多节点环境中,可以扩展为:

用户
 |
DNS 解析
 |
负载均衡 SLB / LVS / Keepalived
 |
多个边缘代理节点
 |
内部源站服务

在这个架构中,边缘网关承担类似 Cloudflare 的角色:

  • 终止 HTTPS;
  • 隐藏源站地址;
  • 缓存静态资源;
  • 过滤恶意请求;
  • 限制异常访问;
  • 记录访问日志;
  • 将请求转发给内部源站。

四、技术选型

1. Nginx

Nginx 是高性能反向代理服务器,非常适合作为网关入口。它可以处理:

  • 反向代理;
  • 静态资源缓存;
  • Gzip 压缩;
  • 限流;
  • IP 控制;
  • HTTPS;
  • 日志输出。

2. OpenResty

OpenResty 基于 Nginx,并集成 Lua 能力。相比原生 Nginx,OpenResty 可以实现更复杂的动态逻辑,例如:

  • 动态黑名单;
  • 动态路由;
  • JWT 校验;
  • 自定义鉴权;
  • API 请求签名验证;
  • Bot 识别逻辑。

3. ModSecurity

ModSecurity 是开源 WAF 引擎,配合 OWASP Core Rule Set 可以防护常见攻击:

  • SQL 注入;
  • XSS;
  • 路径穿越;
  • 命令注入;
  • 恶意 User-Agent;
  • 非法请求头。

4. Docker Compose

为了方便部署,本文使用 Docker Compose 编排多个服务:

  • Nginx 网关;
  • 示例源站服务;
  • 管理 API;
  • Redis;
  • Prometheus;
  • Grafana。

五、目录结构

项目目录如下:

cloudflare-private-demo/
├── docker-compose.yml
├── nginx/
│   ├── nginx.conf
│   ├── conf.d/
│   │   └── gateway.conf
│   ├── cache/
│   └── logs/
├── app/
│   ├── package.json
│   └── server.js
├── admin-api/
│   ├── package.json
│   └── server.js
└── README.md

六、Docker Compose 部署源码

下面是完整的 docker-compose.yml 示例。

version: "3.8"

services:
  nginx-gateway:
    image: nginx:1.25
    container_name: private-cloudflare-gateway
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./nginx/conf.d:/etc/nginx/conf.d:ro
      - ./nginx/cache:/var/cache/nginx
      - ./nginx/logs:/var/log/nginx
    depends_on:
      - origin-app
      - admin-api
    networks:
      - edge-net

  origin-app:
    build:
      context: ./app
    container_name: origin-app
    restart: always
    networks:
      - edge-net

  admin-api:
    build:
      context: ./admin-api
    container_name: admin-api
    restart: always
    environment:
      - ADMIN_TOKEN=change-me-secret-token
    networks:
      - edge-net

networks:
  edge-net:
    driver: bridge

七、Nginx 主配置源码

创建文件:nginx/nginx.conf

user nginx;
worker_processes auto;

events {
    worker_connections 4096;
    use epoll;
}

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

    server_tokens off;

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

    access_log /var/log/nginx/access.log edge_log;
    error_log  /var/log/nginx/error.log warn;

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;

    keepalive_timeout 65;
    client_max_body_size 20m;

    gzip on;
    gzip_comp_level 5;
    gzip_min_length 1k;
    gzip_types
        text/plain
        text/css
        application/json
        application/javascript
        text/xml
        application/xml
        image/svg+xml;

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

    limit_req_zone $binary_remote_addr zone=req_limit_zone:10m rate=10r/s;
    limit_conn_zone $binary_remote_addr zone=conn_limit_zone:10m;

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

八、网关配置源码

创建文件:nginx/conf.d/gateway.conf

upstream origin_backend {
    server origin-app:3000 max_fails=3 fail_timeout=10s;
    keepalive 32;
}

upstream admin_backend {
    server admin-api:4000 max_fails=3 fail_timeout=10s;
    keepalive 16;
}

server {
    listen 80;
    server_name _;

    return 301 https://$host$request_uri;
}

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

    ssl_certificate     /etc/nginx/certs/fullchain.pem;
    ssl_certificate_key /etc/nginx/certs/privkey.pem;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;

    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    limit_req zone=req_limit_zone burst=30 nodelay;
    limit_conn conn_limit_zone 50;

    location = /health {
        access_log off;
        return 200 "ok\n";
    }

    location /static/ {
        proxy_pass http://origin_backend;

        proxy_cache edge_cache;
        proxy_cache_valid 200 301 302 30m;
        proxy_cache_valid 404 1m;
        proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;

        add_header X-Edge-Cache $upstream_cache_status always;

        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;
    }

    location /api/ {
        proxy_pass http://origin_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;

        proxy_connect_timeout 3s;
        proxy_send_timeout 30s;
        proxy_read_timeout 30s;
    }

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

    location / {
        proxy_pass http://origin_backend;

        proxy_cache edge_cache;
        proxy_cache_valid 200 10m;
        proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;

        add_header X-Edge-Cache $upstream_cache_status always;

        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;
    }
}

注意:如果你暂时没有 HTTPS 证书,可以先将 443 配置注释,仅使用 80 端口测试。生产环境建议使用 Let’s Encrypt、内部 CA 或云厂商证书。


九、源站应用源码

创建目录:app/

app/package.json

{
  "name": "origin-app",
  "version": "1.0.0",
  "main": "server.js",
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "express": "^4.18.3"
  }
}

app/server.js

const express = require("express");

const app = express();
const port = 3000;

app.get("/", function (req, res) {
  res.send(`
    
      
        Private Cloudflare Demo
      
      
        

Cloudflare 私有化替代方案演示

当前请求已经经过私有边缘网关代理。

真实客户端 IP:${req.headers["x-real-ip"] || req.ip}

`); }); app.get("/api/hello", function (req, res) { res.json({ message: "hello from origin app", time: new Date().toISOString(), realIp: req.headers["x-real-ip"] || req.ip, forwardedFor: req.headers["x-forwarded-for"] || null }); }); app.get("/static/app.js", function (req, res) { res.type("application/javascript"); res.send(` console.log("static file from origin app"); `); }); app.listen(port, function () { console.log(`origin app listening on port ${port}`); });

十、管理 API 源码

这个管理 API 用于模拟私有网关的后台接口。真实生产环境中,可以将它扩展为:

  • 动态黑名单管理;
  • 域名配置管理;
  • 缓存刷新;
  • WAF 规则管理;
  • 访问统计查询;
  • 审计日志查询。

创建目录:admin-api/

admin-api/package.json

{
  "name": "admin-api",
  "version": "1.0.0",
  "main": "server.js",
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "express": "^4.18.3"
  }
}

admin-api/server.js

const express = require("express");

const app = express();
const port = 4000;

app.use(express.json());

function auth(req, res, next) {
  const token = req.headers["x-admin-token"];
  const expected = process.env.ADMIN_TOKEN || "change-me-secret-token";

  if (token !== expected) {
    return res.status(401).json({
      error: "unauthorized"
    });
  }

  next();
}

let blacklist = [];

app.get("/health", function (req, res) {
  res.json({
    status: "ok"
  });
});

app.get("/blacklist", auth, function (req, res) {
  res.json({
    blacklist
  });
});

app.post("/blacklist", auth, function (req, res) {
  const ip = req.body.ip;

  if (!ip) {
    return res.status(400).json({
      error: "ip is required"
    });
  }

  if (!blacklist.includes(ip)) {
    blacklist.push(ip);
  }

  res.json({
    message: "ip added",
    blacklist
  });
});

app.delete("/blacklist/:ip", auth, function (req, res) {
  const ip = req.params.ip;
  blacklist = blacklist.filter(item => item !== ip);

  res.json({
    message: "ip removed",
    blacklist
  });
});

app.listen(port, function () {
  console.log(`admin api listening on port ${port}`);
});

十一、Dockerfile 源码

分别在 app/admin-api/ 目录下创建相同的 Dockerfile

FROM node:20-alpine

WORKDIR /app

COPY package.json ./

RUN npm install --production

COPY server.js ./

EXPOSE 3000

CMD ["npm", "start"]

对于 admin-api,由于端口是 4000,可以将 Dockerfile 改成:

FROM node:20-alpine

WORKDIR /app

COPY package.json ./

RUN npm install --production

COPY server.js ./

EXPOSE 4000

CMD ["npm", "start"]

十二、启动部署

在项目根目录执行:

docker compose up -d --build

查看容器状态:

docker compose ps

查看网关日志:

docker logs private-cloudflare-gateway

访问测试:

curl http://localhost

如果启用了 HTTPS,并配置了证书,可以访问:

curl -k https://example.com

测试 API:

curl http://localhost/api/hello

测试静态资源缓存:

curl -I http://localhost/static/app.js

如果返回头中出现:

X-Edge-Cache: MISS

再次请求可能变为:

X-Edge-Cache: HIT

说明缓存已经生效。


十三、加入基础 WAF 能力

如果需要实现更接近 Cloudflare WAF 的能力,可以使用 ModSecurity。

示例 Docker 镜像可以选择:

owasp/modsecurity-crs

或者使用 OpenResty + Lua 自行编写规则。

简单的 Nginx 黑名单规则示例:

map $remote_addr $blocked_ip {
    default 0;
    192.168.1.100 1;
    10.10.10.10 1;
}

server {
    if ($blocked_ip) {
        return 403;
    }
}

限制恶意 User-Agent:

map $http_user_agent $bad_bot {
    default 0;
    ~*curl 1;
    ~*python-requests 1;
    ~*sqlmap 1;
    ~*nikto 1;
}

server {
    if ($bad_bot) {
        return 403;
    }
}

不过需要注意,基于 User-Agent 的拦截只能作为辅助策略,因为 User-Agent 很容易伪造。生产环境中,更可靠的方式是结合:

  • 请求频率;
  • IP 信誉;
  • Cookie;
  • JS Challenge;
  • 行为特征;
  • 登录状态;
  • 风险评分。

十四、缓存策略设计

缓存是 Cloudflare 的重要能力之一。私有化方案中,可以通过 Nginx Proxy Cache 实现。

推荐策略如下:

资源类型 缓存时间 说明
HTML 1-10 分钟 视业务动态程度而定
CSS / JS 7-30 天 文件名带 hash 时可长缓存
图片 7-30 天 适合边缘缓存
API GET 10 秒-5 分钟 只缓存幂等接口
API POST 不缓存 避免业务错误
登录态页面 不缓存 防止数据泄露

Nginx 中可以通过如下配置避免缓存登录用户请求:

set $skip_cache 0;

if ($request_method = POST) {
    set $skip_cache 1;
}

if ($http_authorization != "") {
    set $skip_cache 1;
}

if ($http_cookie ~* "session|token|auth") {
    set $skip_cache 1;
}

proxy_no_cache $skip_cache;
proxy_cache_bypass $skip_cache;

十五、源站隐藏方案

如果要达到类似 Cloudflare 的源站隐藏效果,关键点是:源站不应该直接暴露在公网

推荐方式:

  1. 源站服务只监听内网 IP;
  2. 安全组只允许边缘网关访问源站端口;
  3. 业务域名只解析到边缘网关;
  4. 源站服务禁止公网访问;
  5. 使用内网 DNS 或服务发现连接源站。

例如,在云服务器安全组中配置:

源站 3000 端口:
允许:边缘网关内网 IP
拒绝:所有公网 IP

这样即使攻击者知道源站端口,也无法绕过网关直接访问源站。


十六、日志与监控

私有化网关必须具备日志与监控能力,否则安全事件很难追踪。

建议采集以下指标:

  • QPS;
  • 请求状态码;
  • 请求耗时;
  • 上游响应时间;
  • 缓存命中率;
  • 单 IP 请求频率;
  • 4xx / 5xx 错误比例;
  • WAF 拦截数量;
  • 带宽使用量;
  • TLS 握手情况。

Nginx 日志可以接入:

  • Filebeat + Elasticsearch + Kibana;
  • Promtail + Loki + Grafana;
  • OpenTelemetry Collector;
  • Prometheus Exporter。

如果只做简单分析,可以直接使用:

tail -f nginx/logs/access.log

统计访问最多的 IP:

awk '{print $1}' nginx/logs/access.log | sort | uniq -c | sort -nr | head

统计状态码:

awk '{print $9}' nginx/logs/access.log | sort | uniq -c | sort -nr

十七、生产环境优化建议

如果要将该方案用于生产,需要进一步完善以下方面。

1. 高可用

单台网关存在单点故障,建议至少部署两台以上,通过:

  • SLB;
  • LVS;
  • Keepalived;
  • BGP Anycast;
  • DNS 轮询;

实现高可用。

2. 配置热更新

Nginx 支持平滑重载:

nginx -s reload

容器环境中可以执行:

docker exec private-cloudflare-gateway nginx -s reload

3. 动态规则

如果需要动态黑名单、动态缓存刷新、动态路由,可以考虑:

  • OpenResty + Redis;
  • Envoy + xDS;
  • Traefik;
  • Kong Gateway;
  • APISIX。

其中 Apache APISIX 对插件化、动态配置、API 网关能力支持较好,也适合企业级私有化网关。

4. 证书自动化

HTTPS 证书可以使用:

  • Let’s Encrypt;
  • acme.sh;
  • Certbot;
  • Caddy 自动签发;
  • 内部 CA。

推荐使用 acme.sh 自动续期:

acme.sh --issue -d example.com --standalone
acme.sh --install-cert -d example.com \
  --key-file /etc/nginx/certs/privkey.pem \
  --fullchain-file /etc/nginx/certs/fullchain.pem \
  --reloadcmd "docker exec private-cloudflare-gateway nginx -s reload"

5. 安全加固

需要重点关注:

  • 禁止暴露源站;
  • 禁止暴露管理 API;
  • 管理 API 必须鉴权;
  • 日志不能记录敏感 Token;
  • 证书私钥权限最小化;
  • 定期更新镜像;
  • WAF 规则定期更新;
  • 对异常 IP 自动封禁;
  • 对登录接口做更严格限流。

十八、与 Cloudflare 的差异

私有化替代方案虽然可以实现部分功能,但与 Cloudflare 仍然存在明显差异。

对比项 Cloudflare 私有化方案
全球 CDN 节点 原生具备 需要自建
DDoS 清洗 依赖带宽和上游
WAF 成熟规则库 需自行维护
运维成本 中高
数据可控性 较弱
定制能力 有限制
部署复杂度 中高
内网集成 一般

因此,私有化方案更适合以下场景:

  • 企业内部系统;
  • 专有云环境;
  • 合规要求较高业务;
  • 访问规模可控的网站;
  • 需要深度定制网关逻辑的系统。

如果是面向全球公网的大规模业务,仍然建议结合专业 CDN、云安全厂商和 DDoS 清洗服务共同使用。


十九、完整部署命令汇总

mkdir -p cloudflare-private-demo
cd cloudflare-private-demo

mkdir -p nginx/conf.d nginx/cache nginx/logs app admin-api

创建上述配置文件后,执行:

docker compose up -d --build

测试访问:

curl http://localhost
curl http://localhost/api/hello
curl -I http://localhost/static/app.js

查看日志:

tail -f nginx/logs/access.log

停止服务:

docker compose down

清理缓存:

rm -rf nginx/cache/*

二十、总结

Cloudflare 无法真正被“私有化部署”,但可以通过 Nginx、OpenResty、ModSecurity、Docker、Redis、Prometheus 等开源组件,构建一套具备 Cloudflare 核心能力的私有边缘网关方案。

本文提供的方案可以实现:

  • HTTPS 入口;
  • 反向代理;
  • 源站隐藏;
  • 静态资源缓存;
  • 访问限流;
  • 基础安全 Header;
  • 日志记录;
  • 管理 API;
  • 容器化部署。

对于企业内部系统、私有云业务、合规要求较高的系统,这类方案具备较高的实用价值。但在面对大规模公网攻击、全球加速、复杂 Bot 对抗时,自建方案仍然无法完全替代 Cloudflare,需要结合云厂商安全产品、专业 CDN 和 DDoS 清洗能力共同使用。

如果你只是希望拥有一个可控、可扩展、可二次开发的私有网关,那么本文给出的源码和架构可以作为一个基础版本。后续可以继续扩展动态配置、WAF 插件、Redis 黑名单、Prometheus 监控、Grafana 可视化、自动证书续期和多节点高可用,从而逐步演进为一套真正适合企业使用的私有化边缘安全平台。

目录结构
全文