1. ホーム
  2. スクリプト・コラム
  3. ルビートピックス

PythonのFlaskフレームワークでSERVER_NAMEドメイン名を設定するためのチュートリアル

2022-01-04 13:48:10

FlaskのSERVER_NAMEは主に2つのことをします。

  • アクティブなリクエスト(要求)に加えて、絶対的なURLを生成するためにFlaskを支援する(メールに埋め込まれたウェブサイトのURLなど)。
  • サブドメイン対応について

この2つ以外のことができると勘違いしている人が多い。

一つ目、絶対URL
url_forはデフォルトで相対URLを生成することがわかっています。また、_externalというパラメータがあり、これをtrueに設定すると絶対URL(つまり、ドメイン名などの情報を含むHTTPの先頭)が生成されます。SERVER_NAMEが指定されない場合、デフォルトでは現在アクティブなリクエスト(request)を使ってURLが生成されます。

以下はデモの例です。

# filename myapp.py
from flask import Flask, url_for

app = Flask(__name__)

@app.route('/')
def index():
 return 'hello flask'

@app.route('/test')
def test():
 return url_for('index', _external=True)

if __name__ == '__main__':
 app.run(debug=True)



1. [シナリオ1】ブラウザでアクセスする

アプリ実行後、ローカルで5000番ポートをリッスンします。

(env) F:\tmp>python myapp.py
 * Running on http://127.0.0.1:5000/
 * Restarting with reloader


ブラウザで http://127.0.0.1:5000/test にアクセスすると、返されるコンテンツは http://127.0.0.1:5000/ です。

ブラウザで http://localhost:5000/test にアクセスした場合、返されるのは http://localhost:5000/ です。

ご覧のように、SERVER_NAMEが設定されていない場合、url_forによって生成される絶対URLは要求されたURLに依存します。ブラウザからアクセスしない場合について見てみましょう。

2. [シナリオ2】ブラウザを使わないアクセス

このシナリオは、要求がない場合を指します。

これをPython Shellでシミュレーションすると、以下のようになります。

>>> from myapp import app
>>> with app.app_context():
... print url_for('index', _external=True)
...


Traceback (most recent call last):
 File "<stdin>", line 2, in <module>
 File "F:\tmp\env\lib\site-packages\flask\helpers.py", line 287, in url_for
 raise RuntimeError('Application was not able to create a URL '
RuntimeError: Application was not able to create a URL adapter for request indep
You might be able to fix this by setting the SERVER_NAME
You might be able to fix this by setting the SERVER_NAME config variable.


上記は、アプリケーションがリクエストに関連しないURL生成のためのURLアダプタを作成できないことを意味し、これはSERVER_NAMEを設定することで解決できます。

よし、SERVER_NAMEに値を設定した上でもう一度試してみよう。

>>> app.config['SERVER_NAME'] = 'example.com'
>>> with app.app_context():
... print url_for('index', _external=True)
...


http://example.com/


追記:一般的にSERVER_NAMEはウェブサイトのドメイン名に設定されています。

Flask-Mailの関連記事の中に、こんな一節があります。

多くのFlask拡張機能は、アクティブなアプリケーションとリクエストのコンテキストで実行されていることを前提としています。Flask-Mail の send 関数は current_app コンテキストを使うので、mail.send() 関数がスレッドで実行されたときに人工的にコンテキストを作る必要があり、send_async_ app.app_context() で email でコンテキストを作っているのだそうです。

そのため、リクエストに依存しない絶対的なURLを生成する(例えば、非同期でメールを送信する際に、メール内にサイトのページのURLを生成する)には、SERVER_NAMEを設定する必要があります。

2つ目:サブドメインへの対応
SERVER_NAMEキーは、サブドメイン対応のためのものです。Flask は既存のサーバー名を知るまではサブドメイン部分を推測できないので、サブドメインを使用する場合はこのオプションが必要です。また、セッションクッキーにも使用されます。

サブドメインがわからないのはFlaskだけではなく、ブラウザにもこの問題があることを覚えておいてください。最近のウェブブラウザは、サーバー名にドットを含まないクロスサブドメインのクッキーを許可しないので、サーバー名が localhost の場合、localhost とそのすべてのサブドメインにクッキーを設定することはできません。myapplication.local」のような適切なサーバー名を選択し、サーバー名+サブドメインをホスト設定に追加するか、ローカルバインディングを設定してほしい旨を追加してください。

   -------->http://book.muxistudio.com
   ||
http://muxistudio.com-------->http://blog.muxistudio.com
   ||
   -------->http://share.muxistudio.com


1. ローカルテスト

etc/hosts ファイルを修正する

注意:ローカルテストでのみ動作します

使用する必要があるすべてのサブドメインを追加します。

127.0.0.1 flask.dev localhost # domain name
127.0.0.1 test.flask.dev localhost # subdomain
127.0.0.1 othertest.flask.dev localhost # subdomain


Flaskアプリの設定ファイルに'SERVER_NAME'を追加します。

アプリケーションの設定で、'SERVER_NAME' に指定したドメイン名とデフォルトのリスニングポートを設定します。

#...
app = Flask(__name__)
app.config['SERVER_NAME'] = 'flask.dev:5000'
#...



2. コンフィギュレーションブループリント

ブループリントのサブドメインはhostsファイルで追加したサブドメインです

#...
# Blueprint declaration
bp = Blueprint('subdomain', __name__, subdomain="<user>")

#...

# Register the blueprint into the application
app.register_blueprint(bp)
#...



3. サーバー側の設定

Flaskアプリの設定にある「SERVER_NAME」を、本番環境で登録したドメイン名に変更します。

flask.dev:5000 ----> muxistudio.com



4. Nginxの設定

リスニングポートを設定します。以下の例では、ユーザがアクセスするサブドメインを正規表現で取得しています。wwwについては、正規表現を取得した時点でフィルタリングし、ユーザーがアクセスした時点で www.yourdomain.com页面 にリダイレクトするようにしないと、wwwがサブドメインとして扱われることになります。

設定例です。

 server {
 listen 80;
 listen 443 ssl;

 ssl_certificate /usr/local/nginx/ssl/nginx.crt;
 ssl_certificate_key /usr/local/nginx/ssl/nginx.key;

 server_name ~^www\. (? <user>. +\.) ? markdownblog\.com$;
 return 301 "$scheme://${user}markdownblog.com$request_uri";
 }

 server {
 listen 80;
 listen 443 ssl;

 ssl_certificate /usr/local/nginx/ssl/nginx.crt;
 ssl_certificate_key /usr/local/nginx/ssl/nginx.key;

 server_name ~^. +\.markdownblog\.com$ markdownblog.com;

 location / {
  proxy_set_header Host $http_host;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_pass http://127.0.0.1:8085;
 }
}