Immich 自托管需要多少内存?如何安全升级
了解 Immich 的真实内存需求、HTTPS 反向代理端口 2283、exit 137 内存终止错误,以及 Immich v3 无法启动 pgvecto.rs 数据库的原因和恢复步骤。
您要构建的内容
Immich 是一款自托管照片和视频备份服务,可真正替代 Google Photos。它提供手机应用,可在后台上传相机胶卷;还提供时间线、相册、人脸识别和机器学习搜索。您无需手动添加标签,就能搜索“海滩”或某个人。您可以将它运行在自己拥有的 VPS 上,原始文件保留在自己的磁盘中,也不会有人扫描这些文件来向您推销商品。如果您仍在将它与另一个明显的候选方案进行比较,我们的 PhotoPrism 与 Immich 对比会并列展示两者的最低 RAM 要求、手机应用和备份命令。
安装过程需要使用项目自带的 Docker Compose 文件运行 4 个容器。这部分只需 10 分钟。真正容易出问题的是后续配置:在配置较小的服务器上,机器学习容器会占用大量内存;原始文件会快速耗尽磁盘空间;移动应用需要准确的服务器 URL;在服务离开本地网络前,您还需要先在前面配置 HTTPS。此外,Immich 经常发布包含破坏性变更的版本,粗心的 docker compose pull 可能导致服务器无法启动。认真处理这 4 个问题,Immich 就会非常稳定。忽略它们,您可能会损失一个周末。
前置条件和需要正视的问题
- RAM:官方文档要求至少 6 GB,建议 8 GB;请将 4 GB 加 swap 视为绝对下限。
immich-server和 Postgres 容器的内存占用不高。immich-machine-learning容器的占用量最大,因为它会将 CLIP 和人脸识别模型加载到 RAM 中以构建搜索索引。在 2 GB 的服务器上,内核会将其终止。即使有 4 GB RAM,也应配置 swap。 - 磁盘:应按整个图库的大小规划,并预留额外空间。 原始文件会被完整复制,Immich 还会生成缩略图和预览图,额外占用通常约为 10–20%。一个 200 GB 的照片库需要 300 GB 的卷。相比之下,Postgres 的占用量较小。
- CPU:任何较新的 KVM VPS 都可以,但在 CPU 上运行 ML 速度较慢。 大规模导入的智能搜索索引可能会在后台运行数小时。这是正常现象,不需要 GPU。
- 一个指向 VPS 的域名。 移动应用强烈建议使用 HTTPS 端点,并且应在前面配置反向代理。这与 使用 Docker、TLS 和备份自托管 Nextcloud 实例的架构相同;Immich 相当于该文件服务器的照片服务。
- 已安装 Docker 和 Compose 插件。 应从 Docker 官方 apt 仓库安装 Docker Engine 和 Compose v2 插件,具体步骤参见我们的 Docker Compose 基础指南。
第 1 步:先添加 swap
小型 VPS 上最常见的 Immich 故障,是 ML 容器因内存不足而被 OOM killer 终止。首先为内核提供可用的缓冲空间。
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
free -h现在,free -h 应显示一行 Swap: 类型的 4.0Gi。这不会提升 ML 的运行速度。swap 只是缓冲,不是保证,但在 4 GB 的机器上,它可以显著降低容器在索引过程中退出的可能性。
第 2 步:获取官方 compose 文件和环境文件,使用官方文件,不要使用副本
Immich 会在其发布的文件中固定服务版本,尤其是数据库镜像版本。不要将博客中的 compose 文件(包括本文中的文件)作为唯一依据。下载发布资产:
sudo mkdir -p /opt/immich && cd /opt/immich
sudo wget -O docker-compose.yml https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
sudo wget -O .env https://github.com/immich-app/immich/releases/latest/download/example.env这些文件来自带标签的发布版本,因此其中的镜像引用相互匹配。compose 文件定义了 4 个服务。在进行任何修改前,先了解每个服务的作用:
immich-server(ghcr.io/immich-app/immich-server,容器immich_server)负责 API 和 Web UI,监听端口2283。它将您的上传目录挂载到/data。immich-machine-learning(ghcr.io/immich-app/immich-machine-learning,容器immich_machine_learning)负责 CLIP 搜索和人脸识别。它会将下载的模型缓存到model-cache卷中。这是最占用内存的服务。database(容器immich_postgres)运行带有 VectorChord 向量扩展的 Postgres,为相似度搜索提供支持。镜像标签会直接在 compose 文件中通过摘要固定,例如ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:...。较旧的部署使用pgvecto.rs;Immich v3.0 已移除对它的支持,因此现在安装的版本都会使用 VectorChord。绝不要手动编辑此标签。redis(容器immich_redis)运行 Valkey/Redis 实例,为作业队列提供支持。
第 3 步:配置 .env,照片和数据库存储在这里
打开 .env 并设置以下 4 项。标记行之后的所有内容保持不变。
# Where original uploads are stored on the host
UPLOAD_LOCATION=/opt/immich/library
# Where the Postgres data lives. NEVER put this on an NFS/network share.
DB_DATA_LOCATION=/opt/immich/postgres
# "v3" is a floating tag that tracks the latest v3.x. Pin a full tag like
# v3.0.2 instead; then you upgrade on purpose, not by surprise.
IMMICH_VERSION=v3.0.2
# Change this to a long random string. Letters and digits only.
DB_PASSWORD=REPLACE_WITH_A_LONG_RANDOM_STRING
# Set your timezone so timestamps and "on this day" line up
TZ=Europe/London
###################################################################################
DB_USERNAME=postgres
DB_DATABASE_NAME=immich以下两条规则可以避免很多问题。UPLOAD_LOCATION 应指向大容量磁盘。如果之后挂载数据卷,请从一开始就将其设置为该卷的挂载路径,因为事后迁移意味着要移动缩略图并更新资源路径。DB_DATA_LOCATION 必须位于本地磁盘上:在 NFS 或 SMB 共享上运行 Postgres 会导致数据损坏,文档对此已有明确说明。DB_PASSWORD 只使用字母和数字,可以避免一类连接字符串转义错误。
第 4 步:首次运行并创建 admin 用户
cd /opt/immich
sudo docker compose up -d
sudo docker compose ps正确结果应为 4 个容器,全部处于 running 状态,并最终变为 healthy:
NAME STATUS
immich_machine_learning Up (healthy)
immich_postgres Up (healthy)
immich_redis Up (healthy)
immich_server Up (healthy)首次执行 up 时会拉取数 GB 的镜像,请耐心等待。使用 sudo docker compose logs -f immich-server 监控进度;服务器就绪后,会在日志中记录其正在监听端口 2283。现在在浏览器中打开 http://YOUR_SERVER_IP:2283。首次访问时会显示 入门向导,您创建的第一个账户就是 admin。请设置强密码;该账户拥有服务器设置、用户管理权限,以及稍后需要配置的 ML 配置。
第 5 步:移动应用和后台备份
从 App Store 或 Play Store 安装 “Immich”。在登录界面中,应用会要求填写 Server Endpoint URL。输入包含 scheme 的完整 URL,例如 https://photos.example.com(应用会自动追加 /api)。使用刚创建的账户登录,然后打开应用的 Backup 页面,选择要保护的相册(通常是 Camera 和 Screenshots),并启用 Background backup。iOS 会限制后台备份的运行频率;前台上传始终会运行,后台上传则在操作系统允许时执行。
这正是许多用户遇到问题的地方,因此在排查应用之前先阅读第 6 步。
第 6 步:通过反向代理启用 HTTPS,以及完整 URL 规则
移动应用离开家庭网络后,实际上需要使用 HTTPS。将反向代理置于端口 2283 前,并在那里终止 TLS。如果您已经运行多个容器,使用自动 TLS 为多个 Docker 应用配置 Traefik 是最整洁的方案。一个标签配置块即可将 photos.example.com 路由到 immich-server 容器,并代您获取证书。如果您更喜欢 nginx,使用 Certbot 和 nginx 配置 Let's Encrypt 指南会为您获取证书并生成一个 proxy_pass http://127.0.0.1:2283; 配置块。代理配置完成后,添加下一个服务通常只需新增一个子域名。因此,像 Halcyon:适用于 Jellyfin 的 90 年代视频商店界面 这样的媒体前端也可以与 Immich 运行在同一台服务器上。自行托管 HarnessRouter,将 Codex 和 Claude Code 放在同一个 API 后面 也是如此。它会有意绑定到回环地址,只有在代理为其终止 TLS 后才能访问。因此,在为它配置子域名前,请修改默认登录凭据。并非每个容器都需要公网主机名。例如,自行托管的 open-kritt 安全扫描器 仅供管理员使用,最好完全不接入代理;需要打开其 UI 时,再通过 SSH 隧道访问即可。另一些服务完全不使用代理,因为它们不使用 HTTP。自行托管的 RustDesk 中继服务器 就是最典型的例子:它监听少量原始 TCP 和 UDP 端口,需要配置防火墙规则,而不是配置子域名。Immich 有一个重要的代理设置:提高上传大小限制,因为手机视频文件通常很大。在 nginx 中,应在 server 块内设置 client_max_body_size 50000M;。默认的 1 MB 限制会导致视频上传返回 413 Request Entity Too Large。如果您的代理还负责响应 Let's Encrypt 的 HTTP-01 challenge,请确保 /.well-known/immich 仍然路由到 Immich,而不是路由到 challenge handler。
应用强制执行的规则是:端点必须能通过您输入的完整 URL 访问。应用接受普通的 http://YOUR_SERVER_IP:2283(其登录提示为 http://your-server-ip:port),但所有经过互联网的访问都应使用 HTTPS。协议方案错误,或直接使用 IP 地址但省略端口,都会导致“应用无法连接到服务器”。下面会将此问题作为一个命名故障进行说明。
第 7 步:外部库与上传内容:导入现有照片目录
照片进入 Immich 有两种方式,两者并不相同。
- 上传内容是由 Immich 管理的资源。应用或 Web 上传器会将文件复制到
UPLOAD_LOCATION。Immich 可以重命名、移动和删除这些文件。 - 外部库是对服务器目录中现有文件的只读导入,例如旧的
Pictures目录树或 NAS 导出目录。Immich 会在原位置为这些文件建立索引,并在时间线中显示,但不会修改或删除原始文件。
要导入现有目录树,请将其以只读方式挂载到服务器容器中。编辑 docker-compose.yml 下的 immich-server:,并添加一个卷:
immich-server:
volumes:
- ${UPLOAD_LOCATION}:/data
- /etc/localtime:/etc/localtime:ro
- /srv/photos:/mnt/media/photos:ro:ro 可确保 Immich 永远无法修改原始文件。使用 sudo docker compose up -d 重新创建容器,然后在 Web UI 中依次打开您的头像 → 管理 → 外部库 → 创建库,选择所属用户,点击“文件夹”下的 添加,并输入容器路径 /mnt/media/photos,而不是主机路径 /srv/photos。点击扫描。使用主机路径而不是容器路径,是配置外部库时最常见的错误;扫描不会找到任何内容,并显示资源数为 0。
第 8 步:遵循 Immich 要求的升级规范
这一部分决定了 Immich 是稳定运行还是出现故障。Immich 发布速度快,不会回移修复,也不支持降级。浮动的 v3 标签是官方支持的跟踪版本方式,Immich 也尽量将破坏性变更限制在主版本中。但每次拉取时它都会执行升级,无论您是否阅读了变更说明;未计划的升级无法回滚。对于服务器上所有需要长期运行的容器,都应采用同样的“固定版本后阅读变更说明”习惯。因此,自托管的 KiroCrew 代理会固定到一个已知可用的标签,而不是在下一次重启时自行切换版本。具体规范如下:
- 固定版本。 将
IMMICH_VERSION保持为具体标签,例如v3.0.2,不要使用始终拉取最新 v3.x 版本的浮动标签v3。 - 每次升级前都要阅读版本发布说明。 其中会说明破坏性变更,尤其是数据库或向量扩展的变更。v3.0 版本就是一个明显例子:该版本直接移除了 pgvecto.rs,因此仍使用旧扩展的用户必须先完成 VectorChord 迁移(该迁移在 v1.133 中引入),然后才能升级。
- 先备份数据库(第 9 步)。任何时候都应备份;当发布说明提到数据库时,更要严格执行。
- 同时获取新的 compose 文件。
IMMICH_VERSION只固定服务器和 ML 镜像。Postgres 镜像通过docker-compose.yml内部的摘要固定,因此需要新版数据库扩展的版本会随附新的 compose 文件。重新下载这两个版本资源,重新应用您的.env值,然后再升级。 - 先更新移动客户端。 服务器只支持与其匹配的主版本,应用通常兼容当前主版本和前一个主版本。当服务器版本高于应用版本时,当前版本(v3.3.1,检查日期为 2026-10-10)会在手机上显示 App update is available 通知,并提供 Update 按钮。Immich 建议先升级所有移动客户端,再升级服务器。
准备好新文件后,实际执行以下命令:
cd /opt/immich
sudo docker compose pull
sudo docker compose up -d
sudo docker image prune步骤 9:备份、数据库转储和原始文件,并测试备份
Immich 的备份包含两部分,缺少任何一部分都没有用。数据库保存相册结构、人脸数据、搜索索引,以及资源与文件之间的映射。原始文件目录保存实际照片。只恢复其中一部分,要么得到没有组织结构的照片,要么得到指向缺失文件的空壳。这个两部分结构并非 Immich 特有:自托管 Chatwoot 支持台同样需要 Postgres 转储和上传目录的组合,否则恢复后的收件箱会丢失所有附件。将 Postgres 数据目录作为文件树复制,看似可以跳过转储步骤,但这不是可用的备份。这是一个常见陷阱,完整的 Immich 备份与恢复教程会同时说明这一点,以及会让时间线变为空的恢复错误。
在 Postgres 容器内使用 pg_dump 转储数据库,目标是 immich 数据库,而不是整个集群:
sudo docker exec -t immich_postgres pg_dump --clean --if-exists \
--dbname=immich --username=postgres | gzip > /opt/immich/immich-db-$(date +%F).sql.gz然后备份 UPLOAD_LOCATION,即完整的 /opt/immich/library 目录树,尤其是其中的 library/、upload/ 和 profile/ 子目录。使用 restic、rsync 或 borg 将其备份到另一台机器或对象存储。无论使用 cron 条目还是 systemd timer 调度任务,都必须有失败告警渠道。使用指向您自己的 ntfy 推送服务器的 systemd OnFailure= 单元,可以在转储失败的当晚将消息发送到手机,而不是等到恢复时才发现问题。先备份数据库,再备份文件。这样,转储就不会引用尚未复制到文件备份中的照片。外部图库应在其实际源位置单独备份;Immich 不负责管理这些图库。
现在处理所有人都会跳过的部分:测试恢复。 恢复必须在一个全新的栈上执行。该栈的 server 不能启动过,并且必须使用与转储兼容的 Postgres 镜像。这正是不能临时决定数据库镜像标签的原因。在使用相同 compose 和 .env 的临时主机上,删除所有旧状态,只启动数据库,然后加载转储:
cd /opt/immich
sudo docker compose down -v
sudo docker compose pull
sudo docker compose create
sudo docker start immich_postgres
sleep 10
gunzip --stdout immich-db-2026-07-15.sql.gz |
sed "s/SELECT pg_catalog.set_config('search_path', '', false);/SELECT pg_catalog.set_config('search_path', 'public, pg_catalog', true);/g" |
sudo docker exec -i immich_postgres psql --dbname=immich --username=postgres --single-transaction --set ON_ERROR_STOP=on
sudo docker compose up -d在 VectorChord 数据库中,sed 对 search_path 的重写不可省略。省略后,恢复会在中途中止。将原始文件放回原位并重新启动栈后,打开 Web UI。如果照片和相册都存在,说明备份有效。如果从未执行过这项测试,您就没有备份,只有希望。
故障模式及其日志中的提示
ML 容器被 OOM-killed。 sudo docker compose logs immich-machine-learning 突然终止,docker compose ps 显示它被 Restarting,退出码为 137。sudo dmesg | grep -i oom 对此进行了确认:Out of memory: Killed process ... (python3)。随后,搜索和人脸任务会停滞。原因是模型所需的 RAM 不足。按以下顺序处理:添加 swap(步骤 1);为 VPS 增加 RAM;如果确实无法增加,则打开 Administration → Settings → Machine Learning Settings,关闭顶层的 machine learning 开关,一次性禁用所有 ML 功能。仅关闭 Smart Search 和 Facial Recognition 不够,因为 OCR 和其他模型类型默认仍处于启用状态。这样可以保留备份和相册,但会失去按内容搜索功能。从 compose 文件中移除 immich-machine-learning 服务也会产生相同效果。
升级后 Immich server 拒绝启动。 Postgres 容器可能运行正常;实际执行启动时向量扩展版本检查并拒绝启动的是 immich_server,其日志会循环显示类似 The database currently has VectorChord 0.5.3 activated, but the Postgres instance only has 0.4.2 available. This most likely means the extension was downgraded. 的行;在较旧的堆栈中则可能显示 The pgvecto.rs extension is not available in this Postgres instance.。原因是数据库镜像中的扩展版本低于数据升级到的版本。这几乎总是因为手动编辑镜像标签,或将较新的 dump 恢复到较旧的镜像中。解决方法是使用匹配的 Postgres 镜像,使用与数据库匹配的 release 中的 compose 文件,不要降级,并且只能将数据恢复到兼容的镜像中。
移动应用无法连接到 server。 输入 URL 后,登录界面显示类似 Could not connect to server 的连接错误。常见原因包括:在代理仅提供 https:// 的情况下输入了 http://;直接连接后端但省略了端口,因此它尝试连接 example.com(端口 443),而不是 example.com:2283;反向代理未转发 /api;或者处理 Let's Encrypt HTTP-01 challenge 的代理将 /.well-known/immich 路由到了 Immich 之外的位置。请输入完整的 https://photos.example.com URL,并先在手机浏览器中确认可以加载。如果浏览器可以访问而应用无法访问,则可能是代理剥离了路径或错误路由了 /.well-known/immich;也可能是证书为自签名证书。应用会因握手错误拒绝此类证书,除非在其设置中启用自签名证书支持。
导入过程中磁盘空间耗尽。 上传开始失败,缩略图变为空白,日志显示 ENOSPC: no space left on device,或者 Postgres 显示 could not extend file ... No space left on device。df -h 显示 UPLOAD_LOCATION 卷已达到 100%。因此,应在导入大型媒体库前规划磁盘容量。恢复方法是挂载更大的卷,停止堆栈,将 UPLOAD_LOCATION 移到新卷,更新 .env,然后重新启动;如果服务提供商支持,也可以扩展现有磁盘。磁盘空间耗尽可能导致 Postgres 卡住,因此应先释放空间并重启数据库容器,再判断是否发生数据损坏。
FAQ
Immich 需要多少 RAM 和磁盘空间?
Immich 的官方要求是至少 6 GB RAM,建议 8 GB;对于小型图库,配合 swap 使用时,4 GB 是实际可行的下限。无论如何都应配置 swap,因为机器学习容器最容易出现资源峰值。磁盘空间应按完整图库大小计算,并在本地存储上额外预留约 10–20% 用于生成缩略图和预览图。切勿将 Postgres 数据目录放在网络共享上。如果您还在决定运行哪些服务,2026 年适合自行托管的服务指南会将 Immich 的资源占用与其他服务进行对比。
可以不使用 GPU 运行 Immich 吗?
可以。机器学习容器可以稳定地使用 CPU 运行。GPU 只会加快智能搜索索引,并且在使用正确的镜像变体时加快视频转码。在 CPU 上,大型图库的初始索引可能需要在后台运行数小时,但不会阻塞备份或浏览。如果您的设备完全无法承载机器学习任务,可以在管理设置中使用顶层开关彻底关闭机器学习,同时保留其他功能。
如何安全升级 Immich?
将 IMMICH_VERSION 固定为具体标签,例如 v3.0.2。每次升级前都应阅读发行说明,并先备份数据库。由于 Postgres 镜像固定在 docker-compose.yml 中,而不是通过 IMMICH_VERSION 固定,因此请从目标发行版重新下载 compose 文件和 example.env,重新应用您的配置值,然后运行 docker compose pull && docker compose up -d。切勿在无人维护的情况下让版本自动浮动。Immich 不支持降级,因此未经了解就执行的升级无法撤销。
具体需要备份什么?
需要同时备份两项:immich 数据库的 pg_dump,以及完整的 UPLOAD_LOCATION originals 目录。数据库保存相册、人脸和资源到文件的映射;该目录保存实际照片。恢复时还需要这两项,以及一个带有兼容 vector 扩展的数据库镜像。先执行数据库转储,再复制文件,并至少在测试设备上测试一次恢复。未经测试的备份不是真正的备份。
如何导入现有的照片目录?
将该目录以只读方式作为额外卷挂载到 immich-server 容器中,例如 - /srv/photos:/mnt/media/photos:ro,重新创建容器,然后在 Administration → External Libraries 中创建图库,并添加 container 路径 /mnt/media/photos。Immich 会直接在原位置为文件建立索引,不会修改或删除文件。最常见的错误是输入主机路径,而不是容器路径,这会导致扫描不到任何内容。