1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

セキュリティごった煮一人完走チャレンジAdvent Calendar 2024

Day 8

作って学ぶリバースプロキシ④リバースプロキシを経由してサイトアクセスする際にupstreamの仕様でハマった

Last updated at Posted at 2024-12-08

これは何?

前回Lua Scriptについて書いたので今回は実際にLua ScriptとOpenRestyでリバースプロキシを作ってみます。


環境構築

OpenRestyのセットアップ

今回はDocker imageをそのまま使いました。

Lua Scriptのインストール

前回記事にあるようにhererocksをインストールしてhererocks経由でLuaとパッケージ管理ツールのLuaRocksをインストールしました。


proxy_passを設定してリバースプロキシ経由でアクセスしてみる

proxy_pass経由でプロキシされる対象を指定できます。阿部寛のサイトを選んだのは80で動作しており,パケットキャプチャした結果が見やすいからです。

nginx.conf
        location / {
            root   /usr/local/openresty/reverse_proxy/html;

            # もとのhost = OpenRestyを指定してアクセスされることを確認するためつけておく
            proxy_set_header X-Forwarded-Host $host;
            proxy_set_header Connection "";

            default_type 'text/html';
            proxy_pass http://abehiroshi.la.coocan.jp;
        }

この際にproxy_passには以下の仕様があります。

Passing Request Headers
前記事から抜粋。

By default, NGINX redefines two header fields in proxied requests, “Host” and “Connection”, and eliminates the header fields whose values are empty strings. “Host” is set to the $proxy_host variable, and “Connection” is set to close.
NGINXではプロキシされるリクエストに対してデフォルトでは以下を実施している。

  • HTTPヘッダーのHostConnectionが上書きされている。
    • Host: ($proxy_passに指定したFQDN)$proxy_hostに書き換わる

    nginx公式ドキュメントに以下の記述がある。

    $proxy_host
    name and port of a proxied server as specified in the proxy_pass directive;

    つまり,proxy_passを設定すると$proxy_hostが書き換わる

これのなにがうれしいかというと,localhostでリバースプロキシを起動している際に,自動でHTTPのホストヘッダを書き換えてくれるということです。

Wiresharkでみるとわかりやすいのですが,ブラウザからhttp://localhost:80 にアクセスした場合に最初Hostにはlocalhostが格納されています。
しかし,前述したproxy_passの仕様によりHostがabehiroshi.la.coocan.jpに書き換えられるため,正しくアクセスすることができます。

image.png

image.png


nginx.confのupstreamを指定するとうまくいかない

nginx.confにはupstreamというサーバのグループを定義するためのブロックがあります。

nginx.conf
upstream backend {
    server backend1.example.com       weight=5;
    server backend2.example.com:8080;
    server unix:/tmp/backend3;

    server backup1.example.com:8080   backup;
    server backup2.example.com:8080   backup;
}

このブロックはnginx内で名前解決可能です。
そのため,proxy_passにbackendを指定するとupstreamだということを解釈してくれます。

そこで新たにproxied_serverというupstreamブロックを作り,proxy_passに設定してみました。
すると,404ページにつながるようになってしまいました。

原因

upstreamをproxy_passにした場合にはHostヘッダがproxied_serverになってしまい,404になっているようです。
image.png

解決方法

HostヘッダをLuaで無理やり書き換えてやれば良いようです。

うまくいった方法

解決策1: LuaでHostヘッダを書き換える。

nginx.confに新しく変数を追加し,書き換えてやります。

ngix.conf
        location / {
            root /usr/local/openresty/reverse_proxy/html;
            default_type 'text/html';

            access_by_lua_file /usr/local/openresty/reverse_proxy/src/main.lua;

            proxy_pass proxied_server;

            # NOTE: upstreamをproxy_passで指定するとHttp Host Headerがupstrem名になるので,Host名の上書きが必要。
            set $host_header "";
            proxy_set_header Host $host_header;
        }
main.lua
ngx.var.host_header = "abehiroshi.la.coocan.jp"
解決策2: upstreamの名前をproxied_serverからfqdn名に変更する
nginx.conf
    upstream abehiroshi.la.coocan.jp {
        server abehiroshi.la.coocan.jp:80; # テスト用
        keepalive 32;
        keepalive_requests 100;
        keepalive_timeout 10s;
    }

うまくいかなかった方法

  • Luaの中からngx.req.set_header()を使ってHostヘッダを書き換えてみたがだめ。
    • upstreamの中にbalancer_by_lua_fileを定義してluaを実行するパターン
    • main.luaから実行するパターン
  • upstreamの中にproxy_set_headerを定義してみたが,構文エラーになる

おそらくですが,proxied_serverというupstreamの名前の付け方にセンスがないのだと思います。
本来upstreamには使用するFQDNを入れるべきでそこにロードバランシングしたいipを書いていくのが正しいのかなと。
当たり前ですが,ロードバランシングする目的がなければupstreamは使わなくて良いなと(今回興味本位で試しましたが)。


次回

リバースプロキシとして動かすことができたので,次回はBasic認証をかけてみます。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?