# 提示词+出图打包成短链接｜不花一分钱搭个带审核的图片分享站


## 写在前面：这是什么

Prompt Share 是我做的一个小站：把"提示词 + 出图"打包成一个短链接，发到 X / 小红书 / 微信都行。一条作品 = 一个提示词 + 多张示例图（最多 8 张）。

首页是公开画廊：访客不用登录就能逛精选和最新作品、按标签搜；登录后才能上传；分享出去的页面有一键复制提示词按钮。

### 为什么做这个项目

玩 AI 生图的人都有这个痛点：提示词和出图散落在各处，想分享给别人时要么截图、要么复制粘贴大段文字，体验很差。我想要的是：一条作品 = 一个提示词 + 多张示例图，打包成一个短链接，发到 X / 小红书 / 微信，对方点开就能看图、一键复制提示词拿去用。

再往前一步：如果朋友也想往里传，就得有个审核——不能谁传什么都直接上架。所以有了"管理员直发、普通用户进待审队列、管理员在 `/admin` 点通过"的设计；又因为不想开放公开注册（防 spam），登录直接用 Cloudflare Access 的邮箱白名单，加人就是加一行邮箱。

### 适合哪类人

- **AI 生图玩家**：攒了一堆提示词和出图，想沉淀成可分享、可检索的作品集
- **做 AI 内容账号的人**：发图时配一句"提示词自取"，链接往评论区一贴就行
- **小团队 / 小社群**：内部提示词知识库，带审核流程，不想搞注册系统
- **想拿 Cloudflare 全家桶练手的人**：单文件、无依赖、免费额度内跑，抄作业成本极低

如果你只是想找个网盘存图，这篇不适合你——这是"分享站"，不是"备份盘"。

整站的架构长这样：

- **Cloudflare Worker**：`src/worker.js` 一个文件就是前后端全部逻辑（路由、页面渲染、API），无依赖
- **KV**：分享元数据、待审队列、索引（最新 / 标签 / 用户 / 精选）、限流计数器
- **R2**：图片原文件，私有 bucket，不开公开访问
- **Cloudflare Access（Zero Trust）**：登录鉴权，不开放公开注册
- **自定义域名**：绑到 Worker 上对外服务

结构图（一张图看懂请求链路）：

```
        访客 / 用户
            │
            ▼
┌───────────────────────────┐
│ Cloudflare Access（门卫）  │
│ 公开区 Bypass 免登录       │
│ 写操作 Allow 邮箱白名单    │
└─────────────┬─────────────┘
              ▼
┌───────────────────────────┐
│ Worker: src/worker.js     │
│ 路由 / 页面 / API 单文件   │
│ + 二次校验 Access JWT     │
└───────┬───────────┬───────┘
        │           │
        ▼           ▼
  ┌──────────┐ ┌────────────┐
  │ KV       │ │ R2         │
  │ 元数据/  │ │ 图片原文件  │
  │ 索引/待审 │ │ 私有 bucket │
  └──────────┘ └────────────┘
```

读法：所有请求先过 Access（门卫）——公开路径直接放行，`/upload`、`/admin` 等必须登录；Worker 拿到请求后，读 KV 取元数据、经 R2 代理取图。图片不暴露直链，分享页的图片地址带 HMAC 签名（6 小时过期）防盗链。

图片安全与限流是这套架构自带的设计：图片走 Worker 代理（`/img/:id`），Referer 非本站 403、空 Referer 放行（直接打开链接、IM 内分享是正常行为）；分享页图片地址带 HMAC 签名，6 小时过期；强缓存 `Cache-Control: public, max-age=31536000, immutable`，重复访问不回源、不消耗 R2 读取次数。限流方面，上传每 IP 每小时 20 次、图片每 IP 每分钟 120 次，都在 `worker.js` 顶部常量里，按需调。

为什么选这套？三句话：**零服务器**（不用管 VPS、不用配 Nginx）、**免费额度够**（见下表）、**一个文件好维护**（改功能只改 `worker.js`，push 就上线）。

## 用到的免费资源（截至本文发布 2026-09-30）

| 资源 | 免费额度 | 在本项目里的用途 |
|---|---|---|
| Cloudflare Workers | 每天 10 万次请求 | 跑 `src/worker.js`：路由、页面渲染、API |
| KV | 存 1GB，每天 10 万次读 / 1000 次写 | 分享元数据、待审队列、四套索引、限流计数 |
| R2 | 每月 10GB 存储 + 100 万次写入 + 1000 万次读取，**出站流量免费** | 图片原文件（私有 bucket，不开公开访问） |
| Zero Trust Access | 50 用户以内免费 | 登录鉴权：公开区 Bypass、写操作 Allow |
| Workers Builds | 免费 | 连 GitHub 私有仓库，push 到 main 自动部署 |

说明两点：第一，额度是发布日我在 Dashboard 看到的，Cloudflare 政策会变，**以你实际看到的为准**；第二，唯一不免费的是域名本身（你得有一个已经接入 Cloudflare 的域名）。

为什么额度够用？图片走强缓存（`immutable`，重复访问不回源），KV 只存元数据不存图，Access 50 人上限对小社群绰绰有余。真超了再考虑付费，不超就一直白嫖。

## 准备工作

1. 一个 Cloudflare 账号（免费账号就行）
2. 一个已经接入 Cloudflare 的域名（后面绑自定义域名用）

## 第一步：建三个资源

**1. 建 R2 bucket（图床）**

Dashboard → R2 → Create bucket，名字 `prompt-share-imgs`。**不要**开公开访问，保持私有——图片一律走 Worker 代理出去，不暴露 R2 直链。

**2. 建 KV namespace（元数据）**

Workers & Pages → KV → Create namespace，名字 `prompt-share`。KV 里存的东西：

- `s:{id}`：分享 JSON（标题、中英提示词、标签、作者、是否精选、创建时间……）
- `pending:{id}`：待审 JSON（30 天过期）
- `idx:new / idx:tag / idx:user / idx:featured`：最新、标签、用户、精选四套索引
- `rl:*`：限流计数器

**3. 建 Worker**

Workers & Pages 里建一个 Worker，名字 `prompt-share`。代码先不贴，后面接 GitHub 自动部署一步到位。

## 第二步：配绑定和变量（Secret 绝不进仓库）

Workers → prompt-share → Settings → Bindings → Add binding：

- R2 bucket → Variable name `IMGS` → 选 `prompt-share-imgs`
- KV namespace → Variable name `SHARE` → 选上一步建的 namespace

Settings → Variables → Add variable：

- **Secret** `SIGN_SECRET` = 随机字符串。本地电脑跑 `openssl rand -hex 32` 生成，在 Dashboard → Settings → Variables → **Secrets** 里添加
- **Text** `ADMIN_EMAILS` = 管理员邮箱（多个用逗号分隔）
- **Text** `ACCESS_TEAM_DOMAIN` / `ACCESS_AUD` = 建好 Access 应用后回填（见第三步），回填完点 Redeploy

重点强调：`SIGN_SECRET` 只放在 Dashboard 的 Secrets 里，**绝不写进 `wrangler.toml`、绝不进仓库**。走 GitHub 自动部署时，Dashboard 里已有的 Secret 会保留，不会被 CI 覆盖。

## 第三步：Zero Trust Access（重点：拆成两个应用）

这是整套部署里最关键的一步，也是最容易配错的一步。

**为什么拆两个应用？** 公开画廊要免登录、随便逛；上传、审核、管理必须登录。Access 的应用是按路径生效的，所以拆成：

**应用一 `prompt-share-public`（Bypass，所有人免登录）**

Zero Trust Dashboard → Access → Applications → 添加应用，两个域名（`*.workers.dev` 和你的自定义域名）**各加**这些路径：

- `/`
- `/tag/*`
- `/search*`
- `/f/*`
- `/img/*`

**应用二 `prompt-share`（Allow，邮箱白名单登录）**

同样两个域名各加这些路径：

- `/upload`
- `/mine`
- `/api/*`
- `/admin/*`

Policy → Allow → Emails：填管理员 + 普通用户的邮箱。**Access 免费版 50 用户是硬上限**，加人 = 以后直接改这个 Policy 的邮箱名单，即时生效，不用动代码。

两个细节：

1. `/` 是前缀匹配，会覆盖全站；登录区靠**更具体的路径优先命中**。配完后用无痕窗口把每个路径逐个打开验证一遍，以你实际看到的为准。
2. 建好应用二后，把应用总览页的 **AUD**（一串 hex）和你的 Team Domain（如 `yourteam.cloudflareaccess.com`）回填到第二步的 Worker 变量里，再 Redeploy 一次。

另外 Worker 侧还会**二次校验** `Cf-Access-Jwt-Assertion`（证书签名、aud、过期时间），就算有人绕过 Access 直接打 Worker 域名也进不来。双保险。

## 第四步：绑自定义域名

Workers → prompt-share → Settings → Domains → Add Custom Domain，填你的域名（比如 `prompt.minispacex.com`）。

注意：第三步的两个 Access 应用里，`workers.dev` 域名和自定义域名**都要**配路径，只配一个的话另一个域名上的路径鉴权会漏。

## 第五步：GitHub 自动部署

代码仓库是私有的，就两个文件：`src/worker.js` + `wrangler.toml`。

Dashboard 里把 GitHub 仓库连上 Workers Builds：选 `main` 分支，**构建命令留空**（单文件无依赖，不需要构建，填了构建命令反而会失败），push 到 main 自动发布。

`wrangler.toml` 里写好绑定（R2/KV）和普通变量（`ADMIN_EMAILS`、`ACCESS_TEAM_DOMAIN`、`ACCESS_AUD`），`SIGN_SECRET` 留在 Dashboard Secrets 里，CI 部署不会动它。

本地改完 `worker.js`：`git push` 到 main 就行。一个实战经验：如果本地 `.git` 丢了，直接在 GitHub 网页上上传覆盖 `worker.js` 也会触发 Workers Builds 自动部署，亲测可用——但 push 前最好先确认 `.git` 还在，别把仓库搞成裸文件堆。

## 功能清单

部署完你会得到这些：

- **公开画廊首页** `/`：精选大图轮播（全幅、完整显示不裁切、左右滑动）+ 最新瀑布流 + 标签云 + 搜索框，免登录
- **标签页** `/tag/:tag`、**搜索** `/search?q=`：标题 / 标签 / 提示词子串搜索，近 150 条内过滤
- **详情页** `/f/:id`：公开访问，一键复制当前语言提示词；中英双语一键切换
- **多图**：一条作品最多 8 张，第一张为封面；作者/管理员可编辑加图、可勾选删除（至少保留 1 张），删封面后自动提位
- **审核流程**：普通用户上传进待审队列（30 天过期），管理员在 `/admin` 点"通过上架 / 通过并精选 / 驳回删除"；管理员上传直接上架，可设精选
- **`/mine` 我的作品**：登录后看自己的待审 + 已上架
- **`/admin`**：审核 + 精选管理 + 删除作品（仅管理员）

**不做的**：浏览/点赞统计、评论、关注。50 人社区不需要，而且 KV 免费写额度（每天 1000 次）也撑不起全量计数——这是架构取舍，不是没做完。

## 验证清单（部署完逐项过）

1. 浏览器无痕打开自定义域名 → **不跳登录**，直接看到画廊首页（精选 / 最新 / 标签云）
2. 点"分享作品" → 跳 Access 登录
3. 管理员登录 → `/upload` 上传一张图（标题 + 标签，勾选精选）→ 直接拿到 `/f/` 链接；首页精选区出现这张
4. 无痕打开 `/f/` 链接 → 能看图，"一键复制"按钮可用
5. `/tag/xxx`、`/search?q=xxx` 有结果；`/mine` 能看到自己的作品
6. 换个普通用户邮箱登录（先加进 Policy）→ 上传 → 提示"已提交审核"，`/mine` 显示待审核；管理员 `/admin` 点"通过并精选" → 上架

## 最后

整套部署的核心就一句话：**Worker 是唯一的可执行单元，KV + R2 是它的数据层，Access 是它的门卫，GitHub 是它的发布键**。资源建一次，之后所有迭代都只是改 `worker.js` 再 push。

下一篇准备写 Prompt Share 的多图与审核流程是怎么设计的（KV 索引那套 `idx:tag:{tag}:{inv}:{id}` 的玩法），感兴趣的话可以先去站上逛逛。


---

> 作者: [小磊哥](https://github.com/Venice851007)  
> URL: /posts/2026-prompt-share-cloudflare-deploy/  

