Immich 3.3.3 备份与迁移:原图、相册和数据库一起恢复

针对已有 Immich 3.3.3 实例,停写后保存数据库、完整图库与配置,在独立空目标恢复,再核对旧账号、原图、单照片相册和新增上传。

迁移 Immich 时,要一起带走原图、用户和相册关系。先在空环境恢复一份完整备份,用旧账号找到旧照片和相册,再上传新照片,能把“文件已经复制”和“服务可以继续使用”分开核对。

以下处理 Immich 3.3.3 的同版本冷恢复,前提是已有按官方 Compose 配置运行的实例。操作期间暂停上传,保留原实例和原盘;恢复目标使用另一套空目录与数据库。其他版本应查对应版本的恢复文档。

先确定资源和恢复目标

官方要求至少 6GB 内存、2 核 CPU,建议 8GB、4 核;4GB 运行有关闭机器学习的条件。如果为容器设置内存上限,官方还要求 PostgreSQL 至少 2GB。数据库目录应放在本地 SSD,不能放在网络共享上。照片空间还要容纳缩略图、转码和备份,不能只按原图总量准备。

准备迁移机器时,可先对照 Docker VPS 的资源清单检查内存、本地磁盘和备份空间。恢复前应已有可用的 Docker 与 Compose 环境。

如果确实需要另租一台恢复机,先按上述内存、本地 SSD 和图库容量核对实例与磁盘,再从 阿里云ECS选购入口 查看可用规格。已有满足条件的空闲机器,可以直接用于恢复,不必另买服务器。

下面的读者命令按官方默认值写:DB_USERNAME=postgres、DB_DATABASE_NAME=immich、UPLOAD_LOCATION=./library、DB_DATA_LOCATION=./postgres。改过用户名、数据库名或路径的实例,要把命令中的对应值换成实际配置。

恢复示例使用与原实例分开的空 Linux 环境,目标不能已有同名 Immich 容器。官方 Compose 有固定的 container_name 和项目名;在同一个 Docker 守护进程里只换一个目录,不能保证得到独立实例。若要同机并存,需先单独处理项目名、容器名、端口和挂载路径,不能直接套用本段命令。

固定与备份一致的版本

保存现用的 .env、docker-compose.yml 和镜像记录,恢复时不要下载 latest。需要核对原始配置时,可对照 3.3.3 的 Compose 文件与 example.env,不要覆盖正在使用的配置。

本例 .env 的 IMMICH_VERSION 为 v3.3.3,数据库密码沿用原实例。保留该版官方 PostgreSQL 镜像及必需扩展,不换成普通 PostgreSQL 镜像。数据库与 Valkey 的固定镜像摘要也随 Compose 一起保存。

如果使用 IMMICH_CONFIG_FILE、外部图库或其他额外挂载,另外保存对应文件和容器内路径;后面的命令只直接覆盖官方默认的 .env、Compose 与 library。

留一组能核对的数据

在暂停服务前,用普通账号准备一张可识别的照片,建一个只放这张照片的相册。记录账号、相册名,以及下载所得原图的 SHA-256:

sha256sum "原图文件.png"

恢复后继续用同一个账号和同一张原图核对。只比较图片文件数量,不能确认账号、相册关系或后续写入是否正常。

停写后备份数据库和整个文件库

以下命令在原实例目录运行。library 是本例的完整 UPLOAD_LOCATION,不要只挑其中的原图目录。执行账户须能读取整个图库,并保留文件与目录的属主、权限;遇到权限错误先核对已有授权,不放宽受保护目录。复制失败时停止,不能继续恢复。停服务后也要确认其他同步程序没有继续写入同一图库。

set -euo pipefail
umask 077
cd "$HOME/immich-app"
BACKUP_DIR="$HOME/immich-backups/$(date -u +%Y%m%d-%H%M%S)"
mkdir -p "$BACKUP_DIR"
chmod 700 "$BACKUP_DIR"

docker compose stop immich-server
docker compose exec -T database pg_dump \
  --clean --if-exists --dbname=immich --username=postgres \
  > "$BACKUP_DIR/database.sql"

cp -a ./library "$BACKUP_DIR/library"
cp .env docker-compose.yml "$BACKUP_DIR/"
chmod 600 "$BACKUP_DIR/.env" "$BACKUP_DIR/database.sql"

(
  cd "$BACKUP_DIR"
  sha256sum database.sql .env docker-compose.yml > checksums.sha256
  find library -type f -print0 | sort -z | xargs -0 -r sha256sum > media.sha256
)

docker compose images > "$BACKUP_DIR/images.txt"
docker compose stop

先停 immich-server,数据库仍运行,才能执行这份逻辑备份;完成后再停原项目的其余容器。不要用删除卷或清空原目录代替停机。

数据库保存用户、文件和相册等关系,自动数据库备份不包含照片和视频。完整副本还要有整个 UPLOAD_LOCATION、Compose 和环境配置。使用外部图库时,另外保存原图库,并记录它在容器内的挂载路径。把整份备份复制到原盘之外的独立存储,并限制可读取它的账户;其中含环境配置和用户数据。仅在原机多留一个文件夹,不能应对原盘损坏。

在空目标里先恢复数据库

将完整备份复制到恢复目标。下面的 BACKUP_DIR 要改成目标机上实际的备份目录;RESTORE_DIR 必须不存在。示例保留默认数据库名和相对目录,先复制文件并验证校验和:

set -euo pipefail
umask 077
BACKUP_DIR="/srv/immich-backups/待恢复的备份目录"
RESTORE_DIR="$HOME/immich-restore-333"
test -d "$BACKUP_DIR"
test ! -e "$RESTORE_DIR"

(
  cd "$BACKUP_DIR"
  sha256sum -c checksums.sha256
  sha256sum -c media.sha256
)

mkdir -m 700 "$RESTORE_DIR"
cp "$BACKUP_DIR/.env" "$BACKUP_DIR/docker-compose.yml" "$RESTORE_DIR/"
cp -a "$BACKUP_DIR/library" "$RESTORE_DIR/library"
mkdir -m 700 "$RESTORE_DIR/postgres"
chmod 600 "$RESTORE_DIR/.env"
cd "$RESTORE_DIR"
sha256sum -c "$BACKUP_DIR/media.sha256"

创建容器前,检查目标 .env:UPLOAD_LOCATION=./library、DB_DATA_LOCATION=./postgres、IMMICH_VERSION=v3.3.3,数据库密码与备份保持一致。绝对路径和外部挂载也要改到恢复目标,不能指回原实例。

数据库必须是全新的,immich-server 还没在它上面运行。先只启动数据库与缓存,等待 PostgreSQL 的 TCP 服务就绪:

docker compose config --quiet
docker compose create
docker compose up -d database redis

ready=0
for attempt in $(seq 1 60); do
  if docker compose exec -T database pg_isready \
    -h 127.0.0.1 -U postgres -d immich; then
    ready=1
    break
  fi
  sleep 2
done
test "$ready" -eq 1

接着按官方命令行恢复流程导入 SQL。下面只在导入流中调整 search_path,原备份文件保持不变:

set -euo pipefail
sed "s/SELECT pg_catalog.set_config('search_path', '', false);/SELECT pg_catalog.set_config('search_path', 'public, pg_catalog', true);/g" \
  "$BACKUP_DIR/database.sql" \
  | docker compose exec -T database psql \
      --dbname=immich --username=postgres \
      --single-transaction --set ON_ERROR_STOP=on

导入成功后才启动其余服务:

docker compose up -d
docker compose ps
docker compose logs --tail=100 immich-server

导入出错时保留目标和日志,不继续启动应用,也不要把同一份 SQL 反复导入半完成的数据库。先确认版本、空库和报错位置,再决定如何处理这份恢复目标。

用旧数据和新写入一起验收

先用旧普通账号登录,找回原相册,下载旧原图并重新计算 SHA-256。再上传一张不同的照片,下载它并核对哈希。入口是否切换,要等这些数据核对通过后再决定;在此之前不要让自动上传的手机同时连接两个实例。

2026 年 10 月 15 日,在 ARM64 Docker Desktop 中用一张合成 PNG 和一个单照片相册,通过正常应用 API 核对了同版恢复:

核对对象实际结果
旧普通账号恢复后重新登录,用户 ID 保持一致
旧原图重新下载,SHA-256 与恢复前一致
单照片相册名称相同,assetCount 为 1,albumThumbnailAssetId 对应原照片
新增照片恢复后上传另一张合成 PNG,再下载,SHA-256 一致
备份原件SQL 和完整媒体副本保持原有哈希,没有被恢复过程覆盖

实验关闭了机器学习,数据库配额未满足官方在 Docker 限额下至少 2GB 的条件,这个小样本结果不能作为生产配置或容量依据。网页入口、TLS、手机客户端、AMD64 和跨版本升级未在本次验证。

官方资料