勉強中ですが学んだことをまとめていきます。
設定コンテキストについて
Nginxの設定ファイルは、以下のようにいくつかのコンテキスト(要素)によって構成されます。
コンテキスト名 | 説明 |
コアコンテキスト | Nginx自体が使用するコンテキスト。触れる必要はなさそう。 |
メインコンテキスト | コンテキストブロックに含まれない。基本レベルの設定を記述する。 |
イベントコンテキスト | 1つだけ定義できる。グローバルオプションを設定を記述する。 |
HTTPコンテキスト | NginxをWebサーバやリバースプロキシとして利用する際に記述。 |
サーバコンテキスト | HTTPコンテキストの子。仮想サーバを定義するために複数宣言も可能。 |
ロケーションコンテキスト | URI内のパスに対しての設定を記述する。 |
このように、それぞれのコンテキストを正しく設定することでNginxが思い通りの処理をしてくれるようになります。
リバースプロキシ
リバースプロキシの設定をする
リバースプロキシサーバは、Webサーバと利用者の間に置かれ、それぞれの通信を中継するために使われます。今回の僕の目的は、このリバースプロキシサーバを用いてプライベートサーバ上のDockerで動いているアプリケーションを公開することです。
また、リバースプロキシを使うことでセキュリティ向上や負荷分散などが可能になり、メリットもとても大きいです。以下はリバースプロキシを使用するための設定ファイルです。 /etc/nginx/conf.dに以下のような設定ファイルを置きます。
server {
listen 80;
server_name "サーバ名";
proxy_set_header Host $http_host;
location /{
proxy_pass "中継したいURL"
}
}
ちなみに、中継したいURLの最後にスラッシュをつけるかどうかで動作が変わってくるので注意してください。その後、Nginxを再起動させて変更した設定ファイルを読み込ませます。
systemctl restart nginx
最低限の設定ファイルはこのようになります。さらに、ここからSSL設定等を追記していきます。
ユーザのIPアドレスを記録するようにする
リバースプロキシを行う場合、Webサーバ側にはユーザからのアクセスが全てリバースプロキシからのアクセスとなってしまい、ユーザのIPアドレスなどを確認することができなくなってしまいます。そこで、以下のような設定を行うことでユーザの痕跡を残すことができるようにします。
server {
listen 80 default_server;
server_name "サーバ名";
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
location / {
proxy_pass "中継したいURL";
}
}
HTTPSにも対応させる
以下のように設定したファイルをconf.dディレクトリ下に新しく置きます。
server {
listen 443 ssl http2 default_server;
server_name "サーバ名";
ssl_certificate "/etc/letsencrypt/live/"Domain"/fullchain.pem";
ssl_certificate_key "/etc/letsencrypt/live/"Domain"/privkey.pem";
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_ciphers PROFILE=SYSTEM;
ssl_prefer_server_ciphers on;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
location / {
proxy_pass "中継したいURL";
}
}
これでHTTPSにも対応ができました。
websocketをリバースプロキシ
websocketをリバースプロキシする際はlocationにwsを設定し、その中に以下のように記述しましょう。
location /ws/ {
proxy_http_version 1.1; #デフォルトはHTTP 1.0
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass "中継したいURL"
}
アクセスされたURLに応じて振り分け
例えば、https://aaa.comにアクセスされた場合はhttp://bbb.comに、https://aaa.com/hello/worldにアクセスされた場合はhttp://ccc.com/hello/worldに振り分けたい場合もあるかもしれません。そんな時は以下のように設定しましょう。
location / {
proxy_pass http://bbb.com/;
}
location /hello/ {
proxy_pass http://ccc.com;
}
リバースプロキシの際、パスが通らなくなる問題
例えば、http://hogehoge.com/subdirというURLにアクセスすることで、プライベートサーバーで稼働しているDjangoアプリ(http://123.45.678.90:9000)にリバースプロキシするように設定したとします。
この設定の場合、例えばhttp://hogehoge.com/subdir/toppageにアクセスした場合、Djangoアプリのトップページ(http://123.45.678.90:9000/toppage)にアクセスすることができます。
Djangoアプリの方ではトップページからhttp://123.45.678.90:9000/aaaにリンクを張っているのですが、リバースプロキシを行っているので、そのリンクが期待されるURLであるhttp://hogehoge.com/subdir/aaaではなく、http://hogehoge.com/aaaのようになってしまいます。これでは404エラーを吐いてしまい、正しいリンク先にアクセスできません。
そこで僕が行ったのは、Djangoアプリ側の設定を変更して以下のように常にsubdir/を挿入するようにしたことでした。
urlpatterns = [
path('subdir/admin/', admin.site.urls),
path('subdir/', include('hoge.urls')),
]
DjangoのURL設定は階層構造のようになっているのでこのような手が取れましたが、本来であればWebサーバー等で解決すべき問題なのかもしれません。ちなみに、railsの場合はサブディレクトリにデプロイする用の設定ができるらしく、Djangoにも同様の設定がないか探しましたが見つけられませんでした。
Webアプリではなくホームページなど静的ファイルの場合は相対パスで行けると思います。
もしより良い方法を知っている方がいらっしゃいましたらtwitter(@Ryu_programs)で教えてくださると助かります。