JP / EN

広告
2023/10/01

Flaskサーバを外部公開~外から接続できないときのチェックポイント

タグ:python web

Flaskを使ってアプリや自分用ツールなどができて、意気揚々と外から使用しようと したらネットワークの何らかの問題で接続できずがっかりしてしまった経験はないだろうか。 なかなか自宅などの外から自分のサーバを叩くことはないので、どうやって疎通確保するか 慣れないと途方に暮れてしまうだろう。
そこでここでは自宅サーバやレンタルサーバを想定して、 外部ネットワークからFlaskアプリまで接続できるようにする際の確認・設定変更手順 をまとめた。 最近はOSのファイアウォールやルータの設定でネットワークが頑丈に守られているので、 これらを掻い潜ってサーバを公開するのも一苦労である。 もちろんこれは間違って公開したくないものを公開しないための安全措置でもあるので、 わざわざ何かを公開しようとする我々としては 不便さは安心のためのコストだと思ってせっせと設定のチェックにいそしむのが良いだろう。

注意点:この手順でサーバの外部公開に成功すると、当然ではあるがサーバへの クラッキングの被害を受けたり、うっかり公開すべきでない情報が漏洩したりする リスクがある。 脆弱性が残されていないか・また不要なデータが公開されていないか慎重にチェックしてから外部公開しよう。

確認項目
  • Flaskアプリの公開用IPアドレス・ポートが設定されているか確認
  • OSのファイアウォールが閉ざされていないか確認
  • ルータのファイアウォールが閉ざされていないか確認
  • より上流にルータのファイアウォールなどが存在しないか確認
  • 外部ネットワークからの疎通テスト


  • Flaskアプリの公開用IPアドレス・ポートが設定されているか確認

    Flaskのサンプルコードだと次のような書き方が紹介されていることが多い:
        from flask import Flask
    
        app = Flask(__name__)
    
    
        @app.route("/")
        def index():
            return "hello"
    
    
        if __name__ == "__main__":
            app.run(debug=True, host="127.0.0.1", port=8888)
      
    しかし実はこれでは他のマシンからはサーバにアクセスすることはできない。 問題はhost="127.0.0.1"という箇所で、127.0.0.1、 すなわちローカルホストのみでサーバが待ち受けるように設定している。 すると「ローカルホストにアクセスしようとして、このFlaskサーバにたどり着いたリクエスト」 だけにこのサーバは応答する、すなわち同一マシンから飛んできたリクエストにしか 応答しないように設定してしまっている。 開発用にはこれが安全だが、本当に公開するツールではこれではいけない。
            app.run(debug=True, host="0.0.0.0", port=8888)
      
    の様に修正しよう。

    OSのファイアウォールが閉ざされていないか確認

    上記設定のみでLAN内の別のマシンからFlaskサーバにアクセスできるようになっている可能性がある。 別のマシンを繋いで確かめてみるとよい。
    LAN内部からでも繋がらないようなら、まだサーバマシン内部に何らかの障壁があるということだ。 このときはサーバ機のOSファイアウォールを疑おう。OSファイアウォールの設定はWindows/Linuxで 異なるので、個別に見ていこう。

    Windowsの場合

    Windowsはユーザ向けOSとして生まれた経緯もあり、ファイアウォールはだいたいデフォルトでオンにされている。 コントロールパネルからGUIで設定を変えていく。
    • 使うポート(サンプルコードでは8888)がプライベート・パブリックネットワークの内、今自分がいる方で開いていること
    • サーバのために使うバージョンのPythonのネットワーク通信を禁止していないこと
    の2点が確認できれば良い。

    設定はコントロールパネルから図のように 「コントロール パネル > システムとセキュリティ > Windows Defender ファイアウォール > 詳細設定」 とぽちぽちとたどっていき、 ファイアウォールのポリシー項目の確認画面に行く。 ここで必要な通信を許さないような規則が通信されていないかを確認する (規則はたいていたくさん登録されているので大変ではあるが)。 赤の禁止マーク(絵文字でいうと🚫)の規則は禁止、緑のチェックマーク(☑)は許可 である。「プログラム」の項目でPython(の絶対パス)を「ローカルポート」の 項目で使うポート(8080)を禁止している規則があったら、選択してから画面の「削除」 で消せる。なお重要な規則を間違って消してしまうと攻撃に対して危険な状態になったり、 必要なプログラムが動かなくなるかもしれないのでファイアウォールの操作は慎重に行うとよい。


    図:コントロールパネルからのファイアウォール設定の確認方法

    引っかかるポイントとしては、Windowsではネットワークにプライベート・パブリックという2つのラベルのうちどちらかが ついている。現在のネットワークがパブリックであるのにプライベート向けの設定をしていたり、 プライベートに居るのにパブリック向けの設定しか変えていなかったりするとポートが開かない。
    また設定に自信がなかったら、ちょっと危険ではあるが「コントロール パネル > システムとセキュリティ > Windows Defender ファイアウォール > 設定のカスタマイズ」 から一瞬だけ全てのファイアウォールをオフにして 本当にファイアウォールだけが原因で疎通をとれていないのか、確認する手もある。

    Linuxの場合

    サーバー用のLinuxでは普通は後で特別に設定しない限りはポートは全開放されているはずである。 もしファイアウォールソフトが別途導入されていたら、それの設定を確認する。 最近のUbuntu等ではufwでファイアウォールを設定していることが多いので、これでのポートの開け方を 説明しておく。コマンドだけで行けるので楽ちんである。
        # ufwが入っていること前提、そもそもインストールされていない可能性もある
        $ ufw status
        Status: active  # active ならOK, inactiveならまずufwサービスを起動
    
        $ ufw enable
        $ ufw status verbose  # 状態確認、デフォルトでは受信はすべて拒否になっている
        Status: active
        Logging: on (low)
        Default: deny (incoming), allow (outgoing), disabled (routed)
        New profiles: skip
    
        $ ufw allow 8080/tcp  # 必要なポートを開ける、他にも開けておかないといけないものがあれば開ける
      
    ちなみにufw自体はファイアウォール機能を持っているわけではなく、linux プリセットの通信制御ツールiptableを簡単に設定できる補助ツールである。 そのためiptableを手でいじってファイアウォールを設定してしまっていても、 ufwをインストールしてからufw上の操作で開ければ問題ない。

    ルータのファイアウォールが閉ざされていないか確認

    ここまででLAN内部からならFlaskサーバにアクセスできるようになっているはずである。 もしできない場合はまだ設定項目が残っている可能性があるから、 上記の手順を再確認し、それでもだめなら他の障壁(例えば仮想化関係など)が ないか疑う必要がある。

    家庭用ルータはかなり堅牢にできていて、デフォルトでは全ポートがふさがれている。 またそもそもLAN内機器にはグローバルIPアドレスが振られていないので、 ポートフォワーディングの設定が必要になることが多い。 このあたりの設定項目・名称はルータごとにかなり異なっているが、原理は同じなので ここでは筆者の手元にあるを例に設定してみる。 (WIP)

    より上流にルータのファイアウォールなどが存在しないか確認

    これまでの手順をしっかり行ってもつながらない場合、 手元で見えているルータのさらに上流のネットワーク機器がファイアウォールを張ったり アクセス制御している可能性がある。 家庭用ネットワークでそこまでしていることはなかなかないと思うが、会社や大学のネットワークでは 勝手に設定を変えてもよい部門ルータのさらに上に管理者しか触れない全社ルータがあったりする場合が良くある。 この場合はサーバを勝手には立てられないか、あるいはポートを開けたりしてもらうための手続きが整備されている可能性がある。 このやり方はもうこちらでは関知出来ないので、社内の資料などで調べてほしい。

    外部ネットワークからの疎通テスト

    ここまでの設定が終わったらいよいよ外部ネットワーク(WAN)から接続してみよう。 アドレスを送ると外部サーバからリクエストを飛ばしてチェックしてくれるWebツールもあるが、 最近は手元のスマホのwifi接続をOFFにしてモバイルネットワークからサーバにアクセスしてみるのが手っ取り早い。 サーバのグローバルIPアドレスは固定していなくてもサーバ機からcurl http://ipinfo.io/ip 等のコマンドでアドレスを調べてくれる外部Webサービスに繋げばわかる。 このIPアドレスをスマホのブラウザのurl欄にいれてアクセスできるか調べよう。

    ここまでやって接続できなかった場合、もう一度手順を見直しながら ローカルからの接続 / LANからの接続 / WANからの接続を順を追って試すのが良い。 これによりどのポイントで間違えたのか、問題点の切り分けが容易になる。
    接続に成功しても気を抜かず、開けなくてよいもの・後悔したくないアクセスポイントまで 見えていないかを見直したい。 特にファイアウォールを開けるときに不必要なポートまで開けてしまうのは事故や攻撃のもとなので、 確認のためにあけたものや間違って開けたものが開いたままになっていないかは確認するとよいだろう。

    動作確認したバージョン

    • Python 3.7.2
    • Flask==1.1.2


    このエントリーをはてなブックマークに追加

    https://wonderhorn.net/