给自己写了个图床:轻图床 picbed

最近手头多了台小服务器,1 核 / 1G 内存 / 240G 硬盘,想拿来当图床。先看了两个现成方案:Lsky Pro 功能全,但要 PHP + MySQL 这一套,对 1G 内存的机器来说太重;quickly-picture-bed 轻一些,但有些细节不合我的想法。最后干脆自己用 Go 写了一个,取名 轻图床 picbed,现在已经跑在 img.owo.name 上了。这篇把设计和部署方法都记下来,给自己留个档,也供有同样需求的人参考。

它是什么样

  • 单二进制,约 13MB:前端页面全部内嵌进程序,运行时只需要一个数据目录,不依赖数据库服务、不依赖 Docker,扔服务器上就能跑。
  • 存储:元数据存 SQLite(纯 Go 驱动),图片文件按 年/月/日 分目录存磁盘,文件名是 16 位随机串,链接不可猜测。
  • 上传:支持多图、拖拽、粘贴上传;上传成功后给出直链、Markdown、HTML、BBCode 四种格式一键复制。
  • 防滥用:每个 IP 每天最多上传 100 张(可调),提交前整单预检,超限直接拒绝;文件校验只认内容:魔数嗅探定真实格式,只放行 jpg/png/gif/webp/avif/bmp/ico(文件名叫什么都行,按真实格式存);单文件上限 20MB。
  • 管理后台:/adminimgloc,密码登录(失败 5 次锁 10 分钟),能看概览统计、按日期和 IP 筛选、按文件名搜索图库、单张或批量删除图片;另有「设置」页,集中管下面这些功能的开关和上传令牌。
  • 秒传去重:按文件内容的 SHA-256 判重,同一张图重复上传直接返回已有链接,不重复占空间,也不扣每日额度;后台能看到累计命中次数和省下的空间。
  • 令牌接口:后台自动生成上传令牌,PicGo、Typora 这类客户端带上令牌(请求头或表单字段都行)上传即视为可信请求,不受每日限额限制;令牌不对直接 401。
  • 自助删除:每次上传都会附一个专属删除链接,再加结果卡片上的删除按钮,上传者自己就能删掉刚传的图,不用麻烦管理员。
  • 保存期限:上传时可选永久 / 1 / 7 / 30 / 90 天,到期自动清理文件和记录(启动时和每 10 分钟各扫一轮)。
  • 界面:毛玻璃风——彩色光晕打底、半透明玻璃面板,苹果味比较浓;另外有单独的「常见问题」和「服务条款」页,规则都写明了。
  • 缩略图:jpg/png/gif 首次请求时生成 400px 缩略图并缓存;webp、avif 这类 Go 标准库解不了的格式直接回原图。

部署教程

1. 直接运行

从源码构建需要 Go 1.23+:

1go build -trimpath -ldflags "-s -w" -o picbed .

构建完(或者拿到现成的二进制)直接跑:

1PORT=8080 DATA_DIR=/var/lib/picbed ADMIN_PASSWORD='换成你的密码' ./picbed

然后访问 http://服务器:8080/ 是上传页,http://服务器:8080/adminimgloc 是后台。如果没设 ADMIN_PASSWORD,程序会自动生成一个随机密码写到数据目录的 admin-password.txt 里,记得去拿。

2. 配置项(全部是环境变量)

变量默认值说明
PORT8080监听端口
DATA_DIR./data数据目录,图片和 SQLite 库都放这里
SITE_NAME轻图床站点名称
ADMIN_PASSWORD空后台密码,库里只存加盐哈希
MAX_FILE_MB20单文件大小上限
DAILY_LIMIT100每个 IP 每天上传上限
TRUST_PROXYtrue是否信任反代头来识别访客 IP

3. 用 systemd 常驻

 1# /etc/systemd/system/picbed.service
 2[Unit]
 3Description=Picbed image host
 4After=network.target
 5
 6[Service]
 7Type=simple
 8WorkingDirectory=/opt/picbed
 9ExecStart=/opt/picbed/picbed
10Environment=PORT=8080
11Environment=DATA_DIR=/opt/picbed/data
12Environment=ADMIN_PASSWORD=换成你的密码
13Restart=on-failure
14
15[Install]
16WantedBy=multi-user.target
1sudo systemctl daemon-reload && sudo systemctl enable --now picbed

4. 绑域名和 HTTPS(两种方式,任选)

方式一:反代。 前面挂 Caddy 或 Nginx 终结 HTTPS 再转发到程序端口。注意反代必须正确设置 X-Forwarded-For(Caddy 默认就对;Nginx 要写 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;,另外 client_max_body_size 要不小于 MAX_FILE_MB,比如 25m)。如果你是程序直连公网、没有反代,把 TRUST_PROXY 设成 false,防止有人伪造转发头绕过每日限额。

方式二:Cloudflare 橙云(我现在用的)。 域名 DNS 托管在 Cloudflare,把 A/AAAA 记录指向服务器并开橙云代理,SSL 模式选「灵活」(源站只提供 HTTP);程序直接监听 80 端口即可,访客侧自动就是 HTTPS,还能顺带藏源站、挡一部分乱七八糟的流量。纯 IPv6 的服务器也完全没问题,Cloudflare 会帮 IPv4 访客做转换。我在源站还多做了两步:一是防火墙只放行 Cloudflare 的 IP 段访问 80 端口,想绕过 CF 直连源站没门,顺便堵死伪造转发头绕过每日限额的路子;二是图片响应带一年的 immutable 缓存头,再配上 Cloudflare 的缓存规则和分层缓存,图片基本都从边缘节点出,回源很少,这台 1 核小机器轻松得很。

5. 日常使用

打开首页,点选、拖拽或直接粘贴图片就上传,传完复制需要的外链格式即可;上传时顺手选一下保存期限,传错了用删除链接自己删。管理进 /adminimgloc:概览能看到总图片数、占用空间和今日上传量;图库可以翻页、筛选、搜索和删图。常写 Markdown 的话,去后台「设置」页把上传令牌填进 PicGo,之后截图自动上传、链接直接进剪贴板,写博客配图效率拉满。想改密码或限额,改 systemd 里的环境变量后重启服务生效。

已知局限

  • webp / avif 的缩略图会回退成原图,不影响使用,就是后台图库加载稍大一点;
  • 登录会话是内存态,程序重启后需要重新登录后台。

结尾

240G 的盘、每天 100 张/IP 的限额,自用和给朋友用都绰绰有余。这类小工具自己写最大的好处是刚刚好:没有用不上的功能,也没有养不起的依赖。图床地址:https://img.owo.name,欢迎来传图试试。

彩蛋:图床的站点图标和这个博客的头像,现在都是小天(帮我搭这一切的 AI 助手)的头像,算是个签名吧。