用 Docker 自建私有云相册:Immich 完整部署指南(2026 版)
手机里存了三年的照片,最后都去哪儿了?
大多数人的答案是云盘。但云盘这条路,走到后面总会撞上三堵墙:容量要续费、会员涨价、还有就是——你永远不确定那些私密照片被拿去做了什么。去年某网盘"AI 审核误删用户私人照片"的新闻闹了好几天,评论区一片哀嚎,删了就是删了,连个回滚按钮都没有。
所以这两年,"把照片搬回自己家"成了一股不小的潮流。而在这条路上,目前公认做得最完整的一套自建相册方案,叫 Immich。它不是网盘的替代品,而是冲着"自建版 Google Photos"去的:一样的时间线、一样的人脸聚类、一样的按内容搜索,唯一不同的是——数据躺在你自己的硬盘里,服务器关掉就谁也拿不走。
一、它到底能干什么
先别急着敲命令,先看清楚它能给你什么,值不值得你折腾一晚上。
| 能力 | 实际体验 |
|---|---|
| 手机相册自动备份 | iOS / Android 官方客户端,连上 Wi-Fi 后台自动传,支持"只备份新照片"和按相册选择 |
| 时间线浏览 | 按拍摄时间倒序排列,滚动加载,和手机相册几乎一样,10 万张也不卡 |
| 人脸识别 | 自动聚类出"这是谁",可以手动命名,之后按人筛选 |
| 语义搜索 | 输入"海边 日落""猫"这类自然语言就能搜到图,靠 CLIP 模型,不需要手动打标签 |
| 视频转码 | 把 iPhone 的 HEVC 视频转成浏览器能直接播的格式,支持显卡硬件加速 |
| 多用户 / 共享 | 可以给家人各开一个账号,互相隔离,也能建共享相册 |
| 外部库 | 不导入也行,直接挂载已有的照片目录,只读索引,原文件不动 |
| RAW 与实况照片 | CR2/NEF/ARW 等常见 RAW 格式可预览,iPhone 实况照片按视频+静态双份处理 |
| 回收站 | 删除先进回收站,30 天后才真删,手滑也有救 |
最新版本是 v3.3.5(2026 年 10 月),采用 AGPL-3.0 协议开源,服务端是 TypeScript,客户端是 Flutter,社区里已经有超过 11 万星标——这个量级说明一件事:它不是玩具。
二、部署前先想清楚三件事
1. 硬件
- 内存:4GB 是底线,8GB 会比较舒服。机器学习容器在跑人脸识别时很吃内存,2GB 的小鸡基本会 OOM。
- 硬盘:照片本体放机械盘没问题,但数据库一定要放 SSD。数据库里存的是缩略图的索引和向量,随机读写极多,放机械盘会让整个界面卡成 PPT。
- CPU:没有显卡也能跑。有人脸识别需求的话,第一次全量扫描会比较慢,十万张照片大概需要几个小时,之后就是增量的。
- 带宽:这是最容易被忽略的。手机在外面备份时,上传速度取决于你家宽带的上行。100M 下行 / 20M 上行的家庭宽带,传 2GB 视频大概要十几分钟。
2. 系统
Ubuntu 22.04 / 24.04、Debian 12 都行,其他发行版只要 Docker 版本够新也可以。下面以 Ubuntu 24.04 为例。
3. 域名与端口
手机客户端必须通过 HTTPS 访问,否则 iOS 会直接拒绝后台备份。所以你需要一个域名,并且能给它签发证书。纯 IP + HTTP 的玩法在手机上走不通,这一点先记住。
三、安装 Docker
apt update
apt install -y docker.io docker-compose-plugin
systemctl enable --now docker
docker --version
docker compose version
如果 `docker compose version` 报错,说明装的是旧版 compose,需要单独装 v2 插件。国内机器拉取镜像慢的话,配置一下镜像加速器,否则后面几个 GB 的镜像能让你等到天亮。
四、目录规划
建议单独划一个目录出来,把"程序"和"数据"分开。很多人图省事直接在家目录跑 compose,结果重装系统时把照片一起格了。
mkdir -p /opt/immich && cd /opt/immich
mkdir -p /data/immich/library /data/immich/postgres
这里的 /data/immich 建议挂一块独立的大盘。假如你打算存 10 年照片,按每年 100GB 算,准备 1TB 起步不会错。
五、写配置文件
先进目录,创建 .env:
cd /opt/immich
cat > .env <<'EOF'
# 照片实际存放位置
UPLOAD_LOCATION=/data/immich/library
# 数据库数据位置(务必放在 SSD 上)
DB_DATA_LOCATION=/data/immich/postgres
# 时区,影响时间线分组和日志时间
TZ=Asia/Shanghai
# 版本号,后续升级只需改这里
IMMICH_VERSION=v3
# 数据库密码,只能使用大小写字母和数字,不要用特殊符号
DB_PASSWORD=ChangeMeToSomethingLong2026
DB_USERNAME=postgres
DB_DATABASE_NAME=immich
EOF
那个密码别偷懒,长度至少 20 位。它只在容器内部使用,不需要你记住,但泄露了就等于数据库裸奔。
然后是 docker-compose.yml:
cat > docker-compose.yml <<'EOF'
name: immich
services:
immich-server:
container_name: immich_server
image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
volumes:
- ${UPLOAD_LOCATION}:/data
- /etc/localtime:/etc/localtime:ro
env_file:
- .env
ports:
- '2283:2283'
depends_on:
- redis
- database
restart: always
immich-machine-learning:
container_name: immich_machine_learning
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}
volumes:
- model-cache:/cache
env_file:
- .env
restart: always
redis:
container_name: immich_redis
image: docker.io/valkey/valkey:9
restart: always
database:
container_name: immich_postgres
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_USER: ${DB_USERNAME}
POSTGRES_DB: ${DB_DATABASE_NAME}
POSTGRES_INITDB_ARGS: '--data-checksums'
volumes:
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
restart: always
volumes:
model-cache:
EOF
四个容器,各司其职:
immich-server:主程序,Web 界面和 API 都在这里,对外暴露 2283 端口。immich-machine-learning:跑人脸识别和语义搜索模型的,最吃内存的一个。redis:任务队列。上传后生成缩略图、转码、识别,都是异步任务,靠它调度。database:PostgreSQL,注意这里用的是带 VectorChord 和 pgvector 扩展的专用镜像,普通 postgres 镜像跑不起来,别自作聪明换掉。
六、启动
docker compose up -d
# 看日志,等 immich_server 打出 "Immich Server is listening"
docker compose logs -f immich-server
第一次启动要下载镜像,加起来两三个 GB,慢是正常的。等四个容器都变成 Up 状态:
docker compose ps
然后浏览器打开 http://服务器IP:2283,会看到注册页面。第一个注册的账号自动成为管理员。
注册完先别急着传照片,进"管理"里把这两项配一下:
- 外部域名:填上你最终的 HTTPS 域名,生成分享链接时会用到。
- 机器学习:确认开关是打开的,否则人脸和语义搜索都不会工作。
七、上 HTTPS(这一步别省)
手机客户端强制要求 HTTPS,所以必须要有反向代理。用 Nginx 的话,配置大概长这样:
server {
listen 443 ssl;
http2 on;
server_name photo.example.com;
ssl_certificate /etc/letsencrypt/live/photo.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/photo.example.com/privkey.pem;
# 关键:视频上传动辄几个 G,默认 1M 会直接 413
client_max_body_size 0;
location / {
proxy_pass http://127.0.0.1:2283;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 关键:websocket,进度条和实时通知靠它
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 关键:不要缓冲请求体,否则大文件上传会先落盘再转发,白占一倍空间
proxy_request_buffering off;
proxy_buffering off;
proxy_read_timeout 3600s;
}
}
证书用 Let's Encrypt 免费签就行,自动续期脚本配好,别三个月后忘了续导致手机备份集体停摆——这个坑我见过不止一次。
八、手机端接入
iOS 在 App Store 搜 Immich,Android 可以装官方 APK 或从 F-Droid 获取。装好后:
- 服务器地址填
https://photo.example.com,注意别漏协议头。 - 登录你在网页上注册的账号。
- 进入"备份"设置,打开"前台备份"和"后台备份"。
- 选择要备份的相册——建议只选"相机胶卷",别把微信缓存的图片也一起备份进去,不然几万张垃圾图会把时间线淹没。
- 打开"仅在使用 Wi-Fi 时备份",除非你的流量不要钱。
第一次备份是最难熬的,几万张照片可能要跑一整夜。建议插上充电器,让手机保持亮屏或者干脆放一晚上。后台任务被系统杀掉是正常现象,重新打开 App 会自动续传。
九、日常运维
升级
作者更新很勤,几乎每周都有版本。升级前务必先看更新日志有没有数据库迁移,然后:
cd /opt/immich
docker compose pull
docker compose up -d
跨大版本(比如 v2 到 v3)时,官方通常会要求先升到某个中间版本,不能一步到位,这点别犟。
备份
照片文件本身是直接躺在磁盘上的,按 年月/日期 分目录存放,随便用 rsync 同步走就行。真正麻烦的是数据库,它记录着人脸、相册、标签、分享链接这些元数据。
# 停库再备份,热备份可能拿到不一致的数据
cd /opt/immich
docker compose stop database
docker run --rm -v /data/immich/postgres:/var/lib/postgresql/data \
-v /backup:/backup alpine tar czf /backup/pg-$(date +%F).tar.gz -C /var/lib/postgresql/data .
docker compose start database
数据库通常只有几百 MB 到几个 GB,建议每周一次,和照片目录一起同步到另一台机器或者离线硬盘上。不要只备份照片不备份数据库——那样恢复出来会是一堆没有名字、没有人脸、没有相册归类的裸图。
恢复
反过来,把 tar 包解回 /data/immich/postgres,确保目录属主是 postgres,再启动即可。版本必须和备份时一致,跨版本恢复会失败。
十、性能调优
显卡转码
有独立显卡(N 卡)或者带核显的 Intel CPU,可以开硬件转码,转码速度能快 5 到 10 倍。做法是在 compose 里给 server 挂载设备并加一段 extends,常见选项是 nvenc(N 卡)、quicksync(Intel 核显)、vaapi(通用 Linux)和 rkmpp(瑞芯微 ARM 板子)。
需要注意的是,Intel 核显直通要装 intel-media-va-driver,并且容器里要能看到 /dev/dri/renderD128,看不到就是没直通成功。
机器学习加速
同理,机器学习容器也有 cuda、rocm、openvino 等变体。如果你有显卡,换对应 tag 后,十万张照片的人脸扫描能从几小时压到几十分钟。
缩略图缓存
缩略图存放在上传目录下的 thumbs 子目录里,数量会比原图多得多(一张图可能生成 3 种尺寸)。所以实际占用空间通常是原图的 1.2 到 1.5 倍,规划容量时记得算进去。
十一、几个我踩过的坑
- 上传到一半报 413:Nginx 的
client_max_body_size没改。设成 0 表示不限制。 - 手机备份一直"等待中":九成是反向代理没开 websocket,进度推送收不到。
- 时间线全部显示成同一天:容器时区没设,或者照片本身没有 EXIF 时间。可以在后台开"根据文件名推断日期"。
- 人脸识别一直转圈:机器学习容器内存不够被 OOM 杀了,
docker ps -a看退出码 137 就是它。 - 数据库放机械盘后界面卡死:前面说过,这是硬伤,没法优化,只能换盘。
- 升级后打不开:多半是跨版本升级没走中间版本,数据库迁移卡住了。这种情况只能回滚到旧镜像,再按官方路径一步步升。
- 外部库照片重复:既导入了又挂了外部库,同一张图会出现两次。二选一。
- 磁盘满了导致数据库崩溃:Postgres 在磁盘写满时会直接拒绝服务,甚至损坏数据页。建议挂个磁盘监控,超过 85% 就报警。
十二、和商业方案比,值不值
| 对比项 | 自建 Immich | 商业云相册 |
|---|---|---|
| 成本 | 服务器年费 + 电费,一次性买盘后边际成本接近 0 | 按容量订阅,越用越贵 |
| 隐私 | 数据在自家硬盘,服务商看不到 | 依赖服务商政策,存在审核和误删风险 |
| 稳定性 | 硬盘坏了就是坏了,取决于你有没有备份 | 多副本容灾,基本不会丢 |
| 上手难度 | 要会敲命令,要懂点 Docker | 注册即用 |
| 维护成本 | 升级、备份、监控都得自己来 | 零 |
说句实在话:自建不是给所有人准备的。如果你一年拍不到两千张照片,商业云盘那点钱花得值。但如果你有几十万张照片、几个 T 的视频、又对隐私有要求,那这套方案的天花板明显更高——尤其是它支持"外部库",可以直接挂载你已有的照片目录,不导入、不改动原文件,只做索引,试错成本几乎为零。
先挂个外部库试试水,觉得顺手了再考虑全量导入。这是最稳妥的姿势。
至于硬件怎么选、备份怎么做、要不要上显卡——如果你也在折腾自建服务,本站后面还会陆续写几篇同样方向的实战记录,包括文件同步、内网穿透和证书自动化,都是从零踩坑踩出来的东西。






