やりたいこと
Spring Bootで作ったアプリをサーバ上のTomcat配下のコンテキストに配置し、
ブラウザからはルートコンテキストでアクセスさせたい。
ログイン認証も中でやりたい。
Tomcatに複数アプリを設置する必要がある場合等、コンテキストがついてしまうケースがままあると思う。
コンテキストがつくと扱いが面倒なので開発はルートコンテキストでなんとかやりたい。
前提
-
サーバ上のTomcatにspring-bootアプリを配置
- tomcatには複数アプリを配置する必要があったので、ルートコンテキストを専有できない
- contextは/appとする
-
ブラウザからアクセスする際は
http://app.example.com/
のようにアクセスしたい- Apacheで
localhost:8080/app
にプロキシさせる感じで
- Apacheで
-
ソースコード上でコンテキストを意識したくないので、
server.contextPath
は指定しない -
appはSpring Securityによるセッションを使った認証を伴う
- 事前にローカル環境でフォーム認証くらいができる状態にしておいた
とりあえずやってみたら
Tomcatにwarを配置。
Apacheにはとりあえず以下のようにプロキシさせてみた。
(例ではAJPを使わずにhttpでproxyしているけど、AJPでも同じ動作のはず)
<VirtualHost *:80>
ServerName app.example.com
ProxyPass / http://localhost:8080/app/
ProxyPassReverse / http://localhost:8080/app/
</VirtualHost>
これでブラウザからhttp://app.example.com/
にアクセスしたら
ログイン画面が表示された。
なんだ、簡単だなと思った矢先。
usernameとpasswordを打っても打ってもログイン画面に戻ってくる。
なんで?と思ってブラウザのcookieを調べたら何も存在(session idがない)していなかった。
ここからが長かった
Cookieをなんとかするには
色々調べた結果、リクエストのコンテキスト(今回はルートコンテキスト)とproxy後のコンテキスト(今回は/app)が違う場合、cookie pathが異なる為、ブラウザとサーバのcookieがうまくいかないらしい。
ただApacheのmod_proxyにはこれに対応する為、proxy時にcookie pathを書き換える機能が
存在するとのこと(ProxyPassReverseCookiePath
)。
また、合わせてapp.example.comからlocalhostへとドメインが変わっていることから
cookie domainの書き換えも実施する(ProxyPassReverseCookieDomain
)
早速やってみる
<VirtualHost *:80>
ServerName app.example.com
ProxyPass / http://localhost:8080/app/
ProxyPassReverse / http://localhost:8080/app/
ProxyPassReverseCookiePath /app/ /
ProxyPassReverseCookieDomain localhost app.example.com
</VirtualHost>
これで再度ブラウザからアクセスすると、ブラウザ側にcookieが現れました!
よっしゃー!と喜び勇んでusernameとpasswordを打ち込むと相変わらずログイン画面に戻ってくる。
なんなのか。
続・Cookieをなんとかするには
どうもcookieを発行したが、サーバ側が認識していないっぽい。
ログイン画面アクセスの都度、新しいcookieが発行されてる。
色々調べた結果、以下のproxyでついにちゃんと動くようになりました
<VirtualHost *:80>
ServerName app.example.com
ProxyPass / http://localhost:8080/app/
ProxyPassReverse / http://localhost:8080/app/
RewriteEngine on
RewriteRule /app/(.*)$ http://localhost:8080/app/$1 [P]
ProxyPassReverseCookiePath /app/ /
ProxyPassReverseCookieDomain localhost app.example.com
</VirtualHost>
proxyだけでなくmod_rewriteを使ってURLの書き換えもしました。
これでちゃんと動きます。
なぜか?
mod_proxyで飛ばすとHTTP Location header
だけ書き換えになるのですが
これだとSpring側がちゃんと書き換わったように受け取らないっぽい。
mod_rewriteでURLごと書き換えて上げるとちゃんとcookieもつながったみたいです。
まとめ
- リクエストのコンテキストとproxy後のコンテキストが違う場合、cookieに問題が出る
- proxy前と後でcookie pathとcookie domainを揃えてやる必要がある
-
ProxyPassReverseCookiePath
とProxyPassReverseCookieDomain
を使う
-
- springにちゃんとcookieを認識してもらうには更にmod_rewriteでURLの書き換えも必要
参考にさせて頂いたサイト。ありがとうございました。