画像をはじめとした静的コンテンツをキャッシュし、Webサーバから配信することでアプリケーションのパフォーマンス向上が期待できます。
今回はnginxで静的コンテンツをキャッシュ配信する方法について紹介します。
目次
nginxによる静的コンテンツ配信の概要
locationを利用して『静的コンテンツへのリクエストはnginxで処理、それ以外はアプリケーションで処理』という設定をすることでnginxから静的コンテンツを配信できます。
locationとはリクエストごとに処理を分ける際に利用するnginxのディレクティブです。
locationは以下のパターンを利用してリクエストを振り分けます。1
パターン | 意味 |
---|---|
なし | 前方一致 |
^~ | 前方一致。一致したら、正規表現の条件を評価しない。 |
= | 完全一致。パスが等しい場合。 |
~ | 正規表現(大文字・小文字を区別する) |
~* | 正規表現(大文字・小文字を区別しない) |
静的コンテンツをキャッシュし、nginxから配信する方法
静的コンテンツをnginxで配信するための設定ファイルの紹介をします。
今回は以下のようなケースを想定します。
- 静的コンテンツは『/app/public/』ディレクトリに保存されている
- 『/app/public/images』配下の画像をnginxから配信する
- キャッシュ時間は1日とする
前方一致でパスを指定する方法
location /app/public/images/
で/app/public/images/
配下へのファイルアクセスがnginxで処理されます。
つまり、画像へのアクセスはアプリケーションではなくnginxで処理されます。
キャッシュはexpires [キャッシュ時間]
で設定できます。
nginx.conf
upstream web {
# UNIXドメインソケット通信の設定
server unix:///srv/app/tmp/sockets/puma.sock fail_timeout=0;
}
server {
listen 80;
server_name example.com;
# /app/public/images/ 配下へのアクセス
location /app/public/images/ {
expires 24h; # 24時間キャッシュする
}
# 上記の条件にマッチしなかったアクセス
location / {
# 『web』upstreamへプロキシさせる
# つまり、アプリケーションで処理される
proxy_pass http://web;
}
}
rootディレクティブを利用すると以下のようにかけます。
nginx.conf
server {
listen 80;
server_name example.com;
# 静的ファイルのパス
root /app/public;
# /app/public/images/ 配下へのアクセス
location /images/ {
expires 24h;
}
# 上記の条件にマッチしなかったアクセス
location / {
(略)
}
}
正規表現でパスを指定する場合
location ~ ^/images/
で/images/
配下へのファイルアクセスがnginxで処理されます。
正規表現を利用した設定ファイルは以下の通りです。
nginx.conf
server {
listen 80;
server_name example.com;
# 静的ファイルのパス
root /app/public;
# /app/public/images/ 配下へのアクセス
location ~ ^/images/ {
expires 24h;
}
# 上記の条件にマッチしなかったアクセス
location / {
(略)
}
}
正規表現を利用することでlocationの一致条件を簡単に拡張できます。
たとえば/images/
だけでなく、/hoge/
もキャッシュ対象のディレクトリする場合は、location ~ ^/(images|hoge)/
という正規表現になります。
正規表現でファイルの拡張子を指定する方法
正規表現でファイルの拡張子を指定することで、ディレクトリ単位ではなくファイル単位で処理を分けられます。
たとえばimages
ディレクトリにある.jpeg
、.JPEG
、.jpg``.JPG
、.png
のファイルをキャッシュする場合は以下のようになります。
nginx.conf
server {
listen 80;
server_name example.com;
# 静的ファイルのパス
root /app/public;
# マッチする例
# /app/public/images/hoge.jpeg
location ~* ^/images/(.*\.(jpe?g|png))$ {
# ^ : 先頭マッチ
# $ : 末尾マッチ
# .* : 任意の文字が0回以上出現
# \ : 直後の文字をエスケープ
# ? : 直前の文字が0回以上出現
expires 24h;
}
# 上記の条件にマッチしなかったアクセス
location / {
(略)
}
}
もし/app/public
ディレクトリにある.jpeg
、.JPEG
、.jpg``.JPG
、.png
のファイルをキャッシュする場合は以下のようになります。
nginx.conf
server {
listen 80;
server_name example.com;
# 静的ファイルのパス
root /app/public;
# マッチする例
# /app/public/hoge.png
# /app/public/images/hoge.png
location ~* .*\.(jpe?g|png)$ {
expires 24h;
}
# 上記の条件にマッチしなかったアクセス
location / {
(略)
}
}
参考: Railsアプリケーション上のnginxから画像をキャッシュ配信する
Railsアプリケーション上のnginxから画像をキャッシュ配信する手順について紹介します。
今回はチームで共有するための『Rails 6 x MySQL 8』Docker環境構築手順で紹介したDocker Compose環境を利用します。
サンプルアプリケーションの作成
画像を表示する画面のルーティングを作成します。
routes.rb
Rails.application.routes.draw do
+ root to: 'home#index'
end
コントローラとビューの作成をします。
$ rails g controller home index
キャッシュ配信するサンプルとして今回はpublic/images/group_young_world.png
という画像を用意します。
$ ls public/images/group_young_world.png
group_young_world.png
画面を作成します。
views/home/index.html.erb
<%= image_tag '/images/group_young_world.png', width: '500' %>
localhost:3000
にアクセスして画像が表示されればOKです。
アプリケーションサーバにnginxをインストール
Railsが実行されているアプリケーションサーバにnginxをインストールします。
### ローカルで実行
$ /path/to/project
$ docker-compose exec web /bin/bash
### webコンテナ上で実行
$ apt update && apt install -y nginx vim
nginxの設定ファイルを追加する
nginxの設定ファイル(/etc/nginx/nginx.conf
)のinclude /etc/nginx/conf.d/*.conf;
という記述からわかる通り、nginxは/etc/nginx/conf.d/
配下の*.conf
ファイルを設定として読み込みます。
そこで今回は/etc/nginx/conf.d/default.conf
という名前の設定ファイルを作成します。
$ mkdir -p /etc/nginx/conf.d
$ vim /etc/nginx/conf.d/default.conf
/etc/nginx/conf.d/default.conf
server {
listen 80;
server_name localhost;
# 静的ファイルのパス
root /rails6_mysql8/public;
location /images/ {
expires 300;
}
location / {
proxy_set_header Host localhost;
proxy_pass http://web:3000;
}
}
設定ファイル作成後、configtest
コマンドで文法誤りがないかチェックします。
### nginx.confの記述が正しいかチェック
$ /etc/init.d/nginx configtest
[ ok ] Testing nginx configuration:.
画面のキャッシュが有効になっているか確認する
設定ファイル作成後、nginxの起動をします。
$ service nginx start
localhost
にアクセスすると画像が表示されます。
画像のレスポンスヘッダを確認すると先ほど設定したキャッシュ時間(300秒)が反映されていることがわかります。
まとめ
- nginxでコンテンツを配信する場合はlocationディレクティブを利用する
- expiresで静的ファイルをキャッシュ配信できる
Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!