🌐

ラズパイ上のPython+FlaskローカルWebサーバにネットからngrok経由でアクセス

2022/05/06に公開

ラズパイ上で立てたローカルサーバに手軽にインターネットからアクセスしたい

ラズパイ(Raspberry Pi)上に立てたサーバに一時的に外からアクセスできるようにする方法です。

昔はルータのポートを開けたりしていたのですが、ネットワーク環境によっては繋げなかったり、セキュリティ的にも不安だったりするので、何か良い方法ないかなと思っていたのですが、ngrokという便利なものがありました。

イメージ的には以下のようにngrokサーバがローカルサーバとネットをいい感じに中継してくれる感じのようです(あんまりネットワーク詳しくないので間違ってたらすみません)。

ブラウザ -> Internet -> ngrokサーバ -> ローカルサーバ(ラズパイ)

これを使えば手軽にサーバを構築することができそうです。無料である程度使えるので、長期間の運用する前の、ちょっとしたデモやPoCにピッタリですね。

Python+FlaskでローカルWebサーバ構築

ラズパイ側のローカルサーバですが、Python+Flaskでサクッと用意します(もちろんApache2とかでもOKです)。

ここからは、ラズパイのターミナルで実行していきます。まずは、以下コマンドでFlaskをインストールします。

$ python -m pip install flask

続いてapp.pyというファイルを作成します。中身はflask公式のサンプル(flaskのhello world)とします。

https://pythonbasics.org/flask-tutorial-hello-world/

具体的なコードは以下です。

from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return 'Web App with Python Flask!'

app.run(host='0.0.0.0', port=5000)

上記コードは、ポートだけport=81からport=5000に変更しています。81のままだと自分の環境では、このあとプログラムを実行するとpermission deniedのエラーが発生したためです。実行コマンドにsudoをつければ81でも実行できますが、今回は5000番のポートを使うことにしました。

あとは以下コマンド実行すると、サーバが立ち上がります(ポートを81にする場合はsudo python app.pyとしてください)。

$ python app.py

これでローカルにサーバが立ち上がりました。簡単ですね。ラズパイのブラウザで以下アドレスにアクセスして確認しましょう。

http://localhost:5000

以下のように表示されたらOKです。お手軽!

ngrokのインストールと動作確認

ラズパイのターミナルで以下コマンド事項しましょう。

$ wget https://bin.equinox.io/c/bNyj1mQVY4c/ngrok-v3-stable-linux-arm64.tgz
$ tar xvzf ngrok-v3-stable-linux-arm64.tgz
$ sudo mv ngrok /usr/local/bin/

上記コマンドはRaspberry Pi OSが64bitバージョンのものです。32bitの場合はngrok-v3-stable-linux-arm64.tgzngrok-v3-stable-linux-arm.tgzに置き換えれば大丈夫だと思います。

動作確認は、以下のコマンドを実行してください。

$ ngrok version

ngrok version 3.0.3と表示されたらOKです(バージョンは実行したタイミングによっては異なるかもしれません)。

ngrokの実行

まずは以下にアクセスしてユーザー登録をしておきましょう。

https://ngrok.com

以下にアクセスします。

https://dashboard.ngrok.com/get-started/setup

2. Connect your accountに記載されている以下のようなコマンドをコピペしてラズパイ上で実行しましょう。

$ ngrok config add-authtoken xxxxxxxxxxxxxxxxxxx

さらにラズパイ上でngrokを実行して、トンネルを掘ります。5000は先程立ち上げたローカルサーバのポート名です。

$ ngrok 5000

ngrokが起動すると、以下のように表示されます。

ngrok                                                                                   (Ctrl+C to quit)
                                                                                                        
Session Status                online                                                                    
Session Expires               1 hour, 59 minutes                                                        
Terms of Service              https://ngrok.com/tos                                                     
Version                       3.0.3                                                                     
Region                        Japan (jp)                                                                
Latency                       calculating...                                                            
Web Interface                 http://127.0.0.1:4040                                                     
Forwarding                    https://e953-111-98-113-33.jp.ngrok.io -> http://localhost:5000           
                                                                                                        
Connections                   ttl     opn     rt1     rt5     p50     p90                               
                              0       0       0.00    0.00    0.00    0.00

以下がトンネルが掘られていることを意味します。アドレスはngrokを実行するたびに変化します。

Forwarding https://e953-111-98-113-33.jp.ngrok.io -> http://localhost:5000

上記のアドレス(上記の場合は https://e953-111-98-113-33.jp.ngrok.io )に、ブラウザでアクセスしましょう。ラズパイだけでなく、インターネットに繋がっているあらゆるPC・手元のスマートフォンからでも繋がります。

応用例

ちょっとした応用例をいくつか書いておきます。

Webサイトでボタンを押したらサーバで何か処理を実行

サーバー側でボタンを押したら、押したボタンに応じて何かしらサーバーで処理を行うようなプログラムの例です。

ファイルの構成は以下のようにします。

flask
├─ app.py
└─ templates
     └─ index.html

app.pyの中身は以下です。app.run(host='0.0.0.0', port=5000, debug=True)debug=Trueはデバッグモードにしています。

from flask import Flask, render_template, request

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'POST':
        if request.form['send'] == 'left':
            m = 'left'
	    return render_template('index.html', message=m)
        if request.form['send'] == 'center':
            m = 'center'
            return render_template('index.html', message=m)
        if request.form['send'] == 'right':
            m = 'right'
            return render_template('index.html', message=m)
    else:
        return render_template('index.html')


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=True)

HTML側のコードは以下です。

<!DOCTYPE html>
<html>
    <head>
        <title>controller</title>
    </head>
    <body>
    <p>{{ message }}</p>
    <form method="POST">
        <input type="submit" name="send" value="left">
        <input type="submit" name="send" value="center">
        <input type="submit" name="send" value="right">
    </form>
    </body>
</html>

以下は表示例です。ボタンを押すたびに`{{ message }}'部分が押したボタンに応じて書き変わります。

これをベースに色々応用できるのではないかなと思います。

まとめ

ラズパイ上のサーバを手軽にインターネット経由でアクセスする方法に関してまとめました。

ちょっとしたIoT的なデモにピッタリですね。

参考リンク

https://note.com/yoshy_toshy/n/n3857302fac05

https://qiita.com/sunaga70/items/6821772a9bcbdbbc2c03

https://note.com/dorakas1/n/n39302631943b

https://teratail.com/questions/311004

https://toukei-lab.com/python-flask

https://dev2prod.site/python/flask-screen/

Discussion