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知識が乏しいため、情報が効率よく整理しきれておらず分かりにくいかもしれず恐縮ですが、よろしくお願いいたします。

回答2件
あなたの回答
tips
プレビュー