部署与运维

对象存储与图床:选型、R2 自建与配置

出站流量决定了图床账单,选型要先看场景。本文按 1TB 总成本横评主流厂商,再落地 Cloudflare R2 自建图床,最后用 PicGo / PicList 配好本地上传。

图床本质是超高出站流量的应用,选错服务商会把账单打到天上。本文按真实依赖顺序拆成三段:先选型,再落地 R2 自建图床,最后配置 PicGo / PicList 上传工具。

一、选型:先从场景出发

1.1 核心选型维度

对象存储并不只有 AWS S3。市面上十几家服务商,价格差到十几倍,但很多人选的时候只看名气。按 1TB 总成本(存储 + 流量)+ 免费额度 + 适用场景 挑,不同场景的优先级完全不一样:

场景 优先考虑
图床 / 博客静态资源 出站流量便宜(带 CDN 更好)
冷备份 存储便宜(流量基本不消耗)
CDN 回源 国内有节点 + 出站便宜
共享文件 / 网盘 入站便宜 + 单用户上限
数据库 backup API 稳定 + region 多

1.2 13 家服务商完整对比表

厂商 免费额度 区域 存储费 流量费 1TB 总成本/月
Cloudflare R2 10G + 100w A + 1000w B 操作 全球(边缘自动) $0.015/GB 出站免费 $15
Backblaze B2 10G + 每天 1G 下载 美/欧/加 $0.006/GB 3 倍存储免费,超 $0.01/GB $6
Wasabi 30 天 1TB 试用 北美/欧/亚 $0.0068/GB 入站出站全免费(公平用量) $6.99
DigitalOcean Spaces 含基础套餐 250G + 1TB 流量 美/欧/亚/加 基础 $5/月 + 额外 $0.02/GB 1TB 免费 + 额外 $0.01/GB $20.48
Hetzner Storage Box 无 德/芬 $5.99/TB 含 1TB 流量 + 超出 €1.20/TB $5.99
Scaleway 75G + 75G 出站/月 荷/法/波 €0.012-0.0146/GB 75G 免费 + 超出 €0.01/GB 约 €21
Vultr Object Storage 无 全球 $6/TB 含 1TB 流量 + 超 $10/TB $6
Linode Object Storage 无 全球 基础 $5/月 + 额外 $0.02/GB 含 1TB 流量 + 超 $0.005/GB $20
OVH Object Storage 限时出站免费 美/欧 ~$0.008/GB 限时免费 约 $8
七牛云 10G + 10G 出站/月 国内 国内 ¥0.099/GB 国内 ¥0.27/GB 国内场景便宜
Amazon S3 5G(12 个月) 全球 $0.023/GB 前 100G 免费 + 后 $0.09/GB 约 $113
Google Cloud Storage 5G + 5G 出站 全球 $0.020/GB $0.08-0.12/GB 约 $140
阿里云 OSS 区域少量 全球(含国内) $0.018/GB $0.07-0.12/GB 约 $88

价格随时会变,下单前务必去官网核对,这表是 2026 年中的快照。

1.3 按场景推荐

个人图床(首选)

mermaid8 行
graph TD
Q[做图床用?] --> Q1{愿意付费?}
Q1 -->|不愿意| R2[Cloudflare R2
免费 10G + 出站免费]
Q1 -->|愿意小额| B2[Backblaze B2
$6/TB + 流量便宜]
R2 --> CDN[再叠 CF CDN
请求量降到忽略不计]

推荐顺序:

  1. Cloudflare R2:免费 10G + 出站免费 + 全球 CDN,图床首选
  2. Backblaze B2:免费 10G,性价比靠前,但国内访问慢
  3. 七牛云:国内访问快,但价格按量计费容易超支

冷备份 / 归档

存储量大、几乎不下载,要存储便宜、流量按需付:

  1. Backblaze B2:$6/TB,归档首选
  2. Hetzner Storage Box:$5.99/TB,欧洲机房,国内慢
  3. Wasabi:$6.99/TB,出站完全免费

CDN 回源 / 站点资源

需要全球分发 + 出站便宜:

  1. R2 + CF CDN:原生集成,零回源费
  2. B2 + CF CDN:CF 和 B2 有 Bandwidth Alliance,出站到 CF 零费用
  3. 七牛云:国内站推荐,免费 10G/月足以应付小流量

高频读取 + 全球用户

  1. AWS S3 + CloudFront:贵但稳,企业级
  2. CF R2:单机房延迟略高,但带 CDN 后用户感知差不多

临时大数据 / 短期项目

  1. Wasabi 30 天试用:1TB 不要钱
  2. OVH 限时免费出站:流量大的临时跑数据

1.4 流量陷阱

对象存储最贵的是流量,存储反而靠后:

厂商 存 1TB 一年 跑 1TB 流量一次
R2 $180 $0
B2 $72 $10
七牛 ¥1200 ¥270(一次)
AWS S3 $276 $90

真实案例:有人把 10G 视频放七牛云做免费 CDN,被微博转发一次 100w 播放,回来就是几百块的账单。

建议:

  1. 商业级流量 = R2 / B2 + CDN
  2. 七牛、阿里这类国内云 = 设流量上限报警
  3. 视频 / 大文件 = 别放免费额度低的服务

1.5 S3 协议兼容性

S3 协议是事实标准,但所有标榜“S3 兼容”的产品,兼容程度有高有低:

厂商 兼容程度 备注
AWS S3 100% 标准本身
Cloudflare R2 99% 偶尔不支持新 API
Backblaze B2 95% 部分 ACL 行为不同
MinIO 99% 开源 self-host
七牛云 90% 老 API 私有,新增 S3 兼容层

工具选择:rclone / awscli / s3cmd 对所有 S3 兼容的都能用,优先用 rclone,配置最直观。

1.6 图床方案的四种思路

稳定图床比想象中难找:免费的怕跑路、商业的怕封号、自建的怕麻烦。主流方案分四类:

mermaid12 行
graph TD
Q{需要图床?} --> A{用量大不大}
A -->|大| B{在意稳定/隐私?}
A -->|小| C{愿意折腾?}
B -->|是| S1[自建对象存储
R2 / B2 / 七牛]
B -->|否| S2[付费图床
SM.MS / 又拍云]
C -->|是| S3[自部署开源
EasyImages / OneImg]
C -->|否| S4[公共图床
imgur / Postimage / sm.ms]
方案 稳定性 速度 成本 跑路风险
自建对象存储 + CDN 高 高 $0-$5/月 极低
付费商业图床 中上 中上 $5-$20/月 中
自部署开源 + VPS 中 中 VPS 费用 看 VPS 商家
公共图床 中低 看运气 0 高

1.7 第三方公共图床

仅适合临时用、不重要的图——所有第三方图床都有跑路、防盗链、突然清空的可能性。

图床 速度 限制 备注
sm.ms 国内外都还行 注册后 5MB / 张 老牌、较稳的公共图床
imgur 海外快 国内被墙 国际标准,文档/issue 友好
PostImage 海外快 国内一般 老牌
upload.cc CF CDN 永久存储 香港人开
微博图床 国内极快 防盗链 需要登录微博 cookies
聚合图床 看后端 一图多床 superbed.cn

微博图床防盗链越来越严,已经基本不适合做技术博客的图床。不要依赖公共图床做技术博客:sm.ms 这种较稳的也曾经停服过一阵。

1.8 自部署开源图床

已经有 VPS 的话可以自己跑一个:

EasyImages2.0

plaintext1 行
https://github.com/icret/EasyImages2.0
  • PHP 写的,单文件部署
  • 自带管理界面
  • 支持 API 上传
  • 图片直接存 VPS 磁盘,迁移麻烦

OneImg(初春图床)

plaintext1 行
https://github.com/onexru/oneimg
  • 更现代化的 UI
  • 多用户支持

Telegraph-Image

  • 基于 Telegraph 的免费图床,Workers 部署,无需服务器
  • 速度看 CF
  • 图片放别人家有跑路风险

1.9 选型经验

  • 个人 1 个 R2 + 1 个 B2 双开就够覆盖图床 + 备份所有需求
  • 七牛 / 阿里只用于国内 CDN 加速场景,别当通用对象存储
  • AWS S3 / Azure / GCP 是企业的选择,个人玩成本太高
  • 永远开账单告警:设个 $5/月上限,超了就发邮件
  • 新厂商的免费额度别 all in:今天免费明天可能就收钱(参考 Wasabi 政策变化历史)
  • 重要数据至少两份,分两个不同公司

二、R2 自建图床

选完型到这里落地。Cloudflare R2 完全 S3 兼容,关键卖点是出站流量免费——这点直接把传统 S3 一年几百刀的图床账单压到 0。10G 存储 + 100 万 Class A 操作 + 1000 万 Class B 操作的免费额度,对个人图床 / 博客 / 小项目足够。

整体架构:

mermaid9 行
graph LR
U[用户浏览器] -->|访问 img.your-domain.com| W[Cloudflare CDN
边缘缓存]
W -->|miss 时回源| R2[R2 Bucket
实际存储]
PG[PicGo / PicList
本地工具] -->|S3 API| R2
R2 -.绑定.-> CD[自定义域名
img.your-domain.com]
组件 职责
R2 Bucket 存图片文件
自定义域名 让 URL 好看 + 走 CDN 缓存
API Token PicGo 上传用的凭证
PicGo/PicList 本地上传工具

2.1 开通 R2

R2 虽然免费额度,但要绑定信用卡才能开通:CF 控制台 → R2 → Overview → 跟着提示绑卡。绑完会让你选订阅,选免费层:

  • 10G 存储
  • 100 万 Class A 操作(写入相关:PUT/POST/COPY)
  • 1000 万 Class B 操作(读取相关:GET/HEAD)

只要不超过这个额度,账单永远是 $0。

2.2 创建 Bucket

R2 → Create bucket:

字段 推荐
Bucket name img-bed(全小写,连字符)
Location Automatic(CF 自动选最优)

创建完成后,bucket 还没有公开访问入口。

2.3 绑定自定义域名

R2 默认的 pub-xxxxx.r2.dev 域名速度慢、不能商用,必须绑定自定义域名才能正常做图床。前提是域名已经托管到同一个 CF 账号下。在 bucket 详情页 Settings → Public access → Custom Domains → Connect Domain:

字段 值
Domain img.your-domain.com

CF 会自动加 CNAME 记录、签 SSL,几分钟后这个域名就指向你的 bucket 了。

验证:随便上传一张图到 bucket(控制台直接拖文件),然后访问:

plaintext1 行
https://img.your-domain.com/test.png

能看到图片就成功了。走自定义域名的请求全部走 CF CDN,比直连 R2 快好几倍。CDN 命中后大量请求不计 R2 的 Class B 操作。

2.4 创建 API Token

R2 → Manage R2 API Tokens → Create API token:

字段 推荐
Token name picgo-upload
Permissions Object Read & Write
Specify bucket(s) Apply to specific buckets only:选你的 bucket
TTL 不设(永久)

创建后会显示一次 Access Key ID + Secret Access Key,立刻保存,关页面就再也看不到。还有一个关键参数要记:

plaintext1 行
Endpoint:https://<accountid>.r2.cloudflarestorage.com

这三个值千万别传到 GitHub 或共享出去。任何人拿到都能往你 bucket 写文件、删文件、跑爆额度。

2.5 CDN 缓存优化

R2 的请求计费按 Class A/B 操作,通过 CDN 缓存能大幅减少。CF 控制台 → Caching → Cache Rules → Create rule:

字段 值
Rule name r2-images-cache
Field Hostname
Operator equals
Value img.your-domain.com
Eligible for cache 是
Edge TTL 1 month
Browser TTL 7 days

之后大部分请求被 CDN 直接命中,不会回源到 R2,Class B 请求能降到原来的 5%-10%。

三、图床工具配置(PicGo / PicList)

3.1 PicList 与 PicGo 对比

PicList 是 PicGo 的社区 fork,做了大量体验改进:

维度 PicGo PicList
维护活跃度 慢 高
文件管理(删除/重命名) 无 有
监听剪切板 有 有
批量上传 一般 好
自定义命名模板 基本 丰富
多图床配置切换 一般 顺手

建议直接用 PicList,PicGo 不必再装。

3.2 安装 PicList

plaintext1 行
https://github.com/Kuingsmile/PicList/releases

下载对应平台的安装包。

3.3 配置 S3 上传

图床设置 → AWS S3 → 新建配置:

字段 值
应用密钥 ID(Access Key) API Token 的 Access Key ID
应用密钥(Secret Key) API Token 的 Secret Access Key
桶名(Bucket) 你的 bucket 名(如 img-bed)
文件路径 {year}/{month}/{md5}.{extName}
自定义节点(Endpoint) https://<accountid>.r2.cloudflarestorage.com
自定义域名(Custom URL) https://img.your-domain.com
自定义区域(Region) auto
路径风格(path-style) 关闭(即用 virtual-hosted-style)
ACL 不设 / public-read

Endpoint 是 cloudflarestorage.com,和 r2.dev 是两回事,填错其中任何一个值都不会成功。

3.4 文件路径模板

PicList / PicGo 都支持命名模板:

模板 效果 评价
{md5}.{extName} abc123.png 推荐:相同图不重传
{year}/{month}/{md5}.{extName} 2026/06/abc.png 推荐:分目录便于管理
{timestamp}.{extName} 1734567890.png 少用:重复上传会有不同 URL
{filename}.{extName} screenshot.png 避免:文件名冲突

用 {md5} 的好处:同一张图截 100 次也只占一份空间——MD5 相同,上传到 R2 会覆盖同一个 key。

3.5 设为默认 + 测试

设为默认图床后,截图工具调 Win + Shift + S → 复制到剪贴板 → PicList 自动上传 → 返回 markdown 链接。直接试一下:

plaintext1 行
![测试](https://img.your-domain.com/2026/06/abc123def456.png)

3.6 命名一致性 = 后端可随时切换

为什么 {md5}.{extName} 值得坚持:

plaintext4 行
最终 URL = 域名 + 路径
https://img.your-domain.com / 2026/06/abc123def456.png
        ↑                                    ↑
      你完全控制                       你完全控制

只要这两点保持一致,后端存储可以随时切换:

mermaid6 行
graph LR
D[img.your-domain.com] -.指向.-> R2[Cloudflare R2]
D -.或.-> B2[Backblaze B2]
D -.或.-> AL[Alist + OneDrive]
D -.或.-> S3[AWS S3]
D -.或.-> Q[七牛云]

R2 哪天涨价、封号,只要文件名保持一致,旧文章里所有图片链接都不需要改——CF DNS 改个 origin 就行。换命名规则等于所有旧链接重传,这个模板定下来就别动。

3.7 批量替换工具:从旧图床迁到新图床

写了一堆 markdown 文章后想换图床,两类思路:

改 DNS 不改文章(推荐)

只要旧图床域名是你自己的(如 img.your-domain.com)且新后端的文件名和旧的一致,把 DNS 切到新后端,所有文章一行不用改。

实在要改 markdown 的批量替换

plaintext7 行
# Linux/macOS
find /path/to/blog -name "*.md" -exec \
  sed -i 's|old-domain.com|new-domain.com|g' {} +

# macOS(BSD sed 要加空字符串)
find /path/to/blog -name "*.md" -exec \
  sed -i '' 's|old-domain.com|new-domain.com|g' {} +

或者写 Python 脚本检测哪些文件包含旧域名图片:

plaintext15 行
import os
import re
from pathlib import Path

PATTERN = r'!\[([^\]]*)\]\((https://old-domain\.com/[^)]+)\)'

def scan(target_dir):
    for md_file in Path(target_dir).rglob('*.md'):
        with open(md_file, 'r', encoding='utf-8') as f:
            content = f.read()
        matches = re.findall(PATTERN, content)
        if matches:
            print(f"{md_file}: {len(matches)} 张待迁移")

scan("/path/to/blog")

四、多份备份与迁移

重要数据至少存两份,分两个不同的公司。推荐配置:R2 主用、B2 冷备,rclone 自动同步。

4.1 装 rclone + 配置 remote

plaintext2 行
curl https://rclone.org/install.sh | sudo bash
rclone config

按提示加两个 remote:

Remote 名 类型
r2 S3-compatible(填 R2 的 endpoint + token)
b2 Backblaze B2(或换成 gdrive / Alist)

4.2 同步备份

plaintext5 行
# R2 → Backblaze B2
rclone sync r2:img-bed b2:img-bed-backup

# 加进 cron 每周一次
0 3 * * 0 rclone sync r2:img-bed b2:img-bed-backup --log-file /var/log/rclone.log

这套的收益:R2 主存零出站费、CDN 命中率高;B2 冷备 $0.006/GB/月,便宜到可以忽略。R2 主用 + B2 冷备的年成本可以低于 $1。

4.3 灾难恢复

R2 一旦出问题(封号、政策变化),反向同步回新的存储,或直接把域名指向新后端,博客文章一行不用改:

plaintext2 行
# 反向同步回去
rclone sync b2:img-bed-backup r2:img-bed

五、常见问题

按服务商

厂商 现象 原因 解决
R2 PicList 上传 403 API Token 权限不对 重建 Token,选 Object Read & Write
R2 上传成功但访问 404 自定义域名没绑 / DNS 没生效 确认域名绑定 + 等 5 分钟
R2 pub-xxx.r2.dev 速度慢 默认域名没走 CDN 必须绑自定义域名
R2 Endpoint 写错 用了 dashboard URL 用 https://<accountid>.r2.cloudflarestorage.com
R2 Region 报错 S3 库要求 region 而 R2 不用 写 auto 或 us-east-1
R2 同样文件上传两次出现两个 URL 文件名用了 timestamp 改用 {md5}
R2 突然账单从 $0 涨到几刀 Class A 操作超 100w 看监控 + 加 CDN 缓存
B2 国内访问慢 机房在海外 套 CF CDN
B2 每天 1G 下载额度经常触发 流量大 流量大就直接付钱
B2 API 报错 部分 ACL 行为不同 用 rclone / s3 endpoint 时注意
七牛 国内桶海外节点打不开 国内/国外区域要分清 按区域建桶
七牛 流量费超支 按量后付费 设流量上限
AWS S3 账单看不懂 区域/请求类型/流量出口按不同价格算 新手先避开,企业用再学

按通用

现象 原因 解决
第三方图床图挂了 跑路 / 防盗链 / 清空 只传临时图,重要图放自建
自部署图床迁移麻烦 图片存 VPS 磁盘 存对象存储,别存本地盘

六、实用经验

  • 永远绑自定义域名——R2 的 r2.dev 域名只能调试用。
  • PicList 优于 PicGo:社区活跃、bug 修得勤,直接装 PicList。
  • {md5}.{extName} 定下来就别换:永久不冲突 + 重复上传不浪费空间。
  • 加 CDN 缓存规则:让 R2 操作量降一两个数量级,免费额度花不完。
  • rclone 周备份到另一个对象存储,重要图片不至于因为一次误操作消失。
  • 图片直接拖到 R2 控制台也能上传,临时传几张文件不用开 PicList。
  • 自己的域名 = 主权:第三方图床域名挂掉就完蛋,自己域名能随时切后端。

按这套配下来,图床年费可以做到 $0,切换后端零成本。

← 返回文章