# 腾讯云 CDN 配置指南

本文档描述如何为 `xmclassmate.top` 域名配置腾讯云 CDN，实现：
1. 隐藏源站服务器 IP
2. 加速静态资源访问
3. 防止源站被直接攻击

---

## 域名信息

| 域名 | 用途 | CDN 适用性 | 说明 |
|------|------|------------|------|
| `xmclassmate.top` | 主域名 | ✅ 可配置 | 通常作为 API 或主站 |
| `www.xmclassmate.top` | WWW | ✅ 可配置 | 网站入口 |
| `warden.xmclassmate.top` | Warden | ✅ 可配置 | Warden 服务 |
| `gitea.xmclassmate.top` | Gitea | ✅ 可配置 | Git 服务 |
| `dev.xmclassmate.top` | 开发环境 | ✅ 可配置 | 后端开发环境 |
| `psql.xmclassmate.top` | PostgreSQL | ❌ 不适用 | TCP 协议，CDN 无法代理 |

---

## 当前架构

```
用户 → DNS (A记录) → 服务器 IP → Nginx → 服务端口
```

## 目标架构

```
用户 → CDN → DNS (CNAME) → CDN 节点 → 回源 → Nginx → 服务
```

---

## 证书说明

**已有证书**：`xmclassmate.top`（主域名）

**子域名处理方式**：

| 方案 | 适用场景 | 成本 |
|------|---------|------|
| **腾讯云免费证书** | 每个子域名独立申请 | 免费 |
| **泛域名证书** | `*.xmclassmate.top` | 免费/付费 |
| **CDN 自有证书** | 直接使用源站证书 | 需上传到 CDN |

**推荐**：为 `*.xmclassmate.top` 申请泛域名证书，一次覆盖所有子域名。

---

## 配置步骤

### 第一步：获取腾讯云 CDN 回源 IP 段

登录腾讯云 CDN 控制台，获取回源 IP 段：

**控制台路径**：
```
内容分发网络 CDN → 域名管理 → 选择域名 → 基本配置 → 回源配置
```

**腾讯云 CDN 回源 IP 段**（常见段）：
```
101.226.0.0/16   # 上海
119.147.0.0/16   # 广州
123.151.0.0/16   # 天津
182.140.0.0/16   # 成都
```

> **注意**：雨云服务器使用腾讯云 CDN，具体 IP 段需在腾讯云 CDN 控制台查看。

---

### 第二步：添加加速域名

**控制台路径**：
```
内容分发网络 CDN → 域名管理 → 添加域名
```

**配置项**（以 `dev.xmclassmate.top` 为例）：

| 配置项 | 示例值 | 说明 |
|--------|--------|------|
| 加速域名 | `dev.xmclassmate.top` | 要加速的子域名 |
| 业务类型 | Web 网站 | 选择「网站加速」 |
| 源站类型 | IP | 填写服务器公网 IP |
| 源站地址 | `服务器IP` | 服务器真实 IP |
| 回源协议 | HTTPS | 源站已有证书 |
| 端口 | 443 | HTTPS 端口 |

**重复此步骤添加其他域名**：`gitea`、`warden`、`www`

---

### 第三步：配置 HTTPS 证书

#### 方案 A：使用泛域名证书（推荐）

1. 在腾讯云 SSL 证书控制台申请 `*.xmclassmate.top` 泛域名证书
2. 审核通过后，在 CDN 控制台选择该证书

#### 方案 B：每个子域名独立配置

1. 为每个子域名申请独立证书
2. 上传证书到 CDN

#### 方案 C：使用源站证书

如果 Nginx 已配置 HTTPS，可直接「回源协议」选择 HTTPS，CDN 会使用相同证书。

---

### 第四步：获取 CDN CNAME

域名添加成功后，腾讯云会分配一个 CNAME：

```
格式：`xxxxxxxx.xxx.com.w.cdngslb.com`
```

在控制台查看：
```
内容分发网络 CDN → 域名管理 → dev.xmclassmate.top → 基本配置 → CNAME
```

---

### 第五步：修改 DNS 解析（雨云 DNSPod）

**雨云 DNSPod 控制台**：

| 记录类型 | 主机记录 | 记录值 | TTL |
|----------|----------|--------|-----|
| CNAME | dev | `xxxxxxxx.xxx.com.w.cdngslb.com` | 600 |
| CNAME | gitea | `xxxxxxxx.xxx.com.w.cdngslb.com` | 600 |
| CNAME | warden | `xxxxxxxx.xxx.com.w.cdngslb.com` | 600 |
| CNAME | www | `xxxxxxxx.xxx.com.w.cdngslb.com` | 600 |

**注意**：
- 将原有的 A 记录**删除或禁用**
- CNAME 和 A 记录不能共存于同一主机记录

---

### 第六步：配置 Nginx

#### 6.1 记录真实客户端 IP

```nginx
server {
    listen 443 ssl;
    server_name dev.xmclassmate.top gitea.xmclassmate.top warden.xmclassmate.top;

    # SSL 证书
    ssl_certificate /path/to/fullchain.pem;
    ssl_certificate_key /path/to/privkey.pem;

    # 腾讯云 CDN 回源 IP 段（替换为实际值）
    set_real_ip_from 10.0.0.0/8;
    set_real_ip_from 101.226.0.0/16;
    set_real_ip_from 119.147.0.0/16;
    set_real_ip_from 123.151.0.0/16;
    set_real_ip_from 182.140.0.0/16;

    real_ip_header X-Forwarded-For;
    real_ip_recursive on;

    # 日志格式
    log_format main '$real_ip_var - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent"';

    access_log /var/log/nginx/access.log main;
    error_log /var/log/nginx/error.log;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $real_ip_var;
        proxy_set_header X-Forwarded-For $real_ip_var;
    }
}
```

#### 6.2 限制只能 CDN 回源访问（可选）

```nginx
geo $cdn_access {
    default 0;
    10.0.0.0/8 1;
    101.226.0.0/16 1;
    119.147.0.0/16 1;
    123.151.0.0/16 1;
    182.140.0.0/16 1;
}

server {
    if ($cdn_access = 0) {
        return 403;
    }
    # ... 其他配置
}
```

#### 6.3 重载 Nginx

```bash
nginx -t && nginx -s reload
```

---

### 第七步：配置雨云安全组

在雨云控制台配置**端口规则**：

**安全组规则**：

| 方向 | 来源 | 协议端口 | 策略 |
|------|------|----------|------|
| 入站 | `101.226.0.0/16` | TCP:443 | 允许 |
| 入站 | `119.147.0.0/16` | TCP:443 | 允许 |
| 入站 | `123.151.0.0/16` | TCP:443 | 允许 |
| 入站 | `182.140.0.0/16` | TCP:443 | 允许 |
| 入站 | `0.0.0.0/0` | TCP:443 | 拒绝 |

> **注意**：雨云安全组可能需要单独配置 CDN IP 段，具体操作参考雨云文档。

---

### 第八步：验证配置

#### 8.1 检查 DNS 解析

```bash
# 检查 CNAME 是否生效
dig dev.xmclassmate.top

# 期望输出包含：cdn.com.w.cdngslb.com
```

#### 8.2 检查 CDN 回源

```bash
# 通过 CDN 访问
curl -I https://dev.xmclassmate.top

# 检查响应头是否包含 CDN 信息
```

#### 8.3 检查 Nginx 日志

```bash
# 查看是否记录了真实 IP
tail -f /var/log/nginx/access.log

# 期望：$real_ip_var 显示的是用户真实 IP
```

#### 8.4 验证源站隐藏

```bash
# 直接 IP 访问应该被拒绝（如果配置了安全组）
curl -I https://服务器IP

# 期望：连接超时或 403
```

---

## psql.xmclassmate.top 处理

**PostgreSQL 不适合 CDN**，因为：
- CDN 只支持 HTTP/HTTPS 协议
- PostgreSQL 使用 TCP 协议（端口 5432）

**处理方式**：保持现状（A 记录），偶尔手动调试够用。

---

## 静态文件缓存配置

CDN 可以缓存 Rust 后端返回的静态文件（CSS、JS、图片等），减轻源站压力。

### 工作流程

```
用户请求 /static/css/style.css
        ↓
CDN 检查缓存（未命中）
        ↓
回源请求 → Rust 后端
        ↓
Rust 返回文件 + Cache-Control 头
        ↓
CDN 缓存这份响应
        ↓
返回给用户

下一个用户请求 → CDN 直接返回缓存 ✅
```

### Rust 后端配置

在返回静态文件响应时设置 `Cache-Control` 头：

```rust
use actix_web::{HttpResponse, http::header};

/// 返回静态文件（适合带版本号的文件，如 style.v1.css）
pub fn serve_static_file(path: &str) -> HttpResponse {
    HttpResponse::Ok()
        .insert_header(("Cache-Control", "public, max-age=31536000"))  // 缓存 1 年
        .insert_header(("Content-Type", "text/css"))
        .body(read_file(path))
}

/// 返回可能更新的静态文件（缓存时间较短）
pub fn serve_dynamic_static(path: &str) -> HttpResponse {
    HttpResponse::Ok()
        .insert_header(("Cache-Control", "public, max-age=86400"))  // 缓存 1 天
        .insert_header(("Content-Type", "application/javascript"))
        .body(read_file(path))
}
```

### 缓存时间建议

| 文件类型 | 缓存时间 | 说明 |
|----------|----------|------|
| CSS, JS（带版本号） | 1 年 (`max-age=31536000`) | 配合版本号使用 |
| 图片 | 1 个月 (`max-age=2592000`) | 很少变动 |
| HTML | 不缓存 | 动态内容 |
| API 响应 | 不缓存 | 实时数据 |

### 静态文件命名建议

为便于 CDN 长期缓存，建议静态文件带版本号或 hash：

```
# 推荐
style.v1.css
app.v2.js
bundle.abc123.css

# 不推荐（更新时 CDN 仍返回旧缓存）
style.css
app.js
```

### 腾讯云 CDN 缓存配置

在腾讯云 CDN 控制台设置缓存规则：

```
内容分发网络 CDN → 域名管理 → 选择域名 → 缓存配置 → 添加规则

规则类型：文件类型
文件类型：.css,.js,.png,.jpg,.jpeg,.gif,.ico
缓存时间：31536000 秒（1年）
```

---

## 配置检查清单

| 步骤 | 操作 | 状态 |
|------|------|------|
| 1 | 获取腾讯云 CDN 回源 IP 段 | ☐ |
| 2 | 为每个域名添加 CDN 加速 | ☐ |
| 3 | 配置 HTTPS 证书（泛域名或独立） | ☐ |
| 4 | 获取 CDN CNAME | ☐ |
| 5 | 修改雨云 DNSPod DNS 解析 | ☐ |
| 6 | 配置 Nginx 真实 IP | ☐ |
| 7 | 配置雨云安全组 | ☐ |
| 8 | 验证配置生效 | ☐ |

---

## 回滚步骤

如果配置有问题需要回滚：

1. **雨云 DNSPod 删除 CNAME，恢复 A 记录**
2. **Nginx 移除 `set_real_ip_from` 配置**
3. **安全组恢复 0.0.0.0/0 访问**

---

## 常见问题

### Q1：CDN 配置后多久生效？

DNS 解析生效时间取决于 TTL，通常 10 分钟到 48 小时。

### Q2：泛域名证书如何申请？

腾讯云 SSL 证书控制台 → 免费证书 → 申请证书 → 填写 `*.xmclassmate.top`

### Q3：雨云安全组在哪里配置？

雨云控制台 → 云服务器 → 选择服务器 → 安全组

### Q4：如何确认 CDN 已生效？

```bash
curl -I https://dev.xmclassmate.top
# 查看 Age 或 X-Cache-Lookup 头
```

### Q5：psql 域名如何安全访问？

保持现状（A 记录），仅供偶尔手动调试使用。

---

## 参考链接

- [腾讯云 CDN 文档](https://cloud.tencent.com/document/product/414)
- [腾讯云 CDN 回源配置](https://cloud.tencent.com/document/product/414/65505)
- [雨云安全组配置](https://www.rainyun.com/docs/)
- [Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/)
