Featured image of post セルフホストのimmichをCloudflare環境で100MB制限を回避する

セルフホストのimmichをCloudflare環境で100MB制限を回避する

セルフホストで画像を集約するためにimmichを使えるようにする目的で、ちゃんと使うためにCloudflareの100MB制限を対処する方法を検討してみる

immich

Google Oneを100GBで契約しているけどAIプランを使うつもりが無いのでストレージ容量を結構気にしないといけない感じになっている。
画像のアップロード場BAN対象になりやすそうなのもあり、セルフホスト出来るGoogleフォト代替のimmichを試してみる。

Cloudflareの公開アプリケーションにおける制限について

Cloudflareではプロキシトラフィック1ペイロードあたりの制限がプランごとに決まっていて、Freeプランでは100MBに制限されている。Error 413
Cloudflareの1ペイロード制限

画像であれば基本的に問題ないのでimmichで問題になることはあまりないかな?と思っていたけど動画を扱うと一瞬で100MBくらいは飛ぶのでできるだけ回避しておきたい。

方針

以下のような構成を想定して構築する。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
スマートフォン
Cloudflare One Client / WARP
       │
       │ 認証済み端末
       ▼
Cloudflare Zero Trust
       │
       │ Private hostname route
       ▼
cloudflared(自宅)
       │
       ▼
Immich
192.168.x.x:2283

Cloudflare Zero TrustのPrivate hostname routeで公開せずにCloudflare Oneの認証を利用してアクセスする方式にする。
ドキュメントを見ると以下の記載があり、1ファイルが大きい場合はPrivate network routeを使用するように記載がある。Routing

1
2
Public hostname routes proxy traffic through Cloudflare. On Free, Pro, and Business plans, the service-specific terms ↗ require you to use a specific paid service to serve video and other large files.
Refer to Delivering videos with Cloudflare for more information. To transfer large files privately, use a private network route instead.

Private networkについてはCloudflare One経由でのアクセスに限定されるけれど、現状CloudflareAccessの認証でOne/WARP利用を条件にしているので、使い勝手としては変わらないはず。
自分以外、もしくは家族とか特定の人以外がアクセスしないような環境であればこの方法で問題ないはず、ということでこの方法で進める。
そしてPrivate Hostname Routeについては先月一般提供始まった機能らしいので、これを使ってみる。

構成環境

概要

環境としてはRHEL10のPodman環境で構築する。
想定している構成は以下のような感じでtunnel用のcloudflaredをDMZ環境にしてリバースプロキシでやり取りする。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
                     Cloudflare
                         │
                    Immich Tunnel
                         │
                         ▼
┌────────── Immich VM ────────────────┐
│                                     │
│  Podman network: immich-edge        │
│                                     │
│  cloudflared ─── Reverse Proxy      │
│                       │             │
│              ─────────┼────────     │
│                       │             │
│  Podman network: immich-app         │
│                       │             │
│                 Immich Server       │
│                       │             │
│                PostgreSQL / Valkey  │
│                                     │
└─────────────────────────────────────┘

最終的にimmichはEntraIDログインを強制するように出来るようなので、そのようにすることでパスワードを個別に管理することもしないことにする。

使用サービス

以下の構成で検討。

  • edge
    • cloudflared
    • caddy
  • app
    • immich-server
    • postgres
    • valkey

データ自体はNASのHDDに置くようにして、その他はSSDで管理するように。
NASからVMまではNFSで共有。

Cloudflare Zero Trust設定

いくつかの設定はあるけれど基本的には

  • tunnelの追加
  • プライベートホストのルート設定を追加
  • Accessのアプリケーション設定の追加

といった感じでいく。
後述するけどプライベートホストの名前はTLSで通信するための証明書を確保しようとする場合は保有するドメイン名で適当につける。

Cloudflare APIの設定

TLS用の証明書確保のためLet’s Encriptを使うのだけれど、ローカルのIPアドレスのためDNS-01を使用する。そのために更新用のCloudflareでAPI設定をする必要がある。

アカウントの管理
→ アカウントAPIトークン
→ トークンを作成
→ 最初から作成
→ 対象を「指定ドメイン」にして対象を指定
→ DNS & Zone

1
2
DNS:Edit  
Zone: Read

に設定する。
このときのAPIトークンを使用する。

必要なトークンは一度しか表示されないので、記録を忘れたら作り直し。
DNS-01の解説はこちらにありました。ホームサーバーの自己署名証明書を Let’s Encrypt の DNS-01 に変更し、自動配布まで行う

Caddy

Docker構成

DockerHubにある標準?のCaddyだとCloudflareのDNS-01に対応していない?らしいのでCodexにDocerfile書いてもらった。

dockerfile

1
2
3
4
5
FROM docker.io/library/caddy:2-builder-alpine AS builder
RUN xcaddy build --with github.com/caddy-dns/cloudflare
FROM docker.io/library/caddy:2-alpine
COPY --from=builder /usr/bin/caddy /usr/bin/caddy
COPY Caddyfile /etc/caddy/Caddyfile

Caddyfile

リバースプロキシとして使用するCaddyがこのあたりの仕組みに対応しているようなので、Caddyfileに書いてしまう。

caddifile

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
{
	email {$ACME_EMAIL}
	acme_ca https://acme-v02.api.letsencrypt.org/directory
	auto_https disable_redirects
}

https://{$IMMICH_PRIVATE_HOSTNAME} {
	tls {
		dns cloudflare {env.CF_API_TOKEN}
		resolvers 1.1.1.1
	}

	reverse_proxy immich-server:2283
}

ACME_EMAILやIMMICH_PRIVATE_HOSTNAMEは.envでまとめる感じで。
先ほど設定したトークンはCF_API_TOKENに指定する。

テスト

アクセステスト

Cloudflare OneをONにした状態でアクセス出来るか確認してOKなら、その後Cloudflare OneをOFFにしてアクセスできないことを確認する。
ついでに、ローカルからはTLSなしのhttpでアクセスすることにしたのでそういう環境で。
immichのアプリ設定を見たところ、SSIDでローカル切替が出来るようなのでこれを利用してみたけど他のアプリと同様にVPN設定しているとWifiのSSID検出ができないようでうまくいかない。
Cloudflare OneをOFFにしたら超高速でアップロードできたので、ちゃんとローカルと外部で切替はできている模様。
やっぱりインターネット回線を10Gbpsにしたいな。
10Gbpsでつながればゼロトラストな考えでローカルネットワークの通信も大半を一度インターネット側に渡しても良くなる気がする。

大容量転送

この状態で起動して初期設定をしたあと、スマホで2分くらいの動画撮影してCloudflare経由で転送して問題ないことを確認する。
300MBちょいのファイルを問題なく転送できたので、想定通りの動作をしている。