TL;DR
server {
# ...省略
gzip on;
gzip_types image/gif image/png image/jpeg; # Railsは画像を圧縮しないので、欲しいであれば自分で圧縮すること
# ...省略
location /assets {
root /usr/share/rails/app/assets;
location ~ .*.(js|css|html|svg)+$ {
gzip_static on;
# gunzip on; # Railsの`public/assets`に圧縮してないファイルもあるので省略
}
}
目的
最近GoogleのPage Speed Insightsが遅い遅いとつっこまれたので、調べてみたら、「テキスト圧縮の有効化」が効いてないと指摘されて、その対策を探るために調査を行いました。
現象
Nginx Gzipで検索したら、たくさん結果が出て、そのほとんどは、下記の構文で、Nginx自分の機能で圧縮を行う手法を提案しています。
server {
# ...省略
gzip on;
gzip_types text/css application/javascript application/json;
gzip_types application/font-woff application/font-tff;
gzip_types image/gif image/png image/jpeg;
gzip_types application/octet-stream;
# ...省略
}
この手法にはいくつか欠点があります。まず、アクセスする度に、Nginxを使ってアセットのGzipを行うので、サーバーのCPUを大量に使います。そして、NginxはデフォルトSVGのmime typeを認識しないため、SVGの圧縮を行いたい場合は別途設定が必要でした。
また、rake assets:precompile
が実行される際のログを見てみると、ちゃんと.gzファイルも出しているのをわかりました。なぜかNginxこれら.gzファイルを認識していなく、圧縮前のファイルだけ提供しています。
解決策
そこで見つかったのはNginxのgzip_static
の設定でした。その設定をon
にすると、リクエストにgzipしたアセットを優先的に提供していて、もしgzipを明示的に不要とした場合、圧縮前のアセットを提供するしようでした。
ちなみに、もしgzip済のアセットのみ存在する場合、gunzip on
の設定を追加すると、gzip不要なクライアントに対して、Nginxが一回gzipしたアセットを解凍し、提供することになります。
ただし、Railsのassets:precompile
は画像ファイルを圧縮しないため、もしどうしても画像ファイルもgzipとして提供したい場合、おとなしくgzip_types image/gif image/png image/jpeg
を設定しましょう。
また、Nginxはデフォルトでhtmlファイルをgzipしているので、ここでの設定は不要です。
余談: Page Speed Insights点数を改善するための開発手法
施策まで
Googleさんが指摘した問題点を分析すると、「JSの読み込みが遅い」と「アセットが圧縮されていない」が大きくペナルティを食らったことがわかりました。
JSの読み込みが遅い問題に対しては、scriptタグにasyncやdeferを付けることで解決できます。ただし、JSの読み込み順が変わってしまうので、細かく動作確認が必要です。
アセットが圧縮されていない問題は上記のように、Nginxでの施策で対処できます。
効果確認
ここで効果確認するために、production環境のDockerを作って、NginxのDocker、そしてデータベースのDockerと繋いて、Ngrokなどプロキシでフォワーディングして、テストをしました。
対策した結果、だいぶ点数が上がりました。残りの問題点を調べると、TTFBが遅いと指摘されました。それはおそらくローカル環境なので、DBが重いのが原因でした。
結果
対策して、本番リリースしたら、より点数がアップしました。やはりTTFBの遅さはローカル環境のせいでした。
ちなみに、Page Speed Insightsの「モバイル」の方は、回線速度や機器のスペクトルなど、かなりペナルティを課しているそうです。PCだと点数が全く違います。
参考
https://qiita.com/RyoMa_0923/items/55078f6fb57e9d70a37f
https://gist.github.com/equivalent/9352734#file-nginx-on-ruby-on-rails-with-unicorn-and-gzip-assets-L35
https://qiita.com/cubicdaiya/items/2763ba2240476ab1d9dd
https://stackoverflow.com/questions/3972675/how-to-tell-gzip-static-not-to-look-for-image-files
https://qiita.com/yuuna/items/9a2954300a130a9637b8
https://guides.wp-bullet.com/enable-svg-gzip-compression-nginx/