Taglibro de miyacorata

Vi fine falos en la marĉon.

PukiwikiのURL表示を"ちゃんと"httpsにする

みなさまごきげんよう、宮野です。

わかりづらい表題ですが、リバースプロキシしたApache上で運用しているPukiwikiのちょっと気になってた点を修正しましたというエントリです。

Pukiwiki を運用しています

f:id:miyacorata:20210107155837p:plain

doc.miyacorata.net

最近Pukiwikiの運用をはじめました。宮野がオタク資料を集めたり集めなかったりします。名付けてMiyaDoc。最近の更新はもっぱらアサルトリリィです。

ちょっぴりあった問題

MiyaDocで気になっていた点はページタイトル下のURL表示がhttpに固定されてしまうことでした。MiyaDocもちゃんとHTTPSで通信できるようにしていますから、この挙動はあまりよろしくありません。

原因はわかっていて、宮野鯖Mastodonなどを運用している関係でWebサーバにNginxを使っていますが、Apacheを使うやつ(Pukiwikiもその一つ)も動かしているのでNginxからApacheへリバースプロキシもしているためでした。

解決法

Pukiwikiのこのリンクは lib/func.php で定義されている get_page_uri() という関数で呼び出されていますが、HTTPとHTTPSの判別はさらに別の guess_script_absolute_uri() という関数が呼び出されます。

guess_script_absolute_uri() の実装を見てみると、$_SERVER['HTTPS'] が定義されていて値が on であるとき、あるいは $_SERVER['REQUEST_SCHEME'] が定義されていて値が https であるときに $is_ssl がtrueになりスキームがhttpsになります。

ここまでわかればやることは明快です。リバースプロキシで X-Forwarded-Proto ヘッダでHTTPSによるアクセスかどうか飛ばしているならそれを反映させればいいわけです。

$is_forwarded = (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https';
if ($is_ssl || $is_forwarded) {
    $host = 'https://' . SERVER_NAME .
        (($port == 443 || $is_forwarded) ? '' : ':' . $port);
} else {
    $host = 'http://' . SERVER_NAME .
        ($port == 80 ? '' : ':' . $port);
}

今回は $is_forwarded というフラグを別にセットし、リバースプロキシによりフォワードされていた場合はポート番号の付加を省略するようにしました。

解決

f:id:miyacorata:20210119162525p:plain

URLがちゃんとhttps://で始まるようになりました。

補足

X-Forwarded-proto ヘッダは事実上の標準となっているヘッダで、現在は Forwarded という標準化されたヘッダーがあります。

developer.mozilla.org

developer.mozilla.org

いずれ、Forwarded で書くのが当たり前になるのかな~と思っています。