Serverless 全栈 0 运维成本

AI 指令:GitHub + Cloudflare Pages + Rust WASM + HTMX 零服务器全栈规范

本页面向 AI 提供构建「零独立服务器、零运维开销、毫秒级响应」的现代全栈 Web 应用规范。AI 遵循本规范时,前端基于 HTMX + Bootstrap 5 直接接收 HTML 片段,后端逻辑由 Cloudflare 边缘 Rust WASM 处理,持久化首选 Cloudflare D1 (SQLite),代码托管在 GitHub 并由 Actions 自动极速编译部署。

第一步:架构哲学与职责边界

本架构彻底摒弃传统的「自购 VPS + 挂常驻后台进程 + 编写冗余 JSON API」的沉重模式,建立基于全球边缘的轻量循环:

GitHub

作为唯一代码仓库与 CI 调度源。公开仓库下不存任何密码,通过 Actions 自动化构建编译产物。

Cloudflare 边缘

承载 Pages 静态分发与 Rust 编译的 WASM 边缘无状态函数(Functions),按需毫秒级冷启运行。

HTMX 浏览器端

遵循 HTML-over-the-Wire 模式,后端 Rust 直接吐出待替换的 HTML 结构,严禁在前端用 JS 解析 JSON 拼接 DOM。

开发铁律:严禁为前端交互单独开发一套客户端 JSON API!Rust 边缘函数直接向浏览器返回带 Bootstrap 样式的 HTML 片段(Content-Type: text/html),由 HTMX 的 hx-swap 就地挂载。

免费额度与物理红线认知

  • 单次请求 CPU 时间限制:10ms。仅计算 Rust 内部实际计算消耗,等待网络 I/O 或数据库读写不扣 CPU 时间。Rust 拼接 HTML 片段耗时通常 < 0.5ms,完全胜任。严禁在 Worker 内跑大算力挖矿、长死循环或重度图像压缩。
  • 动态请求量:100,000 次 / 天。每天 UTC 0 点重置,纯静态 HTML/CSS 资源走 Pages 缓存,不计入此配额。
  • 无状态(Stateless)特性与数据库演进路径: 函数随用随起、执行完即销毁。严禁使用内存全局变量(如 static mut)存储业务状态,数据必须入库。
    数据库阶梯演进准则(先 D1 → 后 Supabase):
    • 起步/轻量阶段(首选 D1 SQLite):无需自备服务器、零配置开箱即用,每日享 500 万行读 / 10 万行写的大额免费配额,极速搞定产品闭环。
    • 扩展/企业阶段(平滑演进 Supabase Postgres):当数据量激增、需要复杂 SQL 分析、全文索引或要求数据完全私有化时,平滑切到自建 VPS 上的 Supabase,前端 HTMX 视图层代码 0 修改。

第二步:Rust WASM 瘦身与体积控制规范

Cloudflare 免费版限制 Worker / WASM 脚本压缩后必须小于 3 MB。Rust 默认编译会带调试符号并优先展开速度,生成文件常达数兆。AI 在初始化项目时必须按以下规约配置:

1. Cargo.toml 极限体积优化配置

[package]
name = "cf-rust-htmx-app"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib", "rlib"]

[dependencies]
worker = "0.4"          # Cloudflare 官方 Rust SDK
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

[profile.release]
opt-level = "z"         # 极限精简文件大小(size-focused)
lto = true              # 跨 crate 链接优化,剔除所有未使用函数
codegen-units = 1       # 单编译单元,最大化优化空间
panic = "abort"         # 出错直接中止,剥离庞大的栈回溯开销
strip = true            # 剔除符号表调试信息

2. HTML 渲染选型准则

  • 优先使用原生 format! 宏:无任何第三方模板依赖,编译产物仅几十 KB,速度与体积最优,适合简单的表单行、表格行、提示框。
  • 复杂页面选用 maud 宏:使用 Rust 编译期宏生成类型安全 HTML,零运行时开销,杜绝 XSS 注入风险。

第三步:持久化核心 —— Cloudflare D1 (SQLite)

选型铁律:严禁使用 KV 存储作为论坛、博客或 CRUD 系统的业务数据库(KV 每天仅 1,000 次写,且无法做 ORDER BY 分页)。必须统一采用 Cloudflare D1(云原生 SQLite)!

1. D1 核心指标与优势

D1 底层是纯正的 SQLite 引擎。享有每日 500 万行读取、10 万行写入、5 GB 存储容量的免费额度。

D1 核心避坑铁律:读取行数计算的是「扫描行数」而非返回行数!

如果表中存了 10,000 条记录,执行了一句未建索引的查询 SELECT * FROM items WHERE title = '测试',数据库必须遍历整张表,单次查询就会扣除 10,000 行读取额度!

必须遵守的防坑法则:务必为所有频繁用于 WHERE、ORDER BY、分类筛选的字段创建索引(CREATE INDEX)。命中索引后,单次查询仅消耗几行读取,500 万行读足以轻松支撑几十万用户访问!

2. 辅助利器:什么时候用 KV?(读与写的概念释疑)

问:把网站的中英文多语言字典存进 KV,用户访问算“写”吗?

答:绝对不算!读就是「读 (Get)」,写就是「保存/修改 (Put)」:

  • 保存字典(写):你在发布网站时,把中文词典存入 i18n_zh,英文词典存入 i18n_en。这辈子只保存了一次,总共只消耗 2 次写入额度!
  • 用户访问(读):今天全世界有 50,000 个用户打开你的网页,Rust 从边缘执行 kv.get("i18n_zh") 取出文字渲染。这消耗了 50,000 次读取额度,而写入消耗为 0!
  • 黄金定论:多语言字典、全站标题电话配置,是 KV 最完美的教科书级场景(几个月存 1 次,每天几万人免费秒读)。

3. 标准建表规范 (schema.sql)

-- 初始表结构(以留言/任务为例)
CREATE TABLE IF NOT EXISTS items (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    title TEXT NOT NULL,
    content TEXT NOT NULL,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_items_created ON items(created_at DESC);

4. Rust 操作 D1 并在边缘输出 HTML

use worker::*;

// 查询最新数据并直接组装 HTML 返回
pub async fn render_item_list(env: &Env) -> Result<Response> {
    let d1 = env.d1("DB")?;
    let statement = d1.prepare("SELECT id, title, content, created_at FROM items ORDER BY created_at DESC LIMIT 10");
    let result = statement.all().await?;
    let rows: Vec<ItemRecord> = result.results()?;

    let mut html = String::new();
    for item in rows {
        html.push_str(&format!(
            r#"<li class="list-group-item bg-dark text-light border-secondary d-flex justify-content-between align-items-center">
                <div>
                  <h6 class="mb-1">{}</h6>
                  <p class="mb-0 text-secondary small">{}</p>
                </div>
                <button class="btn btn-sm btn-outline-danger"
                        hx-delete="/api/items/{}"
                        hx-target="closest li"
                        hx-swap="outerHTML">
                  删除
                </button>
               </li>"#,
            item.title, item.content, item.id
        ));
    }

    let mut headers = Headers::new();
    headers.set("Content-Type", "text/html; charset=utf-8")?;
    Ok(Response::ok(html)?.with_headers(headers))
}

第四步:GitHub Actions 自动化流水线

在仓库创建 .github/workflows/deploy.yml。开启 Rust 缓存加速,自动编译 WASM,并由 Pages Action 发布:

name: Build and Deploy to Cloudflare Pages

on:
  push:
    branches: [main]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Code
        uses: actions/checkout@v4

      - name: Install Rust Toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: wasm32-unknown-unknown

      - name: Rust Cache
        uses: Swatinem/rust-cache@v2

      - name: Install wasm-opt & worker-build
        run: |
          cargo install worker-build
          sudo apt-get update && sudo apt-get install -y binaryen

      - name: Build Rust WASM
        run: |
          worker-build --release
          # 二次优化瘦身
          wasm-opt -Oz build/worker/shim.wasm -o build/worker/shim.wasm || true

      - name: Deploy to Cloudflare Pages
        uses: cloudflare/pages-action@v1
        with:
          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
          projectName: my-rust-htmx-app
          directory: dist
          gitHubToken: ${{ secrets.GITHUB_TOKEN }}

第五步:极速启动前端模板(Bootstrap 5 + HTMX)

1. 极速启动极简示例模板(Bootstrap 5 + HTMX)

<!DOCTYPE html>
<html lang="zh-CN" data-bs-theme="dark">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Rust WASM + HTMX Fullstack</title>
  <link href="https://cdn.staticfile.net/bootstrap/5.3.3/css/bootstrap.min.css" rel="stylesheet">
  <link href="https://cdn.staticfile.net/bootstrap-icons/1.11.3/font/bootstrap-icons.min.css" rel="stylesheet">
</head>
<body class="py-5" style="background-color: #0a0e17; color: #e2e8f0;">
  <main class="container" style="max-width: 760px;">
    <div class="card bg-dark border-secondary p-4 mb-4 shadow">
      <h2 class="h5 text-primary mb-3"><i class="bi bi-send-fill me-2"></i>发布新记录</h2>
      <!-- 提交成功后清空表单,并将返回的 HTML 片段插入列表顶部 -->
      <form hx-post="/api/items"
            hx-target="#items-list"
            hx-swap="afterbegin"
            hx-on::after-request="if(event.detail.successful) this.reset()">
        <div class="mb-3">
          <input type="text" name="title" class="form-control bg-black text-light border-secondary" placeholder="标题" required>
        </div>
        <div class="mb-3">
          <textarea name="content" class="form-control bg-black text-light border-secondary" rows="2" placeholder="详情内容..." required></textarea>
        </div>
        <button type="submit" class="btn btn-primary">提交到 Cloudflare 边缘</button>
      </form>
    </div>

    <div class="card bg-dark border-secondary p-4 shadow">
      <h3 class="h6 text-secondary mb-3">实时记录列表</h3>
      <!-- 页面初始化自动触发加载 -->
      <ul id="items-list" class="list-group" hx-get="/api/items" hx-trigger="load">
        <div class="text-secondary small p-3 text-center">加载数据中...</div>
      </ul>
    </div>
  </main>
  <script src="https://cdn.staticfile.net/htmx/1.9.12/htmx.min.js"></script>
  <script src="https://cdn.staticfile.net/bootstrap/5.3.3/js/bootstrap.bundle.min.js"></script>
</body>
</html>

2. 如何直接套用现成 Bootstrap 5 模板(开源/商业主题)

这是 HTMX + BS5 的绝对王牌优势!传统 React/Vue 必须将现成模板重写为组件,而 HTMX 原生支持标准 HTML。你可以下载任何现成的 Bootstrap 5 后台或官网模板(如 Tabler、AdminLTE v4、SB Admin、CoreUI),通过以下四步秒变动态全栈:

  1. 第一步:静态资源原样放置:直接将现成模板的 css/、js/、assets/ 和 index.html 复制到你的前端静态目录。
  2. 第二步:圈定动态插槽容器:找到模板中需要动态更新的区域(例如表格 <tbody id="data-rows"> 或统计卡片 <div id="stats-box">),加上专属 id。
  3. 第三步:无侵入挂载 HTMX:在模板原本自带的翻页按钮、筛选下拉框或搜索框上,直接添加 hx-get="/api/..." hx-target="#data-rows" hx-swap="innerHTML"。
  4. 第四步:Rust 照抄模板 HTML 结构输出:后端 Rust 渲染时,直接复制原模板中对应的一行 <tr> 或卡片 <div class="..."> 样式类名进行字符串填充并返回。
收益总结:零前端编译打包、无需重写组件,完美保留现成高颜值模板的所有动画、深色模式与响应式网格,瞬间盘活任何现成 BS5 工业级界面!

第六步:高级演进与公开仓库安全规范

1. 平滑演进:自建 Supabase (PostgreSQL) 替代 D1

当项目业务复杂,需要真正的 PostgreSQL 全文检索、外键与独立数据自主权时,可平滑对接自建 Supabase。前端 HTMX 代码 0 修改,仅在 Rust 内部将 D1 语句换为对 Supabase PostgREST 的 HTTPS 请求:

// Rust 内部请求自建 Supabase 并直接吐 HTML 片段
pub async fn fetch_from_supabase(env: &Env) -> Result<Response> {
    let base_url = env.var("SUPABASE_URL")?.to_string();
    let service_key = env.secret("SUPABASE_SERVICE_ROLE_KEY")?.to_string();

    let mut headers = Headers::new();
    headers.set("apikey", &service_key)?;
    headers.set("Authorization", &format!("Bearer {}", service_key))?;

    let req = Request::new_with_init(
        &format!("{}/rest/v1/items?select=*&order=created_at.desc&limit=10", base_url),
        RequestInit::new().with_headers(headers),
    )?;

    let mut resp = Fetch::Request(req).send().await?;
    let rows: Vec<ItemRecord> = resp.json().await?;

    // 依然直接渲染 HTML 片段给 HTMX
    let mut html = String::new();
    for item in rows {
        html.push_str(&format!(r#"<div class="p-2 border-bottom border-secondary">{}</div>"#, item.title));
    }

    let mut res_headers = Headers::new();
    res_headers.set("Content-Type", "text/html; charset=utf-8")?;
    Ok(Response::ok(html)?.with_headers(res_headers))
}

2. 公开仓库(Public)下的机密隔离铁律

安全铁律:无论 GitHub 仓库是否公开,代码文件内严禁硬编码任何数据库密码、URL 或 Token!所有人都能看代码,但任何人无法窃取密码。
  • Cloudflare Pages 控制台: 进入 Settings → Environment variables 添加机密。 勾选 Encrypt(加密机密)。机密一旦保存,即使后台也无法查看明文,仅在边缘运行时以内存方式注入,物理隔离泄露。
  • GitHub 仓库控制台: 进入 Settings → Secrets and variables → Actions。 仅存放部署授权令牌 CLOUDFLARE_API_TOKEN 与 CLOUDFLARE_ACCOUNT_ID,构建脚本无法向外界回显。
  • 访客浏览器完全不可见: 访客在浏览器端抓包只能看到 Cloudflare 域名与 HTML 片段,真正的后端数据库 IP、域名及密钥完全隐匿在边缘层之后。

附录:给人类看(非 AI)—— GitHub 与 Cloudflare 免费配额速查

开发者必读

本章节专供人类开发者规划项目成本与架构容量时速查。所有指标均为官方最新免费套餐(Free Tier)规约,帮助你在零服务器成本前提下充分发挥平台最大效能,安全规避物理红线:

1. GitHub 平台免费配额与规则

资源维度 公开仓库 (Public Repo) 私有仓库 (Private Repo)
仓库数量 无限制(自由创建) 无限制(自由创建)
GitHub Actions 运行时间 完全无限免费 (Unlimited) 每月免费送 2,000 分钟(Rust 增量构建带缓存约 1~2 分钟/次,月推几百次绰绰有余)
代码与仓库存储空间 建议单仓库 ≤ 1 GB(软上限 5 GB ~ 10 GB,纯代码通常仅数 MB)
机密密钥 (Secrets) 完全免费提供单向加密存储,公开仓库对外彻底隔离,任何人无法窥探明文
Cloudflare 核心机制:按「整个账号」共享总额度!

Cloudflare 的免费配额是按你的整个登录邮箱账号 (Account) 统一计算并共享的,并非单个项目独占。同一账号下的所有 Worker / Pages / D1 / KV 共同消耗每日额度。如果未来不同独立项目流量极大,完全可通过注册多个不同邮箱账号实现完全物理隔离。

2. Cloudflare 平台核心组件免费配额与技术红线

组件类别 核心指标 免费额度 (Free Plan) 核心技术红线与避坑说明
Workers / Pages Functions
后端计算
动态请求量 100,000 次 / 天
(月计约 300 万次)
每日 UTC 0 点重置。纯静态 HTML/CSS/图片走 Pages CDN 缓存,完全无限流量,不扣此额度。
CPU 执行时间 10 ms / 单次请求 仅算纯 CPU 运算!等待网络或数据库 I/O 耗时不计入。Rust 拼 HTML 通常 < 0.5ms,足够使用。严禁跑大算力挖矿/复杂图像压缩。
WASM / 脚本体积 压缩后最大 3 MB
(解压后上限 64 MB)
必须在 Cargo.toml 开启 opt-level = "z" 与 lto = true 极致瘦身,剔除无用符号。
运行内存 128 MB 单实例内存限制,Serverless 随用随起用完即毁,严禁依赖内存全局变量。
Cloudflare D1
SQLite 数据库
主力首选
读取额度 5,000,000 行 / 天
(500 万行)
计算的是扫描行数!未建索引会导致全表扫描瞬间扣完。频繁查询的字段必须加 CREATE INDEX。
写入额度 100,000 行 / 天
(10 万行)
完全足够满足中小企业站、博客、个人工具、论坛日常发帖。超额后当日报错,次日重置。
存储容量 5 GB 支持单库最大 10 GB。无出站流量费用(Egress 0 元)。
Workers KV
键值缓存
辅助加速
读取次数 100,000 次 / 天 毫秒级(0~2ms)全球边缘本地内存直出,多语言词典、全局配置首选。访客查看只算读,完全不算写!
写入 / 删除 仅 1,000 次 / 天 极低额度警示!严禁用于评论、发帖或高频点赞。同一 Key 写入上限为 每秒最多 1 次。
数据有效周期 原生支持 TTL 自动过期 支持设置秒级自动过期(如 expirationTtl: 600),到期全球自动删除,不占写/删额度。
存储与单值 1 GB 存储
单值最大 25 MB
单 Key 下可存大文件(如前端大 HTML 或供浏览器客户端下载执行的 WASM 模块)。
Pages CI 构建 每月自动构建 500 次 / 月 平均每天可通过 git push 触发 16 次以上自动部署上线,单次构建超时 20 分钟。
架构心法口诀:展示选静态(无限),交互选 D1(500万读/10万写),配置/TTL用 KV(秒开但少写),代码推公开仓库放心开源(密钥进 Secrets),全套 0 成本高枕无忧!