SSD Nodes Learn Hosting plans →
ガイド Matt Connor著者 Matt Connor

Immichに外出先からアクセスする方法:MAP-E/DS-Liteでもポート開放なし

自宅のNASやミニPCで動くImmichに、外出先のスマホから安全につなぐ方法。v6プラス(MAP-E)やDS-Liteでポート開放できなくても使えるTailscale、Serve/Funnel、VPS中継の4ルートを比べ、どれを選ぶかを決めます。

結論:まずTailscale、共有リンクか独自ドメインが必要になったらVPSを前に置く

Immichに外出先からアクセスする一番確実な方法は、スマホと、Immichが動いている自宅の機械(NAS、Raspberry Pi、ミニPC)の両方にTailscaleを入れることです。ルーターのポート開放は一切不要で、v6プラス(MAP-E)やtransix(DS-Lite)のようにポートが自由に開けない回線でもそのまま動きます。家族以外に共有リンクを送りたい、あるいは photos.example.com のような自分のドメインで使いたい場合だけ、VPSを公開側の窓口にして、自宅から逆向きのトンネルを張ります。

順番はこうです。最初にImmich特有の「外から届かない時の壊れ方」を整理します。次に日本の回線事情を確認します。そのうえで4つのルートを順位付けし、最後にどれを選ぶかを決めます。

なぜImmichの外部アクセスは他のアプリより面倒なのか

Immichは「家の中でブラウザから使うWebアプリ」ではなく、スマホが一日中話しかけてくるサーバーです。そこが他のセルフホストアプリと違います。外から届かない時の壊れ方は4つあります。

モバイルアプリはサーバーURLをひとつしか知らない。 ログイン時に入力した http://192.168.1.20:2283 のようなURLは、家のWi-Fiを出た瞬間に届かなくなります。アプリは接続できないと表示するだけで、原因が「家のWi-Fiから出たこと」だとは教えてくれません。

バックグラウンドのバックアップは静かに止まる。 Immichのモバイルアプリは、OSのバックグラウンド処理の中で写真をアップロードします。サーバーURLに届かなければ失敗しますが、通知は出ません。次に家に帰ってアプリを開くまで、何日分も溜まったままになります。しかも初期設定ではWi-Fi接続時しかアップロードしないので、モバイル回線でバックアップさせたいなら、アプリのバックアップ設定でモバイルデータの利用を許可しておく必要があります。iOSはさらに、バックグラウンド処理をいつ走らせるかをOSが決めるため、「設定 > 一般 > Appのバックグラウンド更新」を有効にしていても頻度は保証されません。

共有リンクは External Domain の設定どおりのURLで作られる。 Immichの管理画面には External Domain という設定があり、共有リンクとメール通知に使うドメインを上書きします(画面上の場所と表記は、現行バージョンのImmichのドキュメントで確認してください)。ここが http://192.168.1.20:2283 のままなら、家の外にいる相手がリンクを開いても何も表示されません。言い換えると、外から届くURLがひとつ決まらないと、共有リンクという機能そのものが使えません。

Web UIをそのまま公開IPに出すのが、どのルートも避けている行為。 ログイン画面は、認証前の状態で誰でも見られます。Immichは開発が速く、認証まわりの修正も定期的に入ります。アップデートを一度忘れただけで、家族の写真すべてが総当たり攻撃や既知の脆弱性の的になります。下の4ルートはどれも、「Immichそのものをインターネットに直接見せない」か、「見せるならTLS終端と前段を自分で持つ」かのどちらかです。

日本の回線事情:MAP-EとDS-Liteではポート開放を前提にできない

英語圏の記事は「ルーターで2283番をポートフォワードすれば終わり」と書きます。日本の光回線の多くでは、それが通用しません。

いま主流なのはIPoE(IPv6経由の接続)で、その上にIPv4を載せる「IPv4 over IPv6」方式です。代表的な方式が2つあります。MAP-Eは、1つのグローバルIPv4アドレスを複数の契約者で共有し、各契約者には限られたポート範囲だけを割り当てる方式です。80番や443番のような若い番号は、通常その範囲に含まれません。DS-Liteは、IPv4の通信を事業者側の大きなNAT装置(AFTR)が肩代わりする方式で、契約者側でポートを開ける手段が原則ありません。

v6プラス、OCNバーチャルコネクト、クロスパスはMAP-E系、transixはDS-Lite系として知られています。ただし同じ名前でも、提供事業者や契約プランによって、割り当てポート数、固定IPオプションの有無、PPPoE併用の可否が違います。ここでは特定の事業者の方針を断言しません。契約中のISPの説明ページと、ルーターの管理画面で、自分の接続方式と開放できるポートを確認してください。

確認のコツは2つです。ひとつは、ルーターの管理画面の「接続状態」や「WAN側」の表示に MAP-E、DS-Lite、PPPoE のどれが出ているかを見ること。もうひとつは、自宅のPCで次を実行して、ルーターがWAN側に持っているIPv4アドレスと見比べることです。

curl -4 https://ifconfig.me

DS-Liteならルーター自身がグローバルIPv4アドレスを持っていないので、表示されたアドレスとルーターのWAN側アドレスは一致しません。MAP-Eなら一致しますが、そのアドレスは他の契約者とも共有されています。

どちらの方式でも、自宅から外への通信は普通に出ていきます。 下の4ルートはすべて、自宅側から外向きに接続を張り、それを逆向きに使う設計です。だからポート開放が要りません。

Immichに外出先からアクセスする4つのルートと順位

順位の基準は「家族の写真ライブラリを、できるだけ少ない手間で安全に外から使う」です。

  1. Tailscaleをスマホと自宅機に入れる。ポート開放ゼロ。ほとんどの家庭はここで終わります。
  2. Tailscale Serve でtailnet内にHTTPSを用意し、公開の共有リンクが必要な時だけ Funnel を使う。
  3. VPSを公開側の窓口にする。自宅からWireGuardかSSHで逆向きトンネルを張り、VPS上のCaddyかnginxで自分のドメインとTLS証明書を持つ。
  4. ライブラリの大きさが許すなら、Immich自体をVPSで動かす。

ルート1:Tailscaleをスマホと自宅機に入れる

Tailscaleは、WireGuardを土台にした仮想ネットワーク(tailnet)を作るサービスです。各機器が外向きに接続を張り、NATの内側同士でも直接通信できるように調整してくれます。スマホと自宅のImmichホストが同じtailnetに入れば、Immichホストは 100.x.y.z という固定のTailscale IPアドレスでスマホから見えます。ルーターには何も触りません。ポート開放の代わりにこの仕組みを使う考え方は、ポート開放の代わりにTailscaleを使う理由にまとめてあります。

自宅機側の手順

Raspberry Pi、ミニPC、Immichをdocker composeで動かしているLinux機なら、公式のインストールスクリプトで入ります。

curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up

tailscale up は、ブラウザで開くログイン用のURLを表示します。開いてログインすれば、その機械がtailnetに参加します。SynologyとQNAPにはパッケージ形式で、それ以外のNASにはDockerイメージでTailscaleが提供されています。手順はTailscale公式のNAS向けドキュメントに従ってください。

確認します。

tailscale status
tailscale ip -4

tailscale status に自分の機械が並び、tailscale ip -4100. で始まるアドレスを1つ返せば完了です。このアドレスは、その機械がtailnetにいる限り変わりません。

Immichが2283番で応答しているかも、この時点で自宅機の上から確かめておきます。

curl -s http://127.0.0.1:2283/api/server/ping

{"res":"pong"} が返れば、ImmichのAPIは生きています。何も返らない場合は、Immichが起動していないか、docker composeの ports が別の番号になっています。

スマホ側の手順

Tailscaleアプリをインストールして、自宅機と同じアカウントでログインします。次に、スマホのブラウザで http://100.x.y.z:2283 を開いてください。Immichのログイン画面が出れば、経路は通っています。アプリより先にブラウザで確かめる理由は、失敗の切り分けが楽になるからです。ブラウザで開けてアプリで開けないなら、問題はImmichアプリ側の設定です。

ImmichアプリのサーバーURLに http://100.x.y.z:2283 を入れてログインします。Tailscaleの MagicDNS を有効にしていれば、http://<機械名>:2283 のような名前でも届きます。

家のWi-Fiにいる時だけLAN側のアドレスを使いたいなら、Immichアプリには Automatic URL switching(自動URL切り替え)という設定があります。指定したWi-Fiに接続している時はローカルURLを使い、それ以外の時は登録した外部URLを上から順に試します。Wi-Fi名を読むために位置情報の権限を求められます。設定の場所と表記はアプリのバージョンで変わるので、現行のImmichのドキュメントで確認してください。ただし、Tailscaleは同じLANにいる相手とはLAN経由で直接つなぐので、Tailscale IPをそのまま使い続けても速度で困ることはほとんどありません。

バックアップを外でも動かすために

モバイル回線でのバックアップは、Immichアプリの初期設定ではWi-Fi接続時のみです。外でもアップロードさせたいなら、アプリのバックアップ設定でモバイルデータでのアップロードを許可します。次に、Tailscaleの接続が切れていないことを確かめます。iOS版のTailscaleアプリには、VPNが切れた時に自動で再接続する VPN On Demand(オンデマンド)の設定があります。バックグラウンドのバックアップが走る瞬間にVPNが落ちていれば、アップロードは失敗し、通知も出ません。オンデマンドを有効にして、翌朝Immichのタイムラインに前日の写真が並んでいるかで判断してください。

ルート1の正直な限界

共有リンクはtailnetのメンバーにしか届きません。 External Domain を http://100.x.y.z:2283 にすれば共有リンクは作れますが、開けるのはTailscaleに入っている人だけです。祖父母のスマホにTailscaleを入れてtailnetに招待すれば動きますが、「LINEでリンクを送るだけ」にはなりません。

無料プランには人数と台数の上限があります。 家族分のスマホとNASにノートPCまで足していくと、上限に当たることがあります。現在の枠はTailscale無料プランの上限にまとめてありますが、数字はTailscaleの料金ページで確認してください。

Tailscaleの調整サーバーに依存します。 鍵の交換と機器の発見は、Tailscale社のサーバーが担います。通信そのものはWireGuardで端末間が直接暗号化し、Tailscale社は中身を読めません。それでもその依存が気になるなら、調整サーバーを自分で持つHeadscaleでコントロールプレーンを自前で動かすという選択肢があります。

ルート2:Tailscale ServeでHTTPS、Funnelで公開の共有リンク

ルート1の http://100.x.y.z:2283 は平文のHTTPです。Tailscaleのトンネル自体がWireGuardで暗号化されているので盗聴の心配はありませんが、ブラウザはただの http:// として扱います。ブラウザの一部の機能(PWAとしてのインストールなど)はHTTPSでしか使えませんし、共有リンクに http://100.x.y.z と書いてあると、受け取った側は怪しく感じます。

Tailscale Serve は、tailnet内の機器に https://<機械名>.<tailnet名>.ts.net というURLと、Let's Encryptの有効な証明書を用意し、指定したローカルポートに転送します。Immichホストで実行します。

sudo tailscale serve --bg 2283
sudo tailscale serve status

--bg を付けると、端末を閉じても転送が残ります。事前にTailscaleの管理コンソールで MagicDNS と HTTPS証明書 を有効にしておく必要があります(設定の名前と場所はTailscaleの現行ドキュメントで確認してください)。tailscale serve statushttps://<機械名>.<tailnet名>.ts.net から http://127.0.0.1:2283 への転送を表示すれば完了です。スマホからそのURLをブラウザで開き、証明書の警告なしにImmichのログイン画面が出ることを確かめます。ImmichアプリのサーバーURLと External Domain を、このURLに変えてください。

ここまでは、まだtailnetの外からは届きません。誰でも開ける共有リンクが必要なら、Tailscale Funnel を使います。

sudo tailscale funnel --bg 2283
sudo tailscale funnel status

tailnetのポリシーでFunnelがまだ許可されていない場合、初回の実行時に有効化用の管理コンソールのURLが表示されます。それを開いて許可すると、https://<機械名>.<tailnet名>.ts.net がインターネット全体から開けるようになります。Funnelが使えるのは443、8443、10000番の3ポートだけで、通過する帯域には設定で変えられない上限があります。上限の数値やプランごとの条件はここには書きません。Tailscaleの料金ページとFunnelのドキュメントで確認してください。

Funnelを有効にした時点で、Immichのログイン画面は世界中から見える状態になります。「Web UIを公開しない」というルート1の利点は失われ、TLS終端をTailscaleが持ってくれる点だけが残ります。ずっと開けておくより、共有が必要な期間だけ有効にし、終わったら sudo tailscale funnel reset で閉じる運用が現実的です。ServeとFunnelのどちらを、いつ使うべきかは、Tailscale ServeとFunnelの使い分けで詳しく比べています。

ルート3:VPSを公開側の窓口にして、自宅から逆向きトンネルを張る

「誰でも開ける共有リンク」と「自分のドメイン」の両方が要り、それでいてルーターは触れない、という人のルートです。仕組みは3つの部品でできています。

  • 公開IPを持つVPS。ここが https://photos.example.com の窓口になります。
  • 自宅機からVPSへ、外向きに張るトンネル。WireGuardかSSHのどちらかです。MAP-EでもDS-Liteでも、外向きの接続は普通に出ていくので成立します。
  • VPS上のリバースプロキシ(Caddyかnginx)。ドメインのTLS証明書を持ち、受けたリクエストをトンネル越しに自宅のImmichへ渡します。

Immichは https://example.com/immich のようなサブパスでは動きません。ドメインかサブドメインのルートを丸ごと使う必要があるので、photos.example.com のようなサブドメインを作って、DNSでVPSのIPアドレスに向けておきます。

WireGuardでトンネルを張る

VPSがWireGuardのサーバー、自宅機がクライアントです。両方の機械で鍵を作ります。

sudo apt update && sudo apt install -y wireguard
sudo install -d -m 700 /etc/wireguard
sudo sh -c 'umask 077; wg genkey > /etc/wireguard/private.key'
sudo sh -c 'wg pubkey < /etc/wireguard/private.key > /etc/wireguard/public.key'

VPS側の /etc/wireguard/wg0.conf は次のとおりです。

[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = <VPSのprivate.keyの中身>

[Peer]
PublicKey = <自宅機のpublic.keyの中身>
AllowedIPs = 10.8.0.2/32

自宅機側の /etc/wireguard/wg0.conf はこうです。

[Interface]
Address = 10.8.0.2/24
PrivateKey = <自宅機のprivate.keyの中身>

[Peer]
PublicKey = <VPSのpublic.keyの中身>
Endpoint = <VPSの公開IP>:51820
AllowedIPs = 10.8.0.1/32
PersistentKeepalive = 25

自宅側の AllowedIPs10.8.0.1/32 に絞っているのが要点です。VPS宛の通信だけがトンネルに入り、自宅機のそれ以外の通信は今までどおり出ていきます。PersistentKeepalive = 25 は自宅側にだけ必要です。MAP-EやDS-LiteのNATは、通信が途切れるとUDPの対応表を消します。25秒ごとに空のパケットを送り続けることで対応表を維持し、VPSから自宅への戻りの通信がいつでも届く状態を保ちます。これを忘れると、しばらく誰もアクセスしなかった後の最初の1回だけ失敗する、という分かりにくい症状になります。手で書くWireGuardとTailscaleのどちらが自分に向いているかは、WireGuardを手で設定するかTailscaleに任せるかで整理しています。

両方の機械で起動し、VPSではUDPの51820番を開けます。

sudo systemctl enable --now wg-quick@wg0
sudo ufw allow 51820/udp
sudo wg show

VPS側の wg show に自宅機のピアが並び、latest handshake が数十秒以内なら通っています。仕上げに、VPSからトンネル越しにImmichへ届くかを確かめます。

curl -s http://10.8.0.2:2283/api/server/ping

{"res":"pong"} が返れば、トンネルの仕事は終わりです。

SSHでトンネルを張る(WireGuardが動かないNAS向け)

Synologyなど、WireGuardを動かしにくいNASでも、SSHクライアントはたいてい入っています。自宅機からVPSへ逆向きのポート転送を張ります。

ssh -N -o ServerAliveInterval=30 -o ExitOnForwardFailure=yes \
  -R 127.0.0.1:2283:127.0.0.1:2283 tunnel@<VPSの公開IP>

VPSの 127.0.0.1:2283 に届いた通信が、SSHを通って自宅機の 127.0.0.1:2283 に渡されます。VPS側で 127.0.0.1 に縛っているので、VPS上のリバースプロキシ以外からは届きません。この接続を再起動後も自動で張り直す systemd の書き方は、CGNATの内側からVPSへ逆向きSSHトンネルを張る手順にあります。MAP-EとDS-Liteは、そのガイドが想定するCGNATと同じ制約なので、そのまま当てはまります。

VPS上のCaddy

Caddyは証明書の取得と更新を自動でやり、リクエストのサイズ上限も初期状態では持たないので、Immichの前に置くには一番手間が少ない選択です。

sudo apt update && sudo apt install -y caddy
sudo ufw allow 80,443/tcp

/etc/caddy/Caddyfile を次の内容に置き換えます。SSHトンネルを使った場合は 10.8.0.2127.0.0.1 に読み替えてください。

photos.example.com {
    reverse_proxy 10.8.0.2:2283
}
sudo systemctl reload caddy
sudo journalctl -u caddy -n 30
curl -s https://photos.example.com/api/server/ping

journalctl に証明書の取得成功が出て、curl{"res":"pong"} を返せば公開完了です。証明書が取れない時は、DNSがまだVPSに向いていないか、80番と443番がVPSのファイアウォールか事業者側のネットワークファイアウォールで閉じています。

nginxを使う場合は、Immichのドキュメントにある設定をそのまま使います。要点は client_max_body_size とWebSocket用のヘッダーです。

server {
    server_name photos.example.com;
    client_max_body_size 50000M;
    proxy_request_buffering off;
    client_body_buffer_size 1024k;
    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;
    proxy_http_version 1.1;
    proxy_redirect     off;
    proxy_read_timeout 600s;
    proxy_send_timeout 600s;
    send_timeout       600s;
    location / {
        proxy_pass http://10.8.0.2:2283;
        proxy_set_header   Upgrade    $http_upgrade;
        proxy_set_header   Connection "upgrade";
    }
}

証明書は sudo apt install -y certbot python3-certbot-nginx のあと、sudo certbot --nginx -d photos.example.com で取ります。

最後に、Immichの External Domain を https://photos.example.com にし、ImmichアプリのサーバーURLも同じにします。これで共有リンクは誰にでも届き、スマホにVPNは要りません。

この「VPS、WireGuardトンネル、リバースプロキシ、前段の認証」をひとつにまとめたオープンソースのパッケージとして Pangolin があります。手で組む代わりにそれを入れる手もありますが、中で起きていることは上と同じです。

VPSを借りずに済ませたいなら、Cloudflare Tunnelでポート開放なしに公開する方法もあります。ただしCloudflareのプロキシを通るアップロードには1リクエストあたりのサイズ上限があり、2026年9月時点で無料プランは100MBです。長い動画のバックアップはここで失敗します。写真だけなら実用になりますが、動画も撮る家庭には向きません。

ルート3でもImmichのログイン画面は公開されます。Funnelとの違いは、前段を自分が持っていることです。Caddyやnginxの設定でアクセス元を制限したり、fail2banで総当たりを止めたりする余地が残ります。

ルート4:Immich自体をVPSで動かす

自宅にサーバーを置く理由が「写真を手元に置きたい」より「Googleフォトの料金を払いたくない」に近いなら、ImmichをVPSで動かすのが一番単純です。トンネルもTailscaleも要らず、VPS上のCaddyがそのままImmichの前に立ちます。手順はGoogleフォトの代わりにImmichをVPSでセルフホストする手順のとおりです。

判断材料はライブラリの大きさとRAMです。機械学習のジョブ(顔認識、スマート検索)は数GBのRAMを要求し、ストレージは写真の総量そのものです。数百GBを超えるライブラリでは、VPSのディスク代が家庭用NASの数倍になります。Immichに必要なRAMとストレージの見積もりに自分のライブラリを当てはめてから決めてください。

VPSに置くと、バックアップの向きが逆になります。VPSのImmichから自宅のNASへ、写真とデータベースのダンプを定期的に落とす仕組みを、最初の週に作っておいてください。

どれを選ぶか

  • 使うのは家族だけ。共有リンクは要らない、または家族全員がTailscaleを入れられる。ルート1です。
  • 上に加えて、https:// のURLで使いたい。ルート2のServeです。
  • 年に数回だけ、家族以外に共有リンクを送る。ルート2のFunnelを、必要な期間だけ使います。
  • 共有リンクを日常的に使う。自分のドメインが欲しい。相手のスマホに何も入れさせたくない。ルート3です。
  • 自宅の上り回線が遅い。NASが非力。ライブラリが小さい。ルート4です。

結論はこうです。共有リンクか自分のドメインが必要になるまではTailscale。必要になった時点でVPSを前に置く。この順番なら、途中でやり直しになる作業がありません。ルート1で作ったtailnetは、ルート3に進んだ後も、自宅機の管理用の経路として残せます。

つまずきやすい箇所と、その時に見えるもの

アプリがサーバーに接続できない。 まずスマホのブラウザで、アプリに入れたのと同じURLに /api/server/ping を足して開きます。{"res":"pong"} が表示されれば経路は通っていて、問題はURLの打ち間違い(httpshttp、末尾のスラッシュ、ポート番号)です。表示されなければ経路の問題で、Tailscaleならスマホ側の接続状態、VPS中継ならトンネルとCaddyを順に見ます。

バックアップが外では進まない。 順番に3つ確かめます。バックアップ設定でモバイルデータが許可されているか。Tailscaleが切れていないか(切れていればオンデマンドを有効に)。iOSなら「Appのバックグラウンド更新」が有効か。3つが揃っていても、iOSは処理のタイミングを自分で決めるので、アプリを開く頻度が低いほどバックグラウンドの実行は減ります。

共有リンクを開いても何も出ない。 External Domain が古いURLのままです。管理画面で今の公開URLに直します。すでに送ったリンクは古いドメインを含んでいるので、新しいURLで送り直してください。

動画のアップロードだけ失敗する(nginx中継)。 nginxのログに 413 Request Entity Too Large が出ます。client_max_body_size の初期値は1MBなので、Immichのドキュメントどおり client_max_body_size 50000M; を足してください。Caddyには初期状態で上限がないので、この症状は出ません。

しばらく使わないと最初の1回だけ失敗する(WireGuard中継)。 自宅側の PersistentKeepalive = 25 が抜けています。VPSで sudo wg show を見て、latest handshake が数分以上前で止まっていればこれです。

Tailscale Serveが502を返す。 tailscale serve status の転送先と、Immichが実際に聞いているポートが違います。自宅機で curl -s http://127.0.0.1:2283/api/server/ping が応答するポートに合わせてください。

共有リンクが家の外で開けない(Tailscaleのみの構成)。 故障ではなく仕様です。ルート1の共有リンクはtailnetのメンバーにしか届きません。公開リンクが必要ならルート2のFunnelか、ルート3へ進みます。

FAQ:よくある質問

v6プラス(MAP-E)でもポート開放してImmichを直接公開できますか?

割り当てられたポート範囲の中の番号なら、ルーターで転送設定できる場合があります。ただし80番や443番は通常含まれないので、https://photos.example.com:12345 のような番号付きのURLになり、共有リンクを受け取る側には扱いにくいものになります。共有IPアドレスは他の契約者の通信とも混ざるため、不正アクセスの調査でも不利です。使えるポートと転送の可否は契約中のISPの仕様で決まるので、まずそこを確認してください。上の4ルートはどれもポート開放を使わないので、確認して駄目だった場合でも困りません。

スマホのTailscaleをずっとオンにしておく必要がありますか?

バックグラウンドのバックアップをTailscale経由で動かすなら、そうです。バックアップ処理が走る瞬間にVPNが切れていれば、アップロードは失敗し、通知も出ません。iOS版TailscaleのVPN On Demandを有効にすると、切れても自動で再接続します。Tailscaleは待機中の電池消費が小さいので、常時オンにしても実用上の問題はほとんどありません。ルート3(VPS中継)なら、スマホ側にVPNは要りません。

共有リンクを家族以外に送りたい。Tailscaleだけで可能ですか?

Serveだけでは不可能で、Funnelなら可能です。Funnelを有効にすると https://<機械名>.<tailnet名>.ts.net がインターネット全体から開けるようになり、共有リンクも誰でも見られます。代わりにImmichのログイン画面も公開されます。日常的に共有リンクを使うなら、自分のドメインと前段を持てるルート3の方が運用しやすくなります。

Cloudflare Tunnelではだめですか?

写真だけならかなり使えます。VPSが要らず、ポート開放も不要で、TLS証明書もCloudflareが持ってくれます。問題は動画です。Cloudflareのプロキシを通るアップロードには1リクエストあたりのサイズ上限があり、2026年9月時点で無料プランは100MBです。数分の4K動画はこれを超えるので、バックアップが失敗します。上限は変わることがあるので、Cloudflareの現行の仕様を確認してください。

Immichを直接インターネットに公開するのは、そんなに危険ですか?

ログイン画面をそのまま公開すると、認証前のエンドポイントに誰でも届きます。Immichは更新が速く、認証まわりの修正も定期的に入るので、アップデートを止めた瞬間からリスクが増えていきます。家族の写真は取り返しがつかないデータです。少なくともTLS終端と前段を自分で持ち(ルート3)、できれば公開範囲をtailnetに閉じる(ルート1、2)。それが上の4ルートに共通する考え方です。