用阿里云oss自托管一个摄影相册afilmory
为什么要自托管一个摄影相册
买了相机拍了一些照片之后,还是想找个地方好好存照片,最好还能优雅地展示出来。
最开始查的一些方案,在v2ex等地方搜索,大家都还是用piwigo、immich、photoprism这些老牌的应用,技术成熟,但是据我所试是自托管基本只能把图片放在本机了,想在国内访问速度快,一个服务器加个域名备案,性能稍微差点的还体验不到一些功能(例如immich的人脸识别,机器学习等),目前阿里云、腾讯云的这些服务器要有个大点的SSD做存储还是挺贵的,动辄一个月大几百。
也考虑过exif-photo-blog、thumbsup)这样优秀的项目,还有UI流畅的mtphoto(可惜闭源,访问相册也得输入账号密码,不适合公开访问)
最终还是选择了:
Afilmory,一个零数据库的照片相册系统,照片存 OSS,配置存 JSON,前端静态化部署。重点是:
- ✅ 自动提取 EXIF 信息(拍摄时间、地点、相机型号等)
- ✅ 自动生成缩略图
- ✅ 支持按时间线、地图、相机分类浏览
- ✅ iPhone 直接用阿里云 App 上传照片,自动触发构建
- ✅ 成本低
- ✅ 支持实况照片
- ✅ 瀑布流 or 列表视图展示
搭完之后,从 iPhone 上传照片,30 秒后自动出现在相册里,还挺爽的。
这个项目自2025-09开源重构后,算是比较新的一个优秀相册,真的挺值得尝试的!
其实aflimory还推荐以下两种方式搭建:
选项 1:官方 SaaS(推荐)
👉从 aflimory.art 开始 - 零设置,几分钟内上线!
创建照片库的最简单方法。无需部署、无需服务器、无需维护。
优点:
✅ 零配置 - 注册并立即上线
✅ Live CMS - 实时编辑照片、标题和元数据
✅ 自定义域名 - 通过 DNS 验证绑定自己的域名
✅ 自动更新 - 始终运行最新功能
✅ 托管基础设施 - 作者和他的小伙伴们负责扩展、备份和维护
选项2: Docker部署
详见文档:
手动安装
这篇文档我采用手动安装的方式,想着之后可能会对项目代码有点改动方便点
准备工作
环境要求
- 一台 VPS(Ubuntu 20.04+ / Debian 12 +,1C2G、2C2G够用),轻量应用服务器便宜也够用
- 阿里云 OSS(存照片用,按量付费)
- 域名(备案前也能用 IP 访问,备案后可上 CDN)
重要提醒
域名备案前后的部署方式不同:
- 备案前:VPS 跑 SSR 应用(Next.js),用服务器 IP 访问
- 备案后:可迁移到 OSS 静态托管 + CDN 加速,速度更快成本更低
如果你的域名还没备案,先按本文搭建 SSR 模式,备案成功后再迁移到静态托管(我会在文末说明)。
操作流程
按照本文顺序,你会先在阿里云控制台完成所有云端配置,然后 SSH 登录服务器部署应用,最后测试完成。
一、阿里云 OSS 配置
先把阿里云控制台的配置一次性做完,后面就不用来回切换了。
1.1 创建 Bucket
登录阿里云控制台(https://oss.console.aliyun.com/),创建 OSS Bucket:
基本信息:
- Bucket 名称:
afilmory-xxx(全局唯一,可以用afilmory-你的昵称) - 区域:成都(或选离你最近的区域,影响访问速度)
- 存储类型:标准存储
- 同城冗余存储:不开启(个人相册不需要)
读写权限(注意):
- 选择 公共读(允许匿名用户读取,但只有授权用户可以写入)
- ⚠️ 别选”私有”,否则照片无法通过 URL 访问
- ⚠️ 别选”公共读写”,有安全风险
其他设置:
- 版本控制:不开启(节省费用)
- 服务端加密:不开启(照片无需加密)
- 实时日志查询:不开启(非必需)
点击”确定”创建 Bucket。
权限说明:
- 公共读:任何人都可以通过 URL 查看照片(适合相册场景)
- 如果设置为”私有”,需要签名 URL 才能访问,会增加复杂度和成本
- 后续可以通过 Referer 防盗链限制访问来源(第七章说明)
1.2 创建目录结构
进入刚创建的 Bucket,点击”文件管理”,手动创建以下目录:
photos/- 存放原始照片(从 iPhone 上传到这里)thumbnails/- 存放缩略图(Builder 自动生成后上传)
也可以先不创建,直接上传照片到 photos/ 目录,OSS 会自动创建。
1.3 配置 CORS(跨域访问)
OSS 控制台 → 数据安全 → 跨域设置 → 创建规则:
- 来源:
*(允许所有来源,也可以填写你的域名) - 允许 Methods:勾选
GET和HEAD - 允许 Headers:
* - 暴露 Headers:
ETag(可选) - 缓存时间:
600秒
点击”确定”保存。
如果不配置 CORS,前端从浏览器直接访问 OSS 照片时会报跨域错误。
1.4 创建 RAM 用户(获取 AccessKey)
访问控制 RAM 控制台(https://ram.console.aliyun.com/),创建专用账号:
步骤 1:创建用户
- 点击”身份管理” → “用户” → “创建用户”
- 登录名称:
afilmory - 显示名称:
Afilmory 照片相册 - 访问方式:勾选 OpenAPI 调用访问(会生成 AccessKey)
- ⚠️ 不要勾选”控制台访问”(不需要登录控制台)
步骤 2:授予权限
- 创建后点击”添加权限”
- 选择权限:
AliyunOSSFullAccess(OSS 完全访问权限) - 点击”确定”
步骤 3:保存 AccessKey
- 创建完成后会显示 AccessKey ID 和 AccessKey Secret
- ⚠️ AccessKey Secret 只显示一次,务必复制保存到安全的地方
- 建议保存到密码管理器或本地加密文件
安全提示:
- AccessKey 相当于账号密码,不要泄露给他人
- 不要提交到 GitHub 等公开代码仓库
- 如果泄露,立即在 RAM 控制台禁用或删除该 AccessKey
1.5 配置 OSS 事件通知
配置完 OSS 事件通知后,iPhone 上传照片就能自动触发构建,无需手动操作。
步骤 1:创建 OSS 事件通知规则
OSS 控制台 → 事件通知 → 创建规则:
- 规则名称:
photo-upload-notification - 事件类型:勾选以下事件(支持上传、删除、重命名)
- ObjectCreated 类型(上传、复制):
ObjectCreated:PutObject- 简单上传ObjectCreated:PostObject- 表单上传ObjectCreated:CopyObject- 复制对象(重命名第1步)ObjectCreated:CompleteMultipartUpload- 分片上传完成
- ObjectRemoved 类型(删除,可选):
ObjectRemoved:DeleteObject- 删除对象(支持删除照片和重命名第2步)
- ObjectCreated 类型(上传、复制):
- 资源描述:前缀
photos/ - 接收终端:消息服务 MNS 主题(创建新主题
afilmory-oss-events)
说明:
- 如果只需要上传功能,可以只勾选
ObjectCreated类型的 4 个事件 - 如果需要支持删除照片或重命名功能,还要勾选
ObjectRemoved:DeleteObject - iPhone 通过阿里云 App 上传通常使用
PutObject(小文件)或CompleteMultipartUpload(大文件)
步骤 2:创建 MNS 订阅
消息服务 MNS → 主题管理 → 订阅:
- 订阅名称:
webhook-subscription - 推送类型:HTTP
- 接收终端地址:
http://你的服务器IP/webhook/oss(暂时填写,部署后会用到) - 重试策略:EXPONENTIAL_DECAY_RETRY
注意:部署完服务器后,记得回来把”接收终端地址”改成实际的服务器 IP。
二、服务器环境配置
现在切换到服务器端,SSH 登录后开始配置环境。
2.1 安装基础软件
1 | |
2.2 安装并配置 ossutil
1 | |
按提示填入(使用第一章保存的 AccessKey):
- 配置文件路径:直接回车(使用默认
~/.ossutilconfig) - Endpoint:
oss-cn-chengdu.aliyuncs.com(根据你的 OSS 区域填写)- 成都:
oss-cn-chengdu.aliyuncs.com - 北京:
oss-cn-beijing.aliyuncs.com - 上海:
oss-cn-shanghai.aliyuncs.com - 杭州:
oss-cn-hangzhou.aliyuncs.com
- 成都:
- AccessKeyId:粘贴第一章保存的 AccessKey ID
- AccessKeySecret:粘贴第一章保存的 AccessKey Secret
测试连接:
1 | |
如果能正常列出文件(或显示为空),说明配置成功。
三、部署 Afilmory(SSR 模式)
3.1 克隆项目
1 | |
3.2 配置环境变量
创建 /root/projects/afilmory/.env:
1 | |
重要:
- 必须填写
S3_REGION和S3_ENDPOINT,否则会使用 AWS S3 的默认值导致连接失败 S3_ACCESS_KEY_ID和S3_SECRET_ACCESS_KEY填入第一章保存的 AccessKeyS3_BUCKET_NAME填入你创建的 Bucket 名称(如afilmory-specialhua)
3.3 配置站点信息
编辑 /root/projects/afilmory/config.json:
1 | |
备案前用 http://IP,备案后改为 https://你的域名.com
3.4 首次运行 Builder
1 | |
Builder 会:
- 连接 OSS 读取
photos/目录 - 下载照片生成缩略图
- 创建
apps/web/src/data/photos-manifest.json
3.5 上传 manifest 到 OSS
1 | |
3.6 启动应用
1 | |
3.7 配置 Nginx
创建 /etc/nginx/sites-available/afilmory:
1 | |
1 | |
现在访问 http://你的IP 就能看到相册了。
四、Webhook 自动化构建
每次手动跑 Builder 太麻烦,用AI写了个Webhook,可以实现:iPhone 上传照片 → OSS 事件通知 → 自动构建 → 相册更新
有时候连服务器看日志挺麻烦的,直接webhook一个构建状态可以随时查看
4.1 创建 Webhook 服务
1 | |
创建 /root/webhook-service/webhook-server.js:
1 | |
配置说明:
- 脚本开头的
CONFIG对象包含所有需要自定义的配置 - 修改
bucket为你的 OSS Bucket 名称 - 修改
projectDir为你的项目目录(如果不是/root/projects/afilmory) - 修改
buildScript为构建脚本的完整路径 buildDelay是防抖延迟时间(默认 30 秒),可根据需要调整
核心功能:
- ✅ Base64 解码:自动处理 OSS 通过 SMQ 发送的 Base64 编码消息
- ✅ 30秒防抖:多张照片上传、重命名(复制+删除)只触发一次构建
- ✅ 构建队列:防止并发构建,失败后自动重试
- ✅ Web 监控界面:访问
http://你的IP/webhook查看实时状态 - ✅ 日志脱敏:自动隐藏 AccessKey、IP、路径等敏感信息
- ✅ 构建历史:记录最近 10 次构建状态(成功/失败/进行中)
- ✅ 健康检查:提供
/webhook/health接口供监控使用
4.2 创建构建脚本
创建 /root/webhook-service/build-afilmory.sh:
1 | |
配置说明:
- 脚本开头的配置区域包含了所有需要自定义的变量
- 修改
OSS_BUCKET为你的 Bucket 名称 - 如果项目目录不在
/root/projects/afilmory,修改PROJECT_DIR - 如果 PM2 应用名称不是
afilmory,修改PM2_APP_NAME
1 | |
4.3 启动 Webhook 服务
1 | |
4.4 配置 Nginx(添加 webhook 路由)
编辑 /etc/nginx/sites-available/afilmory,在 server 块中添加:
1 | |
说明:
/webhook/oss:仅允许 POST 请求,用于接收 OSS 事件通知/webhook/:管理界面和 API 接口(状态、日志、健康检查),日志已自动脱敏- 所有接口都监听在
127.0.0.1,只能通过 Nginx 访问,外部无法直接访问
1 | |
4.5 测试
方法 1:查看 Web 管理界面
浏览器访问 http://你的服务器IP/webhook,可以看到:
- 实时构建状态(空闲/构建中)
- 服务运行时间
- 最近 5 次构建历史
- 快捷链接(状态 JSON、日志、健康检查)
界面每 10 秒自动刷新,方便实时监控。
方法 2:查看 PM2 日志
1 | |
方法 3:上传照片测试
iPhone 上传一张照片到 OSS 的 photos/ 目录,等待 30 秒,观察 Web 界面或日志:
1 | |
刷新浏览器,新照片就出现了。
提示:
- 访问
http://你的IP/webhook/logs可以查看最近 100 行日志(已自动脱敏) - OSS 事件通知已在第一章配置完成,上传照片就会自动触发
五、使用体验
日常使用流程:
- iPhone 打开阿里云 App(App Store 搜索”OSS”)
- 进入
photos/目录,这里最好使用文件上传,因为OSS调用的是IOS的图库选择器,IOS有严格的照片分享机制,会把exif信息给隐藏掉,而我们搭建的摄影相册还是挺系统把镜头、光圈信息等展现出来的。可以在相册里提前把要上传的图片共享——保留原始信息存储到文件,建个文件夹之类的,并且把名字命好,上传后照片的名字就读取的文件名 - 等 30 秒(防抖时间)
- 刷新网页,新照片自动出现
实测从上传到显示约 40-60 秒,完全可以接受。缩略图加载很快(100KB 左右),原图按需加载(5MB+)。
六、常见问题
6.1 照片上传后不显示
1 | |
6.2 Webhook 未触发
1 | |
6.3 Nginx 502 错误
1 | |
七、备案后优化(可选)
域名备案完成后,可以进行一些优化:配置防盗链、启用 CDN 加速、迁移到静态托管等。
7.1 配置 Referer 防盗链
OSS 控制台 → 数据安全 → 防盗链:
- 类型:白名单
- Referer 列表:
1
2
3
4https://你的域名.com
https://你的域名.com/*
http://你的域名.com
http://你的域名.com/* - 允许空 Referer:建议不勾选(防止直接访问)
配置后,只有从你的域名访问的用户才能加载照片,防止别人盗链。
7.2 配置 CDN 加速(可选)
如果觉得 OSS 直连速度慢,可以配置 CDN 加速:
步骤 1:创建 CDN 域名
CDN 控制台 → 域名管理 → 添加域名:
- 加速域名:
cdn.你的域名.com - 业务类型:图片小文件
- 源站类型:OSS 域名
- 源站域名:
afilmory-xxx.oss-cn-chengdu.aliyuncs.com
步骤 2:配置 HTTPS 证书
CDN 控制台 → cdn.你的域名.com → HTTPS 配置:
- 上传 SSL 证书或使用免费证书
- 开启强制 HTTPS 跳转
步骤 3:配置缓存规则
CDN 控制台 → 缓存配置 → 缓存规则:
- 缩略图(
.webp):缓存 7 天 - 原图(
.jpg, .jpeg, .png):缓存 1 天 - Manifest(
.json):缓存 5 分钟
步骤 4:更新项目配置
编辑 /root/projects/afilmory/.env:
1 | |
重启应用:
1 | |
7.3 迁移到 OSS 静态托管
如果想降低成本,可以从 SSR 模式迁移到 OSS 静态托管。
步骤 1:修改配置
1 | |
步骤 2:构建静态站点
1 | |
步骤 3:上传到 OSS
1 | |
步骤 4:配置 OSS 静态网站托管
OSS 控制台 → 基础设置 → 静态页面:
- 默认首页:
index.html - 默认 404 页:
404.html
步骤 5:绑定域名 + SSL
OSS 控制台 → 传输管理 → 域名管理 → 绑定域名 → 上传 SSL 证书。
步骤 6:停止 SSR 服务(可选)
1 | |
保留 webhook 服务!备案后仍然需要自动构建功能。
后记
折腾了两天总算搭好了,考虑到是相机原图,所以还是得选择国内备案+oss来搭建,aflirmory目前是我最满意的方案,适合摄影作品、后端OSS无数据库,以后迁移也方便。
成本方面,构建用的服务器2C2G之类的,有活动几十块钱拿一个一年的完全够用,主要还是的OSS的存储和CDN的费用,跟我一样看重速度的还是看个人需求吧。
Afilmory 还在活跃开发中,作者 @meetqy 更新很频繁,后续可能会支持更多功能(比如人脸识别、视频支持等)。
有个自己的相册,不妨试试自托管吧
参考资料