読者です 読者をやめる 読者になる 読者になる

huguma’s blog (仮)

IT技術関連中心の備忘録

年末のご挨拶

今年もあっという間に終わってしまいます。お世話になった方々に心より感謝申し上げます。

年末年始は故郷の北海道に帰省します。ほぼ毎日更新している天気データマップは本日より一週間ほど更新をお休みします。それではよいお年を。

Apacheサーバのgzip圧縮最適化: 4. 補足: ファイルのgzip圧縮(初級編)

  1. 確認方法
  2. 設定方法
  3. 事前圧縮による最適化
  4. 補足: ファイルのgzip圧縮(初級編)

はじめに

サイトの事前圧縮処理ではgzipを用いますが、ここではその具体的な方法について補足説明します。できるだけ初級者の方にも分かるような説明を心がけます(Unix系の開発経験者なら読む必要はありません)。

gzipコマンドについて

gzip可逆圧縮アルゴリズムを用いてファイルの圧縮・展開を行うコマンドで、Unix系の環境(LinuxMacなど)には標準でインストールされています。

Windowsgzipを利用するには

Windowsにはgzipは入っていませんが、Windows用のgzipはいくつもあります。私のお勧めはMinGWのMSYSで、これをインストールすればWindowsで(gzipを含む)Unix系基本コマンド一式が使えるようになります。

http://sourceforge.net/projects/mingw/files/

インストール方法は次をご覧ください。msys-baseというのがMSYSで、これを選択するとインストールされます。インストール後のパス設定(例:C:\MinGW\msys\1.0\bin)の追加も忘れずに行って下さい。

http://web.plus-idea.net/2014/06/mingw-install-2014/

使用法(コマンドラインオプション)

ここではサイトの事前圧縮に必要な使用方法だけ説明します。オプションなしでファイル名だけ指定するとそのファイルを消去して拡張子.gzの圧縮ファイルに変換します。次の例はindex.htmlを消去してindex.html.gzを出力します。

$ gzip index.html

すでにターゲットのindex.html.gzが存在する場合はプロンプトを表示して上書きするかどうか聞いてきます。プロンプトを表示させず強制的に上書きするには-fを指定してgzip -f index.htmlとします。

圧縮ファイルを展開して元通りにするには-dを使います。次で圧縮ファイルを消去し、元の非圧縮ファイルを生成します。

$ gzip -d index.html.gz

元ファイルを残して圧縮ファイルを生成する場合は-c(stdoutに出力)を使い、リダイレクトしてファイルを生成します。

$ gzip -c index.html > index.html.gz

圧縮ファイルを残して元ファイルに展開する場合は-d(展開)と-c(stdoutに出力)を組み合わせ、やはり最後はリダイレクトでターゲットファイルを生成します。

$ gzip -dc index.html.gz > index.html

圧縮レベルは-1から-9の間で設定できます(デフォルトは-6)。数値が大きいほど圧縮率が高くなりますが、その分処理に時間がかかります。

最高の-9はデフォルトの約2倍の処理時間を要しますが、圧縮率はあまり変わりません(違いはたかだか1%程度)。特別な理由がなければデフォルト設定で十分です。

ファイルの一括処理

ファイル数が多くなってくると、コマンドを手動でタイプするのが困難になってきます。処理を自動化する方法はいくつもありますが、ここでは次の3通りについて簡単に説明します。

findを使う

(Unixの)findはディレクトリ内を探索し、設定条件に一致したファイルを操作するコマンドです。豊富な機能がありますが使用法はちょっと複雑です(慣れが必要です)。マニュアル(和訳)は次の通りです(しかし読むのは大変でしょう)。

http://linuxjm.osdn.jp/html/GNU_findutils/man1/find.1.html

(Windows用の注意) Windowsのfindコマンドとは全く別です。MSYSにはfindも含まれていますが、普通のパス設定ではWindowsのfind.exeが優先するため動きません。フルパスを指定する(例: C:\MinGW\msys\1.0\bin\find.exe ...)などの対応で利用できます。

まず簡単な使い方の例を示します。./siteディレクトリの中にある全ての.bakファイルを探して削除します(探して表示するだけの場合は-deleteを書かない)。これを知っているだけでも十分便利です。

$ find ./site -name \*.bak -delete

*.bak*の部分をコマンドライン(シェル)が展開しないよう上記の通り\でエスケープするか、またはクォートで囲む必要があります("*.bak")。

次が本題です。-execオプションを使い、条件に一致するファイルに対して任意のコマンドを実行できます。全てのhtmlファイルを検索してgzip圧縮ファイルに変換する例を示します。

$ find ./site -name \*.html -exec gzip {} ";"

元に戻す場合は次の通りです。

$ find ./site -name \*.html.gz -exec gzip -d {} ";"

ポイントをまとめておきます。一番注意する点は最後の;の扱い方です。

  • -execの後;までの引数は実行コマンド名とその引数として認識される
    • コマンドに渡すファイル名の部分には{}を用いる
    • 終了の目印は;(単独の引数として認識させるため手前に空白が必要)
  • bashでは;はコマンド区切り記号なので次の点に注意
    • そのままだとコマンド区切りとして認識される(エラー)
    • \;とエスケープすればOK(bashではポピュラーな書き方)
    • クォートで囲み";"または';'でもOK
  • Windowsコマンドプロンプトの場合は次の通り
    • \;とエスケープするのはエラー
    • 単に;またはクォートで囲めばOK

しかしfindだけでできることには限りがあります。例えば元のファイルを残して圧縮ファイルを生成する場合はリダイレクトを使うため、findの引数一行の中だけで表現するのは困難です。

普通の方法ではできないと思いますが確認していないので「困難」という表現にしました。また仮にできたとしてもシェルスクリプトプログラミング言語を利用した方が理解しやすく管理も容易だと思います。

シェルスクリプトを使う

シェルスクリプトを使えばもっと複雑な処理が可能になります。Bashからfindを起動し、元ファイルを残して.gzファイルを生成する例を示します。-type fは「通常ファイルのみ」の意味です(ディレクトリやシンボリックリンクを除外するための対策)。

#!/bin/bash

# 第一引数($1)のディレクトリ内を探索し、特定の拡張子に対して.gzを生成
find $1 -type f | while read f; do
  # 正規表現マッチして拡張子を判定
  if [[ $f =~ \.(html|js|css|txt)$ ]]; then
    echo $f '=>' $f.gz
    gzip -c $f > $f.gz
  fi
done

スクリプト言語を使う(Rubyの場合)

高級スクリプト言語を使えばさらに複雑な処理を行えます。ここではRubyの場合を説明しますが、Rubyを使うことには次のような利点があります(あくまで個人的見解)。

  • シェルスクリプトと比較して文法が美しく洗練されている
  • 書き方を統一できる(シェルは方言が沢山あるがRubyは基本的にない)
  • 環境依存性をRubyが吸収してくれる(特にWindowsでも同じコードで動く)

PerlPythonなど別の言語が得意な人はそれに置き換えて下さい。得意言語を何か一つ持っているのは大きな武器です。

それでは実際の例を示します。Rubyの標準ライブラリにはfindモジュールがあり、findコマンドと同じ手順でディレクトリ探索を行うことができます(これを使えばfindコマンドは不要です)。

http://docs.ruby-lang.org/ja/2.2.0/library/find.html

Rubyで可能な機能は全て組み込むことができますが、ここではファイルの更新チェック機能を付けます。.gzファイルが存在しない(新規ファイル)か、または元ファイルより古い(ファイルが更新された)場合だけgzipを実行します。

require 'find'

def scan_and_update_gz(dir)
  Find.find dir do |f|
    # 通常ファイルか確認後、拡張子をマッチして特定ファイルタイプを除外
    #                           vvvvvvvvvv <== (例)この部分は要調整
    if File.file?(f) && !(/\.(?:gz|jpg|mp3)$/ =~ f)
      gz = "#{f}.gz"
      # .gzがまだ存在しないか、または元ファイルより古い場合だけ生成
      if !File.exist?(gz) || File.stat(gz).mtime < File.stat(f).mtime
        # puts "#{f} => #{gz}"      # (表示の例) 必要な場合はコメントを外す
        `gzip -c #{f} > #{gz}`     # gzipを実行
      end
    end
  end
end

# 使用例
scan_and_update_gz './site'

この程度までの機能ならシェルスクリプトでも組めますが、(少なくとも私の場合は)Rubyの方がはるかに楽に書けます。またWindowsで同じコードがそのまま使えるのも大きなメリットです。

レンタルサーバを使う場合はさらに改良して、探索時に.gzを更新(生成)したファイルを記憶しておき、更新されたファイルだけftpコマンドで自動アップロードする事もできます。

これは天気データマップの毎日のメインテナンスで実際に行っていますが、非公開部分を含んでいるため割愛します(ご了承下さい)。

Apacheサーバのgzip圧縮最適化: 3. 事前圧縮による最適化

  1. 確認方法
  2. 設定方法
  3. 事前圧縮による最適化
  4. 補足: ファイルのgzip圧縮(初級編)

はじめに

前回説明したmod_deflateを使う方法ではリクエストがある毎にサーバ側でgzip圧縮処理を行いますが、これはサーバ側CPUの負荷を発生します。そこでファイルを事前圧縮しておき、それを直接返すようにすればサーバ負荷を大幅に改善できます。

ファイルのgzip圧縮

まず圧縮効果があるタイプのファイルをgzip圧縮し、元ファイルと同じディレクトリに拡張子.gzで保存します。方法は2通りあります。

  • 元ファイル(例:index.html)を残し圧縮ファイル(index.html.gz)を生成
  • 元ファイルを消去して圧縮ファイルに変換する

具体的な方法は 補足: ファイルのgzip圧縮(初級編) をご覧下さい。

元ファイルを残すかどうか

今のブラウザは全てgzip圧縮対応ですから、実はブラウザからアクセスする場合は元ファイルは使われません。元ファイルが必要なのはcurlなどのコマンドツールRuby/Pythonなどのプログラムコードからアクセスするようなケースだけです。

さらに元ファイルを消去してしまい、非圧縮ファイルを要求された場合はサーバ側で圧縮ファイルを展開処理して返すように設定することも可能です。この方法はファイル数が増えず、さらにディスク容量を大幅に削減する大きなメリットがあります。

非圧縮ファイルを要求された場合に展開処理を行うためわずかなサーバ負荷が発生します。しかし展開処理は圧縮よりはるかにサーバ負荷が少なく、さらに非圧縮で返す要求自体が今ではほとんどありません。

以下両方の場合の設定方法を説明します。バージョンはApache 2.4を対象とします。

元ファイルを残す場合

最小限に単純化した文例を使って説明します。ここではhtml, js, cssの3つの拡張子だけを対象としていますが、きちんと理解すれば自分でいくらでも拡張できます。

RewriteEngine on

RewriteCond %{HTTP:Accept-Encoding} gzip
RewriteCond %{REQUEST_URI} \.(?:html|js|css)$
RewriteCond %{REQUEST_FILENAME}.gz -s
RewriteRule .* %{REQUEST_URI}.gz [L]

<FilesMatch "\.html\.gz$">
  ForceType text/html
</FilesMatch>
<FilesMatch "\.js\.gz$">
  ForceType text/javascript
</FilesMatch>
<FilesMatch "\.css\.gz$">
  ForceType text/css
</FilesMatch>

全体の流れを示します。Apacheサーバは次のように応答します。

  • 次の条件を全て満たす場合だけ対応(それ以外は通常処理)
    • リクエストヘッダがgzip圧縮を受け付ける
    • .gz生成時に指定した拡張子にマッチする
    • 事前圧縮した.gzファイルが存在する
  • 以上を全て満たす場合は次の通り応答
    • URLの末尾に.gzを追加(bodyとして事前圧縮した.gzファイルを返す)
    • ファイルタイプを強制的に.gzなしのタイプに設定する

Apacheではこれをmod_rewriteモジュールを利用して設定します。

http://httpd.apache.org/docs/current/ja/mod/mod_rewrite.html

mod_rewriteを有効にする

初期状態ではmod_rewriteの機能はoffになっています。まずこれを次の一行でonにします。

http://httpd.apache.org/docs/current/ja/mod/mod_rewrite.html#rewriteengine

RewriteEngine on

書き換え条件の設定

次にレスポンスヘッダ書き換え処理を行う条件をRewriteCondディレクティブで設定しますが、書式はとても難解です。全部読んでいるとそれだけで日が暮れそうなので要点を順番に説明します。

http://httpd.apache.org/docs/current/ja/mod/mod_rewrite.html#rewritecond

まず一行の書式は次の通りで、TestStringの部分が条件を設定する対象、CondPatternがマッチさせる条件(通常は正規表現)です。複数RewriteCond行はand結合し、全て満たす場合が書き換え対象となります。

RewriteCond TestString CondPattern

今回はTestStringとしてリファレンスに書かれているServer-variablesを設定します。これらは%{NAME_OF_VARIABLE}の形式で記述します。リファレンスにはNAME_OF_VARIABLEの一覧(四角で囲まれた部分)がありますが、これだけではありません。

リファレンスのずっと先の部分(箇条書きの4)に%{HTTP:header}という書式があり、headerにはリクエストヘッダの任意の項目を指定できます。これを最初に用い、Accept-Encodingの値にgzipが含まれているか判定します。

RewriteCond %{HTTP:Accept-Encoding} gzip

次のREQUEST_URIはURLから(もしあれば)クエリ部分を除いたものです。これで拡張子を判定します。

RewriteCond %{REQUEST_URI} \.(?:html|js|css)$

(参考) クエリはQUERY_STRINGで取得できます。

次のREQUEST_FILENAMEはURLに対応するローカル側ファイルシステムのフルパスで、これに.gzを付けて事前圧縮したファイルが存在するかチェックします。判定は(正規表現は使えないので)-sフラグ(通常ファイルなら真)を使います。

RewriteCond %{REQUEST_FILENAME}.gz -s

書き換え処理の設定

以上の条件を全て満たす場合のレスポンスヘッダ書き換え処理をRewriteRuleディレクティブで設定します(こちらもリファレンスは複雑怪奇です)。

http://httpd.apache.org/docs/current/ja/mod/mod_rewrite.html#rewriterule

書式は次の通りです。

RewriteRule Pattern Substitution [flags]

各項の意味は次の通りで、ここでのURL-pathはURLからスキームとホスト名を除いたものです(http://example.com/path/file.htmlの場合は/path/file.html)。

  • Pattern: URL-pathに対する正規表現パターン
  • Substitution: URL-pathを置換する文字列
  • flags(optional): 各種設定と制御(後述)

今回は次のように設定します(意味は後で説明します)。

RewriteRule .* %{REQUEST_URI}.gz [L]

まず適用条件はすでにRewriteCondで全て処理済みですから、 Patternには.*(全てにマッチ)を指定します。

次のSubstitutionでURLをどう置換するかを記述します。ここではRewriteCondで用いたServer-variablesの書式%{REQUEST_URI}でURLを参照し、その最後に.gzを追加します。

最後のフラグは[L]のように角括弧の中に書きます。[L][last]の略で、置換処理をこれで終了することを意味します。

複数の置換処理を組み合わせることも可能です。デフォルト(フラグなしは)次のルールを(無条件で)評価します。条件のand結合は[C](chain)です。最後に[L]を指定して終了を認識させます。

ファイルタイプの書き換え

以上で圧縮ファイルが存在する場合はパスに.gzを追加して事前圧縮ファイルを返すところまではできました。しかしこのままではファイルタイプ(Content-Type)が.gz(application/gzipまたはapplication/x-gzip)に設定されます。

最後にファイルタイプを書き換える処理が必要です。まずFilesMatchディレクティブで書き換えが必要なファイル拡張子を検出します。

http://httpd.apache.org/docs/current/ja/mod/core.html#filesmatch

そして検出した拡張子別にファイルタイプをForceTypeで強制的に付け替えます。

http://httpd.apache.org/docs/current/ja/mod/core.html#forcetype

以上まとめると次のようになります(htmlの場合)。拡張子別にファイルタイプが異なりますから、他の拡張子も同じ要領で記述して対応します。

<FilesMatch "\.html\.gz$">
  ForceType text/html
</FilesMatch>

<If ...><Elseif ...><Else ...>を利用してひとつにまとめることも可能ですが、かえって分かりにくくなると思います。

元ファイルを残す場合は以上です。次は残さない場合の設定方法を説明します。

元ファイルを残さない場合

Apacheにはコンテントネゴシエーションのサポート機能があり、これを利用して非圧縮コンテンツを返すよう要求された場合にgzip圧縮ファイルを展開して返すことができます。

コンテントネゴシエーションとはリクエストヘッダを読み、それに最も適したコンテンツを提供する機能です。具体的にはAccept-から始まるヘッダ行の値を読み、そこから応答するページ(ファイル)を選択することができます。

http://httpd.apache.org/docs/current/ja/content-negotiation.html

(典型例として)Accept-Languageの値から応答する言語を切り替える場合はindex.html.enindex.html.jaのように拡張子の末尾に言語コードを付けたファイルを用意し、ヘッダの値により応答するファイルを選択します。

http://httpd.apache.org/docs/current/ja/content-negotiation.html#naming

このバリエーションとしてAccept-Encodingの判定機能があり、gzipを含む場合は拡張子の末尾が.gzのファイルを返すように設定できます。さらに非圧縮コンテンツを要求された場合は.gzファイルを探し、それを自動展開して返します。

設定例は次の通りです。

Options +MultiViews
MultiviewsMatch Any
FilterDeclare gzip CONTENT_SET
FilterProvider gzip inflate "%{req:Accept-Encoding} !~ /gzip/"
FilterChain gzip

<FilesMatch "\.html\.gz$">
  ForceType text/html
</FilesMatch>
<FilesMatch "\.txt\.gz$">
  ForceType text/html
</FilesMatch>
# 以下、他のファイルタイプも同様(略)

設定方法はtype-mapファイル(httpd.conf専用)とMultiViewsオプションの2通りありますが、ディレクトリ別の設定や.htaccessに記述する場合はMultiViewsを用います。MultiViewsは初期状態では無効に設定されているので、次で有効にします。

http://httpd.apache.org/docs/current/ja/mod/core.html#options

Options +MultiViews

次にMultiViewsを適用する拡張子を設定します。ここで設定しているAnyは無条件に全て受け付ける事を表します。

http://httpd.apache.org/docs/current/ja/mod/mod_mime.html#multiviewsmatch

MultiviewsMatch Any

設定にはmod_filterを用います。次のリファレンスのExamplesの中にEmulating mod_gzip with mod_deflateという今回の目的そのものの文例があります。

http://httpd.apache.org/docs/current/ja/mod/mod_filter.html

mod_gzipはバージョン1.X時代のモジュール名です(現在は代わりにmod_rewriteを用います)。

今回はこれをそのまま頂くことにします(詳細調査は略)。これでAccept-Encoding: gzipが設定されていない場合だけinflate処理が実行されます。

http://httpd.apache.org/docs/current/ja/mod/mod_filter.html#examples

FilterDeclare gzip CONTENT_SET
FilterProvider gzip inflate "%{req:Accept-Encoding} !~ /gzip/"
FilterChain gzip

なおFilterProviderの書式にはバリエーションがあります。次は関数のreqを使った例です(動作確認済み)。先頭の!とマッチ部の=~の組み合わせで「マッチしなければ」という条件になりますが、この短縮形が上で用いている!~です。

FilterProvider gzip inflate "! req('Accept-Encoding') =~ /gzip/"

(参考) 関数一覧 http://httpd.apache.org/docs/current/ja/expr.html#functions

(次も参考) Apache 2.2以前は書式が異なります(ただし私は動作確認していません)。

http://stackoverflow.com/questions/26895894/get-apache-to-auto-decompress-a-file-but-only-if-needed

FilterProvider gzip INFLATE req=Accept-Encoding !$gzip

リファレンスの記述は以上ですが、この状態で動作確認するとやはり圧縮対応時のContent-Typeが全てgzipの設定になります(元ファイルを残す場合の動作と同様)。そこでForceTypeで拡張子別にファイルタイプを設定します(以下は.htmlの設定例)。

<FilesMatch "\.html\.gz$">
  ForceType text/html
</FilesMatch>

運用例

この方法で天気データマップのサイト設定を行いました。サーバ内部の設定は(バックアップの意味も兼ねて)次のURLで公開しています。

実サイトの.htaccesshtaccess_exampleというファイル名にしています。またdata/hourly/内のファイルはサイズ、ファイル数とも膨大なので.tar.gzアーカイブで保存しています(バックアップ用)。

まとめ

Apacheをこんなに詳しく勉強したのは始めての経験でしたが、書式が非常に難解でかなり苦労しました。

私は(多少のサイト管理はできますが)基本的にはプログラマーで、どちらかと言えばAPI仕様を作る側に近い人間です。大昔に作られたソフトのAPIを長年機能拡張すると最後はここまで複雑になってしまうのかというのを思い知りました。

これは仕方ない事だと思います。あまりにもメジャーなソフトなので後方互換性を考慮した仕様変更しかできません。そのような足し算の変更が積み重なると必然的にこうなるのはよく分かります。

過去のしがらみがない後発サーバはもっとシンプルです。特にNginxは専用設計されたgzip最適化機能があり、設定方法も簡単です。次の解説を読めばそれだけで十分理解できます。

http://qiita.com/cubicdaiya/items/2763ba2240476ab1d9dd

しかしApacheは長年に渡る抜群の実績があります。まだまだ今後も使われるでしょうし、今でもApache.htaccessでがんばっているサイト管理者は多いと思います。本解説が皆さんのお役に立てたら幸いです。

(番外編) 無線ルータ(Buffalo WHR-G301N)のトラブルシューティング

現在使っている無線ルータBuffalo WHR-G301Nは5年ほど前の製品ですが今でも使っている人は多いようです。ところが掃除中に配線整理のため電源を抜き差ししていたら突然壊れてしまいました。

原因調査

今回の故障ではLEDが高速点滅するという特有の現象がありますが、検索すると同様の症例がたくさん見つかります(同じ目にあった人が何と多いことか...)。次のブログ記事を見つけて解決できました。症状と解決方法は秀さんのブログに写真付きで詳しく書かれています。

http://m-syuuta.wp.tcp-ip.or.jp/?p=3487

実はACアダプターの故障です(本体は壊れていません)。推定原因はACアダプターの整流平滑素子の劣化で、LEDの高速点滅と同じ(かなり高速の)周期で電源が乱高下してルータが起動できなくなっていると考えられます。

もう5年も使っていますが機能は全く文句ありません(よい製品です)。しかしACアダプターがやや安物で劣化が早いようです。また検索すると電源抜き差しを頻繁に行うと劣化が早まる傾向が見られます。

テスターを持っている人はACアダプターの電圧を測定すれば12V前後で針がふらふら揺れるのを確認できます。

高速変動なのでデジタルテスターでの確認は難しいでしょう。今回使ったのはアナログで、デジタルより針の反応がよいので揺れを検出できました。オシロスコープがあればベストですが持っている人はなかなかいないと思います。

交換アダプターの購入

ACアダプターの交換だけで簡単に直ります。これも秀さんが調べてブログに購入先URLも全て貼ってくれていますのでそちらをご覧下さい(同じURLですがもう一度)。

http://m-syuuta.wp.tcp-ip.or.jp/?p=3487

ちなみに私はマルツからSW-1212Eを購入して解決しました(税、送料込みでちょうど¥1,900)。Amazon経由でも買えますが¥200ほど高くなりますのでマルツからの直接購入がお勧めです(対応も完璧でした)。

天気データマップ復旧しました

11/25から更新が止まっていましたが、本日よりまた毎日更新できるようになりましたのでお知らせします。

http://higuma.boo.jp/tenki-data-map/

ついでなので最新データを紹介します。11/24,25に北海道(私の故郷です)に大雪が降りました。もう雪は止んでいますが積雪は残っています。昨日深夜の積雪分布マップを貼っておきます。

f:id:huguma:20151129150912p:plain

札幌には40cm以上も積もりましたが、もう半分以上解けています。まだ根雪にはならないと思います。

f:id:huguma:20151129151004p:plain

天気データマップに関するお知らせ(データ更新の一時停止)

(私の自宅で)昨日発生したネットワークトラブル(ルータ故障)により天気データマップのデータ更新が止まった状態になっています(現在の最新データは11/24)。

現在は詳しい原因の調査中で、復旧にはまだ数日を要する見込みです。再開できましたらこの場でお知らせします。

Apacheサーバのgzip圧縮最適化: 2. 設定方法

  1. 確認方法
  2. 設定方法
  3. 事前圧縮による最適化
  4. 補足: ファイルのgzip圧縮(初級編)

サーバの対応方法

サーバがファイルをgzip圧縮して返信する場合の対応方法は2種類あります。

  1. 要求を受信したサーバがその場でgzip圧縮を行い返信する
  2. あらかじめgzip圧縮しておき、それを返信する

設定は1の方が簡単です。しかしサーバが要求を受信するたびに毎回gzip圧縮処理を行うためサーバに負荷が発生します。

一方2はファイルをgzip圧縮しておく事前準備が必要です。しかし運用時にgzip圧縮処理によるサーバ負荷は発生しません。手間は掛かりますがこの方法が最も効率的に処理できます。

具体的な設定方法はサーバソフトウエアの種類によって異なりますが、ここでは今回設定したApacheの場合を解説します。

Apacheの設定

Apacheではサーバの各種設定をhttpd.conf.htaccessの2種類のファイルで記述します。

リファレンス: https://httpd.apache.org/docs/current/ja/configuring.html

(参考用)詳細解説: https://murashun.jp/blog/20141229-01.html

メインの設定ファイルは通常httpd.confという名前で、多くの場合は/etc/httpd/conf/httpd.confなどの場所にあります。

ファイル名と場所(パス)はApacheのインストール(またはビルド)時に自由に設定できます。でも今ではほぼ標準的な規則(convension)があり、大部分の人はそれに従っています(詳しくはhttpd.conf 場所で検索)。

ディレクトリ個別に設定する場合は.htaccessを用います。このファイルは任意の場所に複数置くことができ、その位置から先のディレクトツリー全体に対して作用します。

  • httpd.confと.htaccessで同じ項目で異なる設定をしている場合は.htaccessが優先(オーバーライド)します
  • .htaccess複数ある場合は内側が外側の設定をオーバーライドします

レンタルサーバの場合は通常http.confは業者側で管理しており、自分では設定できません。業者側のメイン設定は通常非公開ですが、多くの設定は.htaccessでオーバーライドして修正できます。

mod_deflateによるサーバサイド圧縮

Apacheにはmod_deflateモジュールを使ってサーバ側で圧縮処理を行う機能があり、.htaccess(またはhttpd.conf)に記述すれば対応できます。まず次のリファレンスの冒頭部から読むのが分かりやすいでしょう。

https://httpd.apache.org/docs/current/ja/mod/mod_deflate.html

Apacheではmod_で始まる名前は拡張モジュールを表します。これらはもともと拡張機能扱いだったものですが、今では大部分が標準的なディストリビューションに最初から含まれています。

モジュール一覧: http://httpd.apache.org/docs/current/ja/mod/

特定のタイプだけ簡単に圧縮したい場合は最初の文例をまねて書けばそれで十分です。必要に応じてtext/cssなど自分で追加すれば機能します。

AddOutputFilterByType DEFLATE text/html text/plain text/xml

もっと詳しい設定は次の「画像以外全て圧縮する」コード例がよい参考になりますが、これは大昔(少なくとも15年以上前)のブラウザに対応するためのコードです。ブラウザ別処理の部分は今はもう省略していいと思います。

ここではリファレンスの例を最小限まで簡略化したものを示します。Apacheの専用書式で記述しますが、やはり#から行末まではコメントです(念のため)。実質たった2行ですが正確に把握するにはリファレンスを隅々まで確認する必要があります。

# Insert filter
SetOutputFilter DEFLATE

# Don't deflate pre-compressed files
SetEnvIfNoCase Request_URI \.(?:gz|gif|jpg|jpeg|png|mp3|ogg|pdf)$ no-gzip

まずApacheでは送受信データに対する処理をフィルタといい、出力のフィルタはSetOutputFilterで設定します。

http://httpd.apache.org/docs/current/ja/mod/core.html#setoutputfilter

Apacheの出力用フィルタはINCLUDESとDEFLATEの2種類あります。DEFLATEはmod_deflateモジュールの機能を使いファイルをgzip圧縮します。

http://httpd.apache.org/docs/current/ja/filter.html

SetOutputFilter DEFLATE

これだけだと全てのファイルタイプを圧縮することになります。特定の拡張子を除外する設定が必要ですが、この部分のメカニズムがApacheはやや複雑です。

Apacheでは操作の各種制御に環境変数という名前付き変数を用います(OSの環境変数とは無関係)。no-gzipgzip圧縮を制御するための特別な環境変数で、設定するとDEFLATEフィルタをOFFにします。

http://httpd.apache.org/docs/current/env.html#special

特定の拡張子を検出して環境変数を設定するにはSetEnvIfを用います。

http://httpd.apache.org/docs/current/ja/mod/mod_setenvif.html#setenvif

ここではRequest_URI(URLのスキームから後ろ全て)に正規表現マッチを用い、末尾の拡張子を検出して判定しています。

http://httpd.apache.org/docs/current/ja/mod/mod_setenvif.html

SetEnvIfNoCase Request_URI \.(?:gz|gif|jpg|jpeg|png|mp3|ogg|pdf)$ no-gzip

正規表現(?:A|B|...)はキャプチャなしのグループ化です。マッチ条件は(A|B|...)と同じですが、キャプチャをしない分だけ若干効率が向上します。

SetEnvIfNoCaseSetEnvIfのバリエーションで、大文字と小文字を同一と見なして処理すること以外は同じです。これで大文字の.GIF.MP3なども除外対象とすることができます。

http://httpd.apache.org/docs/current/ja/mod/mod_setenvif.html#setenvifnocase

説明は以上です。自前でApacheサーバを立てる場合はこれをhttpd.confに記述するのが一般的な方法です。レンタルサーバの場合は自分が管理する起点のディレクトリに.htaccessで記述すれば設定できます。

レンタルサーバの場合

なおレンタルサーバでは業者側(httpd.conf)であらかじめ基本的なファイルタイプに対して設定してくれているケースが多いようです。

今回利用したロリポップのサーバではhtml, htm, js, css, txtに対して設定されているのを確認しています(2015年11月現在)。他のタイプは確認していませんので必要な場合は自分で行って下さい。

必要な設定がされていれば何もする必要はありませんが、詳細は業者で当然異なりますから実際にブラウザで確認することをお勧めします。ファイルをアップロードしてブラウザで読み込み確認し、必要なファイルタイプを.htaccessで追加設定する手順で対応できます。

続く ⇒ Apacheサーバのgzip圧縮最適化: 3. 事前圧縮による最適化