「ELB配下にLaravelをインストールしたらCSSや画像が見れない」「secure_url関数って使う必要があるの?」
LaravelのサイトをHTTPS対応しようとして困ったことはありませんか?
LaravelでのURL生成は、動作環境に応じて柔軟に切り替わるようになっているので、仕組みを理解しないと解決に時間がかかるかもしれませんね。
この記事では、LaravelサイトをHTTPS化するのに必要となる関数や設定を詳しく紹介します。
リンクやリソースへのURLをhttpsにする
まず、リンクのURLや、画像・CSS・JSの参照パスがhttps:// になるようにします。
Bladeテンプレートでは、url()関数やasset()関数、route()関数などを使い、URLを指定しているものとします。
手前にロードバランサがない環境のとき
ELBなどSSLアクセラレータがなく、サーバー1台構成の場合は、url()関数やassets()関数をそのまま使えます。
<a href="{{ route('mypage') }}">Myページ</a>
<link rel="stylesheet" href="{{ asset('css/app.css') }}">
<img src="{{ url('storage/foo.img') }}">
リクエストがHTTPSのとき、assets()関数が生成するURLは自動的にhttps://になります。
<a href="https://example.com/mypage/">TOP</a>
<link rel="stylesheet" href="https://example.com/asset/css/app.css">
<img src="https://example.com/storage/foo.img">
ELB配下のLaravel環境のとき
ELB環境では、App\Http\Middleware\TrustedProxiesミドルウェアを次のように書き換えます。
class TrustProxies extends Middleware
{
/**
* The trusted proxies for this application.
*
* @var array|string|null
*/
protected $proxies = '*';
/**
* The headers that should be used to detect proxies.
*
* @var int
*/
protected $headers = Request::HEADER_X_FORWARDED_AWS_ELB;
}
こうすると、ELB経由のHTTPSリクエストのとき、url()関数やassets()関数、route()関数が生成するURLは自動的にhttps://になります。
Apache配下のLaravel環境のとき
Dockerのローカル開発環境で、Apache(リバースプロキシ)配下にLaravelを構築しているようなケースです。
まず、App\Http\Middleware\TrustedProxiesミドルウェアを次のように書き換えます。
class TrustProxies extends Middleware
{
/**
* The trusted proxies for this application.
*
* @var array|string|null
*/
protected $proxies = '*';
/**
* The headers that should be used to detect proxies.
*
* @var int
*/
protected $headers = Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO;
}
ProxyしているApacheの設定で、X-Forwarded-Protoヘッダを送信します。
例えば、/etc/httpd/conf.d/ssl.conf で、RequestHeaderディレクティブを使い、X-Forwarded-Protoヘッダにhttpsを設定します。
<VirtualHost _default_:443>
:
:
ProxyPass / http://127.0.0.1/
ProxyPreserveHost On
<Proxy *>
RequestHeader set X-Forwarded-Proto https
</Proxy>
</VirtualHost>
こうすると、SSLアクセラレータ代わりのApache経由でHTTPSリクエストがやってきたとき、url()関数やassets()関数、route()関数が生成するURLがhttps://になります。
ちなみに、ELB は X-Forwarded-Protoヘッダを自動的に送信するので、この設定は不要でしたが、ApacheはX-Forwarded-Protoヘッダを送信しないので、この設定が必要です。
HTTP ヘッダーと Application Load Balancer – Elastic Load Balancing
環境に依存せずURLをhttps化できる方法
方法① secure_url()関数やsecure_asset()関数を使う
これまで説明したurl()関数やasset()関数は、環境によって動作が変化するので、分かりにくい面もあります。
代わりに、secure_url()関数やsecure_asset()関数を使うと、環境によらずhttps://で始まるURLを生成できます。
変更前:
<link rel="stylesheet" href="{{ asset('css/app.css') }}">
<img src="{{ url('storage/foo.img') }}">
変更後:
<link rel="stylesheet" href="{{ secure_asset('css/app.css') }}">
<img src="{{ secure_url('storage/foo.img') }}">
helpers.phpのsecure_assets()関数の実装を見ると、secure変数をtrue固定で渡しています。
/**
* Generate an asset path for the application.
*
* @param string $path
* @return string
*/
function secure_asset($path)
{
return asset($path, true);
}
環境によって動作が変わることもなく、確実な方法です。
方法② UrlGeneratorをカスタマイズする
secure_url()関数を使わない方法としては、UrlGeneratorクラスをカスタマイズし、強制HTTPS化する方法があります。
AppServiceProviderクラスで、UrlGeneratorのforceScheme関数を呼び出します。
use Illuminate\Routing\UrlGenerator;
class AppServiceProvider extends ServiceProvider
public function boot(UrlGenerator $url)
{
$url->forceScheme('https');
}
}
セッションCookieにsecure属性を付与する
.envファイルで、SESSION_SECURE_COOKIE
を true に設定します。
SESSION_SECURE_COOKIE=true
SESSION_SECURE_COOKIE
が未設定の時は、Cookieにsecure属性が設定されません。
例えば、ログイン時に送信されるSet-Cookieヘッダは、以下のようになっています。
SESSION_SECURE_COOKIE
をtrueに設定すると、次のようにsecure属性が設定されるようになります。
.envのAPP_URLはHTTPS対応に関係なし
.envファイルにアプリケーションのURLを指定するAPP_URLがありますが、HTTPS判定には使われていません。
LaravelのHTTPS対応には様々な方法があるので、利用環境に応じて、使い分けてみてください。