RaspberryPi 5 上のAPIを、AzureVMを踏み台にして外部公開するまでの内容です。勉強と備忘録も兼ねてまとめてみました。
RaspberryPiOSのインストールやSSH接続といった初期設定は済んでいる前提で話を進めます。初期設定のやり方は他に沢山の記事でわかりやすく説明されているので、そちらを参照ください。
※今回、API常時稼働まではできませんでした。度々Raspberry Pi上でAPIサーバーを起動する必要があります。
アーキテクチャ図
ざっくりとした全体像です。
RaspberryPi 5 上のFastAPIで開発したAPIを、AzureVMのパブリックIPアドレスを使って公開します。インターネット上でAPIが叩かれると、Azure VM上のNginxからRaspberry Piへリクエストを転送するイメージです。
1. Azure VMの構築
Azure VMの設計
- Azure Portal で 「仮想マシンの作成」
- Ubuntu 20.04 LTS or 22.04 LTS を選択
- パブリックIPを有効化(固定IP推奨)
- ポート 80, 443 を開放
-
SSH を有効化(22番ポート)
- RSA SSH 形式を選択し、SSHキーをPCに保存
2. Raspberry PiのFastAPIを起動
以下、FastAPIプロジェクトの場合の起動方法
プロジェクトディレクトリに移動
cd src/hot-bubbles-api/
venv仮想環境を起動(未作成であれば作成する)
※下記fishでの実行コマンド
source venv/bin/activate.fish
サーバー起動
uvicorn app.main:app --host 0.0.0.0 --port 8000
3. SSH接続:Raspberry Pi → Azure VM
参考Doc
Linux VM に接続する - Azure Virtual Machines
sshキーの転送
ここでいうSSHキーとは、VM構築時に払い出された.pem
ファイルのことです。
私は自分のMacでVMを構築したので、Raspberry Piに転送します。
はじめからRaspberry PiでSSHキーを保存した方はこの手順は不要です。
使うのは、scpコマンドです。ssh接続された端末間でのファイルの送受信が可能です。
PCの~/.ssh/hotbubbles-api-dev_key.pem
ファイルをraspberry@pi
というRaspberry Piの/.ssh
ディレクトリ配下に転送します。
scp ~/.ssh/hotbubbles-api-dev_key.pem raspberry@pi.local:~/.ssh
Raspberry Pi上での操作
読み取り権限の確認
chmod 400 ~/.ssh/myKey.pem
下記sshコマンドを実行し、Azrue VMに接続確認
ssh -i ~/.ssh/myKey.pem ${VMのuser名}@${VMのパブリックIP}
VMのuser名を忘れてしまった場合、Azure PortalのJSONビューから確認できます。
4. Raspberry Pi から Azure VM に SSH リバーストンネルを設定
Raspberry Piで以下コマンドを実行
ssh -i ~/.ssh/myKey.pem -R 9000:localhost:8000 ${VMのuser名}@${VMのパブリックIP}
これで Azure VM の localhost:9000
にアクセスすると、Raspberry Pi の localhost:8000
に接続可能となります。
Azure VM環境で下記コマンドを実行してみて、FastAPIで実装したAPI値が返って来れば成功です。
curl http://localhost:9000
アクセス失敗時に考えられる原因
ssh: connect to host ${IPアドレス} port 22: No route to host
私の場合はRaspberry Piがインターネットにアクセスできていませんでした。
その他にも以下のような原因が考えられます。
- Azure VMの起動
- Azure VMがポート22を開放していない
- VMのSSHサーバーを起動
- VMのファイアウォールを設定
5. Azure VM に Nginx をインストールしリバースプロキシを設定
インストール
sudo apt update && sudo apt install nginx -y
設定を変更
sudo nano /etc/nginx/sites-available/api
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://localhost:9000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
設定を有効化する。
Nginxは/etc/nginx/sites-enabled/
にある設定しか読み込まないので、シンボリックリンクを貼る。
※参考→ Nginxのconf.dとsites-availableとsites-enabledの違い - Qiita
sudo ln -s /etc/nginx/sites-available/api /etc/nginx/sites-enabled/
Nginxを再起動
sudo systemctl restart nginx
6. インターネットから API にアクセス
ドメイン名を設定
今の状態でもVMのパブリックIPにアクセスすれば、インターネット上からAPIが叩けるのですが、せっかくならドメイン名で叩きたいですよね。
Azure Portal上で下記操作をして独自のドメイン名を作りましょう。
今回使っているVMの画面のパブリックIPアドレスをクリックすると、構成画面に遷移すると思います。そこのDNS名ラベル
という設定値(はじめは空欄のはず)に任意のドメイン名を設定しましょう。
${設定したドメイン名}.japaneast.cloudapp.azure.com
にアクセスすると、インターネット上からAPIにアクセスできるはずです!
失敗した場合
パブリックIPアドレスにアクセスしてもNginxのデフォルト画面が表示される。
/etc/nginx/sites-enabled/default
が残っているのが原因かも。
削除
sudo rm /etc/nginx/sites-enabled/default
nginxを再起動する
APIの結果の日本語が文字化け
Azure VMのパブリックIPアドレスにアクセスして、jsonファイルが返ってくることを確認したのですが、日本語部分が文字化けした状態で表示されます。
FastAPIの文字コードの設定をいじると治りました。
詳しいことはまだわかりませんが、ensure_ascii=Falseでユニコードエスケープを抑制するようです。