前回(第9回) まででLAN内は完成。最終回は、このダッシュボードを外出先からも安全に見られるようにします。使うのは Cloudflare Tunnel。あなたのブログでも使っているCloudflareをそのまま活かせます。
Table of contents
Open Table of contents
なぜ Cloudflare Tunnel か
自宅サーバーの公開でルーターのポート開放をするのは、攻撃対象を晒すためリスクが高い方法です。Cloudflare Tunnel は、
- Piから外向きに接続するだけ(ポート開放・グローバルIP不要)
- CloudflareのエッジでHTTPSが付く(証明書管理が不要)
- 独自ドメイン(例
temp.example.com)で公開できる - WebSocket対応なので、Blazor Server(SignalR回線)もそのまま動く
STEP 1:cloudflared をPiに入れる
Cloudflare Tunnel のクライアント cloudflared を、Raspberry Pi OS(64bit=ARM64)向けに導入します。公式の .deb パッケージを入れるのが手軽です。
まず、自分のOSが64bitか確認します(aarch64 と出れば64bit=ARM64)。
uname -m
cloudflared をダウンロードしてインストールします。
# 1. ARM64版の .deb をダウンロード
curl -L -o cloudflared.deb \
https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm64.deb
# 2. インストール
sudo dpkg -i cloudflared.deb
# 3. 確認(バージョンが表示されればOK)
cloudflared --version
32bit OS の場合は URL 末尾を
cloudflared-linux-arm.debに変えます。
Cloudflareにログインする
インストールできたら、Cloudflareアカウントと紐付けます。
cloudflared tunnel login
- 実行するとターミナルに認証用のURLが表示されます
- そのURLをブラウザで開き、対象ドメイン(例
example.com)を選んで許可します - 成功すると、認証情報(証明書)が
~/.cloudflared/cert.pemに保存されます
⚠️ この手順には、Cloudflareで管理している独自ドメインが1つ必要です(ネームサーバーがCloudflareのもの)。ドメインをまだCloudflareに載せていない場合は、先にサイトを追加してください。
STEP 2:トンネルを作成しDNSを割り当てる
# トンネル作成
cloudflared tunnel create pi-temp
# 公開したいホスト名をトンネルに割り当て
cloudflared tunnel route dns pi-temp temp.example.com
~/.cloudflared/config.yml を作成し、ホスト名→ローカルのBlazorをマッピングします。
tunnel: <作成時に表示されたTUNNEL_ID>
credentials-file: /home/pi/.cloudflared/<TUNNEL_ID>.json
ingress:
- hostname: temp.example.com
service: http://localhost:5000
- service: http_status:404
- 起点は
http://localhost:5000(第8回のsystemdサービス)でOK。トンネル区間はCloudflareが暗号化します
STEP 3:常駐サービスとして動かす
まず手動で動作確認
サービス化の前に、手動でトンネルを起動して動くか確かめます(~/.cloudflared/config.yml を使います)。
cloudflared tunnel run pi-temp
スマホの回線などから https://temp.example.com が開ければ、設定はOK。Ctrl+C で止めます。
サービス化(自動起動)
ここにハマりどころがあります。
⚠️
cloudflared service installで作られるサービスは、設定を/etc/cloudflared/config.ymlから読みます(~/.cloudflared/ではありません)。手動起動と同じ設定でサービスを動かすため、config と認証情報(.json)を/etc/cloudflared/にコピーします。
# 1. 設定と認証情報を /etc/cloudflared/ に配置
sudo mkdir -p /etc/cloudflared
sudo cp ~/.cloudflared/config.yml /etc/cloudflared/config.yml
sudo cp ~/.cloudflared/<TUNNEL_ID>.json /etc/cloudflared/
# 2. config.yml の credentials-file を /etc/cloudflared/<TUNNEL_ID>.json に直す
sudo nano /etc/cloudflared/config.yml
# 3. サービスをインストールして起動
sudo cloudflared service install
sudo systemctl enable --now cloudflared
# 4. 状態とログを確認
systemctl status cloudflared
journalctl -u cloudflared -e # 「Registered tunnel connection」が出ればOK
外出先から https://temp.example.com を開いて、ダッシュボードが HTTPSで 表示されれば成功です。
STEP 4【重要】:Cloudflare Access で鍵をかける
このままだとURLを知る誰でもアクセスできてしまいます。家庭内のモニタリングを公開するので、Cloudflare Access(Zero Trust)で自分だけに制限します。アクセス時にログイン(メールOTP)が挟まり、許可したメール以外は入れなくなります。
💳 注意:Zero Trust は〜50ユーザーまで無料ですが、開始時に支払い方法(カード等)の登録を求められます。将来の上限超過に備えた登録で、無料枠の範囲では課金されません($0)。
手順
-
Zero Trust を開く:Cloudflareダッシュボード左メニューの Zero Trust へ。プランで Free を選択(この時に支払い方法の登録あり/$0)
-
アプリを追加:Access controls → Applications → Create new application(アクセス制御 → アプリケーション → アプリケーションを追加する)を開く
- タブ:セルフホストとプライベート(Self-hosted and private)
- 種別:パブリックDNS(Public DNS)を選ぶ ← 公開ホスト名でブラウザ公開する今回のケース
- 「セルフホストとプライベートで続行」 をクリック
- ※「プライベート宛先」はWARP必須の内部向け、「サービス認証」は機械間認証。今回は違うので選ばない
続くと「アプリケーションの詳細」フォームが開きます。1画面に上から「宛先/Accessポリシー/認証/詳細」が並ぶので、順に埋めます。
-
宛先 → パブリックホスト名
- サブドメイン:
temp - ドメイン:ドロップダウンで自分のドメイン(例
example.com)を選択(候補に無ければ「カスタム入力に切り替える」) - パス:空のままでOK(=
temp.example.com全体を保護)
- サブドメイン:
-
Accessポリシー(誰を許可するか):**「新しいポリシーを作成」**を押します(既定はすべて拒否なので許可ポリシーが必須)。開いた画面で:
- ポリシー名:任意(例
自分だけ許可) - アクション:許可(既定のまま)
- ポリシールール → 含める:セレクターは… で メール(Emails) を選び、値は… に 自分のメールアドレスを入力
- 「追加設定(MFA等)」「接続設定(RDP等)」は触らずでOK → 右下 「ポリシーを保存」
- 保存したポリシーを、このアプリに関連付ける
- ポリシー名:任意(例
-
認証:このアプリで One-time PIN(メールOTP) を受け入れるようにします。「利用可能なすべてのIDプロバイダーを受け入れる」を ON(または「使用可能なIDプロバイダーを選択」で One-time PIN を選ぶ)。「Cloudflare One Clientで認証」はOFF(WARP不要・ブラウザだけで完結)
- 💡 One-time PIN 自体は既定で用意されています(インテグレーション → IDプロバイダー で確認可。無ければ「IDプロバイダーを追加する」)。ログイン画面に「Cloudflare」しか出ずメール入力欄が出ない場合は、この「認証」でOne-time PINを受け入れていないのが原因です
-
詳細:名前(任意・例
Temp Monitor)と セッション期間(例24 hours)を設定 → 右下の 「作成」 をクリック -
動作確認:
https://temp.example.comを開くと Cloudflareのログイン画面が表示 → メール入力 → 届いたコード(OTP)を入力 → 認証後にダッシュボードが開く。許可リスト外のメールは弾かれます
ログアウトは
https://temp.example.com/cdn-cgi/access/logoutから行えます。WARPアプリのインストールは不要で、ブラウザだけで完結します。
外部公開する自宅サービスには、必ずアクセス制限をかけるのが鉄則です。

運用の仕上げ
- 自動起動・自動再起動:アプリ(第8回)と
cloudflared(本回)とも systemd で常駐済み - 自動デプロイ:第9回のGitHub Actionsで更新を自動化
- ログ:
journalctl -u tempmonitor -f/journalctl -u cloudflared -f - バックアップ:SQLiteの
temps.dbを定期コピー(cron)。データ保持期間を決めて古い行を削除 - ヘルスチェック:定期的に応答を確認し、異常時に通知(MQTT/メール)すると安心
つまずきポイント
- Error 1033 / Tunnel unable to resolve:Cloudflareがトンネルに到達できていない=cloudflaredがそのトンネルを走らせていない。サービスは
/etc/cloudflared/config.ymlを見るので、~/.cloudflared/に置いたままだとこれになる(STEP3のコピー手順を参照)。cloudflared tunnel run pi-tempで手動起動できるかで切り分け、journalctl -u cloudflared -eを確認 - 502 / つながらない:Blazorが
localhost:5000で起動しているか(systemctl status tempmonitor)、config.ymlのポート一致 - ログイン画面にメール入力欄が出ない/「Cloudflare」のみ:アプリの「認証」でOne-time PINを受け入れていない。アプリの認証で
利用可能なすべてのIDプロバイダーを受け入れるをON(またはOne-time PINを選択)。One-time PIN自体は インテグレーション → IDプロバイダー で確認 - That account does not have access(アクセス権なし):ログインしたメールがポリシーのEmailsに未登録。ポリシーのメールと、入力するメールを一致させる
- Accessで締め出された:ポリシーのメールアドレス指定を確認
- リアルタイム更新が来ない:Cloudflare TunnelはWebSocket対応だが、途中の設定でWSを止めていないか
まとめ
- Cloudflare Tunnelなら、ポート開放なしでHTTPS+独自ドメイン公開ができる
- Cloudflare Accessで必ずアクセス制限をかける
- systemd常駐(アプリ/cloudflared)+自動デプロイ+バックアップで運用が回る
連載を終えて(全10回)
これで 「Raspberry Pi × Blazor で作る温度モニタリング・ダッシュボード」 が完成しました。1つのアプリを、環境構築からハード連携・データ蓄積・外部公開まで通しで育てられたはずです。
- 全体像・Server/WASMの選び方
- .NET導入+最初のBlazor
- GPIO:LチカとボタンをWebから
- MCP3208+LM35DZでアナログ温度
- SignalRでライブグラフ
- SQLite+EF Coreで蓄積
- MQTTでIoTダッシュボード
- systemdで常駐化
- GitHub Actionsで自動デプロイ
- Cloudflare Tunnelで外部公開(本記事)
