質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.31%
Flask

FlaskはPython用のマイクロフレームワークであり、Werkzeug・Jinja 2・good intentionsをベースにしています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Amazon EC2

Amazon EC2は“Amazon Elastic Compute Cloud”の略称です。Amazon Web Services(AWS)の一部であり、仮想化されたWebサーバーのコンピュータリソースをレンタルできるサービスです。

Q&A

解決済

2回答

1954閲覧

EC2(Windows Server)上のFlaskアプリケーションへアクセスできません。

pokok_kedua

総合スコア6

Flask

FlaskはPython用のマイクロフレームワークであり、Werkzeug・Jinja 2・good intentionsをベースにしています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Amazon EC2

Amazon EC2は“Amazon Elastic Compute Cloud”の略称です。Amazon Web Services(AWS)の一部であり、仮想化されたWebサーバーのコンピュータリソースをレンタルできるサービスです。

0グッド

0クリップ

投稿2023/06/12 05:31

EC2上のFlaskアプリケーションに外部からアクセスできず困っており、何から調べれば良いか、どのように対応すべきかのお知恵を貸していただきたくお願いいたします。

同じEC2インスタンス内に、HTMLとJavaScript、Flaskアプリケーションを置いています。HTML経由でJavaScriptからFlaskアプリケーションのAPIを呼び出し、結果をJavaScriptからHTMLへ返すようにしたいです。

実現したいこと

EC2インスタンス(Windows server)上で、Flaskアプリケーションを稼働させ外部からアクセスできるようにしたい。
外部からのアクセスでHTMLとJavaScriptへのアクセスはできる一方、JavaScriptからFlaskのAPI呼出でエラーになるため、問題はFlaskアプリケーションへのアクセスだという認識です。

前提

  • Python 3.10.9, Flask==2.3.2
  • EC2インスタンスのWebサーバーはIISを使用。IISの[Default Web Site]にHTMLを設定済で、外部からのアクセスでHTMLの表示とJavaScriptの実行は確認しました。
  • EC2はElastic IPを割り当て済。
  • EC2インスタンスのセキュリティグループのインバウンドルールでは、以下の設定をしています。

HTTPS(IPv4 ポート範囲=443 ソース=0.0.0.0/0)
すべてのICMP-IPv4(IPv4 ポート範囲=すべて ソース=0.0.0.0/0)
カスタムTCP(IPv6 ポート範囲=5000 ソース=::/0)
カスタムTCP (IPv4 ポート範囲=5000 ソース=0.0.0.0/0)
HTTP (IPv4 ポート範囲=80 ソース=0.0.0.0/0)
RDP (IPv4 ポート範囲=3389 ソース=0.0.0.0/0)

  • Flaskアプリケーションは以下のように起動しています。
* Serving Flask app ''myflaskapp'' * Debug mode: off WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Running on all addresses (0.0.0.0) * Running on https://127.0.0.1:5000 * Running on https://(EC2プライベートIPv4アドレス):5000 Press CTRL+C to quit
  • 認証は現時点では何も実装していません。

発生している問題

外部からChromeでHTMLとJavaScriptが表示・動作することは確認できましたが、JavaScriptからEC2上のFlaskアプリケーションへアクセスする際に以下のエラーを確認しました(Chrome Developer's Tool)。

GET https://(Elastic IP):5000/menus/ net::ERR_CONNECTION_TIMED_OUT

該当のソースコード

JavaScript側は関数request_json()にURLを引き渡してfetch()を実行しています。

JavaScript

1myurl = 'https://(EC2 Elastic IP):5000' + '/menus/' 2 3async function request_json(myurl) { 4 try { 5 var requestOptions = { 6 method: 'GET' 7 } 8 var response = await fetch(myurl, requestOptions) 9 10 if (response.ok) { 11 // Extract json 12 var resp_json = await response.json() 13 console.log('Response: ', resp_json) 14 return resp_json 15 } else { 16 // Error response 17 console.log('Request failed with status:', response.status) 18 return null 19 } 20 21 } catch(error) { 22 console.log('Error:', error) 23 return null 24 } 25} 26// end of request_json()

Flaskアプリケーション側

Python

1from flask import Flask 2from flask import request 3from flask import jsonify 4from flask_cors import CORS 5 6''' 7Flask setting 8''' 9app = Flask(__name__) 10app.config['JSON_AS_ASCII'] = False # Be able to handle Japanese. 11CORS(app) 12 13@app.route('/menus/', methods=['GET']) 14def menus(): 15 (省略) 16# end of menus() 17 18if __name__ == '__main__': 19 20 if init() == False: 21 exit() 22 23 app.run(host = '0.0.0.0', port = 5000, threaded = True, debug = False, ssl_context = ('../ssh/cert.pem', '../ssh/key.pem'))

試したこと

  • EC2インスタンスのドメイン(仮: mydomain.com)はお名前.comで取得しており、外部のWindowsからnslookupコマンドでドメイン名とEC2インスタンスの紐づけができていることは確認しました。
>nslookup mydomain.com サーバー: UnKnown Address: xxx.xxx.xx.xxx 権限のない回答: 名前: mydomain.com Address: (Elastic IPアドレス)
  • 'ping (Elastic IPアドレス)' コマンドは通らないので以下の2つを設定しましたが通りません。

・EC2のインバウンドルールにすべてのソースからのICMPを追加。
・外部(Win10)のファイアウォールの有効なプロファイル(プライベート)の受信の規則に "ファイルとプリンターの共有(エコー要求 - ICMPv4受信)" を追加。

  • 外部のブラウザから

・http://(Elastic IP アドレス)/ ← HTMLが表示される
https://mydomain.com/ ← HTMLが表示される
・https://(Elastic IP アドレス)/ ← ERR_CONNECTION_RESET

インフラ, EC2知識が乏しいため、情報が効率よく整理しきれておらず分かりにくいかもしれず恐縮ですが、よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

bsdfan

2023/06/12 09:43

windowsのファイアウォールでふさがってたりしませんか?
guest

回答2

0

最近インフラ触ってないのでそもそも間違っていたらすみません。
あと、構成のイメージがいまいちついていないのでご了承ください。

tls(https)でアクセスできるということはTLS証明書を取得していると思います。
証明書はデフォルトだとドメイン名と紐づけられるため、IP直打ちでhttpsは通信できないと思います。(多分)
調べてみましたが、(お名前.comにあるかわかりませんが)CN (Common Name)、SAN (Subject Alternative Name) DNS、SAN IPあたりにIPの設定をするとipアドレスで通信できるかもしれません(わざわざipにする必要があるかはわかりませんが)
flaskのlogに出ているhttpsはプライベートアドレスなのでglobal ipからhttpsで接続できるとは限りません。

とりあえずやりたいことをやるには、'https://(EC2 Elastic IP):5000' + '/menus/'とかhttps://(Elastic IP アドレス)/でアクセスするのではなく、ht〃ps://mydomain.com:5000/menusでアクセスする必要があると思います。
単純にflaskとの疎通確認であればhttp://(Elastic IP アドレス):5000/menusやht〃p://mydomain.com:5000/menusをブラウザでもcurlでもいいのでやってみるとか。(リンクになってしまうので〃は繰り返しです。ht〃ps -> https)

flaskへのアクセス方法ですが、考え方は二つあります。
一つは回答あるようにec2上に入り口用のサーバー(リバースプロキシ)を一つ置いて、そこからURL等でWebアプリとAPI(flask)を振り分ける方法です。
一般的にはIISも含めApache HTTPやNginxを置いてmydomain.com/に来たらIISに、(例えば)mydomain.com/api/に来たらflask(内部ネットワークで:5000)に流す方法です。

もう一つは今やっている方法ですね。
一つのサーバー(EC2)に対してport80/443と5000を立ち上げ受け入れる方法です。

どっちがベストかは(設定が面倒ですが)一般的にやられている前者がベストだと思います。
リバースプロキシ立ち上げるのは面倒ですが、外部からのアクセスは絞り込みたいですし、ほかの理由で外部からport5000がはじかれている可能性に気づきにくいので、外部からは80/443のみでセキュリティをそんなに気にしなくてもよい内部で色々なポートとの通信をするほうが簡単な気がします。
例えば、EC2のfirewall自体(セキュリティグループとは別)で5000をはじいているかもしれません。
それなら、同じサーバーにプロキシ立てて内部通信すれば上記の設定には引っかからないはずなので問題なく通信できるかもしれません。

投稿2023/06/12 08:27

編集2023/06/12 08:41
YuuT

総合スコア673

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pokok_kedua

2023/06/13 07:54

ありがとうございます。 今回はURLの書き換え設定が足りなかったことが原因のようです。IISで設定を行い解決いたしました。 丁寧にご説明頂き本当に助かりました。ありがとうございます。
guest

0

ベストアンサー

考え方が間違っている気がします。

質問文にある以下が正しい場合、

・http://(Elastic IP アドレス)/ ← HTMLが表示される
https://mydomain.com/ ← HTMLが表示される

以下のJavaScriptは関係が無い場所にアクセスしています。

myurl = 'https://(EC2 Elastic IP):5000' + '/menus/'

これだけだと分からないと思うので、以下に補足を書きます。

前提として、httpの場合は、ポート80。
httpsの場合は、ポート443が使われます。

ここまでは良いですか?

Webページを公開する場合、大抵はWebサーバとアプリケーションサーバを使います。
今回のWebサーバは、IISです。
アプリケーションサーバは、開発用をそのまま使っているようです。(python app.pyとかflask runとかで起動するやつは開発用です。余談ですが、開発サーバで公開するのはやめた方が良いので、IISで使えるアプリケーションサーバを探して下さい、LinuxだとGunicornとかApacheのmod wsgiなどです。LinuxでもApacheでもないので左記のは使えません。。。)

アプリケーションを開発する場合、開発用サーバ(5000で起動している物)に直接アクセスしています。

サーバで公開する場合、Webサーバにアクセスし、Webサーバがアプリケーションサーバに転送してくれたりしてアクセスします。
つまり、外部からアクセス可能なのはhttpのポート80や、httpsのポート443です

現状では、ページが見えているということですので、この転送してくれたりする設定が終わっているものと考えます。

そのため、JavaScriptのアクセス先を公開されているポート(80や443)にすればアクセス可能なんじゃないかと思います。

ついでに書きますと、JavaScriptはブラウザで動作することを理解してください。
サーバではありません。(Node.jsではないので)
つまり、ブラウザで80とか443にアクセスするのと同様の経路を通ってサーバにアクセスします。
なので、相手が居ないポートに情報を読みに行っています。

伝わったでしょうか?

投稿2023/06/12 07:45

FiroProchainezo

総合スコア2443

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pokok_kedua

2023/06/12 09:28

WSGIサーバーがないのはおかしいということでしょうか。 gunicornかwaitress を使って試してみます。 もやもやしていたところを整理していただきありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.31%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問