<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>インフラエンジニアway</title>
    <link rel="alternate" type="text/html" href="http://heartbeats.jp/hbblog/" />
    <link rel="self" type="application/atom+xml" href="http://heartbeats.jp/hbblog/atom.xml" />
    <id>tag:heartbeats.jp,2009-08-24:/hbblog//2</id>
    <updated>2012-04-30T13:13:29Z</updated>
    <subtitle>株式会社ハートビーツのインフラエンジニアから、ちょっとした情報をお届けします</subtitle>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 4.26</generator>

<entry>
    <title>hgweb.cgiでmercurialのリポジトリポータルを作ったよ</title>
    <link rel="alternate" type="text/html" href="http://heartbeats.jp/hbblog/2012/04/hgwebcgimercurial.html" />
    <id>tag:heartbeats.jp,2012:/hbblog//2.69</id>

    <published>2012-04-30T11:35:16Z</published>
    <updated>2012-04-30T13:13:29Z</updated>

    <summary>みなさんどうもこんにちは。CTOの馬場です。 突然ですが、みなさん、会社でリポジ...</summary>
    <author>
        <name>馬場俊彰</name>
        <uri>http://heartbeats.jp/</uri>
    </author>
    
    
    <content type="html" xml:lang="ja" xml:base="http://heartbeats.jp/hbblog/">
        <![CDATA[<p>みなさんどうもこんにちは。CTOの馬場です。</p>

<p>突然ですが、みなさん、会社でリポジトリどうしてます？</p>

<p>インフラエンジニアだとしても管理したいものはたくさんありますよね。
プロダクトの設定ファイル、ドキュメント、
各種運用スクリプト、監視ツールのプラグイン等々...</p>

<p>弊社でもそりゃまぁいろいろありまして、
いままでは使っててSubversionだったんですけれども
2010年代にもなって中央集権はないだろうということで
Mercurialを使って社内用のリポジトリを作ったのでその紹介です。</p>
]]>
        <![CDATA[<h1>なぜMercurial?</h1>

<p>標準ツール(全員が使えるようになるツール)として何を採用するか悩んだのですが、
git/bazaar/Mercurialの中からMercurialに決めました。今のところ。</p>

<p>最大の理由は <strong>MercurialがPythonだから</strong> です。</p>

<p>弊社ではCentOSなサーバを非常に大量に扱ってますが、
そのほぼ全てがお客さまのサーバなので
管理用に導入できるプロダクトは非常に限られているケースが多く、
インストールの敷居が一番低い(=現行環境に対する影響が一番小さい)のが
Python + Mercurialなのです。</p>

<p>従って消去法でMercurialと相成りました。
MercurialいいよMercurial。</p>

<h1>会社リポジトリ?</h1>

<p>正直に言うと、社内github的なものが欲しかったんですよ。</p>

<p>あんな感じでエンジニアがそれぞれプロジェクトを立てられて、
自由に開発もシェアもできる基盤が欲しかったのです。</p>

<ul>
<li>エンジニアがそれぞれ自由にプロジェクトを立てられる</li>
<li>シェアできる</li>
<li>本番サーバからも使える</li>
<li>社内管理できる
(うっかりパスワードとか書いたままコミットしちゃっても被害が即甚大にならないように)</li>
<li>Mercuriaが使える</li>
<li>お高くない</li>
</ul>

<p>github enterpriseとか<a href="http://gitlabhq.com/">gitlab</a>が選択肢になってくるわけですが、
なんせ最後の2つを満たせず不採用と相成りました。</p>

<h1>そこでhgweb.cgi</h1>

<p>とにかくリポジトリ閲覧ができるようにしよう、ということで、
マルチプロジェクトのhgweb.cgiを利用することにしました。
(本当はtracをカスタマイズしたほうがいいんだろうけど、
 ユーザ管理とかいろいろ含めて考えたらめんどくさくなってやめました)</p>

<p>pipで入れたらhgweb.cgiが入っていなかったりといろいろアレだったので、
ここからコピペで貼るといいと思います。</p>

<p>ちなみに参考URLはこちら
→<a href="http://mercurial.selenic.com/wiki/PublishingRepositories">http://mercurial.selenic.com/wiki/PublishingRepositories</a></p>

<h2>環境と仕様</h2>

<ul>
<li>環境はCentOS 6 + apache 2.2.15 + python 2.6 + mercurial 1.7.5(pip)</li>
<li>閲覧はHTTP(S)</li>
<li>push/pullはSSH(共有アカウント)</li>
<li>公開URLはhttp://example.com/repos/</li>
<li>サーバ上のファイルパスは/opt/repo/配下にいろいろ
<ul>
<li>/opt/repo/bin/配下に設定ファイルなど</li>
<li>/opt/repo/repo/配下にリポジトリ(群)</li>
<li>→ここにディレクトリを作成してhg initすると自動的にweb側にも追加される!</li>
</ul></li>
</ul>

<p>リポジトリ利用上は単にSSHでアクセスするだけです。</p>

<p>clone<pre>hg clone ssh://sharedusername@example.com//opt/repo/repo/&lt;REPOSITORYNAME&gt;</pre></p>

<p>push<pre>hg push</pre></p>

<p>URIを指定してpush<pre>hg push ssh://sharedusername@example.com//opt/repo/repo/&lt;REPOSITORYNAME&gt;</pre></p>

<p>SSH秘密鍵を指定してpush<pre>hg push -e &quot;ssh -i /path/othersidrsa&quot; ssh://sharedusername@example.com//opt/repo/repo/&lt;REPOSITORYNAME&gt;  </pre></p>

<p>
ちなみにURI部分はexample.com/〜(/が1つ)とexample.com//〜(/が2つ)で意味が違うのでご注意ください。</p>

<h2>必要なファイルを配置</h2>

<p>hgweb.cgiとhgweb.configの2ファイルを作成します。</p>

<p>/opt/repo/bin/hgweb.cgi</p>

<pre>
#!/usr/bin/env python
#
# An example hgweb CGI script, edit as necessary
# See also http://mercurial.selenic.com/wiki/PublishingRepositories
import os
os.environ["HGENCODING"] = "UTF-8"

# Path to repo or hgweb config to serve (see 'hg help hgweb')
config = "/opt/repo/bin/hgweb.config"

# Uncomment and adjust if Mercurial is not installed system-wide
# (consult "installed modules" path from 'hg debuginstall'):
#import sys; sys.path.insert(0, "/path/to/python/lib")

# Uncomment to send python tracebacks to the browser if an error occurs:
#import cgitb; cgitb.enable()

from mercurial import demandimport; demandimport.enable()
from mercurial.hgweb import hgweb, wsgicgi
application = hgweb(config)
wsgicgi.launch(application)
</pre>

<p>/opt/repo/bin/hgweb.config</p>

<pre>
[paths]
/ = /opt/repo/repo/*

[web]
descend = True
baseurl = /repos
</pre>

<h2>apache設定</h2>

<p>普通にcgiの設定をします。</p>

<p>サンプルだしあんまり厳密に設定していないので、適当にいじってくださいね。</p>

<pre>
ScriptAlias /repos /opt/repo/bin/hgweb.cgi
&lt;Directory /opt/repo&gt;
    Options +ExecCGI
&lt;/Directory&gt;
&lt;Location /repos&gt;
    # Taken from http://www.pmwiki.org/wiki/Cookbook/CleanUrls#samedir
    # Used at http://ggap.sf.net/hg/
    RewriteEngine On
    #write base depending on where the base url lives
    RewriteBase /repos
    RewriteRule ^$ hgweb.cgi  [L]
    # Send requests for files that exist to those files.
    RewriteCond %{REQUEST_FILENAME} !-f
    # Send requests for directories that exist to those directories.
    RewriteCond %{REQUEST_FILENAME} !-d
    # Send requests to hgweb.cgi, appending the rest of url.
    RewriteRule (.*) hgweb.cgi/$1  [QSA,L]
&lt;/Location&gt;
</pre>

<p>そしてapacheをrestartすれば完了です。</p>

<p>うまくいかない場合はapacheのエラーログでも見て対処しましょう。</p>

<p>ね?簡単でしょ?</p>
]]>
    </content>
</entry>

<entry>
    <title>nginx連載5回目: nginxの設定、その3 - locationディレクティブ</title>
    <link rel="alternate" type="text/html" href="http://heartbeats.jp/hbblog/2012/04/nginx05.html" />
    <id>tag:heartbeats.jp,2012:/hbblog//2.68</id>

    <published>2012-04-24T01:00:00Z</published>
    <updated>2012-04-24T01:46:26Z</updated>

    <summary>前回と同様に、バーチャルサーバの設定について説明を行います。特に今回はURIのパ...</summary>
    <author>
        <name>滝澤隆史</name>
        <uri>http://heartbeats.jp/</uri>
    </author>
    
        <category term="nginx" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="ja" xml:base="http://heartbeats.jp/hbblog/">
        <![CDATA[<p>前回と同様に、バーチャルサーバの設定について説明を行います。特に今回はURIのパス名毎の設定を行うlocationディレクティブと関連する設定について説明します。</p>
<p>特に次の設定について説明します。</p>
<ul>
	<li>location</li>
	<li>alias</li>
	<li>index</li>
	<li>try_files</li>
	<li>error_page</li>
	<li>internal</li>
</ul>
]]>
        <![CDATA[<h2>URIのパス毎の設定 - location</h2>
<pre>
location / {
    [locationコンテキスト]
}
</pre>
<p>locationディレクティブではURIのパス毎の設定を記述できます。括弧{ }で囲まれた部分がlocationコンテキストになります。リクエストURIのパスがこのlocationディレクティブのパスの条件に一致した場合にこのlocationコンテキストに記述した設定が適応されます。パスの条件の評価方法は前方一致と正規表現の2つです。locationコンテキストにlocationディレクティブを記述してネストすることもできます。</p>
<p>上記の例ではリクエストURIのパスの先頭が"/"に一致した場合に適応されます。すべてのパスは"/path/to/page.html"のように"/"で始まるため、他のlocationディレクティブのパスの条件に一致したもの以外はこのlocationディレクティブが適応されます。</p>

<p>locationディレクティブではURIのパスの前に"=", "~", "~*", "^~"の4種類のプレフィックスを付けることができます。</p>
<pre>
location プレフィックス URIのパス {
    [locationコンテキスト]
}
</pre>
<p>それぞれの意味は次のようになります。</p>
<table border="1">
	<tr><th>プレフィックス</th><th>説明</th></tr>
	<tr><td>なし</td><td>前方一致</td></tr>
	<tr><td>^~</td><td>前方一致。一致したら、正規表現の条件を評価しない。</td></tr>
	<tr><td>=</td><td>完全一致。パスが等しい場合。</td></tr>
	<tr><td>~</td><td>正規表現（大文字・小文字を区別する）</td></tr>
	<tr><td>~*</td><td>正規表現（大文字・小文字を区別しない）</td></tr>
</table>

<p>locationディレクティブはパスの条件が評価されて選ばれたものが適応されます。この条件はパスの文字列の前方一致あるいは正規表現による評価です。この評価の順番は以下のようになります。</p>
<ol>
	<li>前方一致（"=", "^~", プレフィックスなし）の条件の評価を実施
	<ol>
		<li>最も一致する条件を選ぶ。</li>
		<li>選ばれた条件が、完全一致で、プレフィックスが"="であれば、そこで評価を終了し、そのlocationディレクティブを適応する。</li>
		<li>選ばれた条件のプレフィックスが"^~"であれば、そこで評価を終了して、そのlocationディレクティブを適応する。</li>
	</ol></li>
	<li>正規表現（"~", "~*"）の条件の評価を実施
	<ol>
		<li>正規表現の条件を設定ファイルに定義した順番に評価する。一致したら、そこで評価を終了して、そのlocationディレクティブを適応する。</li>
	</ol></li>
	<li>前方一致の評価で選ばれた条件のlocationディレクティブを適応する。</li>
</ol>
<p>ここで注意して欲しいことがあります。前方一致の条件が先に評価されますが、プレフィックス無しの条件が選ばれたときには、後で評価される正規表現の条件に一致したものが無かった場合に、選ばれたlocationディレクティブが適応されるということです。この点を理解していないと、パスが一致したのに何で適応されないんだろうと悩むことになります。</p>
<p>いくつかの例で確認してみましょう。</p>
<p>まず、プレフィックスがない場合です。次の例では、リクエストURIのパスが"/example/page.html"であるときには設定Bが適応されます。それ以外の場合は設定Aが適応されます。単純に最長一致したものが適応されることがわかります。</p>
<pre>
location / {
    [設定A]
}

location /example/ {
    [設定B]
}
</pre>

<p>次の例は、"="プレフィックスがある場合です。リクエストURIのパスが"/"であるときには、設定Bが、"/page.html"であるときには設定Cが適応されます。それ以外の場合は設定Aが適応されます。例外的なページを指定する場合やlocationのパスの評価を早く確定したい場合に役に立つでしょう。なお、設定Bでは、indexディレクティブが有効であれば"/index.html"などに内部リダイレクトするため、最終的には設定Aが適応されます。</p>
<pre>
location / {
    [設定A]
}

location = / {
    [設定B]
}

location = /page.html {
    [設定C]
}
</pre>

<p>次の例は、プレフィックスがない場合と"~"プレフィックスがある場合です。リクエストURIのパスが"/example/page.html"であるときには、プレフィックスなしのパスが完全に一致していますが、正規表現の条件が優先されるため、設定Bが適応されます。</p>
<pre>
location /example/page.html {
    [設定A]
}

location ~ ^/example/ {
    [設定B]
}
</pre>

<p>今度は"^~"プレフィックスを付けてみます。リクエストURIのパスが"/example/page.html"であるときには、設定Aのパスに一致し、評価が確定するため、設定Aが適応されます。</p>
<pre>
location ^~ /example/page.html {
    [設定A]
}

location ~ ^/example/ {
    [設定B]
}
</pre>

<p>なお、正規表現の条件は次の例のように拡張子に一致させたいときに使うことが多いです。</p>
<pre>
location ~ \.php$ {
    [設定A]
}
</pre>

<p>正規表現を使うときには、括弧( )で囲うことにより後方参照することができます。次の例ではphpのファイル名を設定Aの中で"$1"として参照することができます。</p>
<pre>
location ~ ^/example/(.*\.php)$ {
    [設定A]
}
</pre>

<p>なお、リクエストURIのパスは様々な機能によ正規化され書き替えられた後のものがlocationディレクティブのパスの条件の対象となります。例えば、URIエンコードされていれば、デコードした後のパスが対象になります。</p>

<h3>名前付きロケーション</h3>
<p>locationディレクティブではURIのパスの代わりに次のように@の後に名前を付けることにより、名前付きロケーションを作ることができます。この名前付きロケーションは後述する内部リダイレクトで使用します。内部的なURIのパスの書き換えを行わずに内部リダイレクトを行う際に利用されます。</p>
<pre>
location @名前 {
    [locationコンテキスト]
}
</pre>
<p>なお、この名前付きロケーションはserverコンテキストにしか記述できません。</p>

<h2>ロケーションのパスの割り当て - alias</h2>
<p>aliasディレクティブではlocationディレクティブで指定したURIのパスをファイルシステム上のパスに対応させます。</p>
<p>次の例では、URIのパス"/s/"を"/var/www/s/images/"に対応させます。このとき、リクエストのパス"/s/page.html"と"/s/file.jpg"は、それぞれファイルシステム上のパス"/var/www/s/html/page.html"と"/var/www/s/images/file.jpg"に対応することになります。</p>
<pre>
location /s/ {
    alias /var/www/s/html/;
}
location ~ ^/s/(.+\.(?:gif|jpg|png)$) {
    alias /var/www/s/images/$1;
}
</pre>
<p>このaliasディレクティブは、先の例のようにURIのパスがrootディレクティブで指定したディレクトリからのパスと異なるときに利用します。</p>
<p>次の例では、aliasディレクティブで記述していますが、これはパス"/s/"がaliasディレクティブで指定した"/var/www/html/s/"の最後の"/s/"の部分と一致しています。"/var/www/html"をrootとしたときのパスと考えてもよいでしょう。</p>
<pre>
location /s/ {
    alias /var/www/html/s/;
}
</pre>
<p>このときは、次のようにrootディレクティブで書き直した方がわかりやすいでしょう。</p>
<pre>
location /s/ {
    root /var/www/html;
}
</pre>


<h2>内部リダイレクト</h2>
<p>普通のリダイレクトはレスポンスコードに301や302を、Locationヘッダフィールドにリダイレクト先のURIを指定して返し、クライアントはそのURIに対して再びリクエストを送ります。これとは別に内部リダイレクトというものがあります。これは、レスポンスコードに301や302を指定せずに、内部的にURIのパスの書き換えを行い、その結果のページの内容を返します。クライアントから見るとリダイレクトしているようには見えません。nginxではこのような内部リダイレクトがよく使われます。</p>
<p>次のセクション以降で説明するindexディレクティブ、error_pageディレクティブ、tri_filesディレクティブではこの内部リダイレクトが使われます。内部リダイレクトではリダイレクト先のパスに対して毎回locationディレクティブの評価が行われます。</p>


<h2>インデックス - index</h2>
<p>indexディレクティブにはリクエストのURIが"/"で終わっている（つまりディレクトリになっている）ときにインデックスとして使われるファイル名を設定します。記述方法は次の通りです。</p>
<pre>
index ファイル名 [ファイル名... [フォールバック]];
</pre>
<p>httpコンテキスト、serverコンテキスト、locationコンテキストに記述できます。なお、パスへのファイル名の追加は内部リダイレクトとして行われます。デフォルトの設定値は"index index.html;"であり、"index.html"がパスに追加され、そのパスへ内部リダイレクトします。</p>
<p>次のような設定の場合には、リクエストURIのパスが"/example/"のときに、index.htmlというファイルが存在すれば、"/example/index.html"に内部リダイレクトします。index.htmlが存在せず、index.phpが存在すれば、/example/index.phpに内部リダイレクトします。</p>
<pre>
location /example/ {
    index index.html index.php;
}
</pre>
<p>設定の一番右に、"/"で始まるファイル名のパスを書くと、ファイルが存在しなかったときにフォールバックするURIのパスになります。次のように記述すると、index.htmlやindex.phpが存在しなかったら、/index.phpにリダイレクトします。</p>
<pre>
location /example/ {
    index index.html index.php /index.php;
}
</pre>


<h2>ファイルの存在チェック - try_files</h2>
<p>try_filesディレクティブには存在をチェックするファイルやディレクトリと存在しなかったときにリダイレクトするURIのパスを指定します。</p>
<p>記述方法は次の通りです。</p>
<pre>
try_files ファイル ... パス;
try_files ファイル ... =コード;
</pre>
<p>try_filesという名前の通り、指定したファイルやディレクトリの存在を順番に調べ、存在すれば、そのファイルやディレクトリに対応したファイルを返します。一つも存在しなかったら、最後に記述したパスに内部リダイレクトします。パスの代わりに名前付きロケーションを指定することもできます。"=コード"を指定したときには指定した応答コードが返されます。</p>
<p>このtry_filesディレクティブはバックエンドのウェブアプリケーションと連携するためによく使われます。次の例はPHPのウェブアプリケーションを処理する例です。</p>
<pre>
## URIのパスに対するファイル（静的コンテンツ）が存在すれば、そのファイル返す。
## 存在しなければ、動的コンテンツとして@webappに内部リダイレクトする。
location / {
    try_files $uri $uri/ @webapp;
}

## 拡張子がphpであるファイルに対して処理する。
location ~ \.php$ {
    fastcgi_pass    unix:/var/run/php-fpm.sock;
    fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include /etc/nginx/fastcgi_params;
}

## 動的コンテンツとして処理する。
location @webapp {
    fastcgi_pass    unix:/var/run/php-fpm.sock;
    fastcgi_param   SCRIPT_FILENAME /var/www/html/index.php;
    include /etc/nginx/fastcgi_params;
}
</pre>



<h2>エラーページ - error_page</h2>
<p>error_pageディレクティブには指定したエラーコードが発生したときに表示するページのURIを指定します。</p>
<p>記述方法は次の通りです。</p>
<pre>
error_page コード ... [=[レスポンスコード]] uri;
</pre>
<p>コードには300〜599までの数値を記述できます。"=レスポンスコード"を記述すると、指定したレスポンスコードを返します。"="だけを記述すると内部リダイレクト先のシステムから受け取ったレスポンスコードを返します。URIにパスだけ指定すると内部リダイレクトし、フルで指定するとLocationヘッダ フィールドによりリダイレクトします。名前付きロケーションも使えます。</p>
<p>例えば、次のように記述すると、サーバのエラーが発生したときには"/50x.html"ページへ内部リダイレクトします。</p>
<pre>
error_page 500 502 503 504 /50x.html;
location = /50x.html {
    root   /usr/share/nginx/html;
}
</pre>
<p>リダイレクト先には外部のURIを指定することもできます。</p>
<pre>
error_page 500 502 503 504 http://example.jp/sorry.html;
</pre>
<p>nginxがバックエンドサーバにつながらないときなどにこの機能は便利でしょう。</p>

<p>また、アクセス制御により、アクセスが拒否された場合に表示するページを用意する場合にも使えます。</p>
<pre>
error_page 403 /forbidden.html
location = /forbidden.html {
    internal;
    allow all;
}
</pre>
<p>このerror_pageディレクティブはバックエンドのウェブアプリケーションと連携するときにも使われます。次の例はPHPのウェブアプリケーションを処理する例です。</p>
<pre>
## URIのパスに対するファイル（静的コンテンツ）が存在すれば、そのファイル返す。
## 存在しなければ、動的コンテンツとして@webappに内部リダイレクトする。
location / {
    error_page 404 = @webapp;
}

## 拡張子がphpであるファイルに対して処理する。
location ~ \.php$ {
    fastcgi_pass    unix:/var/run/php-fpm.sock;
    fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include /etc/nginx/fastcgi_params;
}

## 動的コンテンツとして処理する。
location @webapp {
    fastcgi_pass    unix:/var/run/php-fpm.sock;
    fastcgi_param   SCRIPT_FILENAME /var/www/html/index.php;
    include /etc/nginx/fastcgi_params;
}
</pre>


<h2>内部リクエストの指定 - internal</h2>
<p>internalディレクティブは、それを記述したロケーションが内部リダイレクトのように内部からのリクエストのためのみに使われることを宣言します。外部から直接アクセスすることはできません。</p>
<p>次の例では、404エラーが発生したときに/404.htmlに内部リダイレクトします。リダイレクト先のロケーションでは外部から直接このページのURIを指定してアクセスさせたくはないので、internalを記述します。</p>
<pre>
error_page 404 /404.html;
location = /404.html {
    internal;
}
</pre>

<h2>バーチャルサーバの設定のまとめ</h2>
<p>前回と今回はバーチャルサーバの設定について説明してきました。各設定が適応される順番についてまとめてみましょう。</p>
<ol>
	<li>serverコンテキストの選定
	<ul>
		<li>listenディレクティブとserver_nameディレクティブにより適応するserverコンテキストが選ばれる。</li>
	</ul>
	</li>
	<li>locationコンテキストの選定
	<ul>
		<li>locationディレクティブの条件により適応するlocationコンテキストが選ばれる。</li>
		<li>ただし、indexディレクティブ、tri_filesディレクティブ、error_pageディレクティブなどにより、内部リダイレクトが行われると、再びlocationディレクティブが評価される。</li>
	</ul>
	</li>
</ol>

<p>今回はここまでです。設定編の残りとしては次のものを予定しています。</p>
<ul>
	<li>SSL/TLSの設定</li>
	<li>よく使われる設定（認証、アクセス制御、rewriteモジュール等）</li>
</ul>
<p>これが終わったら、ウェブアプリケーションとの連携編に入ります。</p>
]]>
    </content>
</entry>

<entry>
    <title>nginx連載4回目: nginxの設定、その2 - バーチャルサーバの設定 </title>
    <link rel="alternate" type="text/html" href="http://heartbeats.jp/hbblog/2012/04/nginx04.html" />
    <id>tag:heartbeats.jp,2012:/hbblog//2.67</id>

    <published>2012-04-12T01:00:00Z</published>
    <updated>2012-04-12T01:33:20Z</updated>

    <summary>前回と同様に、nginx.orgのパッケージからインストールしたnginxが提供...</summary>
    <author>
        <name>滝澤隆史</name>
        <uri>http://heartbeats.jp/</uri>
    </author>
    
        <category term="nginx" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="ja" xml:base="http://heartbeats.jp/hbblog/">
        <![CDATA[<p>前回と同様に、nginx.orgのパッケージからインストールしたnginxが提供している設定ファイルをサンプルとして説明を行います。</p>
<p>今回はnginxのバーチャルサーバの設定を確認していきます。なお、「バーチャルサーバ」はApache HTTP Serverで言うところ「バーチャルホスト」のことです。</p>
]]>
        <![CDATA[<h2>バーチャルサーバ毎の設定ファイル</h2>
<p>nginxの設定ファイルnginx.confに次のような記述を行うことにより、/etc/nginx/conf.dディレクトリにある拡張子がconfであるファイルを読み込みます。</p>
<pre>
include /etc/nginx/conf.d/*.conf;
</pre>
<p>このconf.dディレクトリにバーチャルサーバ毎の設定ファイルを置くことにより、その設定ファイルが読み込まれます。nginx.orgのパッケージで提供されているサンプルファイルとしては、default.confとexample_ssl.confの2つがあります。前者が標準的なバーチャルサーバの設定ファイルで、後者がTLS/SSLの設定を行ったバーチャルサーバの設定ファイルです。</p>
<p>なお、includeディレクティブで"*.conf"のようにファイル名のパターンマッチを行うときには、ファイル名が読み込まれる順番が不定であることに注意してください。ソースコード レベルの話をすると、パターンを含む文字列はglob()関数により展開され、ファイル名のリストを返します。このとき、返されるファイル名のリストをソートしないことを示すGLOB_NOSORTフラグを付けてglob()関数が呼ばれているため、返されるファイル名のリストの順番は保証されません。後述しますが、デフォルトサーバを決定するときには記述された順番、すなわち読み込まれた順番が意味を持つため注意してください。</p>

<h2>バーチャルサーバの設定</h2>
<p>さて、本題のバーチャルサーバの話をしましょう。</p>
<p>ここでは、設定ファイル/etc/nginx/conf.d/default.confをサンプルとしてバーチャルサーバの設定の説明を行います。内容は次の通りです。ただし、コメントアウトしている箇所の一部は省いています。</p>
<pre>
server {
    listen       80;
    server_name  localhost;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    location ~ /\.ht {
        deny  all;
    }
}
</pre>
<p>それでは、それぞれの設定について確認していきましょう。</p>

<h2>serverコンテキスト - server</h2>
<pre>
server {
    [serverコンテキスト]
}
</pre>
<p>serverディレクティブにはバーチャルサーバの設定を記述します。括弧{ }で囲まれた部分がserverコンテキストになります。</p>
<p>複数のバーチャルサーバを運用するときには、IPベースあるいは名前ベースのバーチャルサーバとして区別するわけですが、serverディレクティブ自体ではこの区別を行っていません。serverコンテキストに記述するlistenディレクティブとserver_nameディレクティブにより、この区別を行います。</p>

<h2>リクエストの受付ソケット - listen</h2>
<p>listenディレクティブにはバーチャルサーバがリクエストを受け付けるIPアドレスやポート番号あるいはUNIXドメイン ソケットを設定します。</p>

<p>IPアドレスを指定するときには"listen IPアドレス"あるいは"listen IPアドレス:ポート"の形式で記述します。</p>
<pre>
listen IPアドレス:ポート番号;
</pre>

<p>次のように"listen 192.0.2.1:80"と記述するとIPアドレス192.0.2.1の80番ポートでリクエストを受け付けるようになります。</p>
<pre>
listen 192.0.2.1:80;
</pre>
<p>後述するようにポート番号のデフォルト値は80であるため、次のようにポート番号を省略して記述することもできます。</p>
<pre>
listen 192.0.2.1;
</pre>

<p>IPアドレスのデフォルト値はすべてのインターフェイス アドレスを意味する"*"であり、ポート番号のデフォルト値は"80"になります。そのため、listenディレクティブを省略すると、次の設定と同じになります。</p>
<pre>
listen *:80;
</pre>
<p>この設定は次のそれぞれの設定と同じ意味を持ちます。</p>
<pre>
listen 80;
</pre>
<pre>
listen *;
</pre>

<p>IPv6の場合は[2001:db8:dead:beef::1]のような角括弧で囲む記法を使います。</p>
<pre>
listen [2001:db8:dead:beef::1]:80;
</pre>

<h3>UNIXドメイン ソケット</h3>

<p>nginxではUNIXドメイン ソケットでもリクエストを受け付けることができます。記述方法は"listen unix:UNIXドメイン ソケットのパス"です。
<pre>
listen unix:パス;
</pre>
<p>次のように記述するとUNIXドメイン ソケット/var/run/nginx.sockでリクエストを受け付けるようになります。</p>
<pre>
listen unix:/var/run/nginx.sock;
</pre>


<h2>バーチャル サーバ名 - server_name</h2>
<p>server_nameディレクティブにはバーチャル サーバの名前を設定します。</p>
<p>ウェブブラウザはウェブサーバに対して次のようなリクエストを送ります。</p>
<pre>
GET / HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:11.0) Gecko/20100101 Firefox/11.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ja,en-us;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
</pre>
<p>このとき、リクエスト先のサーバのホスト名をHost:ヘッダフィールドに指定します。この例では"example.com"というホスト名が指定されています。nginxはこのリクエストを受け取ると、このホスト名がserver_nameディレクティブに設定したサーバ名に一致するserverディレクティブのバーチャルサーバを選び、そのserverディレクティブ内の設定が適応されます。このようにserver_nameディレクティブは名前ベースのバーチャルサーバを設定するために使われます。</p>

<p>それでは、いくつかの指定方法を見ていきましょう。</p>
<p>サーバ名を一つだけ指定するときには次のように記述します。</p>
<pre>
server_name example.com;
</pre>

<p>複数のサーバ名を記述するには次のようにスペース区切りで指定します。最初に記述したサーバ名をプライマリサーバ名と呼びます。</p>
<pre>
server_name example.com www.example.com;
</pre>

<p>サブドメインに全て一致させるには次のどちらかのように記述します。"*"はすべてのサブドメインに一致します。また、"."で始まる場合も同様です。</p>
<pre>
server_name *.example.com;
server_name .example.com;
</pre>

<p>次のように正規表現を使って記述することもできます。</p>
<pre>
server_name ~^www\d+\.example\.com$;
</pre>

<p>空を意味する""を設定すると、Host:ヘッダ フィールドがない場合に一致します。なお、server_nameディレクティブのデフォルト値はこの""となっています。</p>
<pre>
server_name "";
</pre>

<h2>リダイレクト時のサーバ名 - server_name_in_redirect</h2>
<p>server_nameに関連するディレクティブにserver_name_in_redirectというものがありますのでこのディレクティブについても確認しましょう。</p>
<p>server_name_in_redirectディレクティブはリダイレクト時のLocationヘッダに埋め込むサーバ名を制御します。次のようにserver_name_in_redirectディレクティブを"on"にすると、リダイレクトするときにserver_nameディレクティブで設定したプライマリサーバ名が使われるようになります。</p>
<pre>
server_name_in_redirect on;
</pre>
<p>次のように"off"に設定すると、リクエストのHostヘッダ フィールドで指定されたホスト名が使われます。しかし、Hostヘッダ フィールドが無いときにはサーバのIPアドレスが使われることに注意しましょう。</p>
<pre>
server_name_in_redirect off;
</pre>
<p>プライマリサーバ名が正規表現や"*"を使っているときには"off"に設定設定する必要があるでしょう。むしろこの場合は正規なプライマリサーバ名を設定した方がよいとは思いますが。</p>
<p>なお、デフォルト値は"on"です。</p>


<h2>デフォルトサーバ</h2>
<p>複数のバーチャルサーバがあるときには、リクエストのHost:ヘッダ フィールドのホスト名がserver_nameディレクティブのサーバ名に一致するserverディレクティブのバーチャルサーバが適応されます。しかし、一致しない場合にはデフォルトサーバとして選ばれたバーチャルサーバが適応されます。</p>
<p>デフォルトサーバはIPアドレスとポート番号の条件が一致したlistenディレクティブを持つserverディレクティブの中で次のものが選ばれます。</p>
<ul>
	<li>一致したlistenディレクティブの中でdefault_serverオプションを持つ</li>
	<li>設定ファイル内で最初に一致したlistenディレクティブを持つ</li>
</ul>
<p>listenディレクティブにdefault_serverパラメータを付けると、そのserverディレクティブがデフォルトサーバになります。</p>
<pre>
listen *:80 default_server;
</pre>
<p>default_serverパラメータがない場合には、最初にIPアドレスとポート番号の条件に一致したlistenディレクティブを持つserverディレクティブがデフォルトサーバになります。本記事の最初に述べたように複数のバーチャルサーバ毎の設定ファイルがある場合には、読み込まれる順番は不定であるため、どのバーチャルサーバの設定が最初に読み込まれるかはわかりません。そのため、明示的にdefault_serverパラメータを付けた方がよいでしょう。</p>

<p>以上のようにlistenディレクティブとserver_nameディレクティブにより、どのバーチャルサーバが適応されるかが決まります。</p>


<h2>ドキュメントルート - root</h2>
<pre>
root   /usr/share/nginx/html;
</pre>
<p>rootディレクティブにはドキュメントルートのディレクトリを設定します。httpコンテキスト、serverコンテキスト、locationコンテキスト、location内のifコンテキストに記述できます。上記の例では/usr/share/nginx/htmlがドキュメントルートとなります。</p>
<p>大抵はserverコンテキストあるいは次のように"/"のlocationコンテキストに標準のドキュメントルートを設定して、必要に応じて個別のパスのlocationコンテキストに個別にドキュメントルートを設定することになります。</p>
<pre>
location / {
    root   /usr/share/nginx/html;
}
</pre>


<p>今回はここまでです。locationについては書く内容が多くなるので、次回に続きます。</p>
]]>
    </content>
</entry>

<entry>
    <title>#hbstudy #ncstudy #odstudy 共催 トラブル☆しゅーたーず開催しました</title>
    <link rel="alternate" type="text/html" href="http://heartbeats.jp/hbblog/2012/04/hbstudy-ncstudy-odstudy.html" />
    <id>tag:heartbeats.jp,2012:/hbblog//2.66</id>

    <published>2012-04-09T17:37:07Z</published>
    <updated>2012-04-09T18:17:44Z</updated>

    <summary>こんにちは。ばばです。 去る4/7(土)にhbstudy、ncstudy、ods...</summary>
    <author>
        <name>馬場俊彰</name>
        <uri>http://heartbeats.jp/</uri>
    </author>
    
        <category term="イベント" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="ja" xml:base="http://heartbeats.jp/hbblog/">
        <![CDATA[<p>こんにちは。ばばです。</p>

<p>去る4/7(土)にhbstudy、ncstudy、odstudy共催で<a href="http://www.zusaar.com/event/231008">トラブル☆しゅーたーず</a>を開催しました。</p>

<h1>hbstudyの立ち位置</h1>

<p>hbstudyの役割分担としては、障害シナリオの作り込みおよびトラブルシュートのテクニカル全般、報告のロジカルチェック全般でした。 <br />
明確に役割分担したわけではないのですが、たぶんこんなところです。</p>

<p>hbstudyの役割、というよりは、私自身の得意分野と特性(S?)を活かして動かせてもらいました。</p>

<p>実際のところ、最大の功労者は<a href="http://twitter.com/ysaotome">@ysaotomeさん</a>です。実際のコーディングのほとんどは@ysaotomeさんの手によるものでした。あまりの活躍ぶりに、つい五月女商会なるサイトをお題にしてしまいました。あれは私の策略です。すみませんね。やいやい、参っちゃうね。</p>

<h1>なんでわざわざ休日に... トラブル☆しゅーたーず？</h1>

<p>今回のイベントを一言で言うと、壮大なごっこ遊びつまり <strong>ロールプレイ</strong> なわけです。  </p>

<p>本気でやりすぎて胃が痛くなる人まで出る始末。最高です。</p>

<p>動機というかモチベーションとしては以下のものがありました。</p>

<ul>
<li>他社(他者)の事例を知りづらい分野なのでお互いに情報交換したいよね</li>
<li>練習する機会があんまりないから練習したいよね</li>
</ul>

<p>会の最後には私が<a href="https://docs.google.com/presentation/d/117SdD0NjMaunm1UfFBFPPaXxdrgvvkeXnmMETConnMI/edit#slide=id.p22">解答編</a>を話させてもらいましたが、どれも当たり前のことです。でも練習しとかないと本番でできない。残念ながら世の中そんなものです。だから練習大事！ <br />
ハートビーツの新人研修もロールプレイ盛りだくさんです。 <br />
なので非常に実践的で厳しい。受ける側は大変。やる側はもっと大変。 <br />
でもそれがないと何もできるようにならない。現実は厳しいですね。</p>

<p>あと、懇親会などで少し話しましたが、下記のような対応が出てくるとさらに良かったですね〜とおもいます。</p>

<ul>
<li>とりあえずメンテナンス画面を出してユーザ影響を緩和</li>
<li>報告に、障害中のアクセス数を記載</li>
</ul>

<p>今日から使える実践テクニックですね〜 ;)</p>

<h1>まとめ</h1>

<p>今回参加いただいた方々は、<span style="color:red;font-size:120%;"><strong>当たり前のことを実直にやることがどれだけ難しく、精神力が必要か</strong></span> ということを実感していただけたと思います。</p>

<p>当たり前のことは自動化するのがエンジニアとはいえ、トラブルシュートはそもそも想定外のケースなのでそうも言っていられません。 <br />
自分自身の力(心技体的な)、自分自身の力を拡張する力(プログラミング・ナレッジベースなど)の両面から日々向上していきましょうね。</p>

<p>主催側も大変面白かったので、またやりたいです！ <br />
いい感じのレベル感の障害作り込むのはなかなか難しい！</p>

<p>次の企画はアイデア出始めているので、いつやろうかな、いつできるかな〜</p>

<p>ちなみに次回hbstudyは<a href="http://heartbeats.jp/hbstudy/2012/03/hbstudy32.html">4/17(火)USクラウド最新動向勉強会 Softlayer社に学ぶ競争力</a>、<a href="http://heartbeats.jp/hbstudy/2012/04/hbstudy33.html">4/28(土)Mercurialハンズオン</a>と目白押しです！ <br />
そういえばhbstudyはおよそ月1開催なので、5月に2回やるととうとう追いつきます。誰となく。</p>
]]>
        

    </content>
</entry>

<entry>
    <title>リーバスプロキシ／ロードバランサとmod_rpaf </title>
    <link rel="alternate" type="text/html" href="http://heartbeats.jp/hbblog/2012/03/mod-rpaf.html" />
    <id>tag:heartbeats.jp,2012:/hbblog//2.62</id>

    <published>2012-03-12T06:00:00Z</published>
    <updated>2012-03-12T06:15:07Z</updated>

    <summary>リバースプロキシ／ロードバランサ配下のApache HTTP Server（以降...</summary>
    <author>
        <name>滝澤隆史</name>
        <uri>http://heartbeats.jp/</uri>
    </author>
    
        <category term="Apache" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="ja" xml:base="http://heartbeats.jp/hbblog/">
        <![CDATA[<p>リバースプロキシ／ロードバランサ配下のApache HTTP Server（以降、単にhttpdと記す）ではmod_rpafというモジュールを使用すると、アクセス元のIPアドレスを正しく取得して、そのIPアドレスでログに出力したり、アクセス制御を行ったりすることができるようになります。</p>
<p>今回の記事の前半ではこのmod_rpafについてインストール方法や設定方法について説明します。</p>
<p>後半ではmod_rpafを使ってもアクセス制御ができない問題が発生して、それを解決した経緯などを紹介します。具体的にはロードバランサとしてAmazon Elastic Load Balancingを、プロキシサーバとしてnginxを、バックエンドサーバとしてAmazon Linux 2011.09のhttpdを使ったときにアクセス元IPアドレスによるアクセス制御がうまくできない問題が発生しました。このあたりにご興味のある方は是非ご覧ください。少しだけソースコードを読めるITインフラエンジニアがトラブルシューティングをした簡単な事例としてみていただければと思います。</p>
]]>
        <![CDATA[<h2>mod_rpafとは</h2>
<p>リバースプロキシ／ロードバランサの配下のApache HTTP Server（以降、単にhttpdと記す）ではそのままではアクセス元のIPアドレスを取得することができず、リバースプロキシ サーバのIPアドレスがアクセス元IPアドレスとしてアクセスログに記録されます。これでは、実際のアクセス元が正しくログに記録されません。また、アクセス元IPアドレスによるアクセス制御も正しく行うことができません。</p>
<p>この対策として、mod_rpafというモジュールを利用します。 アクセス元IPアドレスはリバースプロキシ側でX-Forwarded-Forというヘッダで提供されることが多いでしょう。mod_rpafを使うと、このヘッダのIPアドレスを取得して、httpdの内部のリモートIPアドレスを保持している変数に上書きしてくれます。これにより、正しいアクセス元IPアドレスがアクセスログに記録されます。</p>
<p>mod_rpafの公式サイトは <a href="http://stderr.net/apache/rpaf/">http://stderr.net/apache/rpaf/</a> です。バージョン0.6で更新が止まっており、保守が継続されていません。</p>

<h2>mod_rpafのインストール</h2>
<p>まず、ビルドに必要なパッケージをインストールしましょう。ここでは、CentOS 6にインストールする例を紹介します。httpd-develパッケージとgccパッケージおよびそれらに依存するパッケージをインストールします。なお、APR関連のツールもhttpd-develパッケージの依存でインストールされます。</p>
<pre>
# yum install gcc
# yum install httpd httpd-devel
</pre>
<p>後半で説明しますが、オリジナルのmod_rpafでは新しめのLinuxディストリビューション（RHEL 6/CentOS 6/Amazon Linux 2011.09）で提供されているhttpdではアクセス制御ができない不具合があります。そのため、次のサイトからtar.gzファイルをダウンロードするか、gitで直接ファイルを取得します。</p>
<p><a href="https://github.com/ttkzw/mod_rpaf-0.6">https://github.com/ttkzw/mod_rpaf-0.6</a></p>

<h3>サイトからダウンロードする方法</h3>
<p><a href="https://github.com/ttkzw/mod_rpaf-0.6">https://github.com/ttkzw/mod_rpaf-0.6</a> にアクセスします。</p>
<p>Downloadをクリックして、Downlaod as tar.gzをクリックすると、ダウンロードできます。後は、展開してインストールします。</p>
<pre>
$ tar xvzf ttkzw-mod_rpaf-0.6-f96f67c.tar.gz
$ cd ttkzw-mod_rpaf-0.6-f96f67c
$ make
$ sudo make install
</pre>

<h3>gitで取得する方法</h3>
<pre>
$ git clone git://github.com/ttkzw/mod_rpaf-0.6.git
$ cd mod_rpaf-0.6
$ make
$ sudo make install
</pre>

<h3>モジュールファイルを直接ダウンロードする方法</h3>
<pre>
$ mkdir mod_rpaf-0.6
$ cd mod_rpaf-0.6
$ wget https://raw.github.com/ttkzw/mod_rpaf-0.6/master/mod_rpaf-2.0.c
$ sudo /usr/sbin/apxs -i -c -n mod_rpaf-2.0.so mod_rpaf-2.0.c
</pre>

<h2>設定</h2>
<p>次の内容の設定ファイル/etc/httpd/conf.d/mod_rpaf.confを作成します。</p>
<pre>
LoadModule rpaf_module modules/mod_rpaf-2.0.so
RPAFenable On
RPAFsethostname On
RPAFproxy_ips 127.0.0.1 10. 172.16.
RPAFheader X-Forwarded-For
</pre>
<p>各ディレクティブの説明は以下の通りです。</p>
<table border="1">
	<tr><td>RPAFenable</td><td>"On"に設定すると、このモジュールの機能が有効になる。</td></tr>
	<tr><td>RPAFsethostname</td><td>"On"に設定すると、リバースプロキシが付与するヘッダX-Forwarded-HostあるいはX-Hostの値をHostヘッダの値として設定する。</td></tr>
	<tr><td>RPAFproxy_ips</td><td>リバースプロキシのIPアドレスをスペース区切りで列挙する。オリジナルにはない付加機能として"10."や"172.16."のようなドットで終わるサブネットの記法も使える。なお、この範囲を可能な限り限定してください。リバースプロキシを経由しないアクセス経路があるときには、X-Forwarded-Hostヘッダの偽装の影響を受ける恐れがある。</td></tr>
	<tr><td>RPAFheader</td><td>リバースプロキシが付与するアクセス元IPアドレスを格納しているヘッダ名を記述する。デフォルトではX-Forwarded-Forが使われる。</td></tr>
</table>
<p>設定内容を確認して、再起動すれば利用できます。</p>
<pre>
$ sudo service httpd configtest
$ sudo service httpd restart
</pre>
<p>以上で設定は完了です。</p>

<p>ウェブブラウザを使って、リバースプロキシ経由でサーバにアクセスし、アクセスログにアクセス元のIPアドレスが記録されているかを確認してください。</p>

<h3>アクセス制御</h3>
<p>mod_rpafにより取得したIPアドレスを使って、次のようなアクセス制御を行うことができます。</p>
<pre>
Order Deny,Allow
Allow from 192.0.2.0/24
Deny from all
</pre>

<h2>アクセス制御に関する不具合の対応</h2>
<p>次のような構成でオリジナルのmod_rpaf 0.6では、mod_rpafにより取得したIPアドレスを使って、アクセス制御を行うことができないというトラブルが発生しました。</p>
<pre>
Amazon Elastic Load Balancing --- nginx --- httpd
</pre>
<p>ロードバランサとしてAmazon Elastic Load Balancingを、リバースプロキシとしてnginxを、バックエンド ウェブサーバとしてhttpd（Amazon Linux 2011.09のもの、バージョン2.2.21）を使っています。</p>
<p>なお、アクセスログにはアクセス元のIPアドレスが正しく記録されているため、IPアドレスの取得そのものはうまく動いています。</p>
<p>とりあえずの回避策として、リバースプロキシが付与したアクセス元IPアドレスのヘッダX-Forwarded-Forを使ってアクセス制御を行いました。下記の例では、リバースプロキシが付与したヘッダX-Forwarded-Forの値がアクセス許可対象のIPアドレスが一致したときに環境変数allowedを設定し、Allow from env=allowedにより許可するという設定です。しかし、リバースプロキシを経由しないアクセス経路があるときにはX-Forwarded-Forヘッダの偽装のリスクがあります。</p>
<pre>
SetEnvIf X-Forwarded-For ^192\.0\.2\.[1-9]?[0-9]$ allowed
SetEnvIf X-Forwarded-For ^192\.0\.2\.1[0-9][0-9]$ allowed
SetEnvIf X-Forwarded-For ^192\.0\.2\.2[0-5][0-9]$ allowed

Order Deny,Allow
Allow from env=allowed
Deny from all
</pre>

<p>この一時的な回避策を実施する一方で、根本的な解決を図るために原因調査を行いました。</p>
<p>RHEL 5/CentOS 5のhttpd 2.2.3では問題なく取得したアクセス元のIPアドレスでアクセス制御できることは確認してます。しかし、RHEL 6/CentOS 5のhttpd 2.2.15では今回問題が起きたAmazon Linux 2011.09のhttpd 2.2.21と同様にアクセス制御ができませんでした。しかし、アクセスログにはアクセス元のIPアドレスが正しく記録されているところから、アクセス元IPアドレスの取得そのものはうまくいっていることがわかります。そのため、mod_rpafとhttpdのソースコードをアクセス制御周りに絞って追いかけてみました。httpd 2.2.22のソースコードで説明します。</p>
<p>httpd 2.2系列でアクセス制御を行っているモジュールはmod_authz_hostです。modules/aaa/mod_authz_host.cを見てみましょう。IPアドレスが一致するかを判断している箇所はfind_allowdeny()関数内のcase T_IPのところです。</p>
<pre>
static int find_allowdeny(request_rec *r, apr_array_header_t *a, int method)
{
    略
    for (i = 0; i &lt; a-&gt;nelts; ++i) {
        略
        case T_IP:
            if (apr_ipsubnet_test(ap[i].x.ip, r-&gt;connection-&gt;remote_addr)) {
                return 1;
            }
            break;
</pre>
<p>ここでap[i].x.ipはアクセス制御の設定のAllow/Denyで指定したIPアドレスに関する情報が格納されています。remote_addrにはアクセス元のIPアドレスに関する情報が格納されています。つまり、mod_rpafではこの内容を書き換えているはずです。さらに、apr_ipsubnet_test()という関数では先の2つのIPアドレスの情報からサブネットが一致するかを判断しています。</p>
<p>次に、mod_rpaf-2.0.cを見てみましょう。change_remote_ip()関数内でIPアドレスの書き換えをしています。</p>
<pre>
r-&gt;connection-&gt;remote_ip = apr_pstrdup(r-&gt;connection-&gt;pool, ((char **)arr-&gt;elts)[((arr-&gt;nelts)-1)]);
r-&gt;connection-&gt;remote_addr-&gt;sa.sin.sin_addr.s_addr = apr_inet_addr(r-&gt;connection-&gt;remote_ip);
</pre>
<p>arrにはX-Forwared-Forヘッダから取得したIPアドレスの情報が入っており、そこからremote_ipにアクセス元のIPアドレスが代入されています。その次に、先ほど見かけたremote_addr内のsa.sin.sin_addr.s_addrにIPアドレスを代入しているのがわかります。</p>
<p>再び、httpdのソースコードに戻ります。今度はapr_ipsubnet_test()について確認してみましょう。srclib/apr/network_io/unix/sockaddr.cを見てみます。</p>
<pre>
APR_DECLARE(int) apr_ipsubnet_test(apr_ipsubnet_t *ipsub, apr_sockaddr_t *sa)
{
#if APR_HAVE_IPV6
    /* XXX This line will segv on Win32 build with APR_HAVE_IPV6,
     * but without the IPV6 drivers installed.
     */
    if (sa-&gt;sa.sin.sin_family == AF_INET) {
        if (ipsub-&gt;family == AF_INET &amp;&amp;
            ((sa-&gt;sa.sin.sin_addr.s_addr &amp; ipsub-&gt;mask[0]) == ipsub-&gt;sub[0])) {
            return 1;
        }
    }
略
#else
    if ((sa-&gt;sa.sin.sin_addr.s_addr &amp; ipsub-&gt;mask[0]) == ipsub-&gt;sub[0]) {
        return 1;
    }
#endif /* APR_HAVE_IPV6 */
</pre>
<p>ここでipsubにはアクセス制御の設定のAllow/Denyで指定したIPアドレスに関する情報が、saにはアクセス元のIPアドレスに関する情報が格納されています。</p>
<p>ここで気になるのはAPR_HAVE_IPV6です。APR_HAVE_IPV6が定義されていなければ、特に問題なく判定できそうです。APR_HAVE_IPV6が定義されているときはどうでしょうか。
アドレス ファミリがAF_INET(IPv4)であるかの条件文が先にあります。先のmod_rpafのコースコードにはアドレス ファミリを設定しているところはありませんでした。ここが非常に怪しいですね。そこで、mod_rpafにアドレスファミリを設定するように追加してみました。AF_INET決めうちです。</p>
<pre>
r-&gt;connection-&gt;remote_ip = apr_pstrdup(r-&gt;connection-&gt;pool, ((char **)arr-&gt;elts)[((arr-&gt;nelts)-1)]);
r-&gt;connection-&gt;remote_addr-&gt;sa.sin.sin_addr.s_addr = apr_inet_addr(r-&gt;connection-&gt;remote_ip);
r-&gt;connection-&gt;remote_addr-&gt;sa.sin.sin_family = AF_INET;
</pre>
<p>このように書き替えた後にモジュールをビルドし直すと、アクセス制御ができるようになりました。</p>
<p>ということで、結論としては、問題が発生したhttpdではAPR_HAVE_IPV6を有効にした状態でビルドされておりアドレス ファミリの指定が必要になっていたことと、mod_rpafがアドレス ファミリを指定していなかったことの2つが原因でアクセス制御ができなくなっていたということです。mod_rpafにアドレス ファミリを指定することでこの問題を解決できました。</p>
<p>その他、細かい修正したもの次のURLのgithubに登録しました。</p>
<pre>
https://github.com/ttkzw/mod_rpaf-0.6
</pre>
<p>ちなみに、私とは別にmod_rpafをフォークして開発している人がgithub上にいて、そちらのバージョンが0.8になっているので、このgithubに置いたバージョンは0.6のままで名前を付けています。</p>

<p>httpdの各モジュールはそんなに大きいソースコードではないので追いかけようと思えば追いかけられます。ITインフラ エンジニアもたまには普段利用しているミドルウェアのソースコードを読んでみてはいかがでしょうか。</p>

<p>えっと、IPv6対応は機会があれば......</p>
]]>
    </content>
</entry>

<entry>
    <title>nginx連載3回目: nginxの設定、その1</title>
    <link rel="alternate" type="text/html" href="http://heartbeats.jp/hbblog/2012/02/nginx03.html" />
    <id>tag:heartbeats.jp,2012:/hbblog//2.61</id>

    <published>2012-02-29T04:00:00Z</published>
    <updated>2012-02-29T03:55:31Z</updated>

    <summary>今回と次回の2回に分けてnginxの設定について紹介します。今回の前半は設定ファ...</summary>
    <author>
        <name>滝澤隆史</name>
        <uri>http://heartbeats.jp/</uri>
    </author>
    
        <category term="nginx" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="ja" xml:base="http://heartbeats.jp/hbblog/">
        <![CDATA[<p>今回と次回の2回に分けてnginxの設定について紹介します。今回の前半は設定ファイルの構成について、後半は設定ファイルのサンプルを元に設定ディレクティブについて説明を行います。</p>

]]>
        <![CDATA[<h2>設定ファイルについて</h2>
<p>パッケージシステムからnginxをインストールすると、nginxの設定ファイル用のディレクトリは通常は/etc/nginxになります。このディレクトリに設定ファイルnginx.confを配置します。</p>
<p>さらに、他のファイルから設定を読み込むincludeディレクティブを次のような内容でnginx.confに記述して、conf.dというサブディレクトリ内の拡張子がconfであるファイルを読み込む設定を行うことがよくあります。</p>
<pre>
include /etc/nginx/conf.d/*.conf;
</pre>

<p>その他に次のようなファイルもインストールされます。</p>
<table border="1">
<tr><td>mime.types</td><td>MIMEタイプと拡張子の関連付けを定義したファイル。</td></tr>
<tr><td>fastcgi_params</td><td>FastCGI用の変数を定義するファイル。fastcgi_paramディレクティブの設定集。</td></tr>
<tr><td>fastcgi.conf</td><td>fastcgi_paramsと同じ。パッケージによっては同梱されない場合もある。</td></tr>
<tr><td>scgi_params</td><td>SCGI用の変数を定義するファイル。scgi_paramディレクティブによる設定集。</td></tr>
<tr><td>uwsgi_params</td><td>uWSGI用の変数を定義するファイル。uwsgi_paramディレクティブによる設定集。</td></tr>
<tr><td>koi-utf</td><td>ロシア語の文字エンコーディングkoi8-rとUTF-8の文字コードのマッピングを行うファイル。</td></tr>
<tr><td>koi-win</td><td>ロシア語の文字エンコーディングkoi8-rとwindows-1251の文字コードのマッピングを行うファイル。</td></tr>
<tr><td>win-utf</td><td>ロシア語の文字エンコーディングwindows-1251とUTF-8の文字コードのマッピングを行うファイル。</td></tr>
</ul>
</table>
<p>これらのファイルのファイル名は特別な意味を持っているのではなく、設定ファイルからincludeディレクティブによりこのファイル名を指定して読み込むことで利用します。例えば、次のようにしてはmime.typesを読み込みます。</p>
<pre>
    include       /etc/nginx/mime.types;
</pre>
<p>なお、koi-utf, koi-win, win-utfの3つのファイルを使うことはありません。</p>

<h2>設定ファイルの記述方法</h2>
<p>nginxの設定の命令（ディレクティブ）は設定ファイル内のどこにでも記述できるものではなく、ディレクティブ毎に決められたコンテキスト内に記述します。</p>
<p>コンテキストはnginxのモジュールのカテゴリと関連があるため、モジュールのカテゴリについて先に説明します。モジュールは大きく分けて4種類のカテゴリに分けられます。</p>
<table border="1">
	<tr><td>core</td><td>プロセスの制御や設定ファイルやエラーログに関するモジュール</td></tr>
	<tr><td>event</td><td>イベント処理に関するモジュール</td></tr>
	<tr><td>http</td><td>httpに関するモジュール</td></tr>
	<tr><td>mail</td><td>mailに関するモジュール</td></tr>
</table>
<p>ディレクティブはこのモジュールのカテゴリ毎に記述します。ただし、coreモジュールに関してはmainコンテキスト、すなわち、設定ファイル内の最上位の階層に記述します。設定ファイルの構成は次のようになります。</p>
<pre>
coreモジュールの設定

events {
    eventモジュールの設定
}

http {
    httpモジュールの設定
}

mail {
    mailモジュールの設定
}
</pre>
<p>httpコンテキストはさらに、バーチャルサーバ（バーチャルドメイン）毎の設定を行うserverディレクティブ、さらにURI毎の設定を行うlocaltionディレクティブにより階層化されます。次のような構成になります。</p>
<pre>
http {
    httpモジュールの設定

    server {
        サーバ毎の設定

        location PATH {
            URI毎の設定
        }
        location PATH {
            URI毎の設定
	}
        ...
    }

    server {
        ...
    }
}
</pre>


<h2>nginx.confの説明</h2>
<p>ここからは、nginx.orgのパッケージからインストールしたnginxが提供している設定ファイルnginx.confをサンプルとして設定について説明をしていきます。</p>

<h2>mainコンテキスト</h2>
<p>まず、mainコンテキストでの設定について確認していきます。</p>
<p>mainコンテキストに記述できる設定はコアモジュールで提供されるディレクティブです。どのようなディレクティブがあるかは次のサイトで確認できます。</p>
<ul>
	<li><a href="http://nginx.org/en/docs/ngx_core_module.html">Core functionality(nginx.org)</a></li>
	<li><a href="http://wiki.nginx.org/CoreModule">CoreModule(Nginx Wiki)</a></li>
</ul>
<p>設定ファイルnginx.confのmainコンテキストには次の設定が行われています。</p>
<pre>
user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;
</pre>
<p>この設定を一つずつ確認していきましょう。</p>

<h3>実行ユーザ - user</h3>
<pre>
user  nginx;
</pre>
<p>userディレクティブはnginxのworkerプロセスの実行権限のユーザを設定します。</p>
<p>この例ではnginxユーザで動作します。nginxが動作しているときのpsコマンドの出力例は次のようになります。nginx: worker processがnginxユーザで動作していることが確認できます。</p>
<pre>
$ ps auxf | grep [n]ginx
root      1395  0.0  0.0  44516   844 ?        Ss   03:27   0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
nginx     1398  0.0  0.1  44936  1528 ?        S    03:27   0:00  \_ nginx: worker process
</pre>

<h3>workerのプロセス数 - worker_processes</h3>
<pre>
worker_processes  1;
</pre>
<p>worker_processesディレクティブは動作させるnginxのworkerプロセスの数を設定します。通常はCPUのコア数以下に設定します。イベント駆動のアーキテクチャであるため、CPUのコア数より多い数のプロセスを動作させても意味がありません。なお、デフォルトの設定値は1です。</P>
<p>この例ではworkerプロセスの数を1個にするように設定されています。</p>

<h3>エラーログ - error_log</h3>
<pre>
error_log  /var/log/nginx/error.log warn;
</pre>
<p>error_logディレクティブはエラーログの出力先のファイル名とロギングのレベルを指定します。このディレクティブはmain, http, server, locationのどのコンテキストでも設定できるため、必要に応じてエラーログの出力先を変えることができます。なお、デフォルトの設定値は"logs/error.log error"であり、errorレベル以上のログをlogs/error.logに出力します。</p>
<p>この例ではwarnレベル以上のログを/var/log/nginx/error.logに出力します。</p>

<h3>PIDファイル - pid</h3>
<pre>
pid        /var/run/nginx.pid;
</pre>
<p>pidディレクティブはmasterプロセスのプロセスIDを保存するファイルを設定します。</p>
<p>この例ではnginxのmasterプロセスのプロセスIDを/var/run/nginx.pidに保存します。</p>

<h2>eventsコンテキスト</h2>
<p>eventsコンテキストでの設定について確認していきます。</p>
<p>eventsコンテキストに記述できる設定はeventモジュールで提供されるディレクティブです。どのようなディレクティブがあるかは次のサイトで確認できます。</p>
<ul>
	<li><a href="http://wiki.nginx.org/EventsModule">EventsModule(Nginx Wiki)</a></li>
</ul>
<p>設定ファイルnginx.confのeventsコンテキストには次の設定が行われています。</p>
<pre>
events {
    worker_connections  1024;
}
</pre>

<h3>最大コネクション数 - worker_connections</h3>
<pre>
worker_connections  1024;
</pre>
<p>worker_connectionsディレクティブは一つのworkerプロセスが同時に処理できる最大コネクション数を設定します。デフォルトの設定値は512です。</p>
<p>この例では一つのworkerあたり最大1024個のコネクションを処理します。</p>

<h2>httpコンテキスト</h2>
<p>httpコンテキストでの設定について確認していきます。</p>
<p>httpコンテキストに記述できる設定はhttpモジュールで提供されるディレクティブです。どのようなhttpモジュールとディレクティブがあるかは次のサイトで確認できます。</p>
<ul>
	<li><a href="http://nginx.org/en/docs/">Module Reference(nginx.org)</a>のngx_httpで始まるモジュール</li>
	<li><a href="http://wiki.nginx.org/Modules">Modules(Nginx Wiki)</a>のHTTPモジュール<li>
</ul>
<p>設定ファイルnginx.confのhttpコンテキストには次の設定が行われています。</p>
<pre>
http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    tcp_nopush     on;

    keepalive_timeout  65;

    gzip  on;

    include /etc/nginx/conf.d/*.conf;
}
</pre>
<p>それぞれの設定について確認していきましょう。</p>

<h3>MIMEタイプの設定 - types, default_type</h3>
<pre>
include       /etc/nginx/mime.types;
</pre>
<p>このincludeディレクティブでは次のような内容のファイルmime.typesを読み込んでいます。</p>
<pre>
types {
    text/html                             html htm shtml;
    text/css                              css;
    text/xml                              xml;
    image/gif                             gif;
    image/jpeg                            jpeg jpg;
    application/x-javascript              js;
    application/atom+xml                  atom;
    application/rss+xml                   rss;
中略
}
</pre>
<p>typesディレクティブはMIMEタイプと拡張子のマッピングを設定します。nginxでは上記のような内容のtypesディレクティブの設定を行ったmime.typesというファイルを用意しており、上述のようにincludeディレクティブで読み込むようにします。</p>

<pre>
default_type  application/octet-stream;
</pre>
<p>default_typeディレクティブではレスポンスのデフォルトのMIMEタイプを設定します。上述のmime.typesで拡張子からMIMEタイプを決定できなかったときに、ここで指定したMIMEタイプが適応されます。なお、デフォルトの設定値はtext/plainです。</p>
<p>この例ではデフォルトのMIMEタイプをapplication/octet-streamに設定します。</p>

<h3>アクセスログの設定 - log_format, access_log</h3>
<pre>
log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                  '$status $body_bytes_sent "$http_referer" '
                  '"$http_user_agent" "$http_x_forwarded_for"';
</pre>
<p>log_formatディレクティブはアクセスログの書式を定義します。後述するaccess_logディレクティブでここで定義した名前を指定することにより利用できます。このディレクティブはhttpコンテキストのみで利用できます。</p>
<p>この例ではmainという名前で書式を定義しています。</p>
<p>なお、次のような"combined"という名前の定義が予め組み込みで用意されています。</p>
<pre>
log_format combined '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
		    '"$http_referer" "$http_user_agent"';
</pre>
<p>これはApache HTTP Serverでよく定義されている"combined"と同じ形式です。</p>

<pre>
access_log  /var/log/nginx/access.log  main;
</pre>
<p>access_logディレクティブはアクセスログの出力先のパスとlog_formatで定義した書式の名前を設定します。デフォルトの設定値は"log/access.log combined"です。書式を省略すると"combined"が適応されます。なお、設定値を"off"にすると、アクセスログを出力しないため、アクセスログの出力を抑制したい場合に利用します。</p>
<p>このディレクティブはhttp, server, location, if, limit_exceptのどのコンテキストでも利用できるため、必要に応じて異なるファイル名のファイルにログを出力することができます。</p>
<p>この例では/var/log/nginx/access.logというファイルにmainの書式でアクセスログを出力します。</p>

<p>なお、ログに関してはhttp_logモジュールの機能です。次のサイトでその機能の詳細を確認できます。</p>
<ul>
	<li><a href="http://nginx.org/en/docs/http/ngx_http_log_module.html">Module ngx_http_log_module(nginx.org)</a></li>
	<li><a href="http://wiki.nginx.org/HttpLogModule">HttpLogModule(Nginx Wiki)</a></li>
</ul>

<h3>sendfile, tcp_nopush</h3>
<pre>
sendfile        on;
</pre>
<p>sendfileディレクティブはコンテンツのファイルの読み込みとクライアントへのレスポンスの送信にsendfile() APIを使うかを設定します。sendfile()を使うとカーネル空間内でファイルの読み込みと送信が完了するため、効率良くファイルの内容をクライアントに送信できます。デフォルトの設定値はoffです。</p>
<p>なお、sendfile()はプラットフォームやファイルシステムによっては問題が起きることもありますので、そのときは無効にしてください。これに関しては、Apacheでもsendfileを使う機能を持っているので、<a href="http://httpd.apache.org/docs/2.2/ja/mod/core.html#enablesendfile">Apache HTTP Server - EnableSendfileディレクティブ</a>が参考になります。</p>
<p>この例ではsendfile()を利用します。</p>

<pre>
tcp_nopush     on;
</pre>
<p>tcp_nopushディレクティブはsendfileが有効なときに、FreeBSDの場合はTCP_NOPUSHソケットオプション、Linuxの場合はTCP_CORKソケットオプションを使うかを設定します。このオプションを使うと、レスポンスヘッダとファイルの内容をまとめて送るようになり、少ないパケット数で効率良く送ることができます。デフォルトの設定値はoffです。</p>
<p>この例ではtcp_nopushの機能を有効にします。</p>

<h3>keepaliveの設定 - keepalive_timeout</h3>
<pre>
keepalive_timeout  65;
</pre>
<p>keepalive_timeoutディレクティブはサーバ側でのキープアライブのタイムアウトの秒数を設定します。デフォルトの設定値は75sです。</p>
<p>この例ではキープアライブのタイムアウトを65秒に設定しています。</p>

<h3>レスポンスの圧縮 - gzip</h3>
<pre>
gzip  on;
</pre>
<p>gzipディレクティブではレスポンスのコンテンツを圧縮するかを設定します。デフォルトの設定値はoffです。</p>
<p>この例では圧縮を行います。</p>

<p>gzipディレクティブはhttp_gzipモジュールの機能です。次のサイトで関連するディレクティブを確認できます。</p>
<ul>
	<li><a href="http://nginx.org/en/docs/http/ngx_http_gzip_module.html">Module ngx_http_gzip_module</a></li>
	<li><a href="http://wiki.nginx.org/HttpGzipModule">HttpGzipModule(Nginx Wiki)</a></li>
</ul>

<p>参考までに、Ubuntu 11.10でのnginxのパッケージで提供される設定ファイルには次の内容のgzip関連の設定が行われています。gzip関連の設定の参考になると思います。</p>
<pre>
gzip on;
gzip_disable "msie6";
# gzip_vary on;
# gzip_proxied any;
# gzip_comp_level 6;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
# gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
</pre>

<h3>バーチャルサーバの読み込み</h3>
<pre>
include /etc/nginx/conf.d/*.conf;
</pre>
<p>この例では/etc/nginx/conf.dディレクトリにある拡張子がconfのファイルを読み込みます。conf.dディレクトリにはバーチャルサーバ毎の設定ファイルを置きます。</p>

<p>このバーチャルサーバ毎の設定については次回で紹介します。特にserverコンテキストおよびlocaltionコンテキストにおけるディレクティブについて説明します。</p>
]]>
    </content>
</entry>

<entry>
    <title>nginx連載2回目: nginxのインストール</title>
    <link rel="alternate" type="text/html" href="http://heartbeats.jp/hbblog/2012/02/nginx02.html" />
    <id>tag:heartbeats.jp,2012:/hbblog//2.60</id>

    <published>2012-02-09T03:00:00Z</published>
    <updated>2012-02-09T02:30:45Z</updated>

    <summary>前回はnginxの概要を紹介しましたが、今回はnginxのインストールについて紹...</summary>
    <author>
        <name>滝澤隆史</name>
        <uri>http://heartbeats.jp/</uri>
    </author>
    
        <category term="nginx" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="ja" xml:base="http://heartbeats.jp/hbblog/">
        <![CDATA[<p>前回はnginxの概要を紹介しましたが、今回はnginxのインストールについて紹介します。なお、設定については今回紹介する予定でしたが、文章が長くなってしまったので次回にします。</p>
<p>「百聞は一見にしかず」ということで、実際にインストールして体験してみましょう。</p>
]]>
        <![CDATA[<h2>インストール方法</h2>
<p>nginxのインストール方法は主に次の3通りです。</p>
<ul>
	<li>ソースコードからビルドしてインストールする</li>
	<li>OSのパッケージシステムからパッケージをインストールする</li>
	<li>nginx.org提供のバイナリパッケージをインストールする</li>
</ul>
<p>お使いのOSがメジャーなLinuxディストリビューションや*BSD系のUNIXであれば、パッケージシステムからインストールできます。なお、本記事ではCentOS 6にnginx.org提供のパッケージを利用する前提で話を書きます。</p>
<p>また、次のサイトにも情報がありますので一度ご覧ください。</p>
<ul>
	<li><a href="http://nginx.org/en/download.html">公式ダウンロードサイト</a></li>
	<li><a href="http://wiki.nginx.org/Install">Wikiサイト</a></li>
</ul>
<p>なお、2012年2月9日時点での最新の安定版のバージョンは1.0.12で、開発版のバージョンは1.1.14です。</p>

<h2>モジュールの組み込みについて</h2>
<p>前回はnginxはモジュールにより機能を拡張できる仕組みであると説明しましたが、そのモジュールの組み込みについてここで説明します。</p>
<p>公式サイトからtar ballをダウンロードして、展開すると次のようになります。</p>
<pre>
$ tar xvzf nginx-1.0.12.tar.gz 
$ cd nginx-1.0.12
$ ls -F
CHANGES     LICENSE  auto/  configure*  html/  src/
CHANGES.ru  README   conf/  contrib/    man/
</pre>
<p>ここで'./configure --help'と入力して実行すると、通常のオプションに加え、次のようにモジュールの組み込みに関するオプションが表示されます。</p>
<pre>
$ ./configure --help
略
  --with-http_ssl_module             enable ngx_http_ssl_module
  --with-http_realip_module          enable ngx_http_realip_module
  --with-http_addition_module        enable ngx_http_addition_module
  --with-http_xslt_module            enable ngx_http_xslt_module
  --with-http_image_filter_module    enable ngx_http_image_filter_module
  --with-http_geoip_module           enable ngx_http_geoip_module
略
  --without-http_charset_module      disable ngx_http_charset_module
  --without-http_gzip_module         disable ngx_http_gzip_module
  --without-http_ssi_module          disable ngx_http_ssi_module
  --without-http_autoindex_module    disable ngx_http_autoindex_module
  --without-http_geo_module          disable ngx_http_geo_module
略
  --add-module=PATH                  enable an external module
</pre>
<p>ここで、--with-FOO_moduleというオプションがあったら、FOOモジュールはデフォルトでは組み込まれません。組み込みたければそのオプションを指定する必要があります。逆に、--without-FOO_moduleというオプションがあったら、FOOモジュールはデフォルトで組み込まれるため、組み込みたくなければ--without-FOO_moduleを指定する必要があります。さらに、--add-moduleによりサードパーティのモジュールのパスを指定して組み込むことができます。</p>
<p>どのモジュールがデフォルトで組み込まれるかは<a href="http://wiki.nginx.org/Modules">nginx wiki - Modules</a>にモジュールの一覧があるので確認できます。</p>
<p>nginxの機能はモジュールをビルド時に組み込むことにより有効になるため、バイナリパッケージを利用する方でもこのようにしてモジュールが組み込まれることを知っておいてください。</p>
<p>ビルド済みのバイナリからもビルド時のオプションを次のようにして確認することができます。パッケージをインストールした場合には一度確認してみるとよいでしょう。</p>
<blockquote>
$ nginx -V<br />
nginx version: nginx/0.8.54<br />
built by gcc 4.4.4 20100726 (Red Hat 4.4.4-13) (GCC)<br />
TLS SNI support enabled<br />
configure arguments: --user=nginx --group=nginx --prefix=/usr/share/nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/var/lib/nginx/tmp/client_body --http-proxy-temp-path=/var/lib/nginx/tmp/proxy --http-fastcgi-temp-path=/var/lib/nginx/tmp/fastcgi --http-uwsgi-temp-path=/var/lib/nginx/tmp/uwsgi --http-scgi-temp-path=/var/lib/nginx/tmp/scgi --pid-path=/var/run/nginx.pid --lock-path=/var/lock/subsys/nginx --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_xslt_module --with-http_image_filter_module --with-http_geoip_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_degradation_module --with-http_stub_status_module --with-http_perl_module --with-mail --with-file-aio --with-mail_ssl_module --with-ipv6
以下略
</blockquote>

<h2>nginx.org提供パッケージのモジュール</h2>
<p><a href="http://nginx.org/en/download.html">公式ダウンロードサイト</a>ではRHEL 5, RHEL 6, CentOS 5, CentOS 6, Debian GNU/Linux 6(squeeze), Ubuntu 10.04 LTS用に安定版の最新バージョンのパッケージおよびその配布リポジトリが提供されています。このパッケージでは次のモジュールが組み込まれいませんが、利用する機会が少ない機能のモジュールであるため、問題は無いでしょう。</p>
<ul>
 <li>ngx_http_xslt_module</li>
 <li>ngx_http_image_filter_module</li>
 <li>ngx_http_geoip_module</li>
 <li>ngx_http_degradation_module</li>
 <li>ngx_http_perl_module</li>
</ul>

<h2>パッケージのバージョン</h2>
<p>Linuxディストリビューションや*BSDでは以下のようなバージョンのnginxのパッケージが提供されています。(2012年2月9日現在)</p>
<h3>Linuxディストリビューション</h3>
<table border="1">
<tr><th>Linuxディストリビューション</th><th>バージョン</th></tr>
<tr><td>RHEL 6/CentOS 6/Scientific Linux 6</td><td>なし, (Fedora EPEL 6: 0.8.54), (nginx.org: 1.0.12)</td></tr>
<tr><td>RHEL 5/CentOS 5/Scientific Linux 5</td><td>なし, (Fedora EPEL 5: 0.8.55), (nginx.org: 1.0.12)</td></tr>
<tr><td>Amazon Linux AMI 2011.09</td><td>0.8.54</td></tr>
<tr><td>Fedora 16</td><td>1.0.5, (updates: 1.0.10)</td></tr>
<tr><td>Fedora 15</td><td>0.8.54, (updates: 1.0.10)</td></tr>
<tr><td>OpenSUSE 12.1</td><td>1.0.5</td></tr>
<tr><td>Debian GNU/Linux squeeze</td><td>0.7.67 (squeeze-backports: 1.1.8), （nginx.org: 1.0.12）</td></tr>
<tr><td>Debian GNU/Linux wheezy</td><td>1.1.12</td></tr>
<tr><td>Ubuntu 11.10</td><td>1.0.5</td></tr>
<tr><td>Ubuntu 10.04 LTS</td><td>0.7.65, (nginx.org: 1.0.12)</td></tr>
<tr><td>Gentoo Linux</td><td>1.0.10</td></tr>
</table>
<h3>*BSD系</h3>
<table border="1">
<tr><th>OS</th><th>バージョン</th></tr>
<tr><td>FreeBSD</td><td>1.0.12</td></tr>
<tr><td>NetBSD</td><td>1.0.10</td></tr>
<tr><td>OpenBSD</td><td>1.0.11</td></tr>
<tr><td>Mac OS X</td><td>なし, (MacPorts: 1.0.11)</td></tr>
</table>

<h2>インストール例</h2>
<p>ここでは、CentOS 6.2にnginx.org提供のリポジトリからnginxのパッケージをインストールする例を示してみます。</p>
<p>まず、<a href="http://nginx.org/en/download.html">公式ダウンロードサイト</a>の"Pre-Build Linux Packages"からリポジトリ用のRPMファイルをダウンロードしてインストールします。"CentOS 6"と書いてあるリンクをクリックするとダウンロードできます。wgetで取得してインストールする例は次の通りです。</p>
<pre>
$ wget http://nginx.org/packages/centos/6/noarch/RPMS/nginx-release-centos-6-0.el6.ngx.noarch.rpm
# rpm -ivh nginx-release-centos-6-0.el6.ngx.noarch.rpm
</pre>
<p>これにより次の内容の/etc/yum.repos.d/nginx.repoというファイルがインストールされます。</p>
<pre>
# nginx.repo

[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/6/$basearch/
gpgcheck=0
enabled=1
</pre>
<p>nginxのリポジトリが登録できたので、yumコマンドでnginxをインストールします。</p>
<pre>
# yum install nginx
</pre>
<p>以上でインストールは完了です。次にnginxのサービスを起動してみましょう。なお、別のWebサーバが動いていたら先に停止しておいてください。</p>
<pre>
# service nginx start
</pre>
<p>Webブラウザでインストールしたサーバにアクセスしてください。nginx.orgのパッケージの場合には"Welcome to nginx!"という文字が表示されます。エラー以外のページが表示されたら成功です。</p>
<p>ドキュメントのルートディレクトリ（nginx.orgパッケージの場合は/usr/share/nginx/html。パッケージ毎に異なる）にHTMLファイルを置くことによりWebサーバとして利用できます。</p>

<p>次回は設定について紹介します。来週を予定しています。</p>
]]>
    </content>
</entry>

<entry>
    <title>nginx連載1回目: nginxの紹介</title>
    <link rel="alternate" type="text/html" href="http://heartbeats.jp/hbblog/2012/01/nginx01.html" />
    <id>tag:heartbeats.jp,2012:/hbblog//2.59</id>

    <published>2012-01-25T05:00:00Z</published>
    <updated>2012-01-25T05:45:36Z</updated>

    <summary>皆様、初めまして。滝澤と申します。今月からここで記事を書いていきますのでよろしく...</summary>
    <author>
        <name>滝澤隆史</name>
        <uri>http://heartbeats.jp/</uri>
    </author>
    
        <category term="nginx" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="ja" xml:base="http://heartbeats.jp/hbblog/">
        <![CDATA[<p>皆様、初めまして。滝澤と申します。今月からここで記事を書いていきますのでよろしくお願いします。</p>

<p>ここ1,2年で注目を集めているWebサーバ<a href="http://nginx.org/en/">nginx</a>について今回から数回にわたってを紹介していきます。</p>
<p>nginxについて初めて知った、あるいは、名前は聞いたことがあるんだけど使ったことはない、といった方のために、1回目のこの記事ではnginxの概要を、2回目の記事ではインストールと設定について紹介します。</p>

]]>
        <![CDATA[<h1>nginxとは</h1>
<p>nginxはロシアのIgor Sysoev氏によって開発されているWebサーバ兼リバースプロキシのソフトウェアです。「エンジン エックス」（engine x）と呼びます。</p>
<p>2002年に開発が始まり、2004年に公開され、今では約10%のシェアを持つまでに成長しています。facebookやWordPress.ORGなどの大規模サイトでの導入実績もあり、導入するWebサーバの選択肢の一つとして考えられます。ちなみに、2011年7月には商用サポートやコンサルティングを行う法人<a href="http://nginx.com/">Nginx, Inc.</a>が設立されています。</p>

<h2>シェア</h2>
<p>英国のインターネット サービスの調査会社<a href="http://news.netcraft.com/">NETCRAFT</a>社による「<a href="http://news.netcraft.com/archives/2012/01/03/january-2012-web-server-survey.html">January 2012 Web Server Survey</a>」という調査によるとnginxのシェアはトップ サーバでは9.63%であり、Apache、Microsoftに続いて3位となっています。アクティブなサイト数としてはnginxのシェアは12.18%であり、Microsoftを超えて2位となっています。<a href="http://news.netcraft.com/archives/2009/01/16/january_2009_web_server_survey.html">2009年1月のレポート</a>ではそれぞれ1.87%、2.85%であることを踏まえると、nginxのシェアが急激に増加していることがわかります。</p>

<h2>nginxに関する情報</h2>
<p>日本でもこの1,2年で注目度も上がっており、nginxを利用しているサイトも増えています。しかし、ロシアで開発されているため、<a href="http://nginx.org/ru/docs/">オリジナルの文書</a>はロシア語であり、英語での文書もそれなりに揃ってはいますが、ロシア語のみの文書も多数あります。しかし、日本語での情報は乏しい状況です。幸いなことに、Clement Nedelcu氏の書籍『<a href="http://www.packtpub.com/nginx-http-server/book">nginx HTTP Server</a>』が日本語に翻訳され『<a href="http://ascii.asciimw.jp/books/books/detail/978-4-04-870227-0.shtml">ハイパフォーマンスHTTPサーバ nginx入門</a>』として出版されています。この書籍は入門書としての位置づけであり、取っかかりをつかむには良い本でしょう。しかし、実運用上はウェブアプリケーションと連携して利用することがほとんどなのですが、それについて十分な記載があるとはいえません。そのため、本ブログの次回以降ではそのあたりのノウハウやモジュールの機能について紹介していきます。</p>


<h1>nginxの特徴</h1>
<p>次のような特徴があります。</p>

<h2>C10K問題</h2>
<p>nginxは「<a href="http://www.kegel.com/c10k.html">C10K問題</a>」（クライアント1万台問題）に対応したWebサーバです。従来のWebサーバでは同時接続数が増えると、プロセス数やスレッド数が増えて、メモリを食いつぶしたり、コンテキストスイッチのオーバーヘッドが大きくなることにより本来の処理に時間が割けなくなったりします。nginxではマルチスレッドを使わずに、イベント駆動のアーキテクチャを採用することにより、このC10K問題に対応するような仕組みを設けております。このため、メモリの使用量も抑えることができ、メモリが少ないサーバでもそれなりに快適に動作します。</p>

<h2>静的なコンテンツを提供するWebサーバ</h2>
<p>nginxはWebサーバとして静的なコンテンツを提供します。ファイル記述子の情報をキャッシュするといった性能を上げるための様々な工夫が用意されています。</p>
<p>動的なコンテンツはnginx単体では提供できません。次に述べるようなWebアプリケーションサーバと連携することにより動的コンテンツを提供します。</p>

<h2>Webアプリケーションとの連携</h2>
<p>nginxではWebアプリケーションを（apacheのmod_phpやmod_wsgiのように）Webサーバ自体に組み込んで動作させることはできません。WebアプリケーションをFastCGIやSCGIやuWSGIに対応したアプリケーションサーバ上で動作させて、ネットワークあるいはUNIXドメインソケットを経由して利用します。PHPの場合はPHP-FPM (FastCGI Process Manager) 上でPHPのWebアプリケーションを動作させて、nginxからはPHP-FPMと通信を行って利用します。</p>
<p>Webアプリケーションとの連携についても性能向上のために次のような機能が用意されています。
<p>キャッシュ。Webアプリケーションサーバから取得したコンテンツをキャッシュできます。</p>
<p>memcached。Webアプリケーション側でコンテンツをmemcachedにキャッシュさせることができるときには、nginxはmemcachedからコンテンツを読み出すことができます。</p>
<p>ロードバランサ。ロードバランサとしての機能を持っており、複数のアプリケーションサーバを利用して負荷を分散することができます。また、利用できなくなったアプリケーションサーバを自動的に外すこともできます。</p>

<h2>リバースプロキシ</h2>
<p>nginxはリバースプロキシの機能を提供します。</p>
<p>性能向上のために次のような機能も用意されています。</p>
<p>キャッシュ。バックエンドのWebサーバから取得したコンテンツをキャッシュできます。</p>
<p>ロードバランサ。ロードバランサとしての機能を持っており、複数のバックエンドのWebサーバを利用して負荷を分散することができます。また、利用できなくなったWebサーバを自動的に外すこともできます。</p>

<h2>機能とモジュール</h2>
<p>nginxはモジュールにより機能を拡張できる仕組みになっており、50個近くのモジュールがあります。サードパーティのモジュールもたくさんあり、<a href="http://wiki.nginx.org/3rdPartyModules">Wikiサイト</a>で紹介されているものだけでも約80個あります。</p>

<p>たくさんのモジュールがありますが、それらを気軽に利用できるかというとそうではありません。この記事の執筆時点（2012年1月）でのnginxのバージョン（安定版1.0.11、開発版1.1.13）では、ビルドするときにしかモジュールを組み込むことができません。あるモジュールを利用する可能性が少しでもあれば、そのモジュールをビルド時に組み込んでおかないと再びビルドし直すことになります。このため、OSのパッケージ管理システムで提供されているnginxのパッケージではほとんどのモジュールが組み込まれています。
ちなみに、<a href="http://fsmsh.com/3657">Igor Sysoev氏へのインタビュー記事</a>によると、次のメジャーリリースで起動時にモジュールをロードできるようにする計画があるとのことです。</p>


<p>今回はここまでです。次回はnginxのインストールと設定について説明します。</p>
]]>
    </content>
</entry>

<entry>
    <title>インフラエンジニアway 2011年間アクセスランキング！</title>
    <link rel="alternate" type="text/html" href="http://heartbeats.jp/hbblog/2011/12/way-2011.html" />
    <id>tag:heartbeats.jp,2011:/hbblog//2.55</id>

    <published>2011-12-27T15:34:16Z</published>
    <updated>2011-12-27T15:43:06Z</updated>

    <summary>こんにちは。CTOの馬場です。 2011年も残すところあと数日となりました。  ...</summary>
    <author>
        <name>馬場俊彰</name>
        <uri>http://heartbeats.jp/</uri>
    </author>
    
    
    <content type="html" xml:lang="ja" xml:base="http://heartbeats.jp/hbblog/">
        <![CDATA[<p>こんにちは。CTOの馬場です。</p>

<p>2011年も残すところあと数日となりました。 <br />
もういくつか寝ると2012年の幕開けです。  </p>

<p>来年のことを言うと鬼に笑われてしまいますので、
このインフラエンジニアwayの
<strong>2011年間アクセスランキング</strong> 
をもとに今年の振り返りをしてみましょう。</p>
]]>
        <![CDATA[<h1>10. <a href="http://heartbeats.jp/hbblog/2011/11/cacti-087h.html">cacti 0.8.7hでハマった件の顛末</a></h1>

<p>cacti最新版のbugで苦労した話。0.8.7hは地雷でした...</p>

<h1>9. <a href="http://heartbeats.jp/hbblog/2009/09/ubuntu-server-904-nagios30.html">Ubuntu Server 9.04 で Nagios3.0 を使う</a></h1>

<p>Nagiosインストラクションシリーズの中のエントリ。Ubuntu Serverの人気にあやかっています</p>

<h1>8. <a href="http://heartbeats.jp/hbblog/2010/04/post.html">プリンタで印刷できない大きなサイズを印刷する方法</a></h1>

<p>ライフハックなエントリ。誰かもっといい方法知らないですか...</p>

<h1>7. <a href="http://heartbeats.jp/hbblog/2010/05/mod-proxy-balancersorry.html">mod<em>proxy</em>balancerでsorryサーバを実現する</a></h1>

<p>ドキュメントの落とし穴。nginxが人気ですが、apacheだって現役です！</p>

<h1>6. <a href="http://heartbeats.jp/hbblog/2011/02/python-1.html">Pythonで日本語メールヘッダをデコードする</a></h1>

<p>メールの日本語処理って鬼門ですよねぇ。このくらい標準ライブラリで用意してほしいところです。</p>

<h1>5. <a href="http://heartbeats.jp/hbblog/2010/10/skype4pyskype.html">Skype4Pyを使ってコマンドラインからSkypeを使う</a></h1>

<p>モリヨシさんの<a href="http://d.hatena.ne.jp/moriyoshi/20100926/1285517353">Linux上で動くSkype用のbotを作る方法 - muddy brown thang</a>を噛み砕いた感じのエントリ。モリヨシさんのおこぼれで年間アクセス5位。さすがモリヨシさん。</p>

<h1>4. <a href="http://heartbeats.jp/hbblog/2009/09/nagios.html">Nagiosプラグインの紹介</a></h1>

<p>Nagiosプラグイン67個の解説です。力作すぎて書くのすごい疲れた思い出。</p>

<h1>3. <a href="http://heartbeats.jp/hbblog/2009/10/nagios-1.html">Nagiosプラグイン自作方法の紹介</a></h1>

<p>スタッフ発のエントリ。このあたりからアクセス数が跳ね上がります。3位は5位の倍近いアクセス数でした。</p>

<h1>2. <a href="http://heartbeats.jp/hbblog/2010/09/bash.html">覚えておきたいbashシェルスクリプトのオプション</a></h1>

<p>実践から生まれた小ネタ。シェルスクリプトをデバッグ実行する方法などを記載した、インフラエンジニアライフハック的なエントリ。</p>

<h1>1. <a href="http://heartbeats.jp/hbblog/2010/12/cgroups.html">超期待の新機能cgroups</a></h1>

<p>非常に地味(笑)で堅実なネタ、cgroupsの概要についてのエントリです。</p>

<h1>ちなみに</h1>

<p>じつはTOP5で全体の約60%、TOP10で全体の約77%のアクセス数でした。</p>

<p>TOP10のうち、2011年のエントリが2本、2010年のエントリが5本、2009年のエントリが3本でした。
古いエントリでも基礎的な内容は長くにわたりアクセスがありますね。</p>

<p>これからも、しっかりしたネタを織りまぜつつ色々と発信していきます！</p>

<p>来年も引き続き<a href="http://heartbeats.jp/">heartbeats</a>と<a href="http://heartbeats.jp/hbstudy/">hbstudy</a>と<a href="http://heartbeats.jp/hbblog/">インフラエンジニアway</a>をよろしくお願いします！</p>
]]>
    </content>
</entry>

<entry>
    <title>cacti 0.8.7hでハマった件の顛末</title>
    <link rel="alternate" type="text/html" href="http://heartbeats.jp/hbblog/2011/11/cacti-087h.html" />
    <id>tag:heartbeats.jp,2011:/hbblog//2.53</id>

    <published>2011-11-10T17:36:29Z</published>
    <updated>2011-11-10T18:22:29Z</updated>

    <summary>こんにちは。CTOの馬場です。 だいぶご無沙汰ですが、今回もインフラエンジニア向...</summary>
    <author>
        <name>馬場俊彰</name>
        <uri>http://heartbeats.jp/</uri>
    </author>
    
        <category term="cacti" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="ja" xml:base="http://heartbeats.jp/hbblog/">
        <![CDATA[<p>こんにちは。CTOの馬場です。</p>

<p>だいぶご無沙汰ですが、今回もインフラエンジニア向けにちょっとした情報を紹介します。  </p>

<p>今回はcacti 0.8.7hでハマったので、その顛末と回避方法を書いておきます。</p>

<p>ハマった事象は <strong>「データ取得は正常だけどrrdファイルが更新されない」</strong> でした。。。</p>

<h1>環境</h1>

<ul>
<li>CentOS 5.6</li>
<li>apache 2.2.21 (ソースインストール)</li>
<li>php 5.3.8 (ソースインストール)</li>
<li>MySQL 5.5.15 (本家謹製rpm)</li>
<li>cacti 0.8.7h + spine</li>
</ul>

<p>イケてるtemplateが使いたかったので、<a href="http://groups.google.com/group/better-cacti-templates">better-cacti-templates</a> を使えるように試行錯誤したのでした。</p>
]]>
        <![CDATA[<h1>ログを集めた</h1>

<p>何はなくともログです。ログ。</p>

<ul>
<li>cactiのweb管理画面で Settings > General > Poller Logging Level をDEVELにしてログ確認</li>
<li>pollerの出力をファイルに出してチェック</li>
</ul>

<p>すると、、、ログに下記の出力がありました。</p>

<ul>
<li><code>CACTI2RRD: rrdtool update &lt;filename&gt; --template  99999:99999</code></li>
<li><code>ERROR: Not enough arguments</code></li>
</ul>

<p>前者のほう、よくよく見るとrrdtoolのsyntaxが間違っている。よくよく見ると、本当は<code>--template</code>の後は引数2つなんです。</p>

<p>rrdtoolのsyntax errorの結果、後者が出力されてました。
このせいでrrdファイルが更新されません。</p>

<h1>回避策を探す</h1>

<p>とりあえずエラーメッセージでググる。</p>

<p><a href="http://forums.cacti.net/viewtopic.php?f=2&amp;t=41673">Poller is missing template parameter according to cacti.log</a></p>

<p>すると、データ取得スクリプトの余計な空行を削除せよ、とのこと。</p>

<p>さっそくやってみると...効果なし。色々試しても効果なし。効果なし。なし。。</p>

<h1>デバッグ</h1>

<p>公式のデバッグマニュアルを見ながらデバッグ <br />
<a href="http://docs.cacti.net/manual:087:4_help.2_debugging">manual:087:4<em>help.2</em>debugging - Cacti Docs</a></p>

<ol>
<li>Check Cacti Log File</li>
<li>Check Basic Data Gathering</li>
<li>Check Cacti's Poller</li>
<li>Check MySQL Update</li>
<li>Check RRD File Update</li>
</ol>

<p>今までの調査で 5. はダメなのがわかっていて、 
3. はokなのがわかっているので、
4. を実施。</p>

<h2>Check MySQL Update</h2>

<p>mysqlの設定を変更して全クエリを出力したのでした。 <br />
設定したら、 <code>show variables</code> して結果の確認を忘れずに！</p>

<ul>
<li><code>set global log_slow_queries=On</code></li>
<li><code>set global long_query_time=0;</code></li>
</ul>

<p>この状態でpollingが走ると、mysqlに対して実行された全クエリがスローログに出力されます。かなり大量なのでびっくりしてください。</p>

<p>実行されたクエリが取得できたら、データソースのIDを頼りに、 <code>poller_output</code> テーブルにデータを投入している箇所を探します。</p>

<pre>
INSERT INTO poller_output (local_data_id, rrd_name, time, output) 
VALUES ( データ ), ( データ ), ( データ ), ( データ ), ( データ ), ( データ ), ( データ ) 
ON DUPLICATE KEY UPDATE output=VALUES(output);
</pre>

<p>このクエリを手動でも実行してみて、データが正常に投入できているかどうか、取得できるかを確認します。</p>

<p>...今回はここは正常でした。明らかにオカシイ。まぁもともとオカシイから調べてるんですが。。。</p>

<h2>ソース読み</h2>

<p>公式マニュアルのお陰でMySQLが原因ではないことがわかったので、ハラを決めてソースを読みます。</p>

<p>今回はログに <code>CACTI2RRD: rrdtool update 〜</code> と記載があり、ここがおかしいことはわかっていたので、この <code>CACTI2RRD</code> ととっかかりに調査します。</p>

<pre>
# find /var/www/cacti/ -type f -name "*.php"|xargs grep -nHi "CACTI2RRD"
/var/www/cacti/lib/rrd.php:80:          cacti_log("CACTI2RRD: " . read_config_option("path_rrdtool") . " $command_line", $log_to_stdout, $logopt);
/var/www/cacti/lib/rrd.php:399:                         cacti_log("CACTI2RRD: " . read_config_option("path_rrdtool") . " tune $data_source_path $rrd_tune");
</pre>

<p>2箇所しかない！ということで、rrd.phpを見てみます。</p>

<ul>
<li><code>rrdtool_execute</code> 関数の中で呼ばれているのがクサい  </li>
<li>→ <code>rrdtool_execute</code> と <code>update</code> の組み合わせで呼ばれている行を探す  </li>
<li>→ <code>rrdtool_function_update</code> がクサい  </li>
<li>→ 呼んでいる箇所を探す。同じファイルにはないのでfindとxargsを組み合わせて探す  </li>
<li>→ <code>/var/www/cacti/lib/poller.php</code> でしか呼んでない  </li>
<li>→ <code>/var/www/cacti/lib/poller.php</code> を該当箇所からさかのぼって読む。読む。  </li>
<li>→ 実行されているはずのSQLが実行されていない！</li>
<li>→ 分岐がおかしい！</li>
<li>→ <code>is_hexadecimal</code>関数の結果がおかしい！</li>
<li>→ 定義されている箇所が見当たらないのでfindとxargsを組み合わせて探す</li>
<li>→ <code>lib/functions.php</code>にあった！</li>
</ul>

<p>と、いうわけで、 <code>lib/functions.php</code> の <code>is_hexadecimal</code> 関数を修正して対応完了。</p>

<p>コーディングミスで複数値対応ができなくなっていたようです。 <br />
(推測ですがipv6対応したかったもよう)</p>

<h1>SVNみてみる</h1>

<p>最新版(0.8.7のHEAD)では直ってる...</p>

<p>rev 6251→6252(2011/1/29)でエンバグして、rev 6850→6851(2011/10/9)に改修されてました。</p>

<h1>まとめ</h1>

<p>オープンソースでよかった。</p>
]]>
    </content>
</entry>

<entry>
    <title>botoを使ってEBSをバックアップ(世代管理つき)</title>
    <link rel="alternate" type="text/html" href="http://heartbeats.jp/hbblog/2011/04/botoebs.html" />
    <id>tag:heartbeats.jp,2011:/hbblog//2.47</id>

    <published>2011-04-27T23:15:28Z</published>
    <updated>2011-04-27T23:33:57Z</updated>

    <summary>こんにちは。CTOの馬場です。 今回もインフラエンジニア向けにちょっとした情報を...</summary>
    <author>
        <name>馬場俊彰</name>
        <uri>http://heartbeats.jp/</uri>
    </author>
    
    
    <content type="html" xml:lang="ja" xml:base="http://heartbeats.jp/hbblog/">
        <![CDATA[<p>こんにちは。CTOの馬場です。</p>

<p>今回もインフラエンジニア向けにちょっとした情報を紹介します。 <br />
少し間があいてしまいましたが今回は珍しくAWSネタです。</p>

<p>botoを使ってEBSをバックアップする方法を紹介します。</p>
]]>
        <![CDATA[<p>元ネタは <a href="http://twitter.com/d_sea">@d_sea</a> さんの <a href="http://d.hatena.ne.jp/d_sea/20091026/p1">Amazon EBS と boto を使って自動バックアップ環境を構築する</a> ですが少しだけupdateしています。</p>

<ul>
<li>Volume IDとDescriptionが同じsnapshotを、指定した世代数だけ保持するよう変更した <br />
(同じVolume IDのEBSを別のDescriptionで保存した場合に、世代にカウントされないようにした) <br />
→手動バックアップと自動バックアップを区別できるようになりました</li>
<li>リージョンを指定できるようにした</li>
</ul>

<p>boto-1.9bで動作を確認しています。
エラー処理がアレなのはご愛嬌で。</p>

<p><code>AWS_ACCESS_KEY_ID</code>、<code>AWS_SECRET_ACCESS_KEY</code>には、
webの アカウント＞セキュリティ証明書＞アクセスキー(タブ)　で表示されるものを指定してください。</p>

<pre>
#!/usr/bin/python 
import sys
import re
from boto import config
from boto import  ec2
from boto.ec2.connection import EC2Connection

AWS_ACCESS_KEY_ID = ''
AWS_SECRET_ACCESS_KEY = ''
DESCRIPTION = 'daily backup'
REGION_NAME = 'us-west-1'

if(len(sys.argv) != 3):
    print "Usage: ebs-snapshot.py &lt;num&gt; &lt;volume-id&gt;"
    sys.exit()
regions = ec2.regions(aws_access_key_id=AWS_ACCESS_KEY_ID,aws_secret_access_key=AWS_SECRET_ACCESS_KEY)
for r in regions:
    if r.name == REGION_NAME:
        _region=r
conn = EC2Connection(aws_access_key_id=AWS_ACCESS_KEY_ID,aws_secret_access_key=AWS_SECRET_ACCESS_KEY,region=_region)
conn.create_snapshot(volume_id=sys.argv[2], description=DESCRIPTION) 
snapshot = {}
for x in conn.get_all_snapshots(): 
    if((x.volume_id == sys.argv[2]) and (x.description == DESCRIPTION)): 
        tmp = {x.id:x.start_time} 
        snapshot.update(tmp) 
snapshot = sorted(snapshot.items(), key=lambda (k, v): (v, k), reverse=True) 
for i in range(int(sys.argv[1]), len(snapshot)): 
    conn.delete_snapshot(snapshot[i][0]) 
</pre>

<p>利用例(cronで実行)</p>

<pre>
30 5 * * * /opt/backup/bin/ebs_snapshot.py 3 vol-XXXXXXXX
</pre>

<p>簡単ですね！</p>
]]>
    </content>
</entry>

<entry>
    <title>Pythonで日本語メールヘッダをデコードする</title>
    <link rel="alternate" type="text/html" href="http://heartbeats.jp/hbblog/2011/02/python-1.html" />
    <id>tag:heartbeats.jp,2011:/hbblog//2.44</id>

    <published>2011-02-06T23:01:55Z</published>
    <updated>2011-02-06T23:13:18Z</updated>

    <summary>こんにちは。CTOの馬場です。 今回もインフラエンジニア向けにちょっとした情報を...</summary>
    <author>
        <name>馬場俊彰</name>
        <uri>http://heartbeats.jp/</uri>
    </author>
    
        <category term="Python" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="ja" xml:base="http://heartbeats.jp/hbblog/">
        <![CDATA[<p>こんにちは。CTOの馬場です。</p>

<p>今回もインフラエンジニア向けにちょっとした情報を紹介します。</p>

<p>インフラエンジニアをしていると、なんだかんだとメールを解析して処理をしたいシーンって多いですよね。 <br />
でも日本語のメールって色々大変ですよね。</p>

<p>特に大変なのがヘッダ部分。 <br />
ヘッダ部分はエンコードされていたり、長いと複数行にまたがったり、複数行の場合はデコードして結合してから処理したり・・・</p>

<p>今回はそんなあなた(=私)向けに、日本語メールのメールヘッダをうまく取り扱う方法を紹介します。</p>
]]>
        <![CDATA[<p>そんなわけでサンプルは下記のとおりです。 <br />
Pythonの標準ライブラリだけで実現できます。</p>

<p>第一引数にメールファイルのパスを指定すると、
From, To, Subjectを取得して表示します。</p>

<p>例: <code>python mail_header_decoder.py hoge.eml</code></p>

<pre><code>
#!/usr/bin/env python
#coding: utf-8

from email.Header import decode_header
from email.Parser import Parser
from sys          import argv,stdout
import re

NEWLINE=re.compile(r'(\r|\n|\r\n)$')
DEFAULT_ENCODING='iso-2022-jp'

def decode_header_multiline(message=None,name='',encoding=None):
    str_encoded=''
    for str_line in NEWLINE.split(message.get(name)):
        decoded_headers=decode_header(str_line)
        for parts in decoded_headers:
            str_encoded = str_encoded + parts[0]
            if encoding == None and  not parts[1] == None:
                encoding=parts[1]
    encoding=DEFAULT_ENCODING if encoding == None else encoding
    return str_encoded.decode(encoding)

def main():
    msg=Parser().parse(open(argv[1]))
    header_from   =decode_header_multiline(msg,'From')
    header_to     =decode_header_multiline(msg,'To')
    header_subject=decode_header_multiline(msg,'Subject')
    result="From: %s, To: %s, Subject: %s"%(
        header_from,
        header_to,
        header_subject,
        )
    stdout.write(result.encode('utf-8'))
    stdout.write('\n')

if __name__ == '__main__':
    main()
</code></pre>

<p>※Python 2.6.1で動作確認しています。 <br />
　デコード周りが若干怪しいような気がしないでもないですが、
　動作確認する限りはこれでうまく動いています。</p>
]]>
    </content>
</entry>

<entry>
    <title>超期待の新機能cgroups</title>
    <link rel="alternate" type="text/html" href="http://heartbeats.jp/hbblog/2010/12/cgroups.html" />
    <id>tag:heartbeats.jp,2010:/hbblog//2.41</id>

    <published>2010-12-06T13:53:21Z</published>
    <updated>2010-12-06T14:00:23Z</updated>

    <summary>こんにちは。CTOの馬場です。 今回もインフラエンジニア向けにちょっとした情報を...</summary>
    <author>
        <name>馬場俊彰</name>
        <uri>http://heartbeats.jp/</uri>
    </author>
    
        <category term="Linux" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="ja" xml:base="http://heartbeats.jp/hbblog/">
        <![CDATA[<p>こんにちは。CTOの馬場です。</p>

<p>今回もインフラエンジニア向けにちょっとした情報を紹介します。</p>

<p>今回は、先日参加した <a href="http://www.jp.redhat.com/event/2010/RedHatForum.html">レッドハットフォーラム 2010</a> で紹介されていた cgroups について紹介します。</p>

<p>※注：ざっくりとした理解で書いているので、誤りがあれば指摘してもらえると嬉しいです！</p>

<p>ここが理解が違う、こんな使い方もあるよ！などの情報は、twitterで
<a href="http://twitter.com/heartbeatsjp/">@heartbeatsjp</a>
<a href="http://twitter.com/hbstudy/">@hbstudy</a>
<a href="http://twitter.com/toshiak_netmark/">@toshiak_netmark</a>
あたりに教えてもらえると嬉しいです。</p>
]]>
        <![CDATA[<h1>cgroupsとは？</h1>

<p>cgroupsは Control Groupsの略で、
Linux kernelに組み込まれているリソース割り当て管理機能です。</p>

<p>「期待の新機能」とかタイトルつけましたが、
マージされたのは2.6.2xの頃のようなのでかなり時間は経っていますね。 <br />
RHEL的に新機能なので、ご愛嬌ということで。</p>

<p>プロセス(プロセスグループ)ごとに、下記のリソースの割り当てを変更できます。</p>

<ul>
<li>CPU</li>
<li>メモリ</li>
<li>ディスクI/O</li>
<li>ネットワークI/O</li>
</ul>

<h1>ざっくりとした使い方</h1>

<p>Linuxなので、ファイルベースで管理します。</p>

<ol>
<li>cgroupファイルシステムをマウントして</li>
<li>cgroupを作成して</li>
<li>CPU、メモリなどのリソース割り当てを定義して</li>
<li>PIDをcgroupに登録する</li>
</ol>

<p>といった感じです。</p>

<p>詳しくは
<a href="http://www.kernel.org/doc/Documentation/cgroups/cgroups.txt">公式ドキュメントの1.5 How do I use cgroups ?</a>
を見てください。</p>

<p>使い方は 2. Usage Examples and Syntax にとても丁寧に書いてあります。</p>

<h1>使いどころ</h1>

<p>レッドハットフォーラム 2010の会場でも宣伝していましたが、
KVMを利用した仮想化基盤でのリソース割り当て管理に最適です。</p>

<p>いままで難しかった「VMごとのディスク・ネットワークI/O制御」がついに実現します！</p>

<p>スゴいでしょう？スゴいですよね？スゴいんですよ。</p>

<h1>詳しい情報</h1>

<p>公式ドキュメントを読みましょう ;)</p>

<p><a href="http://www.kernel.org/doc/Documentation/cgroups/cgroups.txt">http://www.kernel.org/doc/Documentation/cgroups/cgroups.txt</a></p>

<p>最新のLinux kernelにはマージされていますが、
RHEL/CentOS 5.xでは利用できないようです。</p>

<p>RHEL6では利用できるそうなので、これからが楽しみですね。</p>
]]>
    </content>
</entry>

<entry>
    <title>unboundをrpmでインストール</title>
    <link rel="alternate" type="text/html" href="http://heartbeats.jp/hbblog/2010/10/unboundrpm.html" />
    <id>tag:heartbeats.jp,2010:/hbblog//2.38</id>

    <published>2010-10-27T05:07:13Z</published>
    <updated>2010-10-27T05:15:35Z</updated>

    <summary>こんにちは。CTOの馬場です。 今回もインフラエンジニア向けにちょっとした情報を...</summary>
    <author>
        <name>馬場俊彰</name>
        <uri>http://heartbeats.jp/</uri>
    </author>
    
    
    <content type="html" xml:lang="ja" xml:base="http://heartbeats.jp/hbblog/">
        <![CDATA[<p>こんにちは。CTOの馬場です。</p>

<p>今回もインフラエンジニア向けにちょっとした情報を紹介します。</p>

<p>今回は・・・本当にちょっとしたネタです。。。 <br />
unboundをrpmでインストールする方法をご紹介します。</p>

<p>unbound、いいですよね。楽で。 <br />
DNS RR非対応な点以外は、とてもイイ！</p>
]]>
        <![CDATA[<p>CentOS 5.5 64bitでやってみてます。</p>

<pre><code>
sudo yum -y install openssl-devel flex libevent-devel rpm-build gcc expect

wget http://www.unbound.net/downloads/unbound-1.4.6.tar.gz
sudo cp unbound-1.4.6.tar.gz /usr/src/redhat/SOURCES/.
tar zxf unbound-1.4.6.tar.gz
perl -pi -e 's/^Version:.*/Version: 1.4.6/' unbound-1.4.6/contrib/unbound.spec
perl -pi -e 's/^%configure (.*)/%configure $1 --with-libevent/' unbound-1.4.6/contrib/unbound.spec
sudo rpmbuild -ba unbound-1.4.6/contrib/unbound.spec
sudo rpm -ivh /usr/src/redhat/RPMS/x86_64/unbound-1.4.6-1.x86_64.rpm
</code></pre>

<p>sudoがNOPASSWDなら、切って貼るだけ。すばらしい！</p>

<p>(間違ってたら教えてください)</p>
]]>
    </content>
</entry>

<entry>
    <title>Proxy越しのDigest認証</title>
    <link rel="alternate" type="text/html" href="http://heartbeats.jp/hbblog/2010/10/proxydigest.html" />
    <id>tag:heartbeats.jp,2010:/hbblog//2.37</id>

    <published>2010-10-21T04:27:38Z</published>
    <updated>2010-10-21T04:40:18Z</updated>

    <summary>こんにちは。CTOの馬場です。 今回もインフラエンジニア向けにちょっとした情報を...</summary>
    <author>
        <name>馬場俊彰</name>
        <uri>http://heartbeats.jp/</uri>
    </author>
    
        <category term="Apache" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="ja" xml:base="http://heartbeats.jp/hbblog/">
        <![CDATA[<p>こんにちは。CTOの馬場です。</p>

<p>今回もインフラエンジニア向けにちょっとした情報を紹介します。</p>

<p>今回は一部で話題になっていた「Proxy越しのDigest認証」について、
ちょっとしたコツがあるのでノウハウを公開します。</p>
]]>
        <![CDATA[<p>前提として、</p>

<ul>
<li>Digest認証は、認証情報の中にURIを保持しています</li>
<li>Digest認証では、 <code>mod_auth</code> で <strong>「リクエストされたURI」</strong> と <strong>「認証情報の中のURI」</strong> の整合を確認しています</li>
</ul>

<p>と、いうことです。</p>

<p>なので、backendサーバで <code>mod_auth</code> が認証処理をする時に、
<strong>「リクエストされたURI」</strong> と <strong>「認証情報の中のURI」</strong> が一致している必要があります。</p>

<p>大抵の場合、次の図の構成になっていると思いますが、</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://heartbeats.jp/hbblog/assets_c/2010/10/proxy-digest01-26.html" onclick="window.open('http://heartbeats.jp/hbblog/assets_c/2010/10/proxy-digest01-26.html','popup','width=992,height=252,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="http://heartbeats.jp/hbblog/assets_c/2010/10/proxy-digest01-thumb-450x114-26.png" width="450" height="114" alt="proxy-digest01.png" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></span></p>

<p>これを、次の図のように変えることで両立させることができるようになります。</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://heartbeats.jp/hbblog/assets_c/2010/10/proxy-digest02-29.html" onclick="window.open('http://heartbeats.jp/hbblog/assets_c/2010/10/proxy-digest02-29.html','popup','width=1100,height=357,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="http://heartbeats.jp/hbblog/assets_c/2010/10/proxy-digest02-thumb-450x146-29.png" width="450" height="146" alt="proxy-digest02.png" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></span></p>

<p>ポイントは、RewriteするときにPT(PassThrough)を指定することです。 <br />
このフラグ指定により、 <code>mod_proxy</code> 通過後に <code>mod_auth</code> に渡されるリクエストURIが、
元(=backendが受け取ったそのもの)のままになります。</p>

<pre>　RewriteRule ^/proxied/(.*)$ /origin/$1 [PT]
</pre>

<p>別解として、proxyで認証情報をいじる方法(できればそのほうが設定が楽)もありそうですが、
まずは1つの方法として公開しておきます。</p>
]]>
    </content>
</entry>

</feed>

