前提
現在 Vercel (Next.js) → Apache → Wordpress という構成でサーバー構築を行っています。
Vercel には example.com
のドメインが割り当てられていて、Wordpress 側には b.example.com
のドメインが割り当てられているとします。
クライアントは https://example.com
にアクセスし、直接 https//b.example.com
にアクセスすることはありません。
また、セキュリティ上アクセスできないように設定しています。
クライアントから https://example.com
にアクセスがあった場合、ほとんどの場合は Next.js からの応答を返すのですが、特定のパス https://example.com/blog
以下にアクセスがあった場合のみ、Next.js から Wordpress にリクエストを転送し、Wordpress のレスポンスを、Next.js がクライアントに転送して返します。
つまり、この場合のみ、Vercel (Next.js) はリバースプロキシとして振る舞います。
Apache などで構築したリバースプロキシの場合、転送時にリクエストの URL (Host ヘッダ) を書き換えるだけでなく、レスポンスの URL (Location ヘッダ) も書き換えてくれるのですが、Next.js はそれをやってくれません。
起こっていること
前述の前提のため、Apache 側でリダイレクトが発生すると、リダイレクト先の URL が https://b.example.com/blog
になってしまいます。
クライアントから直接 https://b.example.com
にアクセスすることはない前提なので、これだとセキュリティの設定によって、エラーになってしまいます。
実現したいこと
Apache で発生するリダイレクトを発生しないようにするか、リダイレクト先をドメインを含まないパスのみにするか、リダイレクト先のドメインを example.com
に変更するかして、エラーが発生しないようにしたいです。
調べてわかったこと
Apache の挙動
Apache でリダイレクトが発生する理由は、Trailing Slash で、mod_dir が発生させていました。
具体的には、https://example.com/blog
→ https://b.example.com/blog/
のようなリダイレクトを発生させています。
試しに DirectorySlash Off
を設定すると、リダイレクトは発生しなくなります。
mod_dir では、リダイレクトの細かい設定はできないらしく、もしやりたい場合は mod_rewrite でやることになりそうです。
Trailing Slash の扱い
Next.js では Trailing Slash を付けるか付けないかのどちらかの設定しかできないらしく、現在ビジネス上の都合により付けない設定になっているため、Next.js で Trailing Slash が外され、Apache で付けられるということになってしまっています。
クライアントが https://example.com/blog/
にアクセスすると、Next.js が /blog
へのリダイレクトを返し、それを受けてクライアントが https://example.com/blog
にアクセスすると、今度は Apache が https://b.example.com/blog/
へのリダイレクトを返します。
リダイレクト
Next.js では以下のようなリダイレクトレスポンスを返します。
$ curl -I https://example.com/blog/ HTTP/2 308 date: Thu, 15 Apr 2021 06:33:51 GMT content-type: text/plain location: /blog refresh: 0;url=/blog server: Vercel x-vercel-id: hnd1::cmlcm-xxxxxxxxxxxxx-xxxxxxxxxxxx strict-transport-security: max-age=63072000 cache-control: s-maxage=0
これにはドメインが含まれないので、Apache 側でもこのようなリダイレクトができればそうしたいです。
試したこと
解決に向けて、いくつかのプランを考え、それぞれ調べて試してみました。
このうちのどれかでも、別の方法でもいいので、解決方法がわかる方がいらっしゃいましたらご教授ください。
案 1. Next.js でレスポンスの location のドメインを書き換える
Apache でリバースプロキシを立てたときのように、Next.js でレスポンスの location ヘッダーのドメインを書き換えられればいいのですが、方法を見付けられませんでした。
それと、そうすると Next.js が /blog
にリダイレクトし、続いて Apache が /blog/
にリダイレクトし、更に Next.js が……と、無限ループになってしまうので、この方法は断念しました。
案 2. Apache が返すリダイレクト先をパスのみにする
Apache が返すリダイレクトレスポンスを、Next.js が返すものと同じように、ドメインを含まない /blog/
のみにすれば、b.example.com
がクライアントに伝わることもないと思ったのですが、こちらも無限ループが発生してしまいます。
案 3. 特定のパスのみ Trailing Slash を付ける
Next.js で、特定のパスのみ、Trailing Slash を付けるという設定ができればいいと思って調べたのですが、方法を見つけられませんでした。
もしこれが実現できたら、Next.js 側で必ず Trailing Slash が付与されるため、Apache が Trailing Slash のためにリダイレクトすることはなくなります。
ちなみに、Vercel には Trailing Slash について何もしないという設定があるのですが、
Next.js には Trailing Slash を付けるか付けないかのどちらかのオプションしかなさそうでした。
実現できたらこの方法が一番副作用が少なくてよいのですが。
案 4. Apache にリクエストを転送する際に Trailing Slash を付ける
Next.js に来たアクセスを Apache に転送する際に、Trailing Slash を付けられないかと思ったのですが、Wordpress は管理画面などでファイル名のみを指定した相対リンクが作られるので、Trailing Slash なしだとリンク先が変わってしまい、ダメでした。
現在のアドレスと相対パスから、絶対パスを生成するのはブラウザなので、Next.js の裏側でだけ Trailing Slash を付けても意味がありません。
一応試した方法を書いておきます。
現在の Next.js の next.config.js
の設定は以下のようになっています。
js
1module.exports = { 2 async rewrites() { 3 return [ 4 { source: '/blog/:path*', destination: 'https://b.example.com/blog/:path*' } 5 { source: '/:path*', destination: '/:path*' }, 6 ]; 7 }, 8};
これに対して、単純に destination
の :path*
の後ろに /
を付けてみたのですが、ファイルにも /
が付いてしまい、うまくいきませんでした。
例えば、app.css
が app.css/
になってしまいました。
:path*
の部分をもう少し詳細に設定する方法があればとも思ったのですが、前述の相対パスの問題があったため諦めました。
案 5. Apache & Wordpress で Trailing Slash なしを受け入れる
Apache で Trailing Slash を付けるためのリダイレクトをやめて、Trailing Slash が無くてもリダイレクトせず、コンテンツを返すようにする。
まず、Apache ではリダイレクトをしてほしくないので、httpd.conf
に DirectorySlash Off
を設定し、Trailing Slash のためのリダイレクトを停止させます。
Wordpress のトップページと管理画面のトップページ以外は、Wordpress の設定を変えることで、リダイレクトせずにコンテンツを返すようにできました。
これらのページへのアクセスは、mod_rewrite で index.php
に渡されるので、PHP 側でよしなにできます。
もし クライアントが Trailing Slash を付けてアクセスした場合も、Next.js が取ってくれるので、Apache 側は気にしなくて済みます。
しかし、トップページと管理画面のトップページは 403 になってしまいました。
もしかしたら他は mod_rewrite によって index.php
へのアクセスに変わっているが、ディレクトリへのアクセスは、Apache の DirectoryIndex
によって処理されているからなのかもしれません。
403 のとき、Apache のエラーログには以下のような出力がありました。
[Thu Apr 15 03:05:39.770634 2021] [autoindex:error] [pid 15756:tid 139987826042624] [client 10.0.0.1:48594] AH01276: Cannot serve directory /var/www/html: No matching DirectoryIndex (none) found, and server-generated directory index forbidden by Options directive
なお、.htaccess
は Wordpress によって以下のように設定されています。
htaccess
1# BEGIN WordPress 2# "BEGIN WordPress" から "END WordPress" までのディレクティブ (行) は 3# 動的に生成され、WordPress フィルターによってのみ修正が可能です。 4# これらのマーカー間にあるディレクティブへのいかなる変更も上書きされてしまいます。 5<IfModule mod_rewrite.c> 6RewriteEngine On 7RewriteBase /blog/ 8RewriteRule ^index.php$ - [L] 9RewriteCond %{REQUEST_FILENAME} !-f 10RewriteCond %{REQUEST_FILENAME} !-d 11RewriteRule . /blog/index.php [L] 12</IfModule> 13 14# END WordPress
mod_rewrite で /blog/hoge
を /index.php
に渡すことができているので、同じようにして /blog
も index.php
に渡すことができそうな気がするのですが、mod_rewrite に詳しくなく、やり方がわかりません。
ただ、この方法でうまくいったとしても、他の案と同じように、リンク先が相対パスになってるリンクは機能しません。
いくつか案を考えてそれぞれ試してみましたが、問題なく解決できそうなのは 案 3. だけでした。
補足情報(FW/ツールのバージョンなど)
name | version |
---|---|
Next.js | 10.0.9 |
Apache | 2.4.39 |
PHP | 7.3.5 |
Wordpress | 5.5.3 |
Wordpress 側は既存のものを流用しているためバージョンが古めです。
あなたの回答
tips
プレビュー