CakePHP3でリバースプロキシ経由のアクセスだとCake\Routing\Router::urlのアドレスがプライベートIPになる


開発環境では起こらなかったのですが、本番にデプロイしたところURLがプライベートIPになってしまいました。

問題のコード

src/Template/Layout/default.ctp

$this->assign('requestFullUrl', \Cake\Routing\Router::url(NULL, true));

テンプレートでCake\Routing\Router::urlを使ってカレントのURLを取得していました。
このURLをog:urlなどに設定していたのですが、本番でプライベートIPアドレスになったのでFacebookでシェアされた時にリンク切れになってしまいました。

原因調査

CakePHPのコードを見てみるとこちらのコードになっていました。

vendor/cakephp/cakephp/src/Routing/Router.php

    public static function url($url = null, $full = false)
    {
        ...

        if (empty($url)) {
            $output = isset($here) ? $here : $base . '/';
            if ($full) {
                $output = static::fullBaseUrl() . $output;
            }

            return $output;
        }

static::fullBaseUrl()という関数が呼び出されていて、ここに正しいドメインが指定できれば良さそうです。
更にコードを追ってみると。

vendor/cakephp/cakephp/src/Routing/Router.php
...
    /**  
     * Contains the base string that will be applied to all generated URLs
     * For example `https://example.com`
     *
     * @var string
     */
    protected static $_fullBaseUrl;
...
    public static function fullBaseUrl($base = null)
    {   
        if ($base !== null) {
            static::$_fullBaseUrl = $base;
            Configure::write('App.fullBaseUrl', $base);
        }
        if (empty(static::$_fullBaseUrl)) {
            static::$_fullBaseUrl = Configure::read('App.fullBaseUrl');
        }

        return static::$_fullBaseUrl;
    }

static::$_fullBaseUrlが空の時、config/app.phpファイルのApp.fullBaseUrlを代入するになってました。

解決方法

なので、下記の箇所を修正

config/app.php

    'App' => [
         'namespace' => 'App',
         'encoding' => env('APP_ENCODING', 'UTF-8'),
         'defaultLocale' => env('APP_DEFAULT_LOCALE', 'ja-JP'),
         'base' => false,
         'dir' => 'src',
         'webroot' => 'webroot',
         'wwwRoot' => WWW_ROOT,
         // 'baseUrl' => env('SCRIPT_NAME'),
-        'fullBaseUrl' => false,
+        'fullBaseUrl' =>  env('PROTOCOL', 'http')
+            . '://'. env('DOMAIN', 'localhost:8888'),
         'imageBaseUrl' => 'img/',

余談

念の為リファレンスを確認してみると下記のことが書かれています。
https://book.cakephp.org/3.0/ja/development/configuration.html

App.fullBaseUrl
アプリケーションのルートまでの (プロトコルを含む) 完全修飾ドメイン名です。 これは完全な URL を生成する際 に利用されます。デフォルトでは、この値は $_SERVER の環境情報から生成されます。しかし、パフォーマンスを最適化したり、 他人が Host ヘッダーを操作するのを心配するならば、自分で指定すべきでしょう。CLI 環境 (シェル) ではウェブサーバーとの関連が無いので fullBaseUrl を $_SERVER から読むことができません。もしシェルから URL を作成する必要がある場合 (例えばメールの送信) 、自力で指定する必要があります。

想定されていないわけ無いですよね・・・。