docker-composeにnginxのコンテナ追加したらRedirectでハマったのでメモ

自作のWSGIフレームワークKobinのExampleにおいて、手元でも静的ファイルをNginxで返すように変更を加えた。 ただしRedirectがうまくいかないので調査 & 雑にメモ (ところどころ英語)。

Problem

GitHub - kobinpy/kobin-example: Example application using Kobin python web-framework.

  1. ローカル(Mac)の http://127.0.0.1:8080マッピングしてdocker-compose up。
  2. Github OAuthでログイン
  3. GithubからのCallback URLは http://127.0.0.1:8080 に設定してるのでちゃんと帰ってくる
  4. RedirectResponseの設定するLocationのURLが http://127.0.0.1/ になってしまい困った。

Debugging by PDB in Docker Container

Add following options.

  server:
    :
    stdin_open: true
    tty: true
    command: /bin/bash

And attach container.

$ docker ps
$ docker attach <container id>

Insert import pdb; pdb.set_trace and run a server. But if you use slim image, there are no editors, curl and wget. So it's very difficult.

# pip install wsgicli
# wsgicli run app/__init__.py app --host 0.0.0.0 --port 80

Caution

When you just want to run the server, you can use docker-compose exec server /bin/bash. But it's not link from nginx image.

これでデバッグができるようになった。

Nginx

Nginxの設定で解決出来るものではないか調べてみた。

server {
    listen 80;

    location /static {
        alias /usr/src/public;
    }

    location / {
        proxy_pass http://server;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Port $server_port;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

ProxyまわりのHTTPヘッダをちゃんと理解する。

  • X-Forwarded-For: クライアントの IP アドレス。
  • X-Forwarded-Host: オリジナルのホスト名。クライアントが Host リクエストヘッダで渡す。
  • X-Forwarded-Server: プロキシサーバのホスト名。
  • X-Forwarded-Port : プロキシサーバのポート番号。

クライアントが要求していたページはHostヘッダで分かる。 httpsとかも使うときは、そのあたりのPortとscheme設定も気をつける必要がありそう。

(Pdb) p request.headers
{'HOST': '127.0.0.1', 'X_FORWARDED_HOST': '127.0.0.1', 'X_FORWARDED_PORT': '80', 'X_FORWARDED_FOR': '172.23.0.1', 'X_REAL_IP': '172.23.0.1', 'REFERER': 'http://127.0.0.1:8080/', ...

アプリケーション側でそこも考慮するべきなのかもしれない。 HTTP_REFERERの情報を見れば、ちゃんとリダイレクト出来そう。 Kobinの実装が悪いかもしれない。調べてみる。

HTTP Refererヘッダ

これを元にRedirectさせるべきか調べてみたけどどうやらそうではない。 このヘッダ書き換えられると困る。 DjangoやBottle、Flask(Werkzeug)もHTTP REFERERを見たりしてなかった。

Solution

とりあえずDockerのNginxコンテナを捨てる。理由は

  • KobinのRedirectResponseの実装に問題は無さそう
  • CloudFrontとかCDNでキャッシュさせれれば、そんなにアクセスこないのでwsgi-static-middlewareでも対応できる。
  • 本番でNginx使ったとしても、8080番で公開したりすることはないので、この問題にはならない。

自前のフレームワークだけあって調査がやりやすかった。

nginx実践入門 (WEB+DB PRESS plus)

nginx実践入門 (WEB+DB PRESS plus)