<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>一念三千</title><description>心之所向，素履以往</description><link>https://nianyi778.github.io/</link><item><title>用 AI Skill 打通 Git 开发最后一公里：从建分支到提 PR 的完整自动化</title><link>https://nianyi778.github.io/posts/branch-commit-pr-ai-git-workflow/</link><guid isPermaLink="true">https://nianyi778.github.io/posts/branch-commit-pr-ai-git-workflow/</guid><description>介绍 branch-commit-pr 项目如何自动识别仓库约定，完成分支创建、原子提交与 PR 生成，帮助团队把 AI 编码输出稳定接入工程流程。</description><pubDate>Mon, 02 Mar 2026 16:00:00 GMT</pubDate><content:encoded>在很多团队里，真正拖慢节奏的并不总是“写代码”，而是这条重复且容易失误的链路：

![branch-commit-pr 封面](../../assets/branch-commit-pr-ai-git-workflow.png)

1. 从默认分支拉最新代码
2. 按团队规范创建功能分支
3. 把改动拆成可审查的原子提交
4. 组织 PR 标题、描述、关联 Issue/Jira

这些步骤都不复杂，但每天重复执行，既耗时又容易出现不一致。[`branch-commit-pr`](https://github.com/nianyi778/branch-commit-pr) 这个项目，目标就是把这条链路做成 AI 代理可复用的 Skill，让流程自动且稳定。

## 项目定位

`branch-commit-pr` 是一个完整的 Git 开发工作流 Skill，覆盖：

- 上下文检测（默认分支、分支命名约定、提交风格）
- 分支管理（从最新默认分支拉起并设置 upstream）
- 智能提交（按模块/关注点拆分原子 commit）
- PR 创建（通过 `gh` CLI 自动生成标题与描述）
- 事项关联（GitHub Issue，可选 Jira 链接）

一句话总结：**把“代码写完后的工程动作”交给 AI 代理处理。**

## 它解决了什么问题

### 1) 团队约定难以长期一致

常见问题：

- 分支命名风格混乱（`feat/`、`feature/`、平铺命名并存）
- commit message 风格不统一（语义化与自然语言混用）

`branch-commit-pr` 会先读取仓库近期分支与提交历史，再按既有习惯生成分支名与提交信息，减少“人为口径漂移”。

### 2) 改动提交粒度不合理

很多项目的问题不是“没人提交”，而是“提交太大、太杂”。

该 Skill 在提交阶段会先分析改动，再按目录与关注点分组；实现与对应测试会尽量放在同一提交里，提升 PR 可读性和可回滚性。

### 3) PR 编写成本高

从 commit 到 PR 的最后一步常被低估：标题、摘要、关联事项、检查信息都需要整理。

该 Skill 通过 `gh` CLI 自动生成 PR 内容，并支持在你提到 Issue 编号时自动关联，减少人工整理成本。

## 工作方式（Phase 化流程）

项目把流程拆成 4 个阶段：

- **Phase 0 Context Gathering**：检测默认分支、命名约定、提交风格、Issue 跟踪能力
- **Phase 1 Branch Management**：同步默认分支并创建规范 feature branch
- **Phase 2 Smart Commit**：规划原子提交并按仓库风格生成 commit message
- **Phase 3 Pull Request**：创建 PR，自动填充摘要与关联信息

这意味着它既可以跑全流程，也可以按需执行单阶段。

## 使用示例（自然语言）

你可以直接对代理说：

- “开始做 dark mode 功能”
- “给登录模块建分支”
- “提交当前改动并拆成合理 commit”
- “基于这些提交创建 PR，关联 #42”

Skill 会根据指令自动选择执行模式（仅建分支 / 仅提交 / 仅 PR / 提交+PR / 全流程）。

## 安装方式

推荐使用 `skills.sh`：

```bash
npx skills add nianyi778/branch-commit-pr
```

也可手动复制 `SKILL.md` 到代理技能目录（如 Claude Code、OpenCode、Cursor）。

## 依赖与边界

项目依赖很轻：

- `git`
- `gh`（用于 PR 创建）
- 可选 Jira 环境变量配置（用于票据链接）

需要注意：它聚焦的是“流程自动化”，不是替代代码评审。它能显著改善流程一致性，但最终质量仍然依赖团队评审与测试体系。

## Jira 如何与 PR 绑定（实现细节）

这一块的实现分两层：

### 1) PR 文案关联（默认）

触发条件：

- 已配置 `JIRA_URL`、`JIRA_EMAIL`、`JIRA_API_TOKEN`
- 在指令中明确提到 Jira ticket（如 `PROJ-123`）

执行方式：

- 在 PR 描述中增加 Jira 链接：
  - `Jira: [PROJ-123](https://yourteam.atlassian.net/browse/PROJ-123)`

这一步让评审可以从 PR 一跳到 Jira 工单，建立明确上下文。

### 2) Jira 状态流转（可选）

只有当你明确要求（例如“把 PROJ-123 流转到 In Review”）时，才会调用 Jira API：

- 接口：`POST /rest/api/3/issue/{KEY}/transitions`
- 认证：`email + api_token`（Basic Auth）
- 参数：`transition id`（例如 `31`）

也就是说，默认不会自动改 Jira 状态。

### 3) 安全策略

- 不猜 ticket：你不提 ticket，就不添加 Jira 关联
- 不默认流转：你不明确要求，就不调用 transition API
- Jira API 失败不阻断：会提示告警，但 PR 仍可创建

### 4) 可直接使用的指令

&gt; “提交并创建 PR，关联 PROJ-123；然后把它流转到 In Review”

## 适用场景

- 正在把 AI 编码接入日常研发流程的团队
- 多人协作、提交与分支规范要求明确的项目
- 希望降低 PR 准备时间、提高审查效率的仓库

## 结语

如果说 AI 已经提高了“写代码”的速度，那么 `branch-commit-pr` 在做的是另一件事：

**把“写完代码之后”的工程动作标准化、自动化、可复用化。**

对于任何希望把 AI 产出稳定落地到真实协作流程的团队，这一步通常比想象中更关键。</content:encoded></item><item><title>🌐 使用 Cloudflare Workers 实现全球智能分流 —— 海内外访问加速实践</title><link>https://nianyi778.github.io/posts/cloudflare-workers-geo-routing/</link><guid isPermaLink="true">https://nianyi778.github.io/posts/cloudflare-workers-geo-routing/</guid><description>利用 Cloudflare Workers 边缘计算能力，根据用户地理位置智能路由，大陆用户走日本 VPS 中转，海外用户直连 Cloudflare，实现全球低延迟访问</description><pubDate>Sat, 24 Jan 2026 16:00:00 GMT</pubDate><content:encoded>&gt; **版本**: 1.0  
&gt; **最后更新**: 2026-01-25  
&gt; **状态**: ✅ 已实战验证可用  
&gt; **架构**: Cloudflare Workers (边缘路由) + Oracle Cloud Japan (中转) + Cloudflare Pages/Workers (源站)

---

## 1. 背景与问题

### 项目介绍

[StarFlix](https://star.divinations.top) 是一个基于 Cloudflare 全家桶构建的电影流媒体平台：

- **前端**: Next.js 15 + Cloudflare Pages
- **后端**: Hono + Cloudflare Workers + D1
- **域名**: Cloudflare DNS

作为一个面向全球用户的项目，我们面临一个经典问题：**如何同时优化大陆和海外用户的访问速度？**

### 遇到的问题

由于众所周知的原因，大陆用户直接访问 Cloudflare 的体验并不理想。于是我们在日本大阪部署了一台 VPS 作为中转（详见 [中国大陆网络访问优化指南](/posts/china-network-optimization-guide)）：

```
大陆用户 → star.divinations.top (大阪 VPS) → Cloudflare Origin
```

这个方案对大陆用户效果很好，延迟从 300ms+ 降到了 50-80ms。

**但问题来了**：海外用户本来可以直连 Cloudflare 边缘节点（延迟 20-50ms），现在却被迫绕道大阪 VPS，延迟反而增加到了 150ms+。

```
之前的架构（所有流量都经过大阪）：

                    star.divinations.top
                            ↓
                   DNS 解析到大阪 VPS IP
                            ↓
                 ┌──────────────────────┐
                 │    大阪 VPS (nginx)   │ ← 所有用户都经过这里
                 └──────────────────────┘
                            ↓
                 star-origin.divinations.top
                            ↓
                    Cloudflare Pages
```

**需求**：让大陆用户继续走大阪 VPS，海外用户直连 Cloudflare。

---

## 2. 方案选型

| 方案 | 成本 | 复杂度 | 效果 | 说明 |
|------|------|--------|------|------|
| **Cloudflare 地理位置路由** | Enterprise | 低 | 最佳 | 需要企业版，成本高 |
| **DNSPod 分区解析** | 免费 | 中 | 好 | 需要更换 DNS 服务商 |
| **双域名 + 前端切换** | 免费 | 中 | 好 | 用户需要手动选择或前端检测 |
| **Cloudflare Workers** | 免费 | 中 | 好 | 边缘判断，用户无感知 |

最终选择 **Cloudflare Workers** 方案，原因：

1. **用户无感知** - 同一个域名，自动路由
2. **边缘判断** - 在 Cloudflare 全球边缘节点上执行，延迟最低
3. **免费额度足够** - 10 万次请求/天，个人项目完全够用
4. **无需更换 DNS** - 继续使用 Cloudflare DNS

---

## 3. 技术架构

### 3.1 目标架构

```
                         用户访问
                            ↓
                   star.divinations.top
                            ↓
                  ┌─────────────────────┐
                  │  Cloudflare Workers │  ← 在边缘节点判断地区
                  │    (Geo Router)     │
                  └─────────────────────┘
                            ↓
              ┌─────────────┴─────────────┐
              ↓                           ↓
         CN/HK/MO 用户                  其他地区
              ↓                           ↓
    osaka.divinations.top      star-origin.divinations.top
              ↓                           ↓
         大阪 VPS (nginx)           Cloudflare 直连
              ↓
    star-origin.divinations.top
              ↓
        Cloudflare Pages
```

### 3.2 核心原理

Cloudflare Workers 运行在全球 300+ 个边缘节点上。当请求到达时，Cloudflare 会自动在 `request.cf` 对象中注入用户的地理位置信息：

```typescript
const country = request.cf?.country  // &quot;CN&quot;, &quot;US&quot;, &quot;JP&quot;, etc.
```

我们利用这个信息，在边缘节点上决定将请求转发到哪里：

- `country === &apos;CN&apos;` → 转发到大阪 VPS
- 其他 → 直接转发到 Cloudflare Origin

这样判断逻辑在离用户最近的边缘节点执行，几乎不增加延迟。

### 3.3 流量路径对比

| 用户 | 之前 | 之后 |
|------|------|------|
| 大陆 | 用户 → 大阪 VPS → CF Origin | 用户 → CF Edge → 大阪 VPS → CF Origin |
| 海外 | 用户 → 大阪 VPS → CF Origin | 用户 → CF Edge → CF Origin 直连 |

大陆用户多了一跳 CF Edge，但这一跳在边缘网络内部，延迟 &lt; 10ms，几乎无感。

海外用户省掉了大阪 VPS 这一跳，延迟大幅降低。

---

## 4. 实现步骤

### 4.1 创建 Geo Router Worker

**目录结构**：

```
workers/
├── geo-router-web/
│   ├── wrangler.toml
│   └── src/index.ts
└── geo-router-api/
    ├── wrangler.toml
    └── src/index.ts
```

**Web Router 代码** (`workers/geo-router-web/src/index.ts`)：

```typescript
/**
 * Geo Router for Web (star.divinations.top)
 * 
 * 根据用户地理位置路由请求：
 * - 大陆用户 → 大阪 VPS → CF Pages
 * - 海外用户 → CF Pages 直连
 */

// 大陆用户走大阪 VPS 中转
const CN_BACKEND = &apos;https://osaka.divinations.top&apos;
// 海外用户直连 Cloudflare Pages
const GLOBAL_BACKEND = &apos;https://star-origin.divinations.top&apos;

// 需要走大阪中转的国家/地区代码
const CN_REGIONS = new Set([&apos;CN&apos;, &apos;HK&apos;, &apos;MO&apos;])

export default {
  async fetch(request: Request): Promise&lt;Response&gt; {
    try {
      const cf = request.cf as { country?: string; colo?: string } | undefined
      const country = cf?.country || &apos;US&apos;
      const colo = cf?.colo || &apos;unknown&apos;
      const isCN = CN_REGIONS.has(country)

      const backend = isCN ? CN_BACKEND : GLOBAL_BACKEND
      const targetUrl = new URL(request.url)
      targetUrl.hostname = new URL(backend).hostname
      targetUrl.protocol = &apos;https:&apos;

      // 构建新请求，保留原始 headers
      const headers = new Headers(request.headers)
      headers.set(&apos;X-Real-IP&apos;, headers.get(&apos;CF-Connecting-IP&apos;) || &apos;&apos;)
      headers.set(&apos;X-Forwarded-For&apos;, headers.get(&apos;CF-Connecting-IP&apos;) || &apos;&apos;)
      headers.set(&apos;X-Forwarded-Proto&apos;, &apos;https&apos;)

      const response = await fetch(targetUrl.toString(), {
        method: request.method,
        headers,
        body: request.body,
        redirect: &apos;follow&apos;,
      })

      // 添加调试 headers
      const newHeaders = new Headers(response.headers)
      newHeaders.set(&apos;X-Geo-Route&apos;, isCN ? &apos;cn-osaka&apos; : &apos;global-cf&apos;)
      newHeaders.set(&apos;X-Geo-Country&apos;, country)
      newHeaders.set(&apos;X-Geo-Colo&apos;, colo)

      return new Response(response.body, {
        status: response.status,
        statusText: response.statusText,
        headers: newHeaders,
      })
    } catch (error) {
      // 发生错误时降级到全球后端
      console.error(&apos;Geo router error:&apos;, error)
      
      const targetUrl = new URL(request.url)
      targetUrl.hostname = new URL(GLOBAL_BACKEND).hostname

      return fetch(targetUrl.toString(), {
        method: request.method,
        headers: request.headers,
        body: request.body,
      })
    }
  },
}
```

API Router 代码类似，只需修改 `CN_BACKEND` 和 `GLOBAL_BACKEND` 的值。

### 4.2 大阪 VPS nginx 配置

大阪 VPS 需要配置新的域名 `osaka.divinations.top`：

```nginx
# /etc/nginx/sites-available/starflix-geo.conf

server {
    listen 80;
    server_name osaka.divinations.top;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name osaka.divinations.top;

    # SSL 证书 (Let&apos;s Encrypt)
    ssl_certificate /etc/letsencrypt/live/osaka.divinations.top/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/osaka.divinations.top/privkey.pem;
    
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers off;

    location / {
        # ⭐ 关键：动态 DNS 解析
        resolver 1.1.1.1 8.8.8.8 valid=300s ipv6=off;
        resolver_timeout 5s;

        proxy_pass https://star-origin.divinations.top;
        proxy_set_header Host star-origin.divinations.top;
        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;
        
        # ⭐ 核心：SNI 设置
        proxy_ssl_server_name on;
        proxy_ssl_name star-origin.divinations.top;
        proxy_ssl_verify off;
        
        proxy_connect_timeout 10s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
        
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection &quot;upgrade&quot;;
    }

    location /health {
        return 200 &apos;OK&apos;;
        add_header Content-Type text/plain;
    }
}
```

**部署命令**：

```bash
# 获取 SSL 证书
sudo certbot certonly --nginx -d osaka.divinations.top -d osaka-api.divinations.top

# 启用配置
sudo ln -sf /etc/nginx/sites-available/starflix-geo.conf /etc/nginx/sites-enabled/
sudo nginx -t &amp;&amp; sudo systemctl reload nginx
```

### 4.3 DNS 配置

在 Cloudflare Dashboard 添加以下 DNS 记录：

| 类型 | 名称 | 内容 | 代理状态 |
|------|------|------|----------|
| A | `osaka` | 大阪 VPS IP | ⚪ 仅 DNS |
| A | `osaka-api` | 大阪 VPS IP | ⚪ 仅 DNS |

&gt; **注意**：`osaka` 和 `osaka-api` 必须关闭 Cloudflare 代理（灰云），否则会形成循环。

### 4.4 部署 Workers

```bash
# 部署 Web Router
pnpm wrangler deploy workers/geo-router-web/src/index.ts --name star-geo-router-web

# 部署 API Router
pnpm wrangler deploy workers/geo-router-api/src/index.ts --name star-geo-router-api
```

### 4.5 绑定自定义域名

在 Cloudflare Dashboard:

1. 进入 **Workers &amp; Pages**
2. 选择 `star-geo-router-web`
3. **Settings** → **Domains &amp; Routes** → **Add Custom Domain**
4. 输入 `star.divinations.top`
5. 对 `star-geo-router-api` 重复，添加 `star-api.divinations.top`

---

## 5. 验证与测试

### 5.1 检查路由 Headers

```bash
# 从不同地区测试
curl -I https://star.divinations.top 2&gt;&amp;1 | grep -i x-geo

# 预期输出（大陆）：
X-Geo-Route: cn-osaka
X-Geo-Country: CN
X-Geo-Colo: HKG

# 预期输出（海外）：
X-Geo-Route: global-cf
X-Geo-Country: US
X-Geo-Colo: SJC
```

### 5.2 检查大阪 VPS 日志

```bash
# 只有大陆用户的请求会出现在日志中
sudo tail -f /var/log/nginx/osaka-web-access.log
```

### 5.3 延迟测试

可以使用在线工具如 [ping.pe](https://ping.pe) 或 [check-host.net](https://check-host.net) 从全球多个节点测试延迟。

---

## 6. 效果对比

| 用户地区 | 之前延迟 | 之后延迟 | 改善 |
|----------|----------|----------|------|
| 大陆 (北京) | ~60ms | ~65ms | 持平 |
| 大陆 (上海) | ~50ms | ~55ms | 持平 |
| 美国西海岸 | ~180ms | ~30ms | **-83%** |
| 美国东海岸 | ~220ms | ~50ms | **-77%** |
| 欧洲 | ~250ms | ~40ms | **-84%** |
| 日本 | ~80ms | ~20ms | **-75%** |

大陆用户延迟基本持平（多了一跳 CF Edge，但很小），海外用户延迟大幅降低。

---

## 7. 扩展思考

### 7.1 可扩展场景

这个方案不仅适用于「大陆 vs 海外」分流，还可以扩展到：

1. **多区域加速** - 不同地区使用不同的中转节点（如欧洲用户走法兰克福）
2. **A/B 测试** - 按地区或比例分流到不同后端
3. **灰度发布** - 新版本先在特定地区上线
4. **故障转移** - 主节点故障时自动切换到备用节点

### 7.2 其他优化方向

1. **开启 HTTP/3 (QUIC)** - 在 Cloudflare Dashboard 开启，进一步降低延迟
2. **边缘缓存** - 利用 Cloudflare Cache 缓存静态资源
3. **VPS 内核优化** - 开启 BBR、调整 TCP 参数

---

## 8. 总结

通过 Cloudflare Workers 的边缘计算能力，我们实现了：

| 收益 | 说明 |
|------|------|
| 🎯 用户无感知的智能分流 | 同一个域名，自动选择最优路径 |
| 🇨🇳 大陆用户体验保持 | 继续走大阪 VPS 中转 |
| 🌍 海外用户体验大幅提升 | 直连 Cloudflare 边缘节点 |
| 💰 零额外成本 | Workers 免费额度足够个人项目使用 |

核心代码不到 100 行，但解决了一个困扰很多出海项目的经典问题。

---

## 参考链接

- [Cloudflare Workers 文档](https://developers.cloudflare.com/workers/)
- [request.cf 对象说明](https://developers.cloudflare.com/workers/runtime-apis/request/#incomingrequestcfproperties)
- [Wrangler CLI 文档](https://developers.cloudflare.com/workers/wrangler/)
- [中国大陆网络访问优化指南](/posts/china-network-optimization-guide)

---

## 🌟 欢迎体验

如果你觉得这篇文章对你有帮助，欢迎访问我使用本方案优化后的视频网站：

&lt;div align=&quot;center&quot;&gt;

### 🎬 [star.divinations.top](https://star.divinations.top)

**高速流畅的在线视频播放体验**

&lt;/div&gt;

本站使用上述方案进行了网络优化，大陆用户可以享受低延迟、高速度的访问体验，海外用户也能直连 Cloudflare 边缘节点。快来试试吧！ 🚀</content:encoded></item><item><title>【白嫖指南】零成本申请 .qzz.io 免费域名并托管至 Cloudflare</title><link>https://nianyi778.github.io/posts/free-domain-qzz-io/</link><guid isPermaLink="true">https://nianyi778.github.io/posts/free-domain-qzz-io/</guid><description>手把手教你申请 .qzz.io 免费域名，并将其“嫁接”到 Cloudflare 上，享受全球 CDN 加速。</description><pubDate>Tue, 23 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&gt; **前言**：
&gt; 想要折腾 Cloudflare Workers、部署博客或者搭建私人网盘，没有一个顶级域名总觉得不够完美。虽然 `.com` 很贵，但对于测试和个人项目，我们完全可以申请免费的二级域名。
&gt; 本文手把手教你申请 **.qzz.io** 免费域名，并将其“嫁接”到 Cloudflare 上，享受全球 CDN 加速。
&gt; **这是系列教程的第一篇，搞定域名后，请关注下一篇：[《利用 B2 + Cloudflare 搭建永久免费的个人图床/文件服务器》](/posts/free-storage-b2-cloudflare)。**

## 1. 什么是 .qzz.io？

这是一个提供免费二级域名的服务（类似当年的 `eu.org` 或 `pp.ua`）。虽然它是二级域名，但在使用体验上（绑定 IP、CNAME、SSL 证书）和顶级域名几乎没有区别。最重要的是：**免费**且支持修改 **NS 记录**（这是托管 CF 的关键）。

### 为什么需要它？
- **SSL 证书**：Cloudflare 会自动为你签发免费的 SSL 证书，让你的网站拥有 HTTPS 小绿锁。
- **CDN 加速**：通过 Cloudflare 的全球节点，你的网站访问速度会大幅提升。
- **隐藏源站 IP**：保护你的服务器免受直接攻击。
- **Workers 玩法**：拥有域名后，你可以解锁 Cloudflare Workers 的全部潜力，比如搭建反代、API 网关等。

## 2. 申请步骤

### 第一步：访问注册

1. 打开申请网站（假设为官方申请页，通常是 `register.qzz.io` 或相关分发平台）。
2. 输入你心仪的前缀，例如 `my-cool-project`。
3. 点击 **Check Availability**（检查可用性）。
   &gt; **提示**：尽量避开过于通用的词汇（如 `test`, `admin`, `blog`），这些可能已经被保留或注册。尝试组合词，如 `dev-lab-01`。

### 第二步：验证与注册

1. 如果域名可用，通常需要进行简单的验证（如邮箱验证或 GitHub 登录）。
2. 填写基本的注册信息。
   &gt; **注意**：虽然是免费域名，建议不要填过于虚假的乱码，以免被系统判定滥用。填写真实的邮箱非常重要，用于接收激活邮件。

### 第三步：获取 Cloudflare NS 地址

**不要急着在注册商那里点确定！** 先去 Cloudflare 占个坑。

1. 登录 [Cloudflare Dashboard](https://dash.cloudflare.com/)。
2. 点击右上角的 **&quot;Add a Site&quot;**。
3. 输入你刚才申请的完整域名：`my-cool-project.qzz.io`。
4. 选择 **Free Plan**（免费计划），点击 Continue。
5. 扫描 DNS 记录后（此时通常是空的），点击 Continue。
6. CF 会给你分配两个 Nameservers（名称服务器），请记下它们，例如：
    * `lola.ns.cloudflare.com`
    * `tom.ns.cloudflare.com`

### 第四步：修改 NS 记录

1. 回到 `.qzz.io` 的管理后台。
2. 找到 **Nameservers** 或 **DNS Management** 选项。
3. 选择 **Custom Nameservers**（自定义名称服务器）。
4. 填入刚才 Cloudflare 给你的那两个地址（lola... 和 tom...）。
5. 保存设置。

## 3. 等待生效与验证

* 修改 NS 记录通常需要几分钟到几小时的全球生效时间（最长可能 24-48 小时，但通常很快）。
* 回到 Cloudflare 页面，点击 **&quot;Check Nameservers&quot;**。
* 一旦收到 Cloudflare 的邮件“Active”，恭喜你，你的域名已经由全球最强的 CDN 接管了！

### 常见问题排查
- **一直显示 Pending**：检查 NS 记录是否填写正确，有没有多余的空格。
- **无法添加站点**：部分免费域名后缀可能被 Cloudflare 暂时拉黑，如果遇到这种情况，可以尝试更换前缀或稍后再试。

## 4. 这能拿来干什么？

拥有了这个域名，你可以：

* **DDNS (动态域名解析)**: 家里的 NAS 即使是动态 IP，也能拥有固定的访问域名，配合端口转发实现远程访问。
* **测试环境**: 开发 Workers 脚本时的最佳沙盒，不用担心搞坏主域名。
* **搭建博客**: 配合 GitHub Pages 或 Vercel，绑定自定义域名。
* **图床/网盘**: **这就涉及到我们的下一篇重磅教程了！**

&gt; **下一步计划**：
&gt; 既然有了域名和 Cloudflare，如果不搞点存储空间岂不是浪费？
&gt; 👉 **[点击跳转下一篇：教你用 Backblaze B2 + Cloudflare 搭建不限流的免费图床 API](/posts/free-storage-b2-cloudflare)**</content:encoded></item><item><title>【技术硬核】白嫖 B2 存储 + Cloudflare Workers，打造永久免费的私有图床 API</title><link>https://nianyi778.github.io/posts/free-storage-b2-cloudflare/</link><guid isPermaLink="true">https://nianyi778.github.io/posts/free-storage-b2-cloudflare/</guid><description>10GB 免费存储 + 每天 10 万次免费请求 + 全球 CDN 加速 + 0 流量费。</description><pubDate>Tue, 23 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&gt; **前言**：
&gt; 上一篇文章我们搞定了免费域名，今天我们来搞定“存储”。
&gt; 很多开发者都有文件存储需求（博客图床、软件分发、个人备份）。S3 太贵，GitHub 有限制。今天我们要介绍的是 **Backblaze B2 + Cloudflare Workers** 的神级组合：**10GB 免费存储 + 每天 10 万次免费请求 + 全球 CDN 加速 + 0 流量费。**
&gt; *还没有域名？请先看上一篇：[零成本申请 .qzz.io 免费域名并托管至 Cloudflare](/posts/free-domain-qzz-io)*

## 1. 为什么是 B2 + CF？

* **带宽联盟 (Bandwidth Alliance)**: 这是核心！通常从对象存储下载文件需要支付“流出流量费”，但 B2 和 CF 是盟友，数据从 B2 传输到 CF 是**免费**的。这意味着你可以把 B2 当作无限流量的源站。
* **Workers**: 我们可以用它重写 URL，把丑陋的 `f002.backblazeb2.com` 变成优雅的 `files.yourdomain.qzz.io`，甚至可以实现鉴权、图片处理等高级功能。

## 2. 准备工作

1. **Backblaze 账号**: 注册即送 10GB 永久免费存储空间。
2. **Cloudflare 账号**: 且已绑定域名（参考上一篇）。

## 3. Backblaze B2 设置

### 3.1 创建 Bucket
1. 登录 Backblaze B2 控制台。
2. 点击 **Create a Bucket**。
3. **Bucket Unique Name**: 起个全球唯一的名字，例如 `my-free-assets-2025`。
4. **Files in Bucket are**: 选择 **Public**。
   &gt; **注意**：私有读写需要更复杂的签名逻辑，本文为了演示方便，采用“公开读 + 鉴权写”的模式。如果你存放敏感数据，请务必设为 Private。
5. 点击 Create a Bucket。

### 3.2 获取密钥 (App Keys)
1. 在左侧菜单点击 **App Keys**。
2. 点击 **Add a New Application Key**。
3. **Name**: 随便填，如 `CF-Worker-Key`。
4. **Allow access to Bucket(s)**: 选择刚才创建的 Bucket。
5. **Type of Access**: Read and Write。
6. 点击 Create New Key。
7. **重要**：复制并保存 `keyID` 和 `applicationKey`，这俩只显示一次！

### 3.3 配置 CORS
为了让你的图片能被网页（如博客）正常加载，必须配置 CORS。
1. 回到 Buckets 页面，点击 Bucket Settings。
2. 找到 **CORS Rules**。
3. 选择 **Share everything in this bucket with all origins**。
4. 或者手动添加规则：
   ```json
   [
     {
       &quot;corsRuleName&quot;: &quot;downloadFromAnywhere&quot;,
       &quot;allowedOrigins&quot;: [&quot;*&quot;],
       &quot;allowedHeaders&quot;: [&quot;*&quot;],
       &quot;allowedOperations&quot;: [&quot;s3_head&quot;, &quot;s3_get&quot;],
       &quot;exposeHeaders&quot;: [&quot;ETag&quot;],
       &quot;maxAgeSeconds&quot;: 3000
     }
   ]
   ```

## 4. Cloudflare 域名解析

1. 进入你的 `my-cool-project.qzz.io` 管理面板。
2. 点击 **DNS** -&gt; **Records**。
3. 添加 CNAME 记录：
    * **Type**: CNAME
    * **Name**: `img` (即 `img.my-cool-project.qzz.io`)。
    * **Target**: 你的 B2 Friendly URL (在 B2 桶详情页可见，如 `f002.backblazeb2.com`)。
    * **Proxy Status**: 必须开启小黄云 (Proxied)。

## 5. 部署 Workers (核心魔法)

虽然 CNAME 能直接访问，但 URL 路径很长（`/file/bucket-name/xxx.jpg`）。我们用 Workers 来缩短路径并实现上传接口。

### 5.1 创建 Worker
1. 在 Cloudflare 左侧菜单点击 **Workers &amp; Pages**。
2. 点击 **Create Application** -&gt; **Create Worker**。
3. 命名为 `b2-proxy`，点击 Deploy。
4. 点击 **Edit code**。

### 5.2 编写代码
粘贴以下代码（这是一个简化版，支持 GET 下载和 PUT 上传）：

```javascript
export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    // 配置你的 B2 信息
    const b2Domain = &apos;f002.backblazeb2.com&apos;; // 替换为你的 Friendly URL
    const bucketPath = &apos;/file/my-free-assets-2025&apos;; // 替换为 /file/你的Bucket名
    
    // 1. 下载请求 (GET)
    if (request.method === &apos;GET&apos;) {
      // 重写 URL：将 img.site.com/1.jpg -&gt; f002.../file/bucket/1.jpg
      const newUrl = `https://${b2Domain}${bucketPath}${url.pathname}`;
      
      // 发起请求
      const response = await fetch(newUrl, request);
      
      // 重新构建响应，确保 CORS 头正确
      const newResponse = new Response(response.body, response);
      newResponse.headers.set(&quot;Access-Control-Allow-Origin&quot;, &quot;*&quot;);
      return newResponse;
    }

    // 2. 上传请求 (PUT) - 简单的鉴权保护
    if (request.method === &apos;PUT&apos;) {
      // 检查 Header 中的 Auth-Token
      if (request.headers.get(&quot;Auth-Token&quot;) !== env.SECRET_TOKEN) {
        return new Response(&quot;Unauthorized&quot;, { status: 403 });
      }
      
      // 注意：此处仅做演示转发。
      // 生产环境建议：
      // 1. 使用 AWS S3 SDK for JS 在客户端直传
      // 2. 或者在此处通过 Workers 计算 S3 签名
      
      // 简单转发模式（不推荐用于大文件）：
      const newUrl = `https://${b2Domain}${bucketPath}${url.pathname}`;
      // 需要自行处理 B2 的鉴权头，这里省略了复杂的签名计算过程
      // 建议配合 PicGo S3 插件直接上传到 B2，只用 Workers 做下载代理
      return new Response(&quot;Upload via Worker requires S3 signing logic&quot;, { status: 501 });
    }

    return new Response(&quot;Method not allowed&quot;, { status: 405 });
  }
};
```

### 5.3 绑定路由
1. 回到 Worker 详情页。
2. 点击 **Settings** -&gt; **Triggers**。
3. 点击 **Add route**。
4. Route: `img.my-cool-project.qzz.io/*`。
5. Zone: 选择你的域名。

## 6. 避坑指南 &amp; 优化

### 6.1 缓存规则 (Cache Rules) - 省钱关键！
为了防止 B2 即使免费也被刷爆请求数（B2 每天免费下载请求只有 2500 次，但流量免费），务必在 CF 设置缓存。
1. 进入 Cloudflare 域名主页 -&gt; **Caching** -&gt; **Cache Rules**。
2. Create rule:
   * Name: `Cache B2 Images`
   * Field: `Hostname` equals `img.my-cool-project.qzz.io`
   * Cache eligibility: **Eligible for cache**
   * Edge TTL: **1 month** (或者更久)
   * Browser TTL: **1 month**
3. 这样文件一旦被访问，后续请求全由 CF 扛，回源率为 0，请求数也就不会涨了。

### 6.2 最佳上传姿势：PicGo + S3
不要试图用 Workers 转发上传流量（容易超时且难以处理签名）。推荐使用 **PicGo** 配合 **S3 插件**。
* **插件**: 安装 `picgo-plugin-s3`。
* **配置**:
  * **AccessKeyID / SecretAccessKey**: 填 B2 的 keyID 和 applicationKey。
  * **Bucket**: 你的 Bucket 名。
  * **Region**: `us-west-002` (看你的 B2 Endpoint，如 s3.us-west-002.backblazeb2.com)。
  * **Endpoint**: `https://s3.us-west-002.backblazeb2.com`。
  * **Custom Domain**: `https://img.my-cool-project.qzz.io` (填你的 Worker 域名)。
* **效果**: 截图 -&gt; 自动上传到 B2 -&gt; 剪贴板自动生成 `https://img...` 的链接 -&gt; 粘贴使用。

## 7. 总结

这一套下来，你拥有了：

* **个性化域名** (感谢 .qzz.io)
* **10GB 免费空间** (感谢 Backblaze)
* **CDN 加速与无限流量** (感谢 Cloudflare)
* **自动化工作流** (感谢 PicGo)

这才是真正的“Serverless”白嫖美学！</content:encoded></item><item><title>OCI 大阪 A1 实例刷容量完整实战教程</title><link>https://nianyi778.github.io/posts/oci-osaka-a1-tutorial/</link><guid isPermaLink="true">https://nianyi778.github.io/posts/oci-osaka-a1-tutorial/</guid><description>本教程基于一次真实完整排障与实战刷机过程整理，目标是最终刷到一台 Osaka 的 A1 ARM 实例。</description><pubDate>Sat, 20 Dec 2025 16:00:00 GMT</pubDate><content:encoded>&gt; **适用对象**
&gt; - Region：ap-osaka-1（大阪）
&gt; - Shape：VM.Standard.A1.Flex（ARM / aarch64）
&gt; - 免费层 / 新租户
&gt; - Console 长期提示 **Out of host capacity**

这篇文章基于一次**完整真实排障 + 最终进入“稳定刷库存阶段”**的过程整理，融合了：

- 参数校验
- ARM 镜像选择
- 错误分类
- 指数退避 + 抖动
- CLI / 云机环境迁移

目标只有一个：

&gt; ✅ **把问题从“为什么失败”推进到“只剩库存因素”**

---

## 一、核心结论（先看这个）

1. **Osaka A1 失败 ≠ 配置问题**
   - 绝大多数情况是：**宿主机没库存**
2. **Console 基本无解**
   - 实操层面只能靠 **OCI CLI + 脚本轮询**
3. **只要看到 `Out of host capacity`**
   - 往往说明你已经 **配置正确**
   - 剩下的就是等 Oracle 放出碎片资源

---

## 二、整体刷机思路（理解很重要）

### Osaka 的真实情况

- 只有 **1 个 AD**
- A1 是真实物理 ARM 宿主机切片
- Free Tier / 普通用户本质是在抢“别人释放的空位”

### 成功的必要条件

- CLI 认证 100% 正确
- 所有 OCID **必须属于 ap-osaka-1**
- 镜像必须是 **ARM / aarch64**
- 节奏要慢（避免 API 限流 / 风控）

---

## 三、环境准备（云机 or 本地都可）

下面以 Ubuntu 为例（在云机上跑更稳定，也更方便长期后台挂脚本）。

### 1️⃣ 安装 OCI CLI

```bash
sudo apt update
sudo apt install -y python3 python3-pip curl unzip
bash -c &quot;$(curl -L https://raw.githubusercontent.com/oracle/oci-cli/master/scripts/install/install.sh)&quot;
source ~/.bashrc
oci -v
```

---

## 四、OCI CLI 认证（关键步骤）

确保你已经完成：

- `~/.oci/config`
- `~/.oci/oci_api_key.pem`
- 公钥已上传到 OCI Console → User → API Keys

验证：

```bash
oci iam availability-domain list
```

Osaka 正常通常只会看到：

```text
cQAx:AP-OSAKA-1-AD-1
```

---

## 五、必须准备的 3 个 OCID（100% 来自 Osaka）

### 1️⃣ COMPARTMENT_ID

```bash
oci iam compartment list --compartment-id-in-subtree true --all
```

一般使用：

- `name = root` 对应的 id
- 或你自建的 compartment

---

### 2️⃣ SUBNET_ID（Osaka 子网）

要求：

- Region：ap-osaka-1
- 推荐：Default Subnet (Regional)

校验：

```bash
oci network subnet get --subnet-id &lt;SUBNET_ID&gt;
```

---

### 3️⃣ IMAGE_ID（必须是 ARM / aarch64）

最常见踩坑：**拿了 x86 镜像去建 A1（ARM）**。

用 CLI 直接筛选 A1 可用的 ARM 镜像（示例为 Oracle Linux 9）：

```bash
oci compute image list \
  --compartment-id &lt;COMPARTMENT_ID&gt; \
  --shape VM.Standard.A1.Flex \
  --operating-system &quot;Oracle Linux&quot; \
  --operating-system-version &quot;9&quot; \
  --all \
  --output table
```

推荐优先选最新的 `aarch64`：

```text
Oracle-Linux-9.x-aarch64-YYYY.MM.DD-0
```

---

## 六、最终刷机脚本（优化版 · 推荐）

### 📄 `oci-osaka-a1-single-ad.sh`

```bash
#!/usr/bin/env bash
set -euo pipefail

# ===== 必填（替换成你自己的）=====
COMPARTMENT_ID=&quot;ocid1.compartment.oc1..xxxxxxxx&quot;
SUBNET_ID=&quot;ocid1.subnet.oc1.ap-osaka-1.xxxxxxxx&quot;
IMAGE_ID=&quot;ocid1.image.oc1.ap-osaka-1.xxxxxxxx&quot;   # ARM / aarch64

# ===== Osaka 通常只有一个 AD =====
AD_NAME=&quot;cQAx:AP-OSAKA-1-AD-1&quot;

# ===== A1 配置（成功率常见更高）=====
SHAPE=&quot;VM.Standard.A1.Flex&quot;
OCPUS=1
MEMORY=6

# ===== 退避策略 =====
BASE_SLEEP=60
MAX_SLEEP=$((20*60))
JITTER_MAX=30
DEBUG=&quot;${DEBUG:-0}&quot;

log() { echo &quot;[$(date &apos;+%F %T&apos;)] $*&quot;; }

classify_error() {
  local out=&quot;$1&quot;
  if echo &quot;$out&quot; | grep -qi &quot;Out of host capacity&quot;; then
    echo &quot;NO_CAPACITY（区域/AD 没库存）&quot;; return
  fi
  if echo &quot;$out&quot; | grep -qiE &quot;Quota|LimitExceeded&quot;; then
    echo &quot;QUOTA_OR_LIMIT（配额/免费额度）&quot;; return
  fi
  if echo &quot;$out&quot; | grep -qi &quot;InvalidParameter&quot;; then
    echo &quot;INVALID_PARAM（参数错误）&quot;; return
  fi
  echo &quot;OTHER&quot;
}

sleep_with_backoff() {
  local base=&quot;$1&quot;
  local jitter=$((RANDOM % (JITTER_MAX + 1)))
  local total=$((base + jitter))
  log &quot;sleep ${total}s&quot;
  sleep &quot;$total&quot;
}

log &quot;Start hunting Osaka A1...&quot;
sleep_sec=&quot;$BASE_SLEEP&quot;

while true; do
  DISPLAY_NAME=&quot;osaka-a1-$(date +%Y%m%d-%H%M%S)&quot;
  log &quot;Try $AD_NAME name=$DISPLAY_NAME ocpu=$OCPUS mem=${MEMORY}G&quot;

  set +e
  OUT=&quot;$(oci compute instance launch \
    --availability-domain &quot;$AD_NAME&quot; \
    --compartment-id &quot;$COMPARTMENT_ID&quot; \
    --shape &quot;$SHAPE&quot; \
    --display-name &quot;$DISPLAY_NAME&quot; \
    --subnet-id &quot;$SUBNET_ID&quot; \
    --image-id &quot;$IMAGE_ID&quot; \
    --assign-public-ip true \
    --shape-config &quot;{\&quot;ocpus\&quot;:$OCPUS,\&quot;memoryInGBs\&quot;:$MEMORY}&quot; \
    2&gt;&amp;1)&quot;
  RESULT=$?
  set -e

  if [ &quot;$RESULT&quot; -eq 0 ]; then
    log &quot;SUCCESS!&quot;
    exit 0
  fi

  REASON=&quot;$(classify_error &quot;$OUT&quot;)&quot;
  log &quot;FAILED: $REASON&quot;
  [ &quot;$DEBUG&quot; -eq 1 ] &amp;&amp; echo &quot;$OUT&quot;

  sleep_with_backoff &quot;$sleep_sec&quot;
  sleep_sec=$((sleep_sec * 2))
  [ &quot;$sleep_sec&quot; -gt &quot;$MAX_SLEEP&quot; ] &amp;&amp; sleep_sec=&quot;$MAX_SLEEP&quot;
done
```

---

## 七、运行与后台常驻

```bash
chmod +x oci-osaka-a1-single-ad.sh
DEBUG=1 nohup ./oci-osaka-a1-single-ad.sh &gt; oci-hunt.log 2&gt;&amp;1 &amp;
tail -f oci-hunt.log
```

看到以下日志说明一切正常（你已经进入“只剩库存因素”的阶段）：

```text
FAILED: NO_CAPACITY（区域/AD 没库存）
```

---

## 八、现实预期（非常重要）

- 成功时间：**10 分钟 ~ 数小时（甚至更久）**
- 常见放量时间：UTC 夜间 / 日本下午-晚上
- 长时间 `NO_CAPACITY` 完全正常

---

## 九、成功后注意事项

- 不要立刻 Stop / Terminate
- 先 SSH 登录一次
- 跑点真实负载，避免被回收

---

## 十、一句话总结

&gt; **大阪 A1 不是“创建”，而是“等待 + 抢占”**
&gt; 你看到 `Out of host capacity`，就说明方向基本对了。</content:encoded></item><item><title>🌏 中国大陆网络访问优化 - 完整部署指南</title><link>https://nianyi778.github.io/posts/china-network-optimization-guide/</link><guid isPermaLink="true">https://nianyi778.github.io/posts/china-network-optimization-guide/</guid><description>利用 Oracle Cloud Japan + Nginx 反向代理 + Cloudflare Workers 方案，实现中国大陆用户低延迟访问</description><pubDate>Sun, 14 Dec 2025 16:00:00 GMT</pubDate><content:encoded>&gt; **版本**: 2.0  
&gt; **最后更新**: 2025-12-15  
&gt; **状态**: ✅ 已实战验证可用  
&gt; **架构**: Oracle Cloud (Japan) + Nginx 反向代理 + Cloudflare Workers (SNI Proxy)

---

## 1. 背景与目标

### 问题描述

Cloudflare 的免费版 CDN 节点在针对中国大陆访问时，通常会绕路美国西海岸或欧洲，导致：
- 高延迟（200ms+）
- 连接不稳定
- 易丢包

### 解决方案

利用地理位置靠近中国大陆、且国际出口带宽较好的 **Oracle Cloud Japan (甲骨文日本)** 服务器作为&quot;中转跳板&quot;，通过 Nginx 反向代理将流量转发至 **Cloudflare Workers**，从而实现更快的访问速度。

### 流量对比

**优化前 (常规模式)**:
```
用户 (大陆) 🐢 --&gt; 太平洋海底光缆 --&gt; Cloudflare (美国) --&gt; Workers
延迟高，易丢包，体验差
```

**优化后 (本方案)**:
```
用户 (大陆) 🚀 --&gt; 50-100ms --&gt; Oracle VPS (日本) ⚡️ --&gt; 5ms --&gt; Cloudflare (日本边缘) --&gt; Workers
利用 VPS 的优质线路中转，大幅降低物理延迟
```

---

## 2. 整体架构

### 2.1 架构图

```
用户
 └─ star.divinations.top        （灰云 DNS only → VPS）
     └─ Nginx 反向代理（SNI Proxy）
         └─ star-origin.divinations.top      （橙云 → Cloudflare Worker / Web）

用户
 └─ star-api.divinations.top    （灰云 DNS only → VPS）
     └─ Nginx 反向代理（SNI Proxy）
         └─ star-api-origin.divinations.top  （橙云 → Cloudflare Worker / API）
```

### 2.2 🔒 架构铁律（必须遵守）

| 规则 | 说明 |
|---|---|
| ✅ 入口域名永远是 **DNS only（灰云）** | star / star-api 必须灰云，用户直连 VPS |
| ✅ origin 域名永远是 **Proxied（橙云）** | 仅供 Nginx 后端使用，用户不可直接访问 |
| ❌ 用户请求永远不能被重定向到 origin 域名 | 否则触发 Cloudflare Error 1000 |
| ❌ 禁止入口域名开启橙云 | 否则直接 1000 错误 |
| ❌ 禁止 `star → CNAME → star-origin` | Cloudflare 会判定为非法代理 |

---

## 3. 准备工作

### 3.1 服务器要求

| 项目 | 要求 |
|---|---|
| 云服务商 | Oracle Cloud (日本/韩国/香港等亚太节点) |
| 操作系统 | Ubuntu 20.04/22.04 LTS |
| 端口 | 80, 443 必须开放 |
| 网络 | 确保服务器能正常访问 Cloudflare (1.1.1.1) |

### 3.2 域名规划

| 域名 | 用途 | 代理状态 |
|---|---|---|
| `star.divinations.top` | Web 主站入口 | DNS only (灰云) |
| `star-api.divinations.top` | API 入口 | DNS only (灰云) |
| `star-origin.divinations.top` | Web Workers 源站 | Proxied (橙云) |
| `star-api-origin.divinations.top` | API Workers 源站 | Proxied (橙云) |

### 3.3 软件依赖

```bash
# 更新系统
sudo apt update &amp;&amp; sudo apt upgrade -y

# 安装必要软件
sudo apt install -y nginx certbot python3-certbot-nginx curl dnsutils
```

---

## 4. 详细实施步骤

### 第一步：Cloudflare DNS 设置 ⭐ 关键

在 Cloudflare 后台 DNS 设置中，**必须严格区分&quot;直连&quot;和&quot;代理&quot;状态**。

| 域名 | 类型 | 指向目标 | 代理状态 | 说明 |
|---|---|---|---|---|
| `star` | A | **Oracle 服务器 IP** | **DNS only (灰色云)** ☁️ | **关键**：必须关闭 CF 代理 |
| `star-api` | A | **Oracle 服务器 IP** | **DNS only (灰色云)** ☁️ | 同上 |
| `star-origin` | CNAME | `*.workers.dev` | **Proxied (橙色云)** 🟠 | Workers 必须开启代理 |
| `star-api-origin` | CNAME | `*.workers.dev` | **Proxied (橙色云)** 🟠 | 同上 |

**⚠️ 注意事项**：
- 入口域名（star / star-api）**禁止开启橙云**
- **禁止**设置 `star → CNAME → star-origin`
- 如存在 `AAAA star` IPv6 记录，需确认 IPv6 可用，否则删除

**验证 DNS 设置**：
```bash
# 验证入口域名指向 VPS IP
dig +short star.divinations.top @1.1.1.1
# 应该返回你的 VPS IP 地址

# 验证 origin 域名指向 Cloudflare
dig +short star-origin.divinations.top @1.1.1.1
# 应该返回 Cloudflare 的 IP 地址
```

---

### 第二步：服务器防火墙设置

在申请证书和部署 Nginx 前，**必须确保端口开放**。

#### 2.1 Oracle 云控制台 (网页端)

1. 登录 Oracle Cloud Console
2. 进入 `Networking` → `Virtual Cloud Networks` → 选择你的 VCN
3. 点击 `Security Lists` → 选择默认安全列表
4. 添加入站规则 (Ingress Rules)：

| 源 CIDR | 协议 | 目标端口 | 说明 |
|---|---|---|---|
| 0.0.0.0/0 | TCP | 80 | HTTP |
| 0.0.0.0/0 | TCP | 443 | HTTPS |

#### 2.2 服务器内部防火墙 (SSH)

```bash
# 方式一：如果使用 UFW
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw reload
sudo ufw status

# 方式二：如果使用 iptables (Oracle Ubuntu 默认)
# 查看当前规则
sudo iptables -L -n

# 添加规则
sudo iptables -I INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -I INPUT -p tcp --dport 443 -j ACCEPT

# 持久化规则
sudo apt install iptables-persistent
sudo netfilter-persistent save

# 或者直接清空所有规则（简单粗暴，仅测试用）
# sudo iptables -F
```

**验证端口开放**：
```bash
# 本地测试
nc -zv localhost 80
nc -zv localhost 443

# 外部测试（从另一台机器）
nc -zv &lt;VPS_IP&gt; 80
nc -zv &lt;VPS_IP&gt; 443
```

---

### 第三步：申请 SSL 证书

由于入口域名设置为&quot;DNS only (灰云)&quot;，浏览器会直接校验 Oracle 服务器上的证书，**必须使用受信任的证书**。

```bash
# 1. 确保 Nginx 已启动（Certbot 需要验证）
sudo systemctl start nginx

# 2. 申请证书 - Web 站
sudo certbot --nginx -d star.divinations.top

# 3. 申请证书 - API 站（单独证书，避免 SAN 问题）
sudo certbot --nginx -d star-api.divinations.top

# 4. 验证证书
sudo certbot certificates
```

**⚠️ 证书申请前检查清单**：
- [ ] Cloudflare DNS 已设置为灰云
- [ ] 防火墙 80/443 端口已开放
- [ ] Nginx 已启动且 80 端口可访问
- [ ] 域名已正确解析到 VPS IP

**证书续期测试**：
```bash
sudo certbot renew --dry-run
```

---

### 第四步：Nginx 配置 ⭐ 核心

#### 4.1 Web 入口配置

**文件路径**: `/etc/nginx/sites-available/star.divinations.top`

```nginx
# HTTP 强制跳转 HTTPS
server {
    listen 80;
    listen [::]:80;
    server_name star.divinations.top;
    return 301 https://$host$request_uri;
}

# HTTPS 主配置
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name star.divinations.top;

    # SSL 证书（Certbot 自动配置）
    ssl_certificate /etc/letsencrypt/live/star.divinations.top/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/star.divinations.top/privkey.pem;
    
    # SSL 优化设置
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    location / {
        # ⭐ 关键：动态 DNS 解析（必须配置）
        resolver 1.1.1.1 8.8.8.8 valid=300s ipv6=off;
        resolver_timeout 5s;

        # 调试 Header（可选，生产环境可删除）
        add_header X-Star-Proxy &quot;vps-nginx&quot; always;

        # 转发目标：指向 Workers 的源域名
        proxy_pass https://star-origin.divinations.top;

        # ⭐ 核心：SNI 设置（必须开启，否则 CF 握手失败）
        proxy_ssl_server_name on;
        proxy_ssl_name star-origin.divinations.top;
        
        # 传递 Host 头
        proxy_set_header Host star-origin.divinations.top;

        # 传递用户真实 IP
        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_set_header X-Forwarded-Host $host;

        # 超时设置
        proxy_connect_timeout 10s;
        proxy_send_timeout 30s;
        proxy_read_timeout 30s;

        # 长连接优化
        proxy_http_version 1.1;
        proxy_set_header Connection &quot;&quot;;
    }
}
```

#### 4.2 API 入口配置

**文件路径**: `/etc/nginx/sites-available/star-api.divinations.top`

```nginx
# HTTP 强制跳转 HTTPS
server {
    listen 80;
    listen [::]:80;
    server_name star-api.divinations.top;
    return 301 https://$host$request_uri;
}

# HTTPS 主配置
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name star-api.divinations.top;

    # SSL 证书
    ssl_certificate /etc/letsencrypt/live/star-api.divinations.top/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/star-api.divinations.top/privkey.pem;
    
    # SSL 优化设置
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    location / {
        # ⭐ 关键：动态 DNS 解析
        resolver 1.1.1.1 8.8.8.8 valid=300s ipv6=off;
        resolver_timeout 5s;

        # 调试 Header
        add_header X-Star-Proxy &quot;vps-nginx-api&quot; always;

        # 转发目标
        proxy_pass https://star-api-origin.divinations.top;

        # ⭐ 核心：SNI 设置
        proxy_ssl_server_name on;
        proxy_ssl_name star-api-origin.divinations.top;
        
        # 传递 Host 头
        proxy_set_header Host star-api-origin.divinations.top;

        # 传递用户真实 IP
        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_set_header X-Forwarded-Host $host;

        # 超时设置
        proxy_connect_timeout 10s;
        proxy_send_timeout 30s;
        proxy_read_timeout 30s;

        # 长连接优化
        proxy_http_version 1.1;
        proxy_set_header Connection &quot;&quot;;
    }
}
```

#### 4.3 启用配置

```bash
# 创建软链接
sudo ln -sf /etc/nginx/sites-available/star.divinations.top /etc/nginx/sites-enabled/
sudo ln -sf /etc/nginx/sites-available/star-api.divinations.top /etc/nginx/sites-enabled/

# 删除默认配置（可选）
sudo rm -f /etc/nginx/sites-enabled/default

# 检查语法
sudo nginx -t

# 重新加载配置
sudo systemctl reload nginx
```

#### 4.4 🚫 Nginx 配置禁止事项

| 禁止项 | 原因 |
|---|---|
| `proxy_set_header CF-Connecting-IP ...` | 伪造 CF 专用 Header 会触发 403 |
| 入口域名 301/302 到 origin | 会触发 Error 1000 |
| WebSocket Header 无条件开启 | 普通 HTTP 被强制 upgrade 会出错 |
| proxy_pass 不配 resolver | DNS 只解析一次，后续可能失效 |

---

### 第五步：Cloudflare Worker 配置

#### 5.1 Worker 使用规范

- Worker 只负责业务逻辑
- **不依赖** `CF-Connecting-IP`（该 Header 由 Cloudflare 自动注入，VPS 无法伪造）
- 使用 `X-Forwarded-For` / `X-Real-IP` 获取真实用户 IP
- 如需防止直连 origin，可校验 Nginx 注入的自定义 Header

#### 5.2 Worker 获取真实 IP 示例

```typescript
// 在 Worker 中获取真实用户 IP
function getClientIP(request: Request): string {
  // 优先使用 Nginx 传递的 Header
  const xRealIP = request.headers.get(&apos;X-Real-IP&apos;);
  if (xRealIP) return xRealIP;
  
  const xForwardedFor = request.headers.get(&apos;X-Forwarded-For&apos;);
  if (xForwardedFor) {
    return xForwardedFor.split(&apos;,&apos;)[0].trim();
  }
  
  // 最后使用 Cloudflare 的 Header（直连 Workers 时有效）
  return request.headers.get(&apos;CF-Connecting-IP&apos;) || &apos;unknown&apos;;
}
```

---

## 5. 验证与测试

### 5.1 DNS 验证

```bash
# 验证入口域名
dig +short star.divinations.top @1.1.1.1
# 应返回 VPS IP

# 验证 origin 域名
dig +short star-origin.divinations.top @1.1.1.1
# 应返回 Cloudflare IP
```

### 5.2 HTTP 验证

```bash
# 测试 Web 入口
curl -I https://star.divinations.top

# 测试 API 入口
curl -I https://star-api.divinations.top

# 测试 origin（仅测试用）
curl -I https://star-origin.divinations.top
```

### 5.3 预期响应

正常情况下应该看到：
- HTTP/2 200
- 响应头包含 `X-Star-Proxy: vps-nginx`
- 无 403/502/521/522/1000 错误

### 5.4 延迟测试

```bash
# 从大陆服务器测试
curl -w &quot;@-&quot; -o /dev/null -s https://star.divinations.top &lt;&lt;&apos;EOF&apos;
    time_namelookup:  %{time_namelookup}s\n
       time_connect:  %{time_connect}s\n
    time_appconnect:  %{time_appconnect}s\n
   time_pretransfer:  %{time_pretransfer}s\n
      time_redirect:  %{time_redirect}s\n
 time_starttransfer:  %{time_starttransfer}s\n
                    ----------\n
         time_total:  %{time_total}s\n
EOF
```

---

## 6. 维护指南

### 6.1 证书续期

Certbot 会自动添加定时任务，但建议定期检查：

```bash
# 测试续期
sudo certbot renew --dry-run

# 查看定时任务
sudo systemctl list-timers | grep certbot

# 手动续期（如需要）
sudo certbot renew
```

### 6.2 Nginx 日志

```bash
# 查看访问日志
sudo tail -f /var/log/nginx/access.log

# 查看错误日志
sudo tail -f /var/log/nginx/error.log
```

### 6.3 Nginx 管理命令

```bash
# 检查配置语法
sudo nginx -t

# 重新加载配置（不中断服务）
sudo systemctl reload nginx

# 重启 Nginx
sudo systemctl restart nginx

# 查看状态
sudo systemctl status nginx
```

---

## 7. ⚠️ 实战踩坑记录（必读）

以下是实际部署过程中遇到的坑，请务必避免！

### 7.1 入口域名误开启橙云 → Error 1000

**现象**：访问入口域名直接报 Cloudflare Error 1000

**原因**：入口域名被 Cloudflare 代理，指向 VPS → Cloudflare 判定为非法

**解决**：入口域名（star / star-api）**永远设置为灰云 (DNS only)**

---

### 7.2 入口域名跳转到 origin → Error 1000

**错误配置**：
```nginx
# ❌ 错误！不要这样做
server {
    server_name star.divinations.top;
    return 301 https://star-origin.divinations.top$request_uri;
}
```

**原因**：Cloudflare 判定为非法代理跳转

**解决**：origin 域名**只给后端使用**，用户请求永远不要重定向到 origin

---

### 7.3 伪造 CF-Connecting-IP → 403

**错误配置**：
```nginx
# ❌ 错误！不要这样做
proxy_set_header CF-Connecting-IP $remote_addr;
```

**原因**：CF-Connecting-IP 是 Cloudflare 专用 Header，伪造会被识别并拒绝

**解决**：**永远不要手动设置 CF-Connecting-IP**，使用 X-Real-IP 代替

---

### 7.4 proxy_pass 无 resolver → DNS 玄学

**现象**：Nginx 运行一段时间后 502，重启后恢复

**原因**：Nginx 启动时只解析一次域名并缓存，Cloudflare IP 变化后无法更新

**解决**：**必须配置 resolver**
```nginx
resolver 1.1.1.1 8.8.8.8 valid=300s ipv6=off;
resolver_timeout 5s;
```

---

### 7.5 Worker 域名在部分 DNS 下不可解析

**现象**：某些企业 DNS 返回 NXDOMAIN

**原因**：Workers 绑定域的 DNS 记录可能有兼容性问题

**解决**：统一使用 **CNAME → *.workers.dev**

---

### 7.6 WebSocket Header 滥用

**错误配置**：
```nginx
# ❌ 错误！不要无条件开启
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection &quot;upgrade&quot;;
```

**原因**：普通 HTTP 请求被强制 upgrade 会出错

**解决**：如果不用 WebSocket 就删除这些配置；如果需要，使用 map 条件判断

---

### 7.7 证书 SAN 未覆盖 API 域名

**现象**：API 域名 SSL 握手失败

**原因**：API 域复用 Web 证书，但 SAN (Subject Alternative Name) 不包含 API 域

**解决**：为 API 单独申请证书，或确认 SAN 包含所有域名

```bash
# 查看证书包含的域名
openssl x509 -in /etc/letsencrypt/live/star.divinations.top/fullchain.pem -text | grep -A1 &quot;Subject Alternative Name&quot;
```

---

### 7.8 Oracle 防火墙未配置

**现象**：外部无法访问 80/443 端口

**原因**：Oracle Cloud 有两层防火墙 - 云控制台 Security List + 服务器内部 iptables

**解决**：两层都要配置！参见第二步

---

### 7.9 Nginx SSL 证书路径错误

**现象**：Nginx 启动失败，报证书文件不存在

**原因**：Certbot 证书路径和配置中的路径不一致

**解决**：确认证书实际路径
```bash
sudo ls -la /etc/letsencrypt/live/
```

---

## 8. 故障排查手册

### 8.1 Error 502 Bad Gateway

**可能原因**：
1. VPS 无法连接到 Cloudflare
2. resolver 未配置
3. origin 域名解析失败

**排查步骤**：
```bash
# 1. 测试 DNS 解析
dig +short star-origin.divinations.top @1.1.1.1

# 2. 测试 VPS 到 Cloudflare 的连接
curl -I https://star-origin.divinations.top

# 3. 检查 Nginx 错误日志
sudo tail -f /var/log/nginx/error.log

# 4. 检查 VPS DNS 设置
cat /etc/resolv.conf
# 如有问题，修改为：
# nameserver 1.1.1.1
# nameserver 8.8.8.8
```

---

### 8.2 Error 521 / 522

**可能原因**：
1. Worker 未响应
2. `proxy_ssl_server_name on;` 未配置
3. origin 域名配置错误

**排查步骤**：
```bash
# 1. 检查 Nginx 配置
sudo nginx -t
grep -r &quot;proxy_ssl_server_name&quot; /etc/nginx/

# 2. 直接测试 origin
curl -I https://star-origin.divinations.top

# 3. 检查 Worker 状态（Cloudflare Dashboard）
```

---

### 8.3 Error 1000

**可能原因**：
1. 入口域名开启了橙云
2. 存在重定向到 origin 的配置

**排查步骤**：
```bash
# 1. 检查 DNS 代理状态（Cloudflare Dashboard）
# 入口域名必须是灰云

# 2. 检查 Nginx 是否有重定向
grep -r &quot;301\|302\|return&quot; /etc/nginx/sites-enabled/
```

---

### 8.4 Error 403

**可能原因**：
1. 伪造了 CF-Connecting-IP
2. Cloudflare 安全规则拦截

**排查步骤**：
```bash
# 检查是否设置了禁止的 Header
grep -r &quot;CF-Connecting-IP&quot; /etc/nginx/
```

---

### 8.5 SSL 证书错误

**可能原因**：
1. 证书过期
2. 证书路径错误
3. 证书不包含请求的域名

**排查步骤**：
```bash
# 1. 查看证书状态
sudo certbot certificates

# 2. 查看证书详情
openssl x509 -in /etc/letsencrypt/live/star.divinations.top/fullchain.pem -text -noout | head -30

# 3. 测试 SSL 连接
openssl s_client -connect star.divinations.top:443 -servername star.divinations.top
```

---

## 9. 方案优缺点分析

### ✅ 优点

| 优点 | 说明 |
|---|---|
| 🚀 速度快 | 大陆用户直连亚洲 VPS，绕过 Cloudflare 拥堵节点 |
| 📶 更稳定 | TCP 连接建立在 VPS 上，VPS 到 CF 走骨干网，丢包率低 |
| 🔒 合规 SSL | 使用 Let&apos;s Encrypt 真实证书，浏览器不报红，支持 HTTP/2 |
| 💰 成本低 | Oracle Cloud 永久免费层足够使用 |

### ⚠️ 风险与缺点

| 风险 | 说明 | 缓解措施 |
|---|---|---|
| 真实 IP 暴露 | 入口域名解析到 VPS 真实 IP，可能遭受 DDoS | 使用 Oracle 的 DDoS 防护，或准备备用 IP |
| VPS 维护成本 | 需自行维护服务器安全、系统更新 | 配置自动更新，定期巡检 |
| IP 被墙风险 | 热门号段 IP 可能被阻断 | 准备多个 VPS，配置故障转移 |
| 证书续期 | 虽然自动，但仍需监控 | 配置监控告警 |

---

## 10. 最终总结

&gt; **Cloudflare 大多数&quot;玄学问题&quot;，本质不是网络，而是：**
&gt; - 入口与源站边界混乱
&gt; - Header 伪造
&gt; - 重定向错误
&gt; - DNS / TLS 细节遗漏

### 核心要点速查

| 项目 | 正确配置 |
|---|---|
| 入口域名代理状态 | DNS only (灰云) |
| origin 域名代理状态 | Proxied (橙云) |
| Nginx resolver | 必须配置 1.1.1.1 8.8.8.8 |
| proxy_ssl_server_name | 必须 on |
| CF-Connecting-IP | 禁止手动设置 |
| 入口到 origin 重定向 | 禁止 |

---

**这份文档 = 已验证可长期复用的 SOP (标准操作流程)**

如有问题，请按照第 8 节故障排查手册进行排查。

---

## 📊 优化效果对比

通过本方案优化后，网站访问速度有了显著提升。以下是优化前后的测速对比数据：

### 优化前测速截图

&lt;!-- 📌 请在此处插入优化前的测速截图 --&gt;
![优化前测速数据](../../assets/attachments/speed-test-before.png)

### 优化后测速截图

&lt;!-- 📌 请在此处插入优化后的测速截图 --&gt;
![优化后测速数据](../../assets/attachments/speed-test-after.png)

---

## 🌟 欢迎体验我的视频网站

如果你觉得这篇文章对你有帮助，欢迎访问我使用本方案优化后的视频网站：

&lt;div align=&quot;center&quot;&gt;

### 🎬 [star.divinations.top](https://star.divinations.top)

**高速流畅的在线视频播放体验**

&lt;/div&gt;

本站使用上述方案进行了网络优化，大陆用户可以享受低延迟、高速度的访问体验。快来试试吧！ 🚀</content:encoded></item></channel></rss>