服务器部署

启动服务

我们可以购买云服务器进行服务部署,也可以在本机部署

借助docker进行服务器部署。

好处:不需要复杂的环境配置,轻量部署、轻装上阵。

cloudflare

后续的域名购买、dns解析(域名映射)、cdn加速、s3存储、边缘函数计算(worker处理)等等均借助cloudflare完成。

域名购买

image

dns解析(域名映射)

通过Zero Trust建立Tunnels,将域名与服务器进行链接

Cloudflare Tunnels的实现原理1 Tunnels: 本地下载一个cloudflare程序,它会启动一个websocket链接,会连接cloudflare的边缘服务器,而这个服务器上会存在实际的路由映射表,tunnelId和ip的对映,相同于进行了一层代理转发。

image​选择操作系统类型,安装并运行连接器

image

服务映射

通过不同主机名进行同一服务器下不同服务的映射

image

cdn加速

内容分发网络,dns解析时,自动匹配最近的空闲服务节点

s3存储

S3是一种对象存储服务,不同于传统的文件系统存储。

我们将图片、文件等一些静态资源存放在一些网络服务商的网络磁盘中,而不需要实际占用我们的实际服务器空间资源。

  • 创建一个存储桶(bucket)类似于磁盘的概念

image

可以定义bucket的对外域名

image

r2/s3是一种对象存储服务,不同于传统的文件系统存储。

上传完成后,会生成访问链接

imageimage

此外,我们可以借助sdk、api调用的形式,接入我们的应用程序

image

todo: s3存储的静态资源的cdn加速配置

cloudflare r2进行cdn加速2

边缘函数计算(worker处理)

边缘函数的一种实现方式:worker

当我们有一些独立且轻量的函数或者api调用,同时我们对服务器要求不是很高时,可以将它们部署到worker上。

与传统的部署不同,我们不需要提供实际的服务器,而是将代码托管到了网络服务商的云服务器中,同时也支持我们指定子域名及路由进行不同边缘函数。

image


  1. Cloudflare Tunnels的实现原理

    Tunnels基本概念

    Cloudflare Tunnels(原名Argo Tunnel)是一种安全的连接方式,它创建了一个从你的服务器到Cloudflare边缘网络的加密隧道。

    实现原理架构

    Internet用户 → Cloudflare边缘 → 加密隧道 → 你的服务器(无需公网IP)
    

    1. 隧道建立过程

    // 简化的隧道建立流程
    const tunnelSetup = {
      step1: "cloudflared客户端启动",
      step2: "与Cloudflare API进行身份验证", 
      step3: "建立WebSocket/HTTP2连接到最近的Cloudflare数据中心",
      step4: "注册隧道路由信息",
      step5: "开始代理流量"
    }
    

    2. 核心组件

    cloudflared守护进程

    # 安装和运行示例
    cloudflared tunnel create my-tunnel
    cloudflared tunnel route dns my-tunnel app.example.com
    cloudflared tunnel run my-tunnel
    

    配置文件示例

    # config.yml
    tunnel: my-tunnel-id
    credentials-file: /path/to/credentials.json
    
    ingress:
      - hostname: app.example.com
        service: http://localhost:3000
      - hostname: api.example.com
        service: http://localhost:8080
      - service: http_status:404
    

    详细工作流程

    1. 出站连接建立

    // 模拟隧道连接过程
    class TunnelConnection {
      constructor(tunnelId, credentials) {
        this.tunnelId = tunnelId;
        this.credentials = credentials;
        this.connections = [];
      }
    
      async establishConnection() {
        // 1. 认证
        const authToken = await this.authenticate();
          
        // 2. 建立多个并发连接(通常4个)
        for(let i = 0; i < 4; i++) {
          const conn = await this.createConnection(authToken);
          this.connections.push(conn);
        }
          
        // 3. 保持连接活跃
        this.startHeartbeat();
      }
    
      createConnection(token) {
        return new WebSocket('wss://region.argotunnel.com', {
          headers: {
            'Authorization': `Bearer ${token}`,
            'Cf-Tunnel-Token': this.tunnelId
          }
        });
      }
    }
    

    2. 流量代理机制

    // 简化的流量处理逻辑
    class TrafficProxy {
      handleIncomingRequest(request) {
        // 1. Cloudflare边缘接收用户请求
        const userRequest = this.parseRequest(request);
          
        // 2. 通过隧道转发到本地服务
        const tunnelRequest = {
          method: userRequest.method,
          url: userRequest.url,
          headers: userRequest.headers,
          body: userRequest.body,
          metadata: {
            'CF-Connecting-IP': userRequest.clientIP,
            'CF-Ray': generateRayID()
          }
        };
          
        // 3. 发送到cloudflared客户端
        return this.forwardThroughTunnel(tunnelRequest);
      }
    
      forwardThroughTunnel(request) {
        // 选择可用的隧道连接
        const connection = this.selectAvailableConnection();
          
        // 通过WebSocket发送请求
        return connection.send(JSON.stringify(request));
      }
    }
    

    安全特性

    1. 加密传输

    // 所有隧道流量都经过TLS加密
    const securityFeatures = {
      encryption: "TLS 1.3",
      authentication: "Mutual TLS + API Token",
      integrity: "Message authentication codes",
      firewall: "无需入站端口开放"
    }
    

    2. 身份验证

    // 隧道认证流程
    const authFlow = {
      clientCertificate: "cloudflared客户端证书",
      apiToken: "Cloudflare API令牌", 
      tunnelCredentials: "隧道专用凭据文件",
      domainValidation: "域名所有权验证"
    }
    

    网络流量处理

    1. HTTP/HTTPS处理

    // HTTP请求转发示例
    app.get('/api/data', (req, res) => {
      // 本地服务正常处理请求
      // cloudflared会自动代理这些请求
    
      // 可以获取原始客户端IP
      const clientIP = req.headers['cf-connecting-ip'];
      const rayID = req.headers['cf-ray'];
    
      res.json({
        message: "通过Tunnel访问成功",
        clientIP: clientIP,
        rayID: rayID
      });
    });
    

    2. WebSocket支持

    // WebSocket通过隧道的处理
    const WebSocket = require('ws');
    
    const wss = new WebSocket.Server({ port: 8080 });
    
    wss.on('connection', (ws, req) => {
      // WebSocket连接也会通过隧道代理
      console.log('WebSocket连接建立,客户端IP:', req.headers['cf-connecting-ip']);
    
      ws.on('message', (message) => {
        // 处理WebSocket消息
        ws.send(`Echo: ${message}`);
      });
    });
    

    高可用性设计

    1. 多连接冗余

    const redundancyConfig = {
      connectionsPerTunnel: 4,  // 每个隧道4个连接
      failoverTime: "数秒内",   // 故障切换时间
      loadBalancing: "自动负载均衡",
      healthCheck: "连接健康检查"
    }
    

    2. 故障恢复

    class TunnelManager {
      constructor() {
        this.reconnectInterval = 5000;
        this.maxRetries = 10;
      }
    
      async handleConnectionLoss() {
        let retries = 0;
          
        while(retries < this.maxRetries) {
          try {
            await this.reestablishConnection();
            console.log('隧道重连成功');
            break;
          } catch(error) {
            retries++;
            console.log(`重连失败,${this.reconnectInterval}ms后重试`);
            await this.sleep(this.reconnectInterval);
          }
        }
      }
    }
    

    与传统VPN的区别

    特性 Cloudflare Tunnels 传统VPN
    安装复杂度 简单(一个二进制文件) 复杂(需要配置服务器)
    网络要求 仅需出站连接 需要入站端口开放
    安全性 应用层安全 网络层安全
    性能 Cloudflare全球网络加速 取决于VPN服务器位置
    可见性 详细的流量分析 有限的日志记录

    实际部署示例

    # docker-compose.yml
    version: '3.8'
    services:
      app:
        build: .
        ports:
          - "3000:3000"
          
      cloudflared:
        image: cloudflare/cloudflared:latest
        command: tunnel --config /etc/cloudflared/config.yml run
        volumes:
          - ./cloudflared:/etc/cloudflared
        depends_on:
          - app
    

    Cloudflare Tunnels通过建立安全的出站连接,实现了无需公网IP和开放入站端口的安全远程访问,这对于现代应用部署和安全架构设计具有重要意义。

  2. cloudflare r2进行cdn加速

    当我们声明了自定义域名时,实际上,当我们访问资源时,也是会通过cf的代理转发,所以也是经过dns解析的,而cf的dns解析过程中加入了cdn处理,优先访问边缘节点服务器缓存,如果不命中缓存,则回源美国节点,因此不需要额外的配置,当然我们可以通过cdn服务商(webp.se)进行多层cdn的配置。

    image

    CF DNS 常见记录类型

    R2 记录类型

    R2 是 Cloudflare 特有的 DNS 记录类型,专门用于连接 R2 对象存储服务。

    特点:

    Type: R2
    Name: data.tianran.org  # 你的域名
    Content: public         # R2存储桶名称
    Proxy status: Proxied   # 启用CDN代理
    

    作用:

    • 直接将域名指向 R2 存储桶
    • 自动启用 CDN 加速
    • 无需手动配置复杂的存储桶 URL

    CNAME 记录类型

    CNAME(Canonical Name)是标准的 DNS 记录类型,用于创建域名别名。

    特点:

    Type: CNAME
    Name: cdn                    # 子域名
    Content: 37789669-2af8-4...  # 目标域名或服务地址
    Proxy status: Proxied        # 启用CDN代理
    

    作用:

    • 将一个域名指向另一个域名
    • 常用于 CDN、负载均衡等服务
    • 更灵活的域名映射

    实际应用对比

    使用 R2 记录:

    // 直接访问 R2 存储的文件
    const imageUrl = 'https://data.tianran.org/images/photo.jpg';
    

    使用 CNAME 记录:

    // 通过 CNAME 别名访问
    const cdnUrl = 'https://cdn.tianran.org/assets/style.css';
    

    在你的配置中:

    从截图可以看到:

    1. R2 记录data.tianran.org​ 直接连接到名为 public​ 的 R2 存储桶
    2. CNAME 记录cdn​、blog​ 等都是域名别名,指向不同的服务

    代码使用示例:

    <!-- 使用 R2 记录访问存储文件 -->
    <img src="https://data.tianran.org/uploads/avatar.png" alt="Avatar">
    
    <!-- 使用 CNAME 记录访问 CDN 资源 -->
    <link rel="stylesheet" href="https://cdn.tianran.org/css/main.css">
    

    性能对比:

    // R2 记录 - 直接访问存储
    fetch('https://data.tianran.org/api/data.json')
      .then(response => response.json())
      .then(data => console.log('R2数据:', data));
    
    // CNAME 记录 - 通过别名访问
    fetch('https://cdn.tianran.org/resources/config.json')
      .then(response => response.json())
      .then(data => console.log('CDN数据:', data));
    

    总结

    • R2 记录是 Cloudflare 为 R2 存储服务专门设计的,使用更简单
    • CNAME 记录是通用的 DNS 别名机制,使用更灵活
    • 两者都可以启用 Proxied 状态来享受 Cloudflare 的 CDN 加速