这是「Docker 好项目」系列的第 4 期。每期挑一个真正能在自己服务器上跑起来、并且能解决具体问题的项目,给出能直接复制的配置。
手机相册满了,iCloud 和各大云盘开始按月收费;照片存在别人服务器上,你想按「去年在海边」这种话搜一张图,就得把整段人生交给对方的算法;更实际的问题是,一旦哪天服务商涨价、改规则或者停服,你的照片要搬家,导出来的是一堆丢了一半时间信息的压缩包。
Immich 解决的就是这件事。它是一个自托管的照片与视频管理服务,手机装个 App 就能自动备份相册,网页端有完整的时间线和智能搜索,人脸识别、语义搜索、地图、"回忆"这些 Google Photos 上的体验它基本都有——区别是全部跑在你自己的机器上,原始文件就是磁盘上的普通文件,随时 rsync 走人。

这个项目目前的规模是 11.4 万 star、AGPL-3.0 协议,2022 年启动,2024 年加入 FUTO 后核心团队全职开发,迭代速度快到有点夸张:v2.0.0 是 2025 年 10 月的首个稳定版,v3.0.0 在 2026 年 7 月带来工作流、HLS 流媒体和移动端无损编辑,本文写作时的最新版是 v3.2.2(2026 年 9 月 15 日发布)。
它到底能干什么
先把能力边界说清楚,避免部署完发现不是自己要的。
能做的:
- 手机自动备份:iOS / Android 官方 App,后台备份,支持选择相册、仅在 Wi-Fi 下上传、原画质或省空间
- 智能搜索与人脸识别:CLIP 模型做语义搜索(输入「海边的日落」能找到对应照片),InsightFace 做人脸聚类,OCR 能识别图片里的文字
- 外部库(External Library):直接挂载你已经存在的照片目录,只读导入,不移动不复制原文件——这个功能对已经有 NAS 照片库的人很关键
- 多用户:家人各自一个账号,相册可共享,伴侣共享(Partner Sharing)
- 存储模板:可以指定原始文件在磁盘上的目录结构,比如按
年/月/日归档,方便你自己直接访问文件 - 工作流(v3 新增):类似自动化规则,按条件自动打标签、归档、整理相册
它不做的:
- 不做共享媒体库。所谓"家庭共享"目前是共享相册 + 伴侣共享,不是 Google Photos 那种 6 人共用一个库、时间线自动合并的效果。官方明确把这块架构改动冻结了,说要设计好了再做,短期内别指望
- 不做跨设备的实时协作,也不提供企业级 SSO / LDAP / 合规审计
- 不替你做备份。Immich 是照片的"家",不是备份方案。相册、人脸、元数据全在 PostgreSQL 里,丢了就得重新识别一遍
还有一个必须提前知道的前提:它比前几期推荐的项目都重。官方硬件要求是最低 6GB 内存 + 2 核,推荐 8GB + 4 核,得同时跑 4 个容器(服务端、机器学习、PostgreSQL、Valkey)。4GB 的机器能跑,但要关掉机器学习容器,代价是没有人脸识别和语义搜索——这一条下面会详细说。
部署前准备
先确认 Docker 和 Compose 插件:
docker --version
docker compose version
注意必须是 docker compose(V2 插件,中间是空格),不是老式的 docker-compose。Immich 官方明确说了旧版不兼容,用 docker-compose 会报 The Compose file is invalid because: 'name' does not match any of the regexes。
然后确认三件事:
- 磁盘空间要按照片总量 × 1.2 算。官方说明缩略图和转码视频会让库体积增加 10~20%,别卡着容量部署
- 内存。跑
free -h看一眼。低于 6GB 建议直接按后面的"低配方案"来 - 端口 2283。Immich 服务端默认监听 2283,这是 HTTP,HTTPS 交给反向代理。华为云这类云主机的安全组里不需要放行 2283,只放行 80 和 443
方式一:三条 docker run 快速尝鲜
Immich 不像前几期的项目能单容器跑,它必须依赖 PostgreSQL 和 Valkey(Valkey 是 Redis 的开源分叉,官方 compose 里用的就是它)。所以"一行版"实际是三条命令,好处是不用先建目录和配置文件,适合想先看看界面的人:
docker network create immich
docker run -d --name immich_postgres --network immich --restart always \
-e POSTGRES_PASSWORD=换成你的强密码 \
-e POSTGRES_USER=postgres \
-e POSTGRES_DB=immich \
-e POSTGRES_INITDB_ARGS='--data-checksums' \
-v /opt/immich/postgres:/var/lib/postgresql/data \
--shm-size=128mb \
ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0
docker run -d --name immich_valkey --network immich --restart always \
docker.io/valkey/valkey:9
docker run -d --name immich_server --network immich --restart always \
-p 2283:2283 \
-e DB_HOSTNAME=immich_postgres \
-e DB_USERNAME=postgres \
-e DB_PASSWORD=换成和上面一样的密码 \
-e DB_DATABASE_NAME=immich \
-e REDIS_HOSTNAME=immich_valkey \
-e IMMICH_MACHINE_LEARNING_ENABLED=false \
-e TZ=Asia/Shanghai \
-v /opt/immich/library:/data \
-v /etc/localtime:/etc/localtime:ro \
ghcr.io/immich-app/immich-server:v3.2.2
几点解释:
POSTGRES_INITDB_ARGS='--data-checksums'是官方 compose 里带的,开启数据校验和,能在磁盘出问题早点发现--shm-size=128mb必须给,PostgreSQL 默认 64MB 共享内存在处理大批量导入时不够用IMMICH_MACHINE_LEARNING_ENABLED=false是这一版没有启机器学习容器,所以要在服务端明确关掉,否则后台任务会一直重试连接 ML 并报错- 等到能登录了,再往下看正式方案。不要把这套当长期方案,升级和备份都麻烦
访问 http://服务器IP:2283 能看到注册页面就说明起来了。
方式二:docker-compose(推荐)
正式用必须写成文件。Immich 官方把 compose 和 .env 都放在 release 里,直接下载当前版本的即可,不要从 main 分支拉——main 上的 compose 可能和最新 release 不兼容。
mkdir -p /opt/immich && cd /opt/immich
wget -O docker-compose.yml https://github.com/immich-app/immich/releases/download/v3.2.2/docker-compose.yml
wget -O .env https://github.com/immich-app/immich/releases/download/v3.2.2/example.env
下载不动的话(国内服务器访问 GitHub release 经常抽风),可以在本地浏览器打开
https://github.com/immich-app/immich/releases/latest手动下载这两个文件再传上去,注意example.env要改名为.env。
然后把 .env 改成下面这样。这是全文最关键的一个文件,所有路径和版本都在这里控制:
# 照片和视频原始文件的存放位置,写得下多少照片就给它多大空间
UPLOAD_LOCATION=/opt/immich/library
# PostgreSQL 数据目录。必须在本机磁盘上,不能是网络共享(NFS/SMB)
DB_DATA_LOCATION=/opt/immich/postgres
# 时区,影响日志时间、定时任务,以及照片元数据里读不出时区时的兜底
TZ=Asia/Shanghai
# 镜像 tag。官方默认是 v3(滚动主版本),这里钉死到具体版本
# 升级时手动改这个数字,出问题能一眼知道回退到哪
IMMICH_VERSION=v3.2.2
# 数据库密码,只用于容器间本地认证,不会被公网访问
# 只能用 A-Za-z0-9,不要带特殊字符和空格,否则 Docker 解析会出错
DB_PASSWORD=换成一长串随机字母数字
# 下面三行一般不用改
DB_USERNAME=postgres
DB_DATABASE_NAME=immich
生成密码:
openssl rand -base64 24 | tr -d '/+=' | head -c 20; echo
官方默认的 docker-compose.yml 内容如下(v3.2.2 版本,逐项和官方一致):
name: immich
services:
immich-server:
container_name: immich_server
image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
volumes:
# 不要改这一行。要换媒体存放位置,改 .env 里的 UPLOAD_LOCATION
- ${UPLOAD_LOCATION}:/data
- /etc/localtime:/etc/localtime:ro
env_file:
- .env
ports:
- '2283:2283'
depends_on:
- redis
- database
restart: always
healthcheck:
disable: false
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
healthcheck:
disable: false
redis:
container_name: immich_redis
image: docker.io/valkey/valkey:9
healthcheck:
test: redis-cli ping | grep -q PONG || exit 1
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'
# 数据库不在 SSD 上时,把下面这行的注释去掉
# DB_STORAGE_TYPE: 'HDD'
volumes:
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
shm_size: 128mb
restart: always
healthcheck:
disable: false
volumes:
model-cache:
启动:
docker compose up -d
docker compose logs -f immich-server
看到 Immich Server is listening on ... 就起来了。第一次启动会慢一些,服务端要跑数据库迁移。
几个配置项为什么要这么写
| 配置 | 说明 |
|---|---|
IMMICH_VERSION=v3.2.2 |
官方 .env 默认给的是 v3,也就是滚动跟随 3.x 大版本。想省心可以用 v3,但绝不要用 release 或 latest——Immich 迭代太快,跨大版本升级偶尔有破坏性改动,钉死版本号才能在出问题时精确回退 |
ghcr.io/immich-app/... |
镜像托管在 GitHub Container Registry,不在 Docker Hub。国内服务器拉取经常超时,这是最容易卡住的一步,解决办法见踩坑清单 |
${UPLOAD_LOCATION}:/data |
容器内固定是 /data。想改宿主机路径请改 .env,不要动冒号右边。老教程里写的 /usr/src/app/upload 是 v1.x 的路径,早废了 |
${DB_DATA_LOCATION}:/var/lib/postgresql/data |
数据库目录必须在本机 SSD。官方明确说网络共享存数据库会有性能和数据丢失风险;照片文件本体倒是可以放网络盘 |
postgres:14-vectorchord0.4.3-pgvectors0.2.0 |
这是 v3 的一个大变化:向量检索从 pgvecto.rs 换成了 VectorChord。v3.0.0 起不再支持 pgvecto.rs,从 v1.133.0 之前升级上来要按官方升级指南走 |
valkey:9 |
不是 Redis,是 Valkey(Redis 分叉出来的开源 fork),官方 v3 的 compose 就是它。改名只是历史原因,行为对 Immich 来说一致 |
DB_PASSWORD |
官方文档要求只用 A-Za-z0-9。带特殊字符时 Docker 和 Postgres 的解析方式不一致,会出现"密码明明对但连不上"的怪事 |
TZ=Asia/Shanghai |
不只是日志时间。Immich 用 exiftool 抽取照片元数据,读不出时区时用它兜底;定时任务(比如"回忆"生成)也按它跑 |
shm_size: 128mb |
PostgreSQL 默认 64MB 共享内存,大批量导入时会报 could not resize shared memory segment,加上这行基本能避免 |
model-cache:/cache |
机器学习模型下载在这里,默认模型约几百 MB 到 1GB 多。删掉这个卷只是重新下载,不影响照片 |
/etc/localtime:/etc/localtime:ro |
保证容器时间和宿主机一致 |
在 1Panel 里怎么搞
1Panel 用户推荐走编排,因为 Immich 是 4 个服务的应用,应用商店版本容易落后于官方 release:
- 容器 → 编排 → 创建编排,名称填
immich,把上面的docker-compose.yml整段贴进去 - 1Panel 的编排目录就是工作目录,所以
.env里的路径建议写绝对路径(/opt/immich/library而不是./library),避免找不到挂载点 - 环境变量在 1Panel 编排界面里可以直接填,但 Immich 依赖
env_file读.env,更省事的做法是在服务器上手工创建/opt/immich目录和.env文件,然后编排里只贴 compose - 启动后去 容器 页面看 4 个容器是否都是
running。第一次启动immich_postgres会初始化数据目录,需要几十秒 - 去 防火墙 确认 2283 没有对外放行——反代走本机回环即可
如果内存只有 4GB,1Panel 里可以只起 immich-server + redis + database 三个服务,把 immich-machine-learning 那段删掉,并在 .env 里加一行:
IMMICH_MACHINE_LEARNING_ENABLED=false
首次访问:先建管理员账号
访问 http://服务器IP:2283(配好反代后用域名),第一个注册的账号自动成为管理员。
填邮箱、姓名、密码完成注册。登录后先别急着开备份,按下面的顺序做最小配置。
最小可用配置
这一步做完才算"能用":
- 关闭公开注册(如果你打算公网访问)。管理后台 → 系统设置 → 用户管理,或者直接加环境变量
IMMICH_ALLOW_SETUP=false——这个变量会同时禁用/auth/admin-sign-up和数据库恢复端点,适合初始化完成后封口 - 确认存储位置。管理后台 → 设置 → 存储模板,默认是按
年/月/日归档原始文件。这一项改了之后要跑存储迁移任务,建议一开始就定好 - 装手机 App 并填服务器地址。iOS / Android 搜 "Immich",或者去 release 页面下 APK。App 里服务器地址填
https://你的域名(结尾不要加/),App 会通过/.well-known/immich这个端点做服务发现 - 开启后台备份。App → 备份 → 选择要备份的相册 → 打开"后台备份"。Android 上 3.0 起允许后台上传整个图库(以前只能传新拍的),记得在电池优化里把 Immich 设成不受限制
- 跑一遍机器学习任务(如果没关 ML)。管理后台 → 任务,依次点运行:缩略图生成 → 提取元数据 → 智能搜索 → 人脸识别。首次导入的照片多的话,这个过程会持续几小时到几天,取决于 CPU
通知与告警配置
Immich 本身没有"服务挂了发消息"这类告警,它的通知体现在应用内活动与邮件上。要配的东西有两块:
一、邮件(SMTP),用于新设备登录提醒、密码重置、共享相册邀请。加在 .env 里:
# 只有 HOST 和 FROM 都填了,邮件功能才会启用
SMTP_HOST=smtp.qq.com
SMTP_FROM=你的邮箱@qq.com
SMTP_FROM_NAME=Immich
SMTP_USERNAME=你的邮箱@qq.com
SMTP_PASSWORD=你的授权码
SMTP_SECURITY=starttls
SMTP_PORT=587
SMTP_SECURITY 和端口是绑定的:starttls 配 587,force_tls 配 465,off 配 25。混着填是最常见的失败原因。QQ 邮箱、163 这类要填授权码而不是登录密码。
改完 .env 必须重建容器才会生效——光 restart 不换掉容器内的环境变量:
docker compose up -d --force-recreate
二、服务可用性监控,这块可以复用本系列第 1 期的 Uptime Kuma:加一个 HTTP 监控,地址填 https://你的域名/api/server/ping,期望返回 {"res":"pong"}。这是 Immich 官方提供的探活端点,不需要登录。
套上域名和 HTTPS
Immich 可以纯 HTTP 跑(不像 Vaultwarden 那样有硬限制),但公网用必须上 HTTPS:照片是全家的隐私,而且 App 在 HTTP 下传输会直接走明文。
重要前提:Immich 不支持挂在子路径下。 不能配成 example.com/immich,必须是某个域名或子域名的根路径,比如 photos.example.com。这一条官方文档写得很明确,很多人在这里白折腾。
用 1Panel 的话:网站 → 反向代理 → 新建,域名填 photos.你的域名.com,代理地址填 http://127.0.0.1:2283,然后申请 Let's Encrypt 证书并开启 HTTPS。
反代有两个 Immich 特有的坑,1Panel 生成的默认配置不包含,要手动去"配置文件"里补:
- 上传大文件会被拦。默认 1MB 限制,传一段手机视频直接 413
/.well-known/immich必须路由到 Immich。这个端点是手机 App 做服务发现的,也是 Let's Encrypt 校验收的路径
完整的 Nginx 配置(官方推荐参数):
server {
listen 80;
server_name photos.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name photos.example.com;
ssl_certificate /etc/letsencrypt/live/photos.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/photos.example.com/privkey.pem;
# 照片和视频动辄几十上百 MB,官方示例直接给到 50000M
client_max_body_size 50000M;
# 关掉请求缓冲:官方文档说明这能避免反代 OOM,并让上传快一倍
proxy_request_buffering off;
client_body_buffer_size 1024k;
# 大文件上传耗时长,默认 60s 会断
proxy_read_timeout 600s;
proxy_send_timeout 600s;
send_timeout 600s;
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_redirect off;
}
# 手机 App 服务发现 + Let's Encrypt http-01 校验,别漏
location = /.well-known/immich {
proxy_pass http://127.0.0.1:2283;
}
}
配完后如果日志里的客户端 IP 全是 127.0.0.1,加环境变量 IMMICH_TRUSTED_PROXIES 告诉 Immich 信任反代:
IMMICH_TRUSTED_PROXIES=172.16.0.0/12,10.0.0.0/8
踩坑清单
- 镜像拉不下来是头号问题。Immich 所有镜像都在
ghcr.io,国内服务器直接docker compose pull大概率超时。解决办法:给 Docker 配置镜像加速器,或用docker_proxy类的代理;实在不行就在能联网的机器上docker save出来再docker load进去 - 别用
:release和:latest。v3.2.0 曾引入同步时耗尽数据库连接池的 bug(v3.2.1 修复),滚动 tag 会让你在不知情的情况下吃到 - 4GB 内存硬跑全套会 OOM。机器学习容器加载模型后常驻 600MB~1.5GB,加服务端、数据库、Valkey,4GB 机器在首次导入大相册时基本必崩。要么加到 8GB,要么关 ML
- 跨大版本别跳级升。特别是从 v1.133.0 之前升级,pgvecto.rs 已被废弃,必须按官方升级指南走,直接改 tag 重启会起不来
- 改了
.env必须重建容器。docker compose restart不会替换容器内的环境变量,官方专门加了提醒,正确命令是docker compose up -d --force-recreate - 别把数据库放网络存储。NFS / SMB 上跑 PostgreSQL 会有性能和数据损坏风险,官方明确不建议。照片本体可以放网络盘
- 老教程的路径和端口全是过时的。看到
/usr/src/app/upload、pgvecto.rs、tensorchord/pgvecto-rs、immich-typesense这些字眼的教程,都是 v1.x 时代的产物 - 外部库要小心删除操作。默认可读写模式下,在 Immich 里清空回收站会真的删掉原文件。只想让 Immich 读你已有的照片库,挂载时加
:ro只读 docker compose down -v会删掉 model-cache 卷。模型重新下载只是慢,但如果你把数据库也用命名卷管理(官方 compose 默认用绑定挂载,不会误删),那才是真麻烦- Docker 版本太旧会报
can't set healthcheck.start_interval。需要 Docker Engine v25 以上,临时办法是注释掉 compose 里 database 段的start_interval行
备份
Immich 有两份数据,必须一起备份才有意义:
- 原始文件:
UPLOAD_LOCATION指向的目录,就是普通文件 - 数据库:
DB_DATA_LOCATION指向的目录,里面是相册、人脸、用户、元数据
只备份照片文件,恢复后所有相册和人脸识别结果全没,得重新跑一遍机器学习。
数据库用 pg_dumpall 在线导出,不用停机:
docker exec -t immich_postgres pg_dumpall -c -U postgres > /opt/backup/immich-db-$(date +%F).sql
配合一个打包原始文件的脚本:
tar czf /opt/backup/immich-library-$(date +%F).tar.gz -C /opt/immich library
v2.5.0 起 Immich 在管理后台内置了数据库备份与恢复功能(
/admin/database-backups),可以直接在界面上生成和回滚数据库快照,配合文件级备份用更省事。
两个原则:
- 备份和源数据不在同一块盘上,才叫备份。华为云主机的话,用 1Panel 的计划任务每周跑一次上面的命令,产物同步到对象存储或另一台机器
- 恢复演练至少做一次。备份没验证过等于没有,特别是数据库那份
小结
适合:
- 手机照片越攒越多、不想为云空间持续付费的人
- 已经有 NAS 或家庭服务器的,用外部库功能可以直接把现有照片库纳管进来
- 在意照片隐私、希望原始文件始终是自己能
cp走的普通文件的人 - 机器有 8GB 内存,愿意让它跑机器学习的(体验最接近 Google Photos)
不适合:
- 4GB 以下的小鸡,且不愿意关掉机器学习的——关了之后只剩时间线和基础搜索,性价比不高
- 想要 Google Photos 那种"一家人共用一个库、时间线自动合并"的,这个功能官方还没做
- 需要团队协作、企业 SSO、合规审计的场景
最低成本的上手路径:先按方式二跑起来,确认能登录、手机能备份,再决定要不要为它升级内存。
项目地址
- 官网:https://immich.app
- GitHub:https://github.com/immich-app/immich
- 文档:https://docs.immich.app
- 在线 Demo:https://demo.immich.app
- 本文对应版本:v3.2.2(2026-09-15 发布)