自建 iCloud 完整方案:Immich + Cloudflare Tunnel 全家共享照片库(永久免费)
视频主要目标
Section titled “视频主要目标”用一台Mac mini + Immich + Cloudflare Tunnel,搭一套全家共享、多账号多设备、永久免费的私人 iCloud:
- 全家多账号自动备份,浏览器随时打开
- 共享相册:孩子照片 / 旅行 / 聚会,全家都能加都能看
- 给爷爷奶奶发链接,扫码即可看孙子照片,无需注册
- 不开端口、不要公网 IP,数据全在自家电脑上
视频主要内容
Section titled “视频主要内容”- 服务器选择 + Docker 环境准备
- 在 Cloudflare「联网」菜单创建 Tunnel
- Docker Compose 部署 Immich + 初始化管理员和家庭成员账号
- 配置 Cloudflare Access 邮箱鉴权(防陌生人扫到)
- 移动端 App 安装、远程登录、自动备份
- 共享相册 / Partner Sharing / Public Link 三种共享方式
- 验证清单和常见错误排查
- 一个 Cloudflare 账号
- 一个已经托管到 Cloudflare 的域名,例如
example.com - Cloudflare Zero Trust 组织(到第六步配置 Access 时再开通即可,创建 Tunnel 不依赖 Zero Trust)
- 每位家庭成员一个能收邮件的邮箱(爸 / 妈 / 老婆 / 老公 / 老人 各一个)
照片是不可再生的家庭资产,用一台专用、可靠、24 小时常开的设备做主机:
| 设备 | 说明 |
|---|---|
| Mac mini | macOS Docker Desktop,体验最简单 |
| 台式机 + Linux | 性能足、硬盘大、Docker 部署稳定 |
| 群晖 / 飞牛 NAS | RAID 自带磁盘冗余,套件中心或 Docker 装 Immich |
最低配置:4 核 CPU / 4G 内存 / 256G 系统盘 + 独立照片盘(NAS 务必 RAID 1 双盘镜像)。Immich 后台扫描和缩略图持续吃 CPU,低于此配置会跑得很慢。
请把下面示例里的域名和 IP 换成你自己的:
| 项 | 示例 |
|---|---|
| 域名 | example.com |
| Immich 外网域名 | photos.example.com |
| Immich 服务器局域网地址 | 192.168.1.50 |
| Immich Web 端口 | 2283 |
多用户多账号能力确认
Section titled “多用户多账号能力确认”Immich 真的能多人共享吗?提前把答案说清,避免做完才发现不对:
| 能力 | 是否支持 | 视频里怎么用 |
|---|---|---|
| Admin 创建无限用户账号 | 支持 | 全家每人一个 |
| 每账号多设备登录 | 支持 | iPhone + iPad + 电脑同时 |
| 每账号独立时间线和隐私 | 支持 | 老婆备份的不影响老公 |
| Shared Album 共享相册(多人写) | 支持 | 全家共享孩子照片 |
| Partner Sharing 配偶单向共享整个库 | 支持 | 夫妻互看对方所有照片 |
| Public Share Link 生成链接发外人 | 支持 | 给爷爷奶奶看孙子,无需注册 |
第一步:服务器选择和系统准备
Section titled “第一步:服务器选择和系统准备”本手册以 Ubuntu 24.04 LTS 为示范,命令在 macOS / 其他 Linux 发行版基本一致。
1)确认 Docker 已安装:
docker --versiondocker compose version如果没装:
# Ubuntu / Debiancurl -fsSL https://get.docker.com | shsudo usermod -aG docker $USER# 重新登录 shell 让组生效2)给 Immich 准备一个独立的目录:
例如在系统默认的“Pictures”目录下创建一个 “immich” 的文件夹,用于存储原始的图片文件
3)测试本机Immich端口未占用:
sudo lsof -i :2283无输出即可用。
第二步:在 Cloudflare 创建 Tunnel
Section titled “第二步:在 Cloudflare 创建 Tunnel”⚠️ 创建 Tunnel 不需要先初始化 Zero Trust。第六步的 Access 邮箱鉴权才需要 Zero Trust,到时候再开通即可。
进入 Cloudflare Dashboard(dash.cloudflare.com),左侧栏「保护和连接」分组下:
联网(Networks) → Tunnels(隧道) → Create a tunnel(创建隧道)2.1 填写隧道名称
Section titled “2.1 填写隧道名称”home-photos-tunnel2.2 设置环境
Section titled “2.2 设置环境”我们用 Docker Compose 跑 cloudflared,主机上不需要装任何 cloudflared 二进制——选项只是用来定位那串 token。
2.3 复制 Tunnel token
Section titled “2.3 复制 Tunnel token”页面下方「安装并运行」区有三个命令框:
Install cloudflared ← 安装二进制(用不上,跳过)Install as service ← 装为系统服务(用不上,跳过)Or, run tunnel (manual) ← 手动运行命令(含我们要的 token)从 Install as service 或 Or, run tunnel (manual) 任选一个,只复制命令里的 token 部分——也就是 eyJhIjoi... 这一长串 base64 字符(通常 200+ 字符):
# Install as service 长这样(Debian 选项):sudo cloudflared service install eyJhIjoi**********...**********aC... └─────── 这就是 token ───────┘
# Or, run tunnel (manual) 长这样:cloudflared tunnel run --token eyJhIjoi**********...**********aC... └─────── 这就是 token ───────┘
# 如果选了 Docker 环境,命令会长这样(一眼就能看到 token):docker run cloudflare/cloudflared:latest tunnel --no-autoupdate run --token eyJhIjoi**********...**********aC...复制保存到密码管理器——后面 Docker Compose 的 .env 文件里会用到。关闭这个页面就找不回了(只能删除 Tunnel 重建)。
2.4 关于「连接状态」
Section titled “2.4 关于「连接状态」”页面最底部「连接状态」会一直显示「正在等待您的隧道连接…」,这是正常的——因为我们还没有启动 cloudflared 容器。第三步起完 docker compose 后,这里会自动变成「Healthy」,再回头确认即可。
第三步:Docker Compose 部署 Immich
Section titled “第三步:Docker Compose 部署 Immich”3.1 创建工作目录
Section titled “3.1 创建工作目录”在服务器上选一个工作目录存放 Immich 的配置文件。本手册统一用 ~/immich/(即当前用户家目录下的 immich 文件夹):
mkdir -p ~/immichcd ~/immichpwd # 应输出类似 /home/yourname/immich,确认你已进入这个目录⚠️ 后续所有
docker compose命令都必须在这个目录下执行——docker compose会自动读取当前目录的docker-compose.yml和.env。如果在其他目录运行命令会找不到配置。
💡 为什么选
~/immich/:
- 当前用户家目录,普通用户也有读写权限,不必每次都
sudo- 路径短、好记
- 数据库文件(
./postgres/)会自动放在这个目录下,方便集中备份- 如果你想放别的位置(例如
/opt/immich/或/srv/immich/),随意——只要把后面所有~/immich替换成你的实际路径,且确保当前用户对该目录有读写权限即可
3.2 创建 .env 文件
Section titled “3.2 创建 .env 文件”在 ~/immich/ 目录下新建 .env(注意:文件名以点开头,是隐藏文件)。可以用 nano、vim、vi 任意编辑器:
vim ~/immich/.env# 或: nano ~/immich/.env填入下面内容(Tunnel token 替换成第二步复制的):
# === 照片实际存储位置(重要)===# 这是宿主机磁盘路径,所有照片、缩略图、转码视频都存这里# 强烈建议指向独立的大容量存储盘,单独一份可以方便用 rsync 备份UPLOAD_LOCATION=/mnt/photos/immich-library
# === PostgreSQL 数据库存储位置 ===# 元数据(文件名、EXIF、相册关系、用户、共享)存这里# 数据库挂了照片还在,但相册结构会丢,**务必单独定期备份这个目录**DB_DATA_LOCATION=./postgres
TZ=Asia/Shanghai
# === Immich 版本 ===# v2 = 锁定大版本号,自动获取 v2.x.x 最新补丁,不会跳到 v3 breaking change# release = 永远最新(含 v3+),不推荐生产环境# v2.7.5 = 锁定具体版本,最稳定但需手动升级IMMICH_VERSION=v2
# === 数据库账号密码 ===# ⚠️ 重要:DB_PASSWORD 只能包含字母和数字(A-Za-z0-9),# 不能含特殊字符(! @ # $ % & * 等)和空格,# 否则 PostgreSQL 容器初始化时会失败DB_PASSWORD=改成一个强密码仅限字母数字DB_USERNAME=postgresDB_DATABASE_NAME=immich
# === Cloudflare Tunnel ===TUNNEL_TOKEN=粘贴你刚才第二步复制的 Cloudflare Tunnel token保存退出:nano 按
Ctrl+O回车保存,Ctrl+X退出;vim 按Esc然后输入:wq回车。
3.3 创建 docker-compose.yml 文件
Section titled “3.3 创建 docker-compose.yml 文件”仍然在 ~/immich/ 目录下(与 .env 同目录)新建 docker-compose.yml:
nano ~/immich/docker-compose.yml填入下面内容(精简版,已剔除机器学习服务,已对齐 Immich v2.7.5 官方模板):
name: immich
services: immich-server: container_name: immich_server image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-v2} volumes: - ${UPLOAD_LOCATION}:/data - /etc/localtime:/etc/localtime:ro env_file: - .env ports: - "2283:2283" depends_on: - redis - database restart: always healthcheck: disable: false
redis: # ⚠️ 注意:Immich 已从 Redis 迁移到 Valkey(Redis 协议改 license 后的 BSD 分叉) # 不要再用 docker.io/redis:6.2-alpine,会触发兼容性告警 container_name: immich_redis image: docker.io/valkey/valkey:9 healthcheck: test: redis-cli ping || 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" volumes: - ${DB_DATA_LOCATION}:/var/lib/postgresql/data shm_size: 128mb restart: always healthcheck: disable: false
cloudflared: container_name: cloudflared image: cloudflare/cloudflared:latest restart: unless-stopped command: tunnel --no-autoupdate run --token ${TUNNEL_TOKEN}关键字段说明:
| 字段 | 作用 | 不写会怎样 |
|---|---|---|
name: immich | Docker Compose 项目名(影响容器网络名 immich_default) | 不写默认用目录名,但官方模板写了,跟着写不会错 |
image: ...:${IMMICH_VERSION:-v2} | 锁定 Immich 大版本号 | 用 release 会跳到 v3 breaking change |
valkey/valkey:9 | Redis 兼容缓存 | 老镜像 redis:6.2-alpine 会触发 Immich 启动告警 |
shm_size: 128mb | PostgreSQL 共享内存 | 默认 64MB,大库扫描时性能会下降 30-50% |
healthcheck: disable: false | 启用容器内置健康检查 | docker compose ps 显示 running 而不是 healthy,故障排查更慢 |
关于机器学习服务的取舍:
Immich 默认提供一个独立容器 immich-machine-learning,做四件事——人脸识别、CLIP 语义搜索(“找一下海边的狗”)、重复照片检测、OCR 文字识别。本手册默认精简版不启用,原因是:
- 多数家庭用户的核心需求是「备份 + 共享」,不是 AI
- 首次扫描几万张照片要 1-2 天,吃 CPU
- 内存额外多吃 1-2 GB
- 中文 CLIP 语义搜索效果一般
如果后期想用「重复照片检测」或「按内容搜索」,把下面这段加回 docker-compose.yml:
immich-machine-learning: container_name: immich_machine_learning image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-v2} volumes: - model-cache:/cache env_file: - .env restart: always healthcheck: disable: false
# 同时在文件最底部加(与 services 同级):volumes: model-cache:支持 GPU 加速(NVIDIA CUDA / Apple Silicon Neural Engine / Intel OpenVINO),CPU 也能跑只是慢。详见 官方硬件加速文档。
3.4 验证目录结构
Section titled “3.4 验证目录结构”启动前用 ls -la ~/immich/ 确认两个文件都在 同一个目录:
ls -la ~/immich/预期输出(关键看后两行):
drwxr-xr-x 4 yourname yourname 128 Apr 30 12:00 .drwxr-xr-x 30 yourname yourname 960 Apr 30 12:00 ..-rw-r--r-- 1 yourname yourname 650 Apr 30 12:00 .env ← 第 3.2 步创建-rw-r--r-- 1 yourname yourname 1450 Apr 30 12:00 docker-compose.yml ← 第 3.3 步创建⚠️ 如果只看到
docker-compose.yml没看到.env:执行ls ~/immich/(不带-a)会因为.env是隐藏文件(点开头)而看不见。-la才能列出隐藏文件。
快速核对 .env 关键字段已填(可选但推荐):
# 确认 token 不是占位符grep TUNNEL_TOKEN ~/immich/.env# 期望:TUNNEL_TOKEN=eyJhIjoi...(一长串),不能是 "粘贴你刚才..."
# 确认密码已改且只含字母数字grep DB_PASSWORD ~/immich/.env# 期望:DB_PASSWORD=YourStrong123(不含 ! @ # $ 等特殊字符)启动后还会自动生成第三个目录:
~/immich/├── .env├── docker-compose.yml└── postgres/ ← docker compose 启动时自动创建(DB_DATA_LOCATION=./postgres)3.5 启动并验证
Section titled “3.5 启动并验证”确认在 ~/immich/ 目录下,启动所有容器:
cd ~/immich # 再次确认在正确目录docker compose up -d查看容器状态:
docker compose ps期望全部 STATUS = Up ... (healthy)(healthcheck 启用后会显示 healthy 标记,可能需要 30-60 秒才转为 healthy):
NAME STATUS PORTScloudflared Up 30 secondsimmich_postgres Up 45 seconds (healthy)immich_redis Up 45 seconds (healthy)immich_server Up 30 seconds (healthy) 0.0.0.0:2283->2283/tcp跟踪日志确认 cloudflared 已连上 Cloudflare:
docker compose logs -f cloudflared看到 Registered tunnel connection 就是连上了,按 Ctrl+C 退出日志。
跟踪 Immich 服务器日志确认监听端口:
docker compose logs -f immich-server看到 Listening on port 2283 即可,按 Ctrl+C 退出。
本机访问验证:
浏览器打开(把 192.168.1.50 换成你 Immich 服务器的实际局域网 IP;本机访问也可用 http://localhost:2283):
http://192.168.1.50:2283应能看到 Immich 的「Welcome / Getting Started」初始化页面。看到这个页面 = 第三步完成。
第四步:初始化 Immich 管理员 + 创建家庭账号
Section titled “第四步:初始化 Immich 管理员 + 创建家庭账号”浏览器打开 http://192.168.1.50:2283:
- 创建管理员账号——用你自己的主邮箱,密码强度要够
- 登录管理员后台
进入:
Administration → Users → Create User为每位家庭成员创建账号,邮箱必须填本人真实邮箱(后面 Cloudflare Access 验证码会发到这里):
| 用户 | Storage Quota(可选) | |
|---|---|---|
| 老婆 | wife@example.com | 不限 |
| 孩子 | kid@example.com | 100 GB |
| 父亲 | dad@example.com | 50 GB |
| 母亲 | mom@example.com | 50 GB |
每个新账号会收到一个临时密码,让对方第一次登录后改密码。
必做:开启 Storage Template 让磁盘文件可读
Section titled “必做:开启 Storage Template 让磁盘文件可读”Immich 默认把照片以 UUID 命名存盘(<asset-uuid>.jpg),万一数据库挂了,文件夹里全是无意义的 UUID。
强烈建议第一时间开启 Storage Template,让文件按”用户名 / 年 / 年-月 / 原文件名”组织。万一 Immich 哪天挂了,照片仍可当普通相册直接用。
这一步最大的价值:未来任何时候都可以直接 rsync 这个目录到外挂硬盘做冷备份,备份盘上看到的是按年月组织的相册,不是一堆 UUID。
第五步:在 Tunnel 里添加路由(Public Hostname)
Section titled “第五步:在 Tunnel 里添加路由(Public Hostname)”5.1 进入 Tunnel 详情页
Section titled “5.1 进入 Tunnel 详情页”回到 Cloudflare Dashboard 的「联网」菜单,点击进入第二步创建的 Tunnel:
联网(Networks) → Tunnels(隧道) → home-photos-tunnel ← 点进去5.2 先确认 Tunnel 健康(验证第三步成功)
Section titled “5.2 先确认 Tunnel 健康(验证第三步成功)”进入 Tunnel 详情页应看到「概览」tab,确认下面 4 个指标:
| 指标 | 期望值 | 含义 |
|---|---|---|
| 活动副本 | 1 | cloudflared 容器已连上 Cloudflare 边缘 |
| 状态 | 健康 | 连接稳定 |
| 边缘位置 | 显示就近数据中心(如 sjc06, sjc07... / nrt01... / lax02... 等) | 已建立 4 条 QUIC 长连接做高可用 |
| 副本表 | 一行 linux_amd64 + 版本 2026.x.x | 容器版本正确 |
| 路由 | 0(暂时是 0,本步骤就是来加这条路由的) | ✅ |
如果「活动副本 = 0」或状态「不健康」:第三步 cloudflared 容器没起来。回到服务器上
docker compose logs cloudflared看错误(最常见是TUNNEL_TOKEN复制时漏了首尾字符,或包含了换行)。
5.3 添加路由(公开应用)
Section titled “5.3 添加路由(公开应用)”进入路由配置有两个入口(任选其一):
- A. 顶部点「路由」tab → 选
Create a route/添加路由 - B. 概览页底部「路由」可视化图里点「+ 添加路由」按钮
路由类型如果让选,选 「公开应用程序」(Public Application / Published Application)——而不是「私有主机名」「私有 CIDR」或「Workers VPC」。这三个是 Zero Trust WARP 客户端场景,本手册不用。
弹出「添加已发布应用程序」表单,按下表填写:
| 字段 | 填写 | 说明 |
|---|---|---|
| 子域(可选) | photos | 你想用什么二级域名访问 |
| 域 *(必填) | example.com | 从下拉菜单选你已托管到 CF 的域名 |
| 完整主机名(自动拼接,只读) | photos.example.com | 上两项填完会自动显示 |
| 路径(可选) | 留空 | 整个域名都给 Immich,不分路径。⚠️ 该字段是正则表达式,留空 = 匹配所有 |
| 服务 URL *(必填) | http://immich-server:2283 | ⚠️ 必须以 http:// 开头,不是 https://——见下方说明 |
⚠️ URL 必须含协议前缀(scheme):
表单的 placeholder 显示
https://localhost:8080是 Cloudflare 给的通用示例(误导:不是要求 https):
- ✅ 正确:
http://immich-server:2283(Immich 容器内部是裸 HTTP)- ❌ 错误:
https://immich-server:2283(Immich 容器没装证书,TLS 握手失败 → 502 Bad Gateway)- ❌ 错误:
immich-server:2283(必须有 scheme,否则保存报错)外网访问时浏览器看到的
https://photos.example.com那一段 https 是 Cloudflare 边缘自动加的,与 cloudflared → Immich 这段内部连接的协议无关,不冲突。
💡 为什么 URL 用
immich-server而不是localhost或192.168.1.50:
- cloudflared 是个容器,它的
localhost是容器内部,不是主机- 但 cloudflared 和 immich-server 在同一个 Docker Compose 项目里,Docker 自动建了内部网络,可以直接用
服务名互相访问(即immich-server)- 如果你把 cloudflared 部署在另一台机器上(不和 immich-server 在同一个 compose),就要写 Immich 服务器的实际局域网 IP,例如
http://192.168.1.50:2283
5.4 进阶设置(可选)
Section titled “5.4 进阶设置(可选)”📌 因为 URL 直接用了
http://(不走 TLS),TLS 验证开关不需要;HTTP/2 也是默认开启。直接点「添加路由」保存即可,不用展开任何高级设置。仅当你的 URL 用了
https://(例如后端真的有 HTTPS 自签证书)才需要找「TLS 设置」分组打开「No TLS Verify」。本手册不涉及。
5.5 保存并验证 DNS 自动创建
Section titled “5.5 保存并验证 DNS 自动创建”点「保存(Save)」。Cloudflare 会做两件事:
-
在 Tunnel 上加一条路由
-
自动给你 CF 域名加一条 DNS CNAME 记录:
photos.example.com CNAME <tunnel-id>.cfargotunnel.com (代理)
通常 30 秒内 DNS 生效。回到 Tunnel 概览页应看到「路由 = 1」(不再是 0)。
初步可达性测试(不需要等 Access 配置,先确认链路通):
curl -I https://photos.example.com期望返回 HTTP/2 302 或 HTTP/2 200(302 跳转到 /auth/login 是正常的,说明已通到 Immich)。
如果返回
502 Bad Gateway:通常是「服务 URL」字段写错。常见错误(按出现频率):
- 写成
https://了——Immich 容器没装证书,必须http://(placeholder 显示 https 极易误导)- 容器名拼错(应为
immich-server,不是immich_server/immich)- 端口错或漏了
:2283- 漏了协议前缀(直接写
immich-server:2283,必须有 scheme)修复后回 5.3「服务 URL」字段改为
http://immich-server:2283重新保存。 如果返回530:DNS 还没生效,等 1-2 分钟。 如果curl直接连不上:DNS 还没传播完,等 1-2 分钟再试。
第六步:配置 Cloudflare Access 邮箱鉴权(必做,安全核心)
Section titled “第六步:配置 Cloudflare Access 邮箱鉴权(必做,安全核心)”只把 Immich 放到 Tunnel 后面还不够——任何知道 photos.example.com 的人都能看到登录页。Tunnel URL 会被 Cloudflare 公开 cert log 收录,分分钟被扫描器扫到。
Access 给你加一道邮箱白名单:陌生人即使知道域名,也过不了第一关。
6.1 首次进入 Zero Trust 的初始化
Section titled “6.1 首次进入 Zero Trust 的初始化”Dashboard 左侧栏点「Zero Trust」,第一次进入会看到欢迎页,点右上角「开始使用」按钮:
- 选择免费套餐 Free(个人用够用,最多 50 个用户)
- 设置 team domain,例如
yourfamily,完整地址变成yourfamily.cloudflareaccess.com(这是后面用户登录验证页的域名,全家人会看到,起一个能记住的名字) - 绑定一张支付方式(Free 套餐不会扣款,仅用于身份验证;可选信用卡或 PayPal)
- 完成后会跳到「开始使用 Cloudflare Zero Trust」onboarding 引导向导(4 个大场景选择 + 底部「暂时跳过此步骤」)
6.2 跳过 Zero Trust 引导向导
Section titled “6.2 跳过 Zero Trust 引导向导”点底部「暂时跳过此步骤」直接进入 Zero Trust 完整仪表板
6.3 创建 Self-hosted Application
Section titled “6.3 创建 Self-hosted Application”进入:
Cloudflare Zero Trust → 访问控制(Access controls) → 应用程序(Applications) → 添加应用程序(Add an application)6.4 选择应用程序类型:自托管和私有
Section titled “6.4 选择应用程序类型:自托管和私有”弹出「添加应用程序」对话框,左侧有 4 个大类
直接点右下角「继续使用 自托管和私有」按钮进入下一步。
6.5 配置「目标」公共主机名
Section titled “6.5 配置「目标」公共主机名”页面顶部「目标」section,下面有「公共主机名」一栏,三个字段:
| 字段 | 填写 | 说明 |
|---|---|---|
| 子域 | photos | 留空意味着保护根域 example.com;本期填 photos |
| 域(必需) | example.com | 从下拉菜单选你已托管到 CF 的域名 |
| 路径 | 留空 | 整个域名都给 Immich,不分路径保护 |
6.6(跳过)允许浏览器 RDP/SSH/VNC 访问
Section titled “6.6(跳过)允许浏览器 RDP/SSH/VNC 访问”6.7 配置 Access 策略
Section titled “6.7 配置 Access 策略”继续向下滚动到「Access 策略」section,初始状态显示「未添加策略」。
6.7.1 加第一条策略:家庭成员邮箱白名单(Allow)
Section titled “6.7.1 加第一条策略:家庭成员邮箱白名单(Allow)”点「添加策略」按钮,按下表填写:
| 字段 | 填写 |
|---|---|
| 策略名称 | Family members only |
| 操作(Action) | Allow(允许) |
| 会话持续时间 | 与应用程序会话超时相同(默认即可,全局在 6.10 配置) |
| 配置规则(Include) | 电子邮件(Emails) |
| Value | 第四步在 Immich 里创建的所有家庭成员邮箱,逐一添加(如 wife@example.com、kid@example.com、dad@example.com 等) |
确认这条策略。
6.7.2 不在本应用加 Bypass 策略(架构变化,移到 6.13 独立应用)
Section titled “6.7.2 不在本应用加 Bypass 策略(架构变化,移到 6.13 独立应用)”⚠️ 关键架构说明:策略层没有路径字段——路径在**目标(公共主机名)**层面配置。
单个 Application 无法实现”全站需邮箱 + /api/* 放行”。Cloudflare 推荐的架构是建两个独立 Application 共存于同一域名,按”更具体路径优先”匹配:
应用 1(本步骤建) 应用 2(6.13 步骤再建) 名称: Family Photos名称: Family Photos - API Bypass目标: photos.example.com,路径留空目标: photos.example.com,路径 =api/*策略:6.7.1 的 Allow + 家庭邮箱 策略:Bypass + 所有人 命中:浏览器访问首页/相册 → 走邮箱验证 命中:移动 App API 调用 → 直接放行 CF 按”更具体路径优先”匹配——
/api/...落入应用 2,其他路径落入应用 1。本步骤只加 6.7.1 那一条 Allow 策略,不要在本应用里加 Bypass。Bypass 在 6.13 单独建应用 2 解决。
⚠️ 不要在本应用里加 Bypass 策略:策略层无路径字段,加 Bypass + 所有人会让 CF 对整个
photos.example.com全部路径都绕过 Access——任何人都能直接进 Immich 登录页,邮箱保护彻底失效。
6.8(可选)用「策略测试器」预先验证
Section titled “6.8(可选)用「策略测试器」预先验证”6.9 配置「身份验证」section
Section titled “6.9 配置「身份验证」section”页面右上角的「身份 / MFA」切换:保持「身份」即可。
6.10 填「详细信息」section(页面最底部)
Section titled “6.10 填「详细信息」section(页面最底部)”继续滚动到页面最底部「详细信息」section:
| 字段 | 填写 | 说明 |
|---|---|---|
| 名称(必需) | Family Photos | 应用名,会显示在登录页和 App Launcher 上给家庭成员看 |
| 会话持续时间(必需) | 从默认 24 hours 改为 1 month | ⚠️ 默认 24 小时对家庭场景太短(每天都要重验证);改为 1 月后家人 30 天内不用反复输验证码 |
💡 字段提示「策略和全局会话持续时间会覆盖应用程序会话持续时间」——意思是 6.7.1 策略级别和系统全局级别的 Session 设置,会覆盖这里的应用级 Session。我们 6.7.1 用了「与应用程序会话超时相同」= 跟随这里的 1 month。
6.11 保存应用 1(Family Photos)
Section titled “6.11 保存应用 1(Family Photos)”页面最底部点「保存」(Save)按钮,应用 1 创建完成。回到「应用程序」列表页应能看到 Family Photos 一行,状态正常。
6.13 创建应用 2:Family Photos - API Bypass(移动 App 必需)
Section titled “6.13 创建应用 2:Family Photos - API Bypass(移动 App 必需)”回到「访问控制 → 应用程序」列表页,再点「添加应用程序」,按下面流程复用 6.4 路径:
6.13.1 选择应用程序类型
Section titled “6.13.1 选择应用程序类型”与 6.4 相同:选「自托管和私有」→「继续使用 自托管和私有」。
6.13.2 配置目标(关键差异:填路径)
Section titled “6.13.2 配置目标(关键差异:填路径)”「目标 → 公共主机名」section:
| 字段 | 填写 | 说明 |
|---|---|---|
| 子域 | photos | 与应用 1 完全相同 |
| 域 | example.com | 与应用 1 完全相同 |
| 路径 | api/* | ⚠️ 这是与应用 1 的唯一区别——只匹配 API 路径 |
⚠️ 路径语法说明:
Application Path 字段使用 glob 通配符(
*),不是正则表达式。正确写法:
- ✅
api/*(推荐)—— 标准 glob,匹配/api/后所有路径- ✅
/api/*—— 加斜杠也行故障验证(用最稳定的 ping 端点,避免 API 重命名问题):
Terminal window curl -I https://photos.example.com/api/server/ping# 错误状态:HTTP/2 302,location 跳转到 *.cloudflareaccess.com → Bypass 路径写错(最常见是写成了 regex)# 正确状态:HTTP/2 200 + 含 "pong" 的 JSON → Bypass 已生效## 提示:如果返回 404,说明 Bypass 已生效但 Immich 版本端点路径不同——# 换用浏览器访问 https://photos.example.com/ 测邮箱验证流程是否正常即可。
6.13.3 跳过 RDP/SSH/VNC、跳过身份验证调整、加 Bypass 策略
Section titled “6.13.3 跳过 RDP/SSH/VNC、跳过身份验证调整、加 Bypass 策略”- RDP/SSH/VNC section:跳过(与 6.6 相同)
- 「Access 策略」section 点「添加策略」:
| 字段 | 填写 |
|---|---|
| 策略名称 | API bypass for mobile apps |
| 操作(Action) | Bypass(绕过) |
| 配置规则(Include) | 所有人(Everyone) |
💡 Bypass 策略只配身份层规则(包含=所有人/IP/Country/Group),没有路径字段——路径已经在 6.13.2 目标里限定为
api/*,不会泛滥。
「身份验证」section:保持默认即可(Bypass 不走身份验证,无关紧要)。
6.13.4 填详细信息 + 保存
Section titled “6.13.4 填详细信息 + 保存”页面底部「详细信息」section:
| 字段 | 填写 |
|---|---|
| 名称 | Family Photos - API Bypass |
| 会话持续时间 | 默认即可(Bypass 不依赖 session) |
页面最底部「保存」。
6.13.5 验证两个应用共存
Section titled “6.13.5 验证两个应用共存”回到应用程序列表,应能看到 2 行:
Family Photos photos.example.com AllowFamily Photos - API Bypass photos.example.com (api/*) Bypass6.14 验证 Access 策略已生效
Section titled “6.14 验证 Access 策略已生效”外网(不要在自家 Wi-Fi 下——CF 可能因 IP 缓存让本地放行;手机切 4G 或换台电脑)访问 https://photos.example.com,预期看到 Cloudflare 的邮箱验证页(域名是 yourfamily.cloudflareaccess.com/...):
Sign in to Family Photos Enter your email below to receive a one-time code. [输入邮箱框] [Send me a code]输入第四步在 Immich 里创建的家庭成员邮箱 → 收到 6 位验证码 → 输入后跳转到 Immich 登录页 = 应用 1 工作正常。
命令行验证两个应用各自生效:
# ① 验证应用 1(Allow):根路径应跳转到 cloudflareaccess.comcurl -I https://photos.example.com# 期望:HTTP/2 302# 期望 location 头含 yourfamily.cloudflareaccess.com
# ② 验证应用 2(Bypass):/api 路径应直接打到 Immich,不被 Access 拦截curl -I https://photos.example.com/api/server/version# 期望:HTTP/2 200 或 401(Immich 自身处理)# 不应:302 跳转 cloudflareaccess(说明 Bypass 没生效,App 会登录失败)故障排查:
| 症状 | 原因 | 修复 |
|---|---|---|
| 根路径直接看到 Immich 登录页(没邮箱验证) | 应用 1 的 Allow 策略没生效 | 6.5 公共主机名是否与第五步 Tunnel 路由完全一致 |
/api/server/version 返回 302 跳 cloudflareaccess | 应用 2 的 Bypass 策略没生效 | 6.13.2 路径必须用 glob api/*(不是 regex ^/api/.*);列表页是否真有 2 行应用 |
/api/server/version 返回 404 | Bypass 已生效(请求到了 Immich),但端点路径在你的 Immich 版本里不存在 | 这是好消息!换用 /api/server/ping(v1.113+ 通用)或浏览器访问 https://photos.example.com/ 测邮箱验证 |
/api/... 返回 200,根路径也返回 200(不跳验证) | Bypass 策略覆盖范围太大,把根路径也绕过了 | 6.13.2 路径写成了 * 或留空——改回 api/* |
| 邮箱验证页显示但收不到验证码 | 邮箱不在 Allow 列表 / 进了垃圾箱 | 6.7.1 检查 Value 列表 + 检查垃圾邮件箱 + 把 notify.cloudflare.com 加邮箱白名单 |
| 保存报错或登录页 500 | 顶部「Access 服务降级」告警 | 等 1-2 小时,看 CF 状态页 恢复后重试 |
关于 Immich API 端点变化:v1.113.0 起
/api/server-info/*全部重命名为/api/server/*。如果你看到的是 v1.112 或更老版本,验证命令应换回/api/server-info/version。最稳定的健康检查端点是/api/server/ping,所有现代版本都支持。
第七步:移动端 App 安装 + 远程登录
Section titled “第七步:移动端 App 安装 + 远程登录”App Store / Google Play 搜索 Immich,认准开源标识。
家庭每个成员在自己手机上:
- 打开 Immich App
- Server Endpoint URL 填:
https://photos.example.com/api- App 直接跳转到 Immich 用户名 / 密码登录页
- 输入管理员在第四步发给你的账号和临时密码
- 首次登录后改密码
第八步:配置备份设置
Section titled “第八步:配置备份设置”触发备份的方式:
- 前台备份:打开 Immich App,备份进度条自动出现在顶部,App 保持前台运行即持续上传
- 后台备份(iOS 系统限制较多):需要额外开启
iPhone 设置 → 通用 → 后台 App 刷新 → Immich = 开启第九步:设置共享方式(三种选一种或组合用)
Section titled “第九步:设置共享方式(三种选一种或组合用)”家庭照片共享在 Immich 里有三种姿势,按需选用:
共享方式 A:Shared Album 共享相册(推荐主用)
Section titled “共享方式 A:Shared Album 共享相册(推荐主用)”最适合”全家相册”场景。
操作(任意账号都能创建):
相册 → 新建相册 → 命名"我家相册 2026" → 添加照片 → Share → 邀请用户 → 选家庭成员 → 给他们写权限(可上传)效果:
- 全家人都能往这个相册加照片
- 所有人都能看
- 适合:孩子成长、旅行、聚会、节日
共享方式 B:Partner Sharing 配偶共享(夫妻向)
Section titled “共享方式 B:Partner Sharing 配偶共享(夫妻向)”适合”我老婆所有照片我都能看,反之亦然”。
Partner Sharing 需通过浏览器 Web 端配置,iOS App 的设置页没有此入口。
操作(浏览器打开 https://photos.example.com):
右上角头像 → 账号设置 → 好友共享 → 添加协作者 → 选另一半的账号 → 保存配置后,另一半打开 App 会收到”邀请”通知,接受后双方照片互可见。
在 iOS App 查看对方照片:
底部 资源库(Library)→ 伙伴照片(Partner Photos)效果:
- 单向只读(双方各自添加对方 = 双向可见)
- 对方整个时间线在”资源库 → 伙伴照片”里可见
- 不会混入你自己的主时间线(各自独立)
共享方式 C:Public Share Link 公开链接(给爷爷奶奶用)
Section titled “共享方式 C:Public Share Link 公开链接(给爷爷奶奶用)”适合”老人不想注册账号,扫码就能看孙子最新照片”。
操作:
打开任意相册 / 选一组照片 → Share → Create Link → 设置过期时间(建议 30 天) → 设置密码(可选) → 复制链接第十步:远程访问验证
Section titled “第十步:远程访问验证”家里 Wi-Fi 下(建议先在家里测一遍):
浏览器访问 https://photos.example.com应该:邮箱验证 → 进入 Immich 登录页 → 输入密码 → 看到自己的相册。
外网验证(关掉家里 Wi-Fi,手机切 4G/5G):
重复上面流程,确认在外面也能进。
移动 App 远程上传验证:
- 出门拍一张照片
- 等 1-2 分钟(Wi-Fi 状态下应秒传)
- 在浏览器 photos.example.com 看是否出现
如能出现,说明全套链路打通。
优化效果汇总
Section titled “优化效果汇总”| 阶段 | 效果 | 全家可达成的能力 |
|---|---|---|
| 初始(裸 iPhone + iCloud 50G) | iCloud 月费 + 容量焦虑 + 无法共池 | 各拍各的,分享靠微信压缩图 |
| 完成第三步(Immich 已部署) | 局域网内可访问 | 在家电脑能看,外面不能 |
| 完成第六步(CF Tunnel + Access) | 外网域名可访问 + 邮箱白名单 | 任何设备浏览器都能看,陌生人扫不到 |
| 完成第七、八步(移动端备份) | 全家自动备份 | 拍照就传到家里,iOS 受系统限制需偶尔手动触发 |
| 完成第九步(共享) | 共享相册 + Public Link | 全家共池 + 给爷爷奶奶发链接 |
实际上传速度 / 后台稳定性 / 大库扫描时间因家庭宽带、服务器配置和 iOS 行为而异,建议搭好后实测一周再决定是否取消 iCloud 付费。强烈建议保留 iCloud 50G 免费档作为系统级兜底,Immich 作为永久镜像和家庭共享中枢。
502 Bad Gateway
Section titled “502 Bad Gateway”原因:Cloudflare Tunnel 找不到 Immich 容器。
排查:
# 在服务器上测本地是否通curl -I http://localhost:2283
# 看 cloudflared 日志docker compose logs cloudflared | tail -50常见错误:
| 错误 | 修复 |
|---|---|
「服务 URL」写成 https://immich-server:2283(placeholder 是 https 极易误导) | 改成 http://immich-server:2283 |
漏了协议前缀,写成 immich-server:2283 | 必须含 scheme:http://immich-server:2283 |
| 容器名写错 | 必须和 docker-compose.yml 里 service 名一致:immich-server(不是 immich_server 或 immich) |
| cloudflared 和 immich-server 不在同一 compose 项目 | 用局域网 IP:http://192.168.1.50:2283 |
Cloudflare Access 验证码收不到
Section titled “Cloudflare Access 验证码收不到”原因:
- 邮箱不在 Access Policy 的 Include 列表
- 邮件被识别为垃圾邮件
- 企业邮箱拦截
noreply@notify.cloudflare.com
解决:
- 检查 Cloudflare Zero Trust → Access → Applications → 你的 App → Policies → Include Emails 列表
- 检查垃圾邮件箱
- 把
notify.cloudflare.com加入邮箱白名单
移动端 App 登录后看不到照片
Section titled “移动端 App 登录后看不到照片”原因:通常是 Server Endpoint URL 填错。
正确格式:
https://photos.example.com/api注意:
- 必须是
https://,不是http:// - 末尾必须是
/api,不是裸域名 - 不能有结尾斜杠
如果还是不行:
# 检查 Bypass 策略是否生效(用 ping 端点最稳定,所有 Immich 版本都支持)curl -I https://photos.example.com/api/server/ping# ✅ 200 + JSON → Bypass 工作 + Immich 响应正常# ✅ 404 → Bypass 工作(请求到了 Immich),只是该版本端点不同;浏览器测试即可# ❌ 302 → cloudflareaccess.com → Bypass 没生效,回 6.13 检查路径字段是 glob `api/*` 不是 regex如果返回 302 跳转到 *.cloudflareaccess.com,说明 Bypass 策略没生效,回去第 6.13 步检查独立的 Family Photos - API Bypass 应用是否真的存在,且其目标路径为 glob api/*。必须有 2 个独立应用才行——单一应用加 Bypass 策略带路径的方式不可用。
上传速度很慢
Section titled “上传速度很慢”可能原因和优化:
| 原因 | 优化 |
|---|---|
| 家庭宽带上行小(电信常见 30Mbps) | 给 Immich 配独立时段(午夜上传) |
| 服务器 CPU 卡在缩略图生成 | 暂停后台 ML 任务 → 上传完再开 |
| 同时多人上传抢带宽 | 错峰上传 |
| Cloudflare 中转远 | 一般家庭可以忽略,移动端 App 直传速度通常稳定 |
服务器睡眠后访问失败
Section titled “服务器睡眠后访问失败”原因:
- Mac 自动睡眠 / Windows 进入待机
- 笔记本合盖默认睡眠
解决(按系统):
| 系统 | 命令 / 设置 |
|---|---|
| macOS | caffeinate -dimsu 或装 Amphetamine(免费) |
| Linux 桌面 | 系统设置 → 电源 → 永不待机 |
| Windows | 控制面板 → 电源选项 → “高性能” |
| 笔记本合盖 | macOS:sudo pmset -c disablesleep 1;Windows:电源选项 → 合盖时不操作 |
最稳的方案是专门买一台便宜 N100 Mini PC 当家庭服务器(人民币 800-1500),24 小时通电不睡眠,全年电费几十块。
多账号怎么互相分享
Section titled “多账号怎么互相分享”参见第九步。最常用的是:
- 全家共享相册 = Shared Album(多人写)
- 夫妻互看全部 = Partner Sharing(单向,双方各设置一次=互看)
- 给老人/朋友分享 = Public Share Link(无需账号)
想存电影 / 电视剧能行吗
Section titled “想存电影 / 电视剧能行吗”不建议把 Immich 当电影库用。Immich 是相册(按日期组织、EXIF 元数据),不是影音媒体中心。
⚠️ 免责声明:本教程仅供技术学习与家庭自托管交流,请遵守您所在国家/地区的相关法律法规。Immich 不应作为唯一备份方案——官方明确建议配合 iCloud / 外挂硬盘 / 第三方云任一种作双备份,避免版本升级或硬件故障导致数据丢失。