服务器部署
服务器部署
启动服务
我们可以购买云服务器进行服务部署,也可以在本机部署
借助docker进行服务器部署。
好处:不需要复杂的环境配置,轻量部署、轻装上阵。
cloudflare
后续的域名购买、dns解析(域名映射)、cdn加速、s3存储、边缘函数计算(worker处理)等等均借助cloudflare完成。
域名购买
dns解析(域名映射)
通过Zero Trust建立Tunnels,将域名与服务器进行链接
Cloudflare Tunnels的实现原理1 Tunnels: 本地下载一个cloudflare程序,它会启动一个websocket链接,会连接cloudflare的边缘服务器,而这个服务器上会存在实际的路由映射表,tunnelId和ip的对映,相同于进行了一层代理转发。
选择操作系统类型,安装并运行连接器
服务映射
通过不同主机名进行同一服务器下不同服务的映射
cdn加速
内容分发网络,dns解析时,自动匹配最近的空闲服务节点
s3存储
S3是一种对象存储服务,不同于传统的文件系统存储。
我们将图片、文件等一些静态资源存放在一些网络服务商的网络磁盘中,而不需要实际占用我们的实际服务器空间资源。
- 创建一个存储桶(bucket)类似于磁盘的概念
可以定义bucket的对外域名
r2/s3是一种对象存储服务,不同于传统的文件系统存储。
上传完成后,会生成访问链接
此外,我们可以借助sdk、api调用的形式,接入我们的应用程序
todo: s3存储的静态资源的cdn加速配置
cloudflare r2进行cdn加速2
边缘函数计算(worker处理)
边缘函数的一种实现方式:worker
当我们有一些独立且轻量的函数或者api调用,同时我们对服务器要求不是很高时,可以将它们部署到worker上。
与传统的部署不同,我们不需要提供实际的服务器,而是将代码托管到了网络服务商的云服务器中,同时也支持我们指定子域名及路由进行不同边缘函数。
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和开放入站端口的安全远程访问,这对于现代应用部署和安全架构设计具有重要意义。 ↩
cloudflare r2进行cdn加速
当我们声明了自定义域名时,实际上,当我们访问资源时,也是会通过cf的代理转发,所以也是经过dns解析的,而cf的dns解析过程中加入了cdn处理,优先访问边缘节点服务器缓存,如果不命中缓存,则回源美国节点,因此不需要额外的配置,当然我们可以通过cdn服务商(webp.se)进行多层cdn的配置。
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';
在你的配置中:
从截图可以看到:
- R2 记录:
data.tianran.org
直接连接到名为public
的 R2 存储桶 - 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 加速 ↩