Cloudflare Tunnel で Raspberry Pi Model 4B(Ubuntu 23.0) 自宅サーバーを公開する

自宅APIサーバーをドメイン付きで公開したくなったのでやってみる。
何をするか
- 自宅の Raspberry Pi 4 Model B (Ubuntu 23.0) で動作させているAPIサーバをインターネット上から実行できるようにしたい
- APIは固定ドメインでコールできるようにしたい
例:curl -X POST https://example.domain/foo

Cloudflare側のドメイン設定
こちらの記事 を参考に設定した。
上記記事では Cloudflare で取得したドメインを使っているが、今回ドメインはCloudflareで取得したものを使用したので、適宜記事を読み替えてドメイン設定を行った。
cloudflared
をラズパイにインストール
公式のcloudflaredの記事 を参考に、以下のコマンドをラズパイ上で実行。
wget -q https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb && sudo dpkg -i cloudflared-linux-amd64.deb
これだと「パッケージアーキテクチャ(amd64)がシステム(arm64)と一致しません」とエラーが出て失敗する。再度アーキテクチャを変えて実行。
wget -q https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm64.deb && sudo dpkg -i cloudflared-linux-arm64.deb
上記コマンドだと問題なくインストールできた。
最後に問題なく動作しているかチェックする。
cloudflared --version
きちんとバージョンが表示されたのでOK。
メモ
最新のリリースは https://github.com/cloudflare/cloudflared/releases で確認できる。

cloudflared
から Cloudflare にログイン
以下を実行する。
cloudflared tunnel login
ブラウザ側でログインし、接続に利用するドメインを選ぶ。
これで証明書がダウンロードされて/home/ユーザー名/.cloudflared/cert.pem
にあれば完了。
...なのだが、あまりにもブラウザが重すぎてダウンロードに失敗してしまった。
代わりに手動でダウンロードする方法がコマンドラインに表示されるのでそれを試す。
ログイン用のURLと Get "https://login.cloudflareaccess.org/xxxxxx-yyyyyy_zzzz"
のような文言が表示されているはずなのでこれらを使って証明書をDLする。
はじめにラズパイではドメインが login.cloudflareaccess.org になっている方のURLに対してGETリクエストを送る。
wget https://login.cloudflareaccess.org/xxxxxx-yyyyyy_zzzz > ~/.cloudflare/cert.pem
リクエスト待ち状態に入るので、別のコンピュータでログイン用のURLにアクセスし、ログインを行ってドメインを選択する。Authorize が完了すると自動的にラズパイ側もGETリクエストが完了し、証明書がダウンロードされる。最後にダウンロードされた証明書を~/.cloudflare/cert.pem
に配置する。
配置を確認する。
ls /home/ユーザー名/.cloudflared/cert.pem
これでログインはOK。

tunnel を作成する
設定ファイル作成。
今回は以下の設定値を使った設定を行う。
- トンネル名:
ubuntu-foo
- 取得済みドメイン名:
mydomain.xyz
設定ファイルを作成する。
cloudflared tunnel create ubuntu-foo
# Tunnel credentials written to /home/ユーザ名/.cloudflared/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.json. cloudflared chose this file based on where your origin certificate was found. Keep this file secret. To revoke these credentials, delete the tunnel.
# Created tunnel ubuntu-foo with id xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
~/.cloudfraled/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.json
が作成される。
このUUID xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
は後で用いる。
続いて設定ファイルを作成する。名前はなんでも良い。
touch ~/.cloudflared/config_ubuntu_foo.yml
設定ファイルを手動編集する。
ubuntu-foo.mydomain.xyz
への通信は http://127.0.0.1:8000 につながる。
tunnel: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
credentials-file: /home/ユーザ名/.cloudflared/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.json
ingress:
- hostname: ubuntu-foo.mydomain.xyz
service: http://127.0.0.1:8000
- hostname: bar.mydomain.xyz
service: http://127.0.0.1:8001
- service: http_status:404
warp-routing:
enabled: true
複数のルーティングを割り当てる場合、ubuntu-foo.mydomain.xyz
と ubuntu-bar.mydomain.xyz
を割り当てる場合には以下のようにすることができる。
tunnel: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
credentials-file: /home/ユーザ名/.cloudflared/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.json
ingress:
- hostname: ubuntu-foo.mydomain.xyz
service: http://127.0.0.1:8000
- hostname: ubuntu-bar.mydomain.xyz
service: http://127.0.0.1:8001
- service: http_status:404
warp-routing:
enabled: true
CNAMEを設定する
このままではDNSレコードがないため Cloudflare にCNAMEを登録する必要がある。
以下のコマンドで ubuntu-foo
に向いた mydomain.xyz
のサブドメインを Cloudflare に登録できる。
cloudflared tunnel route dns xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx ubuntu-foo.mydomain.xyz
Cloudflare 管理画面で DNS Record から mydomain.xyz
を開き CNAME (サブドメイン)が登録されていればOK。画像では chatbot-ui-rag
と言う名前で登録した。

アクセスする
以下を有効化する。
cloudflared tunnel run ubuntu-foo
これで https://ubuntu-foo.mydomain.xyz にアクセスできるようになる。ただし、リクエストはまだ通らない。
これは Zero Trust の Access が許可されていないため。なので管理画面を開いて Access を許可する。
Access の設定
Zero Trust > Access > Applications から Add Application を選択する。
Self-Hosted を選択する。
続いて次の画面でサブドメインに ubuntu-foo
, ドメインに自分のドメインを登録する。
他の項目はそのままで次へ。
次の画面で認証方法を設定する。この認証に合格したユーザーだけがローカルサーバへアクセスすることができる。今回は特定のメールアドレスだけを許可し、ワンタイムパスワードを送信することでアクセス権を付与する形にした。
他の設定はそのままでOK。最後まで登録を進める。
改めて https://ubuntu-foo.mydomain.xyz アクセスすると、メールアドレスで認証が通るようになり、アクセスできることが確認できる。
WIP: アクセスが通らないケースあり。調査中。

参考
arch
コマンドで取得できるARMアーキテクチャのバージョン名
-
aarch64
: ARMアーキテクチャバージョン8 / Raspberry Pi OS 64bit 版で採用 -
armhf
: ARMアーキテクチャバージョン7 / Raspberry Pi OS 32bit 版で採用 -
armv6
: ARMアーキテクチャバージョン6 / 初代 Raspberry Pi で採用(らしい) -
armv6l
: ARMアーキテクチャバージョン6のうちメモリフォーマットがリトルエンディアンのもの / Raspberry Pi Zero で実行できる Raspberry Pi OS 32bit 版で採用
64bit版になるのは aarch64 、それ以前は32bitである様子。
cloudflared
は armv7 以上を要求するため、 Raspberry Pi Zero では動作しない。
(Issue: https://github.com/cloudflare/cloudflared/issues/359 )