ソフトウェアアーキテクチャ チートシート

このブログ記事の内容がよかったので、翻訳してみた。
原文はこちら http://gorban.org/post/32873465932/software-architecture-cheat-sheet
あまり英語はうまくないので誤訳御免。

============================================
ここ数週間ソフトウェアアーキテクチャにどのようにアプローチしたらよいかを考えてた。いくつかアプリ開発を経験したけど、将来のプロジェクトで良い仕事をするために、もっともっと勉強したくなった。

このトピックについていくつか記事や本を読んだ。要点を抽出し、最重要事項を一枚のシートにまとめることが目標だ。それを壁に貼っておいて、チラッと見て確認できるようにしたかったんだ。そのシートはソフトウェアをデザインする際の重要事項をコミットする前に、自分自身でよく考えることを強制するんだ。

今日、ついに完成したから印刷して壁に貼っておいたよ!
PDFでダウンロードできるように用意したから、好きなようにしていいよ!
PDFはこちら

それじゃ、その内容について解説する。



それは "良いアイディア" か?

Avoid "Good Ideas"」からの引用だよ。

"良いアイディア" というのは潜在的に本当に "いいもの" だ。誰しも "悪いもの" を認識しリジェクトすることができる。良いものは、ビジネスに不要なトラブルを引き起こしたり、複雑だったり、悪い影響を与えない。

言い換えれば、これは本当に必要か考えよう、そうしないと徐々に悪化していくぞ、ということ。ソフトウェアの複雑さは指数的に増加する。2つの機能を有すれば、そのコードは2倍以上複雑になる。



DRY. Don't Repeat Yourself

DRY はよく知られたソフトウェアデザインの原則だ。「Pragmatic Programmers」にもこの説明があって、"システムにおいてすべてのナレッジのかけらは単一であり、明白であり、信頼できる表現であるべきである" としている。
ボクはすでにDRYについては本能的に習慣づけてたよ。だけどすごく良い情熱的なアイディアなので、忘れないようにしたいね。



直交性か?(※どうやら独立性をもったアーキテクチャのことらしい?こちらの記事が参考になった2007-03-22

言い換えれば、どうやってシステムからモジュールやブロックを独立させようか?ということだ。ソフトウェアにおいてモジュール性は重要だ。後の人生を楽にするし、可読性が高まる。



テスト可能か?

システムにおいてどうやってテストするか考えよう。テストが簡単になるようなデザインになってる?テスタビリティはモジュール性、複雑さ、コードスタイルに依存するよ。テストすることは重要だ。マニュアルテストは良いことだ。自動テストはもっといい。



他に方法はあるか?

これはまた「Pragmatic Programmers」から。この本は各チャプターにいいことが書かれてる。Emil-Augste Chartier が "アイディアがひとつしかないことよりも危険なことはない" と言っている。
問題を解決する時に別解があるとハッピーだ。不幸なことに、はじめの解決法はベストじゃないこともしばしばだ。もう一度考えよう、クリエイティブに、違うアプローチをためそう。新しいアイディアが浮かんだ時、次のアイディアは多少よくなって、多分最初のアイディアは急ぎすぎだったと思うんじゃないかな。



あとで修正するときのコストはどれくらい?

決定を採用する前に考慮しよう。プロジェクトの後のフェイズで何が修正のコストになる?この決定は従える?もしその決定が明確じゃなければ、後に修正するとき、それを破壊しないまたは不要な仕事を増やさないでデザインすることができるかい?



もし問題がなかったら?

これは「Don't Be a Problem Solver」からの引用だ。

設計者はすぐさま問題解決しなきゃいけないときがある。その問題はすでに忘れていたことだったり、学んだことがないことだったりする。だから我々は望遠鏡のようにズームイン/アウトしながら問題の骨組みを明らかにして学ばなければいけない。単に与えられたことを受け入れるだけじゃダメだ。
現在起こっている問題にすぐとりかかるまえに、その問題自体を変更できないか考えよう。設計がどうなっているか、自分自身に問題がなかったかを考えよう。そうすることで、エレガントで恒久的な解決法を導くことができるはずだ。




何が事実で何が前提?根拠をドキュメント化しよう。

最後の二つは「Challenge assumptions - especially your own」から。

それぞれの決定において、どのようなトレードオフがあるか(パフォーマンス vs メンテナンス性、コスト vs 開発期間 などなど...)などの根拠を記すことは、ソフトウェアアーキテクチャのベストプラクティスだ。
このプラクティスは各要因をリスト化し、設計デザインにおける決定に影響する前提を目立たせる助けになる。(※訳難しい・・・)時々これらの前提は "歴史的背景"、意見、開発者の言い伝え、FUD(〜かもしれない、と根拠のない恐れを言うこと)が根拠になることがある...

言い換えれば、ソフトウェア設計をデザインしているときには、なぜその決定を下したかの事実と前提を書きだそう、ということだ。前提をチェックしようね。

事実と前提はソフトウェアの柱になる。いずれにせよ基礎はしっかりしよう。

PDFのダウンロードはこちらから。


なにか意見や質問があれば、連絡してね!※ただし、英語。

=======================================================
内容について意見があればこちら
http://gorban.org/post/32873465932/software-architecture-cheat-sheet
ここのページの下の方でコメントしたり、筆者のツイッターも公開してるので、そちらで連絡してください。
翻訳についての意見があれば、私に連絡ください。

一応本人の許可とりました。
https://twitter.com/katsuren/status/254081573165621248
https://twitter.com/apparentsoft/status/254093703185051650

CentOS 6.2 サーバー構築手順

今まで何回かLinux構築やってて前の記事も古くなってきたので、ここらで新しく記事を書きなおすことにした。そして色々なミドルウェアの入れ方も一緒に書いておく。下記はその一覧。

目次

  1. サーバーの前準備
    1. パッケージの更新
    2. ファイアウォールの設定
    3. ユーザーの作成
  2. 必要なライブラリのインストール
    1. epelリポジトリの追加
    2. ライブラリのインストール
  3. MySQLのインストール
  4. Apacheのインストール
  5. PHPのインストール

サーバーの前準備

パッケージの更新

何はともあれインストールされているパッケージの更新を行う。

# yum -y update




ファイアウォールの設定

余分なポートは閉じる。解放ポートの追加/削除は適宜自分で設定すること。
このスクリプトはこちらを参考にさせてもらった。
俺史上最強のiptablesをさらす - Qiita
iptables.sh を下記のように作成。

# vim /etc/sysconfig/iptables.sh

#!/bin/bash

###########################################################
# このスクリプトの特徴
#
# 受信・通過については基本的に破棄し、ホワイトリストで許可するものを指定する。
# 送信については基本的に許可する。ただし、サーバが踏み台になり外部のサーバに迷惑をかける可能性があるので、
# 心配な場合は、送信も受信同様に基本破棄・ホワイトリストで許可するように書き換えると良い。
###########################################################

###########################################################
# 用語の統一
# わかりやすさのためルールとコメントの用語を以下に統一する
# ACCEPT : 許可
# DROP   : 破棄
# REJECT : 拒否
###########################################################

###########################################################
# チートシート
#
# -A, --append       指定チェインに1つ以上の新しいルールを追加
# -D, --delete       指定チェインから1つ以上のルールを削除
# -P, --policy       指定チェインのポリシーを指定したターゲットに設定
# -N, --new-chain    新しいユーザー定義チェインを作成
# -X, --delete-chain 指定ユーザー定義チェインを削除
# -F                 テーブル初期化
#
# -p, --protocol      プロコトル         プロトコル(tcp、udp、icmp、all)を指定
# -s, --source        IPアドレス[/mask]  送信元のアドレス。IPアドレスorホスト名を記述
# -d, --destination   IPアドレス[/mask]  送信先のアドレス。IPアドレスorホスト名を記述
# -i, --in-interface  デバイス           パケットが入ってくるインターフェイスを指定
# -o, --out-interface デバイス           パケットが出ていくインターフェイスを指定
# -j, --jump          ターゲット         条件に合ったときのアクションを指定
# -t, --table         テーブル           テーブルを指定
# -m state --state    状態              パケットの状態を条件として指定
#                                       stateは、 NEW、ESTABLISHED、RELATED、INVALIDが指定できる
# !                   条件を反転(〜以外となる)
###########################################################

# パス
PATH=/sbin:/usr/sbin:/bin:/usr/bin

###########################################################
# IPの定義
# 必要に応じて定義する。定義しなくても動作する。
###########################################################

# 内部ネットワークとして許可する範囲
# LOCAL_NET="xxx.xxx.xxx.xxx/xx"

# 内部ネットワークとして一部制限付きで許可する範囲
# LIMITED_LOCAL_NET="xxx.xxx.xxx.xxx/xx"

# 全てのIPを表す設定を定義
# ANY="0.0.0.0/0"

# 信頼可能ホスト(配列)
# ALLOW_HOSTS=(
#   "xxx.xxx.xxx.xxx"
#   "xxx.xxx.xxx.xxx"
#   "xxx.xxx.xxx.xxx"
# )

# 無条件破棄するリスト(配列)
# DENY_HOSTS=(
#   "xxx.xxx.xxx.xxx"
#   "xxx.xxx.xxx.xxx"
#   "xxx.xxx.xxx.xxx"
# )

###########################################################
# ポート定義
###########################################################

SSH=22
FTP=20,21
DNS=53
SMTP=25,465,587
POP3=110,995
IMAP=143,993
HTTP=80,443,8080,8443
IDENT=113
NTP=123
DBPORT=3306,6379,27017
NET_BIOS=135,137,138,139,445
DHCP=67,68

###########################################################
# 関数
###########################################################

# iptablesの初期化, すべてのルールを削除
initialize() 
{
    iptables -F # テーブル初期化
    iptables -X # チェーンを削除
    iptables -Z # パケットカウンタ・バイトカウンタをクリア
    iptables -P INPUT   ACCEPT
    iptables -P OUTPUT  ACCEPT
    iptables -P FORWARD ACCEPT
}

# ルール適用後の処理
finailize()
{
    /etc/init.d/iptables save && # 設定の保存
    /etc/init.d/iptables restart && # 保存したもので再起動してみる
    return 0
    return 1
}

# 開発用
if [ "$1" == "dev" ]
then
    iptables() { echo "iptables $@"; }
    finailize() { echo "finailize"; }
fi

###########################################################
# iptablesの初期化
###########################################################
initialize

###########################################################
# ポリシーの決定
###########################################################
iptables -P INPUT   DROP # すべてDROP。すべての穴をふさいでから必要なポートを空けていくのが良い。
iptables -P OUTPUT  ACCEPT
iptables -P FORWARD DROP

###########################################################
# 信頼可能なホストは許可
###########################################################

# ローカルホスト
# lo はローカルループバックのことで自分自身のホストを指す
iptables -A INPUT -i lo -j ACCEPT # SELF -> SELF

# ローカルネットワーク
# $LOCAL_NET が設定されていれば LAN上の他のサーバとのやり取りを許可する
if [ "$LOCAL_NET" ]
then
    iptables -A INPUT -p tcp -s $LOCAL_NET -j ACCEPT # LOCAL_NET -> SELF
fi

# 信頼可能ホスト
# $ALLOW_HOSTS が設定されていれば そのホストとのやり取りを許可する
if [ "${ALLOW_HOSTS[@]}" ]
then
    for allow_host in ${ALLOW_HOSTS[@]}
    do
        iptables -A INPUT -p tcp -s $allow_host -j ACCEPT # allow_host -> SELF
    done
fi

###########################################################
# $DENY_HOSTSからのアクセスは破棄
###########################################################
if [ "${DENY_HOSTS[@]}" ]
then
    for host in ${DENY_HOSTS[@]}
    do
        iptables -A INPUT -s $ip -m limit --limit 1/s -j LOG --log-prefix "deny_host: "
        iptables -A INPUT -s $ip -j DROP
    done
fi

###########################################################
# セッション確立後のパケット疎通は許可
###########################################################
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

###########################################################
# 攻撃対策: Stealth Scan
###########################################################
iptables -N STEALTH_SCAN # "STEALTH_SCAN" という名前でチェーンを作る
iptables -A STEALTH_SCAN -j LOG --log-prefix "stealth_scan_attack: "
iptables -A STEALTH_SCAN -j DROP

# ステルススキャンらしきパケットは "STEALTH_SCAN" チェーンへジャンプする
iptables -A INPUT -p tcp --tcp-flags SYN,ACK SYN,ACK -m state --state NEW -j STEALTH_SCAN
iptables -A INPUT -p tcp --tcp-flags ALL NONE -j STEALTH_SCAN

iptables -A INPUT -p tcp --tcp-flags SYN,FIN SYN,FIN         -j STEALTH_SCAN
iptables -A INPUT -p tcp --tcp-flags SYN,RST SYN,RST         -j STEALTH_SCAN
iptables -A INPUT -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j STEALTH_SCAN

iptables -A INPUT -p tcp --tcp-flags FIN,RST FIN,RST -j STEALTH_SCAN
iptables -A INPUT -p tcp --tcp-flags ACK,FIN FIN     -j STEALTH_SCAN
iptables -A INPUT -p tcp --tcp-flags ACK,PSH PSH     -j STEALTH_SCAN
iptables -A INPUT -p tcp --tcp-flags ACK,URG URG     -j STEALTH_SCAN

###########################################################
# 攻撃対策: フラグメントパケットによるポートスキャン,DOS攻撃
# namap -v -sF などの対策
###########################################################
iptables -A INPUT -f -j LOG --log-prefix 'fragment_packet:'
iptables -A INPUT -f -j DROP

###########################################################
# 攻撃対策: Ping of Death
###########################################################
# 毎秒1回を超えるpingが10回続いたら破棄
iptables -N PING_OF_DEATH # "PING_OF_DEATH" という名前でチェーンを作る
iptables -A PING_OF_DEATH -p icmp --icmp-type echo-request \
         -m hashlimit \
         --hashlimit 1/s \
         --hashlimit-burst 10 \
         --hashlimit-htable-expire 300000 \
         --hashlimit-mode srcip \
         --hashlimit-name t_PING_OF_DEATH \
         -j RETURN

# 制限を超えたICMPを破棄
iptables -A PING_OF_DEATH -j LOG --log-prefix "ping_of_death_attack: "
iptables -A PING_OF_DEATH -j DROP

# ICMP は "PING_OF_DEATH" チェーンへジャンプ
iptables -A INPUT -p icmp --icmp-type echo-request -j PING_OF_DEATH

###########################################################
# 攻撃対策: SYN Flood Attack
# この対策に加えて Syn Cookie を有効にすべし。
###########################################################
iptables -N SYN_FLOOD # "SYN_FLOOD" という名前でチェーンを作る
iptables -A SYN_FLOOD -p tcp --syn \
         -m hashlimit \
         --hashlimit 200/s \
         --hashlimit-burst 3 \
         --hashlimit-htable-expire 300000 \
         --hashlimit-mode srcip \
         --hashlimit-name t_SYN_FLOOD \
         -j RETURN

# 解説
# -m hashlimit                       ホストごとに制限するため limit ではなく hashlimit を利用する
# --hashlimit 200/s                  秒間に200接続を上限にする
# --hashlimit-burst 3                上記の上限を超えた接続が3回連続であれば制限がかかる
# --hashlimit-htable-expire 300000   管理テーブル中のレコードの有効期間(単位:ms
# --hashlimit-mode srcip             送信元アドレスでリクエスト数を管理する
# --hashlimit-name t_SYN_FLOOD       /proc/net/ipt_hashlimit に保存されるハッシュテーブル名
# -j RETURN                          制限以内であれば、親チェーンに戻る

# 制限を超えたSYNパケットを破棄
iptables -A SYN_FLOOD -j LOG --log-prefix "syn_flood_attack: "
iptables -A SYN_FLOOD -j DROP

# SYNパケットは "SYN_FLOOD" チェーンへジャンプ
iptables -A INPUT -p tcp --syn -j SYN_FLOOD

###########################################################
# 攻撃対策: HTTP DoS/DDoS Attack
###########################################################
iptables -N HTTP_DOS # "HTTP_DOS" という名前でチェーンを作る
iptables -A HTTP_DOS -p tcp -m multiport --dports $HTTP \
         -m hashlimit \
         --hashlimit 1/s \
         --hashlimit-burst 100 \
         --hashlimit-htable-expire 300000 \
         --hashlimit-mode srcip \
         --hashlimit-name t_HTTP_DOS \
         -j RETURN

# 解説
# -m hashlimit                       ホストごとに制限するため limit ではなく hashlimit を利用する
# --hashlimit 1/s                    秒間1接続を上限とする
# --hashlimit-burst 100              上記の上限を100回連続で超えると制限がかかる
# --hashlimit-htable-expire 300000   管理テーブル中のレコードの有効期間(単位:ms
# --hashlimit-mode srcip             送信元アドレスでリクエスト数を管理する
# --hashlimit-name t_HTTP_DOS        /proc/net/ipt_hashlimit に保存されるハッシュテーブル名
# -j RETURN                          制限以内であれば、親チェーンに戻る

# 制限を超えた接続を破棄
iptables -A HTTP_DOS -j LOG --log-prefix "http_dos_attack: "
iptables -A HTTP_DOS -j DROP

# HTTPへのパケットは "HTTP_DOS" チェーンへジャンプ
iptables -A INPUT -p tcp -m multiport --dports $HTTP -j HTTP_DOS

###########################################################
# 攻撃対策: IDENT port probe
# identを利用し攻撃者が将来の攻撃に備えるため、あるいはユーザーの
# システムが攻撃しやすいかどうかを確認するために、ポート調査を実行
# する可能性があります。
# DROP ではメールサーバ等のレスポンス低下になるため REJECTする
###########################################################
iptables -A INPUT -p tcp -m multiport --dports $IDENT -j REJECT --reject-with tcp-reset

###########################################################
# 攻撃対策: SSH Brute Force
# SSHはパスワード認証を利用しているサーバの場合、パスワード総当り攻撃に備える。
# 1分間に5回しか接続トライをできないようにする。
# SSHクライアント側が再接続を繰り返すのを防ぐためDROPではなくREJECTにする。
# SSHサーバがパスワード認証ONの場合、以下をアンコメントアウトする
###########################################################
iptables -A INPUT -p tcp --syn -m multiport --dports $SSH -m recent --name ssh_attack --set
iptables -A INPUT -p tcp --syn -m multiport --dports $SSH -m recent --name ssh_attack --rcheck --seconds 60 --hitcount 5 -j LOG --log-prefix "ssh_brute_force: "
iptables -A INPUT -p tcp --syn -m multiport --dports $SSH -m recent --name ssh_attack --rcheck --seconds 60 --hitcount 5 -j REJECT --reject-with tcp-reset

###########################################################
# 攻撃対策: FTP Brute Force
# FTPはパスワード認証のため、パスワード総当り攻撃に備える。
# 1分間に5回しか接続トライをできないようにする。
# FTPクライアント側が再接続を繰り返すのを防ぐためDROPではなくREJECTにする。
# FTPサーバを立ち上げている場合、以下をアンコメントアウトする
###########################################################
# iptables -A INPUT -p tcp --syn -m multiport --dports $FTP -m recent --name ftp_attack --set
# iptables -A INPUT -p tcp --syn -m multiport --dports $FTP -m recent --name ftp_attack --rcheck --seconds 60 --hitcount 5 -j LOG --log-prefix "ftp_brute_force: "
# iptables -A INPUT -p tcp --syn -m multiport --dports $FTP -m recent --name ftp_attack --rcheck --seconds 60 --hitcount 5 -j REJECT --reject-with tcp-reset

###########################################################
# 全ホスト(ブロードキャストアドレス、マルチキャストアドレス)宛パケットは破棄
###########################################################
iptables -A INPUT -d 192.168.1.255   -j LOG --log-prefix "drop_broadcast: "
iptables -A INPUT -d 192.168.1.255   -j DROP
iptables -A INPUT -d 255.255.255.255 -j LOG --log-prefix "drop_broadcast: "
iptables -A INPUT -d 255.255.255.255 -j DROP
iptables -A INPUT -d 224.0.0.1       -j LOG --log-prefix "drop_broadcast: "
iptables -A INPUT -d 224.0.0.1       -j DROP

###########################################################
# 全ホスト(ANY)からの入力許可
###########################################################

# ICMP: ping に応答する設定
iptables -A INPUT -p icmp -j ACCEPT # ANY -> SELF

# HTTP, HTTPS
iptables -A INPUT -p tcp -m multiport --dports $HTTP -j ACCEPT # ANY -> SELF

# SSH: ホストを制限する場合は TRUST_HOSTS に信頼ホストを書き下記をコメントアウトする
iptables -A INPUT -p tcp -m multiport --dports $SSH -j ACCEPT # ANY -> SEL

# FTP
# iptables -A INPUT -p tcp -m multiport --dports $FTP -j ACCEPT # ANY -> SELF

# DNS
# iptables -A INPUT -p tcp -m multiport --sports $DNS -j ACCEPT # ANY -> SELF
# iptables -A INPUT -p udp -m multiport --sports $DNS -j ACCEPT # ANY -> SELF

# SMTP
# iptables -A INPUT -p tcp -m multiport --sports $SMTP -j ACCEPT # ANY -> SELF

# POP3
# iptables -A INPUT -p tcp -m multiport --sports $POP3 -j ACCEPT # ANY -> SELF

# IMAP
# iptables -A INPUT -p tcp -m multiport --sports $IMAP -j ACCEPT # ANY -> SELF

###########################################################
# ローカルネットワーク(制限付き)からの入力許可
###########################################################

if [ "$LIMITED_LOCAL_NET" ]
then
    # SSH
    iptables -A INPUT -p tcp -s $LIMITED_LOCAL_NET -m multiport --dports $SSH -j ACCEPT # LIMITED_LOCAL_NET -> SELF

    # FTP
    iptables -A INPUT -p tcp -s $LIMITED_LOCAL_NET -m multiport --dports $FTP -j ACCEPT # LIMITED_LOCAL_NET -> SELF

    # 各種DB
    iptables -A INPUT -p tcp -s $LIMITED_LOCAL_NET -m multiport --dports $DBPORT -j ACCEPT # LIMITED_LOCAL_NET -> SELF
fi

###########################################################
# 特定ホストからの入力許可
###########################################################

if [ "$ZABBIX_IP" ]
then
    # Zabbix関連を許可
    iptables -A INPUT -p tcp -s $ZABBIX_IP --dport 10050 -j ACCEPT # Zabbix -> SELF
fi

###########################################################
# それ以外
# 上記のルールにも当てはまらなかったものはロギングして破棄
###########################################################
iptables -A INPUT  -j LOG --log-prefix "drop: "
iptables -A INPUT  -j DROP

###########################################################
# SSH 締め出し回避策
# 30秒間スリープしてその後 iptables をリセットする。
# SSH が締め出されていなければ、 Ctrl-C を押せるはず。
###########################################################
trap 'finailize && exit 0' 2 # Ctrl-C をトラップする
echo "In 30 seconds iptables will be automatically reset."
echo "Don't forget to test new SSH connection!"
echo "If there is no problem then press Ctrl-C to finish."
sleep 30
echo "rollback..."
initialize

以上をコピペして、iptables を起動させる。

# chmod u+x /etc/sysconfig/iptables.sh
# /etc/sysconfig/iptables.sh

iptables.sh を実行して Ctrl-C を入力すると設定が保存されるが、
新しい ssh の接続が可能かどうか確認してから保存すること。
締め出しをくらうと、遠隔操作は二度と出来なくなる。
それから、hosts.allow と hosts.deny も編集しておく。
# vim /etc/hosts.allow

ALL : 127.0.0.1
sshd : ALL

# vim /etc/hosts.deny

ALL : ALL




ユーザーの作成/設定

こちらのブログを参考にした。
VPS 借りたら、せめてこれくらいはやっとけというセキュリティ設定 | dogmap.jp
リンク先の記事の方がセキュリティしっかりしているので、ガッチリやりたい人はそっちを参照のこと。
まずはユーザー作成。ここでは "mogera" というユーザーを作成。

# useradd mogera
# passwd mogera

このユーザーに sudo 権限を渡したい場合は wheel グループを追加する。

# usermod -G wheel mogera

※usermod -G でのグループ登録は、追加ではなくて上書きのため今まで参加していたグループも消えてしまう。今までのグループも保持したい場合は、下記のようにグループを確認して、そのグループも追加してやる必要がある。

# groups mogera
mogera : mogera svn git unko
# usermod -G svn,git,unko,wheel mogera # ← このように、グループをカンマで区切って追加する。ユーザーの初期グループは指定する必要はない。
# groups mogera #確認
mogera : mogera svn git unko wheel

そして、wheel には sudoer 権限を与える。

# /usr/local/sbin/visudo

visudo の
# %wheel ALL=(ALL) ALL
この行のコメントアウトを外す。この時点で、作成したユーザーで sudo ができるかを確認しておくこと!sudo 権限の付与に失敗している場合はサーバー設定が行えなくなる。
root でのログインを禁止。
# vim /etc/ssh/sshd_config

#PermitRootLogin yes
  ↓ 以下のように変更
PermitRootLogin no

sshd を再起動。

# service sshd restart




必要なライブラリのインストール

ここまできたら一端ログアウトして、ユーザーで sudo しながら作業をすすめる。

epel リポジトリの追加

さくらのVPSではすでに入ってるけど、一応追加方法を書いておく。

$ cd /usr/local/src/
$ sudo yum install wget # wget がない場合はyumからいれておく
$ sudo wget http://ftp.riken.jp/Linux/fedora/epel/6/x86_64/epel-release-6-7.noarch.rpm
$ sudo rpm -ivh epel-release-6-7.noarch.rpm
$ sudo yum -y update epel-release # epel-releaseアップデート

epel 入れたらとりあえず tmux とか git とか入れておく。

$ sudo yum -y install tmux git




ライブラリのインストール

ミドルウェアのインストールに必要なライブラリを入れていく。さくらのVPSだと意外と揃っているので、半分ぐらいいらないかも。他のVPSだと必要だったりするし、重複して指定する分には「すでに最新版があります」みたいなことを言われるだけなので、全部ぶっこんでインストールしてOK。

$ cd /usr/local/src
$ yum install -y  \
gettext gettext-devel ncurses-devel libpng-devel libjpeg-devel \
freetype-devel libxml2-devel curl-devel gd gd-devel cmake \
openssl libevent-devel libxml2-devel libmcrypt-devel openssl-devel \
bzip2-devel t1lib-devel gmp-devel libicu-devel aspell-devel \
readline-devel libtidy-devel libxslt-devel gcc gcc-c++ wget bison tcl make

zlib 入れる。

$ sudo wget http://zlib.net/zlib-1.2.7.tar.gz
$ sudo tar zxf zlib-1.2.7.tar.gz
$ cd zlib-1.2.7
$ sudo ./configure --shared && make all install
$ cd ../




MySQLのインストール

MySQL 用のユーザーを作成する。

$ sudo /usr/sbin/groupadd mysql
$ sudo /usr/sbin/useradd -d /home/mysql -g mysql -r -s /sbin/nologin mysql

ソースファイルをダウンロード & コンパイルする。

$ cd /usr/local/src/
$ sudo wget http://dev.mysql.com/get/Downloads/MySQL-5.5/mysql-5.5.27.tar.gz/from/http://cdn.mysql.com/
$ sudo tar zxf mysql-5.5.27.tar.gz
$ cd mysql-5.5.27
$ sudo cmake . -DCMAKE_INSTALL_PREFIX=/usr/local/mysql -DDEFAULT_CHARSET=utf8mb4 -DDEFAULT_COLLATION=utf8mb4_general_ci
$ sudo make
$ sudo make install
$ sudo mkdir /usr/local/mysql/etc
$ cd /usr/local/mysql
$ sudo chown -R mysql:mysql /usr/local/mysql
$ sudo ./scripts/mysql_install_db --user=mysql --skip-name-resolve
$ sudo cp /usr/local/src/mysql-5.5.27/support-files/my-medium.cnf /usr/local/mysql/etc/my.cnf
$ sudo chown -R root .
$ sudo chown -R mysql:mysql /usr/local/mysql/data
$ sudo install -o root -g root -m 755 /usr/local/src/mysql-5.5.27/support-files/mysql.server /etc/rc.d/init.d/mysql
$ sudo /sbin/chkconfig --add mysql # サーバー起動時に稼働させたい場合
$ sudo /sbin/chkconfig --list mysql # 起動スクリプト確認
$ cd /usr/local/src

一応 .bashrc にもパスを記述する

# vim ~/.bashrc

以下2行を一番下に追記
---------------------------------------
PATH=$PATH:/usr/local/mysql/bin
export PATH
---------------------------------------

# source ~/.bashrc

これでインストール完了。

起動/終了:
$ sudo /etc/init.d/mysql (start|stop|restart)
ログイン
$ mysql -u ユーザー -p

一応パスワードを変更しておく。

# sudo /etc/init.d/mysql start
# mysql -u root

root> SET PASSWORD FOR root@localhost=PASSWORD('hoge');
root> exit;

# mysql -u root # これで弾かれることを確認
# sudo /etc/init.d/mysql stop # 一応停止しておく
# cd /usr/local/src

このへんのインストール後のセットアップは、下記のコマンドでやってくれる。便利。

$ sudo mysql_secure_installation



Apacheのインストール

Apache 用のユーザーを作成する。めんどくさいので、Webサーバー系の仕事をするユーザーは www-data でまとめたほうがいいと思う。(Nginx とか FPM-PHP のユーザーの切り替えが面倒)

$ sudo /usr/sbin/groupadd www-data
$ sudo /usr/sbin/useradd -d /home/www-data -g www-data -r -s /sbin/nologin www-data

それからダウンロード/インストール

$ cd /usr/local/src/
$ sudo wget http://ftp.riken.jp/net/apache//httpd/httpd-2.2.23.tar.gz
$ sudo tar zxf httpd-2.2.23.tar.gz 
$ cd httpd-2.2.23
$ sudo ./configure \
--with-libdir=lib64 --prefix=/usr/local/apache2 --with-layout=PHP --with-pear \
--with-apxs2=/usr/local/apache2/bin/apxs --enable-calendar \
--enable-bcmath --with-gmp --enable-exif --with-mcrypt \
--with-mhash --with-zlib --with-bz2 --enable-zip --enable-ftp \
--enable-mbstring --with-iconv --enable-intl --with-icu-dir=/usr \
--with-gettext --with-pspell --enable-sockets --with-openssl \
--with-curl --with-curlwrappers --with-gd --enable-gd-native-ttf \
--with-jpeg-dir=/usr --with-png-dir=/usr --with-zlib-dir=/usr \
--with-xpm-dir=/usr --with-freetype-dir=/usr --with-t1lib=/usr \
--with-libxml-dir=/usr --with-mysql=mysqlnd --with-mysqli=mysqlnd \
--with-pdo-mysql=mysqlnd --enable-soap --with-xmlrpc --with-xsl \
--with-tidy=/usr --with-readline --enable-pcntl --enable-sysvshm \
--enable-sysvmsg --enable-shmop  --enable-ssl=shared --enable-rewrite \
--enable-deflate --enable-headers
$ sudo make
$ sudo make install
$ sudo chown -R www-data:www-data /usr/local/apache2

Apache の設定ファイルを編集する。

$ sudo vim /usr/local/apache2/conf/httpd.conf

# 実行ユーザーを変更
-------------------------------------------------
User daemon
Group daemon
	↓
User www-data
Group www-data
-------------------------------------------------

# index を html から php に変更
-------------------------------------------------
<IfModule dir_module>
    DirectoryIndex index.html
</IfModule><IfModule dir_module>
    DirectoryIndex index.php
</IfModule>
-------------------------------------------------

# バーチャルホストを設定する場合は、デフォルトのバーチャルホストは Basic 認証をかけて見れないようにする。
# (追記)
-------------------------------------------------
NameVirtualHost *:80

<VirtualHost *:80>
    ServerAdmin admin@example.com
    DocumentRoot "/usr/local/apache2/htdocs"
    ServerName dummy.example.com
    ServerAlias dummy.example.com
    ErrorLog "logs/dummy-host.error_log"
    CustomLog "logs/dummy-host.access_log" common
    <Directory "/usr/local/apache2/htdocs">
    	Options All
    	AllowOverride All
    </Directory>
</VirtualHost>
-------------------------------------------------

# 追加設定ファイル用のフォルダもIncludeしておく
-------------------------------------------------
Include conf.d/*.conf
-------------------------------------------------
$ sudo mkdir /usr/local/apache2/conf.d
$ sudo chown www-data:www-data /usr/local/apache2/conf.d

Basic認証をかける場合は下記を実行する。

$ sudo vim /usr/local/apache2/htdocs/.htaccess # Basic 認証用に .htaccess を作成、追記
-------------------------------------------------
AuthUserFile /usr/local/apache2/.htpasswd
AuthGroupFile /dev/null
AuthName "Please enter your ID and password"
AuthType Basic
require valid-user
-------------------------------------------------
$ sudo /usr/local/apache2/bin/htpasswd -cb /usr/local/apache2/.htpasswd [ユーザー名] [パスワード] # パスワードファイル作成

起動スクリプトをソース内からコピー&編集。

$ sudo cp /usr/local/src/httpd-2.2.23/build/rpm/httpd.init /etc/rc.d/init.d/httpd
$ sudo vim /etc/init.d/httpd
-------------------------------------------------
httpd=${HTTPD-/usr/sbin/httpd}
	↓
httpd=/usr/local/apache2/bin/httpd
 
pidfile=${PIDFILE-/var/log/httpd/httpd.pid}
	↓
pidfile=/usr/local/apache2/logs/httpd.pid
 
CONFFILE=/etc/httpd/conf/httpd.conf
	↓
CONFFILE=/usr/local/apache2/conf/httpd.conf
-------------------------------------------------

これで動くか確認。ブラウザからのアクセスもチェックすること。

$ sudo /etc/init.d/httpd (start|stop|restart)

ここまでOKだったら、設定ファイルをGitで管理する。

$ cd /usr/local/apache2/conf
$ sudo git init
$ sudo git add .
$ sudo git commit -m "Initial commit"
$ cd /usr/local/apache2/conf.d
$ sudo git init
$ sudo git add .
$ sudo git commit -m "Initial commit"

自動起動の設定も行っておく。

$ sudo /sbin/chkconfig --add httpd
$ sudo /sbin/chkconfig httpd on
$ sudo /sbin/chkconfig --list httpd




PHPのインストール
$ cd /usr/local/src/
$ sudo wget http://www.php.net/get/php-5.4.7.tar.gz/from/this/mirror
$ tar zxf php-5.4.7.tar.gz
$ cd php-5.4.7
$ sudo ./configure --with-libdir=lib64 --prefix=/usr/local/php547 --with-layout=PHP \
--with-pear --with-apxs2=/usr/local/apache2/bin/apxs --enable-calendar \
--enable-bcmath --with-gmp --enable-exif --with-mcrypt --with-mhash \
--with-zlib --with-bz2 --enable-zip --enable-ftp --enable-mbstring --with-iconv \
--enable-intl --with-icu-dir=/usr --with-gettext --with-pspell --enable-sockets \
--with-openssl --with-curl --with-curlwrappers --with-gd --enable-gd-native-ttf \
--with-jpeg-dir=/usr --with-png-dir=/usr --with-zlib-dir=/usr --with-xpm-dir=/usr \
--with-freetype-dir=/usr --with-t1lib=/usr --with-libxml-dir=/usr \
--with-mysql=mysqlnd --with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd \
--enable-soap --with-xmlrpc --with-xsl --with-tidy=/usr --with-readline \
--enable-pcntl --enable-sysvshm --enable-sysvmsg --enable-shmop \
--enable-cli --enable-fpm --with-fpm-user=www-data --with-fpm-group=www-data \
$ sudo make
$ sudo make test
$ sudo make install

Apache にモジュールを読み込ませる。
$ sudo vim /usr/local/apache2/conf/httpd.conf

下記を追記
----------------------------------------
LoadModule php5_module modules/libphp5.so
AddType application/x-httpd-php .php
----------------------------------------

php.ini をコピーする。本番環境なら php.ini-production を。

$ cd /usr/local/src/php-5.4.7
$ sudo cp php.ini-development /usr/local/php547/lib/php.ini

php.ini の設定を編集する。(デフォルトのタイムゾーン指定)
$ sudo vim /usr/local/php547/lib/php.ini

追記
date.timezone = "Asia/Tokyo"

シンボリックリンク作って、パスを通す。

$ sudo ln -s /usr/local/php547 /usr/local/php

追記
$ vim ~/.bashrc

PATH=$PATH:/usr/local/php/bin
export PATH

どこぞのディレクトリに index.php とか書いて phpinfo 表示させて、Apache 再起動して問題なければOK.
httpd.conf が更新されたので一応 git コミットする。

$ cd /usr/local/apache2/conf
$ sudo git add httpd.conf
$ sudo git commit -m "add php"
Nginxのインストール

公式サイトでRPMを配布しているのでRPMでインストールする。

$ cd /usr/local/src
$ sudo wget http://nginx.org/packages/centos/6/noarch/RPMS/nginx-release-centos-6-0.el6.ngx.noarch.rpm
$ sudo rpm -ivh nginx-release-centos-6-0.el6.ngx.noarch.rpm
$ sudo yum -y install nginx

設定ファイルは /etc/nginx/conf.d に書く。

Redisのインストール

同じようにソースダウンロードしてビルドしてインストールして終わり。

$ cd /usr/local/src
$ sudo wget http://redis.googlecode.com/files/redis-2.4.17.tar.gz
$ sudo tar zxf redis-2.4.17.tar.gz
$ cd redis-2.4.17
$ sudo make
$ sudo make test
$ sudo make install

起動スクリプトが必要な場合は

$ cd utils
$ sudo ./install_server.sh

を実行するといろいろ聞かれるので、必要情報を設定すると起動スクリプトができあがる。
上記のインストール方法だと、全部デフォルトで大丈夫。
同じサーバーでRedisを別々のサービスで使いたい場合はポートを分けて起動するのもひとつの手なので、このインストールスクリプトは消さずに置いといたほうがいいとおもう。
この起動スクリプトをインストールすると、起動は下記のようになる。

$ sudo /etc/init.d/redis_[ポート番号:デフォルト6379] (start|stop|restart)





MongoDBのインストール

MongoDB はソースからのビルドに失敗するので、パッケージを利用する。
まずはリポジトリの追加。

$ sudo vim /etc/yum.repos.d/10gen.repo

このファイルに下記をコピペ

[10gen]
name=10gen Repository
baseurl=http://downloads-distro.mongodb.org/repo/redhat/os/x86_64
gpgcheck=0
enabled=1

そして yum でインストール実行

$ sudo yum install mongo-10gen mongo-10gen-server

これで下記のコマンドが使えるようになる。

  • mongo
  • mongodump
  • mongorestore
  • mongoexport
  • mongoimport
  • mongostat
  • mongotop
  • bsondump

起動/停止は下記

$ sudo /etc/init.d/mongod (start|stop|restart)
または
$ sudo service mongod (start|stop|restart)

サーバー再起動時に起動するように設定するには

$ sudo chkconfig mongod on

とかやっとけばいい。






RTMFP野郎の会行ってきた

イデア次第では化ける可能性があると思ったので簡単にまとめる。
トゥギャッターまとめRTMFP Lab に大幅に遅刻したボクが RTMFP Lab 関連のツイートをまとめてみた。 - Togetter

RTMFPとは?

ウィキペディアReal Time Media Flow Protocol - Wikipedia
簡単に言うとUDPベースのプロトコルの一種。メディアをやりとりするのに向いていて、P2Pでのやりとりが可能。


使い方

  1. NetConnectionを作成・接続する
  2. NetGroupの仕様を設定する(GroupSpecifier)
  3. NetGroupを作成・接続する
  4. メッセージ/ストリームのやりとりを行う

具体的なコードはこちら

// NetConnection の作成・接続
var nc:NetConnection = new NetConnection();
nc.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus);
nc.connect("rtmfp:");

// NetConnection のステータスハンドラ
function onNetStatus(e:NetStatusEvent):void
{
	// 接続成功したらNetGroupを作成する
	if (e.info.code == "NetConnection.Connect.Success") 
	{
		setupGroup();
	}
}

// NetGroup
var ng:NetGroup;
function setupGroup():void
{
	// NetGroup の仕様を設定
	var gs:GroupSpecifier =  new GroupSpecifier("myGroup/g1");
	gs.ipMulticastMemberUpdatesEnabled = true;
	gs.multicastEnabled = true;
	gs.objectReplicationEnabled = true;
	gs.peerToPeerDisabled = false;
	gs.postingEnabled = true;
	gs.routingEnabled = true;
	gs.serverChannelEnabled = true;
	gs.addIPMulticastAddress("224.0.0.254:30000");
	
	// NetGroup を作成/接続
	ng = new NetGroup(nc, gs.groupspecWithAuthorizations());
	ng.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus2);
}

// NetGroup のステータスハンドラ
function onNetStatus2(e:NetStatusEvent):void
{
	switch (e.info.code) 
	{
		case "NetGroup.Connect.Success":
			trace("connected");
			break;
		
		case "NetGroup.Posting.Notify":
			receiveMessage(e.info.message);
			break;
	}
}

// メッセージ/ストリームのやりとり
// 受信
function receiveMessage(message:Object):void
{
	trace(message.text);
}

// 送信
function sendMessage():void
{
	var message:Object = new Object();
	message.sender = ng.convertPeerIDToGroupAddress(nc.nearID);
	message.text = "hogehoge"; // 任意のメッセージを記述
	
	// post 以外にもsendToNeighborやsendToAllNeighborsなどの方法がある
	ng.post(message); 
	
	message.text = "post - " + message.text;
	receiveMessage(message);
}

実際動くコードとしては@mousepancyoさんや@SIHO_oさんのものを参考にしたほうがいいかも
@mousepancyoさん http://wonderfl.net/c/vXBY
@SIHO_oさん http://wonderfl.net/c/edvz


解説

サーバーについて

従来RTMP系のプロトコルを利用するにはFCS(FlashCommunicationServer)またはFMS(FlashMediaServer)が必要だった(これはまた次バージョンで名前がAMS (AdobeMediaServer) に変わるらしい)。しかし、RTMFP は同一ネットワーク上で待ち受けるノードに直接アクセスができる。その場合は NetConnection の connect の際にURLを "rtmfp:" と指定する。

NetGroupの仕様について

リファレンスGroupSpecifier - Adobe ActionScript® 3(AS3 )API リファレンス
このGroupSpecifierっていうクラスの値を変更することで設定する。

  • ipMulticastMemberUpdatesEnabled
  • multicastEnabled
  • objectReplicationEnabled
  • peerToPeerDisabled
  • postingEnabled
  • routingEnabled
  • serverChannelEnabled

この7つのプロパティと

  • addIPMulticastAddress(address:String, port:* = null, source:String = null)

このメソッドあたりは基本的に設定したほうが良い。
マルチキャストIPの範囲については http://www.infraexpert.com/study/multicast2.htm この辺を参考にすると良い。ローカルネットワーク上で接続した場合は 224.0.0.0 〜 224.0.0.255 の範囲を設定する。

メッセージの送受信について

多数のノードが接続するような環境では、メッセージング方法によって速度に影響が出る。
例えば上のソースコードではpostを使っているが、postはグループ内のすべてのピアにメッセージを送るのですごく遅い。
sendToAllNeighbors(message:Object)を利用したほうがネットワーク負荷的にも良いらしい。
sendToAllNeighbors を使うにはピア同士が円状に繋がっているのを意識して書く。このあたりの記事が参考になる。Flash Real-Time - Ihr Immobilien-Ratgeber

TIPSとか

Cent OS 6.2 に Flash Media Server 4.5 をインストールした

こちらのブログを参考にした。 http://myhour.orz.hm/archives/1044
ありがとうございました。

自分もお金はないので、調査・研究用ということで開発版を入れる。Adobe のサイトからバイナリを落として、/usr/local/src あたりにおく。

# cd /usr/local/src
# mv ~/FlashMediaDevServer_4_5_all.zip ./
# unzip FlashMediaDevServer_4_5_all.zip -d FlashMediaDevServer_4_5_all
# cd FlashMediaDevServer_4_5_all



中には linux 版と windows 版が入っているので、linux 版をインストールする。

# cd linux
# tar xfz FlashMediaServer4.5_x64.tar.gz
# cd FMS_4_5_0_r297



ここでこのままインストールスクリプトを走らせてもインストールできないので、上記のブログを参考に必要なライブラリ等を準備する。

# yum install -y libcap
# ln -s /lib64/libcap.so.2 libcap.so.1



それからインストール

# ./installFMS



あとは条件規約とかポートとかアカウントとかいろいろ言われるがままに設定していくだけで完了。

Nginx と FuelPHP 入れてみた

速いと噂の Nginx と何かといいらしい FuelPHP を導入してみた。導入だけだと簡単なので、hoge.foo.com に新しくサイトを作るという想定で Apache/Nginx、FuelPHP の設定をメモしておく。


FuelPHPの導入

まずは FuelPHP。こいつは git と CLI 版の PHP が必要なので入れておく。前回紹介した PHP の導入では CLI 版は入らないので、--enable-cli オプションつけてコンパイルし直すこと。一応追記してある。
で、導入は非常に簡単で下記のコマンドを叩くだけでいい。

# curl get.fuelphp.com/oil | sh



そしてバーチャルホストのディレクトリまで移動して雛形を作る。仮に /var/www/hoge とする。雛形を作るのも非常に簡単で、
oil create [ディレクトリ名]
とすればいい。

# cd /var/www
# oil create hoge
# chown apache:apache hoge
# cd hoge
# php oil refine install   # これで一発で権限を変更してくれる

これだけで FuelPHP の導入は完了。超簡単。



Nginxの導入

Nginx も導入は簡単で、公式サイトが yum リポジトリを作って公開してくれているので、最新版も yum で管理できる。現時点で 1.2.0。超便利。このへんから rmp の情報は確認できる。今回は CentOS 6.2 なので、CentOS 6 用のリポジトリを入れる。

# cd /usr/local/src
# 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
# yum -y install nginx



yum で入れた場合の起動停止処理は /etc/init.d/nginx で start/stop/restart 等行えば良い。
設定ファイルは /etc/nginx/ 以下にある。Apache と同じようにメインは nginx.conf で、細かい設定は Include できるようになっており、デフォルトでは /etc/nginx/conf.d/ 以下の conf ファイルをすべて読むようになっている。
ログに関しては /var/log/nginx 以下に出るようになっている。
これらの設定を変更してバーチャルホストにアクセスできるようにしてみる。
まずは /etc/nginx/nginx.conf を編集。ユーザーを nginx じゃなくて apache に統一する。多分これは www-data とかに統一したほうがスマートなんだと思うけど、すでに apache で動いてるものがあるのでとりあえず今は apache にしておく。

user  nginx;
	↓
user apache;



それから Include の方のサンプルは全部バックアップして読み込まない様にしておく。

# mv /etc/nginx/conf.d{,.bak}
# mkdir -m 755 /etc/nginx/conf.d



バーチャルホストの conf ファイルを編集する。今回は SSL の設定も一緒に書いてみた。先日ブログに書いた自己証明書を用いているので、きちんとしたサイトならしかるべき認証局から証明書を発行してもらうこと。
# vim /etc/nginx/conf.d/hoge.conf

server {
  listen 80; 
  server_name hoge.foo.com;
  root /var/www/hoge/public/;
  charset utf-8;
  index index.php;
  access_log  /var/www/hoge/fuel/app/logs/nginx.log  main;
  error_log  /var/www/hoge/fuel/app/logs/error.log warn;

  # 静的ファイルは nginx で処理
  location ~ .*\.(jpg|JPG|gif|GIF|png|PNG|swf|SWF|css|CSS|js|JS|inc|INC|ico|ICO) {
    expires 1d;
    break;
  }
  # その他は Apache へ
  location / { 
    try_files $uri /index.php?$uri;
    proxy_set_header Host               $host;
    proxy_set_header X-RealIP           $remote_addr;
    proxy_set_header X-Forwarded-Host   $host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
    proxy_pass  http://127.0.0.1:8080;
    break;
  }
  # すべての不可視ファイルをアクセス不可に
  location ~ /\. {
    access_log off;
    log_not_found off;
    deny all;
  }
}

server {
  listen 443;
  server_name hoge.foo.com;
  root /var/www/hoge/public/;
  charset utf-8;
  index index.php;
  access_log  /var/www/hoge/fuel/app/logs/nginx-ssl.log  main;
  error_log  /var/www/hoge/fuel/app/logs/error.log warn;

  # SSL は nginx で処理
  ssl                   on;
  ssl_certificate       /etc/pki/tls/certs/server.crt;
  ssl_certificate_key   /etc/pki/tls/certs/server.key;
  ssl_session_timeout   5m;
  ssl_protocols         SSLv2 SSLv3 TLSv1;
  ssl_ciphers           HIGH:!aNULL:!MD5;
  ssl_prefer_server_ciphers on;

  # 静的ファイルは nginx で処理
  location ~ .*\.(jpg|JPG|gif|GIF|png|PNG|swf|SWF|css|CSS|js|JS|inc|INC|ico|ICO) {
    expires 1d;
    break;
  }
  # その他は Apache へ
  location / {
    try_files $uri /index.php?$uri;
    proxy_set_header Host               $host;
    proxy_set_header X-RealIP           $remote_addr;
    proxy_set_header X-Forwarded-Host   $host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
    proxy_pass  http://127.0.0.1:8080;
    break;
  }
  # すべての不可視ファイルをアクセス不可に
  location ~ /\. {
    access_log off;
    log_not_found off;
    deny all;
  }
}



Nginx は静的なファイルの処理が速いので、画像やJSなどのコンテンツ、それから SSL の対応をしてもらう。PHP のような動的な部分を Apache で処理する。そして FuelPHP のルーティングが上手くいくように try_files を使ってリダイレクトを行っている。編集が完了したら Nginx を起動する。

# /etc/init.d/nginx start




Apache の設定

Nginx から Apache にプロキシするために、Apache にも設定を加える。フロント側に Nginx をたてるので、もちろん Apache は 80 で Listen はできなくなる。今回は 8080 ポートで待ち受ける。このときサーバー自体の 8080 ポートは閉じたままでよい。また、ApacheSSL の処理をしなくても良いので、8443 番ポート等での待ち受けもしなくてよい。
NameVirtualHost と Include の設定がなければ追加する
# vim /usr/local/apache2/conf/httpd.conf

NameVirtualHost 8080
Include conf.d/*.conf



次にバーチャルホスト用の設定ファイルを編集。
# vim /usr/local/apache2/conf.d/hoge.conf

<VirtualHost *:8080>
    ServerAdmin admin@foo.com
    DocumentRoot "/var/www/hoge/public"
    ServerName hoge.foo.com
    ServerAlias hoge.foo.com
    ErrorLog "/var/www/hoge/fuel/app/logs/error.log"
    CustomLog "/var/www/hoge/fuel/app/logs/access.log" common

    <Directory "/var/www/hoge/public">
      Options Indexes FollowSymLinks
      AllowOverride None
      Order allow,deny
      Allow from all 
    </Directory>

    <FilesMatch "^\.ht">
        Order allow,deny
        Deny from all 
        Satisfy All 
    </FilesMatch>
</VirtualHost>



こんな感じで編集が完了したら、Apache を再起動しておく。

# /usr/local/apache2/bin/apachctl stop
# /usr/local/apache2/bin/apachctl start




サイトの確認

ここまできたらとりあえず FuelPHP の Welcome ページが見れると思う。
http://hoge.foo.com
http://hoge.foo.com/hello
http://hoge.foo.com/hello/
http://hoge.foo.com/bad/uri
https://hoge.foo.com
それぞれ確認してみるべし。



んで、せっかくなので自分でも Hello world をやってみる。こちらのサイトを参考にした。
まずはコントローラークラス
# vim fuel/app/classes/controller/sample1.php

<?php
class Controller_Sample1 extends Controller
{
  public function action_index()
  {
    return Response::forge(View::forge('sample1/index'));
  }
}

そしてビューを作成
# mkdir -m 755 fuel/app/views/sample1
# vim fuel/app/views/sample1/index.php

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Sample1</title>
</head>
<body>
<h1>Hello,World!</h1>
<p>これはsample1のビューファイルです</p>
</body>
</html>

ページを確認してみる。
http://hoge.foo.com/sample1


これでとりあえず一連の導入作業は完了。

CentOS6.2 でメールサーバーを構築した

さくらの VPS ではデフォルトで postfix が入ってたのでそれを使う。POP3IMAP には dovecot を利用する。認証には SSL を利用するが、自分だけしか使わないのとお金がないので自己証明書を用いる。きちんとしたサービスでは認証局から証明書を発行してもらうこと。


自己証明書

まずは自己証明書を作成する。こちらを参考にした。

# cd /etc/pki/tls/certs
# make server.key # "server" は好きな文字列でよい
Enter pass phrase:# パスフレーズ設定
Verifying - Enter pass phrase:# 再入力

2014/02/19 追記 下記のコマンドはパスフレーズを削除してしまうので実行しないでください。

# openssl rsa -in server.key -out server.key
Enter pass phrase for server.key:# パスフレーズ入力

# make server.csr # 色々聞かれるので解答していく
Country Name (2 letter code) [XX]:JP# 国
State or Province Name (full name) [e]:Tokyo  # 地域(県)
Locality Name (eg, city) [Default City]:Meguro-Ku # 都市
Organization Name (eg, company) [Default Company Ltd]:Individual   # 組織名
Organizational Unit Name (eg, section) []:Individual  # 組織の部門名
Common Name (eg, your server's hostname) []:www.hoge.com   # サーバーのFQDN
Email Address []:admin@hoge.com # 管理者アドレス
A challenge password []:# 空Enter
An optional company name []:# 空Enter

# openssl x509 -in server.csr -out server.crt -req -signkey server.key -days 3650 # 有効期限が10年の自己署名証明書を作成
# chmod 400 server.* 

これで

  • server.key
  • server.csr
  • server.crt

が出来ているはず。


SMTPサーバー構築

送信サーバーを立てる。さくら VPS ではすでに Postfix がインストールされ、Sendmail はアンインストールされているので、設定ファイルをいじっていく。
CentOS6 では、Postfix の設定ファイルは /etc/postfix 以下にある。起動停止は /etc/init.d/postfix に対して start とか stop とかやれば処理できる。

Postfix の設定

2012/05/05 現在では、バージョンは2.6.6が入っていた。以下設定ファイルの変更点。こちらと、こちらを参考にした。
# vim /etc/postfix/main.cf

# 追加
myhostname = mail.hoge.com
mydomain = hoge.com
myorigin = $mydomain
home_mailbox = Maildir/
smtpd_banner = $myhostname ESMTP unknown

# 変更
inet_interfaces = localhost
	↓
inet_interfaces = all

mydestination = $myhostname, localhost.$mydomain, localhost
	↓
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain

# SMTP-Auth 系の設定追加
disable_vrfy_command = yes 
smtpd_sasl_auth_enable = yes 
broken_sasl_auth_clients = yes 
smtpd_sasl_security_options = noanonymous
smtpd_sasl_local_domain = $myhostname
smtpd_sender_restrictions = reject_unknown_sender_domain
smtpd_client_restrictions = permit_mynetworks,reject_unknown_client,permit
smtpd_recipient_restrictions = permit_mynetworks,permit_sasl_authenticated,reject_unauth_destination
message_size_limit = 10485760

# TLS を利用するための設定、先ほど作った自己証明書を指定する
smtpd_tls_cert_file = /etc/pki/tls/certs/server.crt
smtpd_tls_key_file = /etc/pki/tls/certs/server.key
smtpd_use_tls = yes 

TLSを利用するために /etc/postfix/master.cf の下記の部分のコメントアウトを外す。

submission inet n       -       n       -       -       smtpd
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
  -o milter_macro_daemon_name=ORIGINATING



SMTP-Auth の設定

このままでは誰でもメールが使えてしまうので、認証をかけるために saslauthd を利用する。Postfix の設定でも一部出てきているが、ここでは SASL 単体の設定を行う。現時点でのバージョンは 2.1.23 で、さくら VPS ではすでにインストールされている。
設定ファイルは /etc/sasl2/smtpd.conf にあり、行数も少ないので全部下記に載せる。

pwcheck_method: auxprop
auxprop_plugin: sasldb
mech_list: plain login



saslauthd は /etc/init.d/saslauthd に起動/停止スクリプトがあるので、設定を変更したら忘れずに再起動しておく。また、下記のようにOS再起動時にも起動するように設定しておく。

# chkconfig saslauthd on
# chkconfig --list saslauthd #確認
saslauthd       0:オフ  1:オフ  2:オン  3:オン  4:オン  5:オン  6:オフ




POP・IMAPサーバー構築

今回は dovecot をインストールして設定する。こちらも /etc/init.d/dovecot あたりで起動・停止処理を行う。設定ファイルは /etc/dovecot 以下にある。
まずはインストール。現時点のバージョンは 2.0.9。

# yum -y install dovecot



設定ファイルは /etc/dovecot/ 以下にある。まずは ssl を利用出来るようにする。
/etc/dovecot/conf.d/10-ssl.conf

#追加
ssl = yes
ssl_key_password = "上記で設定した自己証明書のパスフレーズ"

#変更(上記で設定した自己証明書を指定、値の先頭に"<"がつくので気をつけること)
ssl_cert = </etc/pki/tls/certs/server.crt
ssl_key = </etc/pki/tls/certs/server.key



受信に認証をかける。
/etc/dovecot/conf.d/10-auth.conf

#追加
auth_mechanisms = plain login



それからポートの設定等。
/etc/dovecot/conf.d/10-master.conf

# imap と pop3 のポートとかsslのコメントアウトを外しておく
service imap-login {
  inet_listener imap {
    port = 143 
  }
  inet_listener imaps {
    port = 993 
    ssl = yes 
  }
}
service pop3-login {
  inet_listener pop3 {
    port = 110 
  }
  inet_listener pop3s {
    port = 995 
    ssl = yes 
  }
}



基本設定。
/etc/dovecot/conf.d/10-mail.conf

#追加
mail_location = maildir:~/Maildir
valid_chroot_dirs = /home



こっちも基本設定?
/etc/dovecot/dovecot.conf

#追加
protocols = imap pop3 lmtp




ユーザー設定

ssh ログインなしのユーザーを作成する。

# useradd -s /sbin/nologin [ユーザー名]
# passwd [ユーザー名] #パスワードを設定
# saslpasswd2 -u [FQDN] [ユーザー名] #パスワード設定
# sasldblistusers2 #作成したユーザー確認
# chgrp postfix /etc/sasldb2 #認証DBの所有権変更

メールディレクトリのスケルトンを作成する。

# mkdir -p /etc/skel/Maildir/{new,cur,tmp}
# chmod -R 700 /etc/skel/Maildir

既存ユーザーがいる場合は下記のようにディレクトリを作成する。

# mkdir /home/[ユーザー名]/Maildir
# chmod 700 /home/[ユーザー名]/Maildir
# chown [ユーザー名]:[ユーザーグループ] /home/[ユーザー名]/Maildir




ファイアウォールの設定

下記のポートを開けておく。

  • 110, 995 (POP3)
  • 143, 993 (IMAP)
  • 25, 587 (SMTP) ※25番ポートは踏み台にされやすいので閉じておいた方が無難。

※基本的にはSSLを利用するので、上記の左側のポートは閉じていても良い
※2012/05/07追記 25番開けないと外部からのメール受けられませんでした
具体的には下記のコマンドを叩く。

-A INPUT -m state --state NEW -m tcp -p tcp --dport 110 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 995 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 143 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 993 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 25 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 587 -j ACCEPT





クライアントの設定

自分の Android でメールが受信できるようにした。その設定の一例。
クライアントソフトは K-9 Mail を利用した。https://play.google.com/store/apps/details?id=com.fsck.k9

  1. まずは上記で設定したアカウントを入力する
    1. メールアドレス(hoge@hoge.com)
    2. パスワード(****)
  2. 受信メールサーバーの種類を選択(POP3サーバー)
  3. 受信メールサーバー設定
    1. アカウント名(上記のメールアドレスと同じ)
    2. パスワード(上記のパスワードと同じ)
    3. POP3サーバー(今回設定したホスト名)
    4. 保護された接続(SSLを使用する)※なぜかTLSではrejectされてしまい、SSLではいけたのでSSLにしておいた。
    5. 認証タイプ(PLAIN)
    6. ポート(995)
  4. 証明書が無効ですと言われるけど、許可して次へ
  5. 送信メールサーバー設定
    1. SMTPサーバー(今回設定したホスト名)
    2. 保護された接続(TLSを使用する)
    3. ポート(587)
    4. このサーバーは認証が必要にチェックを入れる
    5. セキュリティ設定(PLAIN)
    6. アカウント名(上記で設定したユーザー名)
    7. パスワード(上記で設定したパスワード)

これで送受信できるはず。既存の Gmail かなんかとやりとりできるか確認しておく。



デバッグ方法

ログ

ログは基本的に /var/log/maillog に出力される。別窓で tail -f /var/log/maillog とかで監視しながらメールの送受信を行って動作確認をすると良い。
SSL 周りで動かなかったり、外部からのメールが reject されてたりするときに、このへんに出力されるキーワードをもって Google 先生に指南いただいた。

メールの打ち方

サーバーに ssh で入ってメールするときには

# mail hoge@hoge.com

って打つとタイトルを聞かれた後に本文を聞かれる。行頭で「.」のみ入力して改行すると、メールが送信される。ただ "mail" コマンドのみだけを打つと新規メールが来たかを確認できる。これで、サーバー内部、もしくは内部ネットワークからはメール可能なのか、外部から弾かれているのかが確認できる。

2012/11/12 追記 Google Apps を利用してメールを送信する

メールサーバーがグローバルに出ていない場合、スパムと判断されて正常に届かないことが多い。サーバー借りるお金なんかないし、自宅サーバーだけでスモールな感じでメールサーバー構築したいときに GAppsなんかを利用してメールを送信する。

基本的には上記の設定をひととおり終える。
んで、下記のライブラリをインストールする。

# yum install -y cyrus-sasl-plain

んで、Gmail のアカウントの情報を書く。
vim /etc/postfix/sasl_passwd

[smtp.gmail.com]:587    hoge@gmail.com:mogera123

ここで、[hoge@gmail.com]は自分のメールアカウント。GApps 利用しているなら gmail.com じゃなくて設定しているドメインでもいい。
mogera123 はそのパスワード。
それから、リレーホストも編集する。
vim /etc/postfix/main.cf

relayhost = [smtp.gmail.com]:587

この一行を追加。
そして postmap する。

# postmap /etc/postfix/sasl_passwd 

これでおそらくいけるはず・・・
念のため postfix と sasl2 を再起動

# /etc/init.d/postfix restart
# /etc/init.d/saslauthd restart

CentOS 6.2 に Apache 2.2.22 と MySQL 5.2.22 と PHP 5.4.0 をインストール

新しくお名前.comにサーバー借りて構築したのでメモ。
新しく書きなおしたので、こっちのほうを参照のこと。
CentOS 6.2 サーバー構築手順 - 俺の成長日記


まずは必要なライブラリのインストール

# cd /usr/local/src
# yum install -y  \
gettext gettext-devel ncurses-devel libpng-devel libjpeg-devel \
freetype-devel libxml2-devel curl-devel gd gd-devel cmake \
openssl libevent-devel libxml2-devel libmcrypt-devel openssl-devel \
bzip2-devel t1lib-devel gmp-devel libicu-devel aspell-devel \
readline-devel libtidy-devel libxslt-devel gcc gcc-c++ wget bison\

# wget http://zlib.net/zlib-1.2.6.tar.gz
# tar xfz zlib-1.2.6.tar.gz
# cd zlib-1.2.6
# ./configure --shared && make all install
# cd ../
# wget http://elders.princeton.edu/data/puias/unsupported/6/x86_64/libmcrypt-2.5.8-9.puias6.x86_64.rpm
# wget http://elders.princeton.edu/data/puias/unsupported/6/x86_64/libmcrypt-devel-2.5.8-9.puias6.x86_64.rpm
# rpm -ivh libmcrypt-2.5.8-9.puias6.x86_64.rpm
# rpm -ivh libmcrypt-devel-2.5.8-9.puias6.x86_64.rpm


ユーザーを作成する

# groupadd mysql
# useradd -d /home/mysql -g mysql -r -s /sbin/nologin mysql
# groupadd apache
# useradd -d /home/mysql -g apache -r -s /sbin/nologin apache


MySQL をインストールする

# curl -o mysql-5.5.22.tar.gz http://ftp.iij.ad.jp/pub/db/mysql/Downloads/MySQL-5.5/mysql-5.5.22.tar.gz
# tar xfz mysql-5.5.22.tar.gz
# cd mysql-5.5.22
# cmake . -DCMAKE_INSTALL_PREFIX=/usr/local/mysql -DDEFAULT_CHARSET=utf8mb4 -DDEFAULT_COLLATION=utf8mb4_general_ci
# make 
# make install
# mkdir /usr/local/mysql/etc
# chown -R mysql:mysql /usr/local/mysql
# cd /usr/local/mysql
# ./scripts/mysql_install_db --user=mysql --skip-name-resolve
# cp /usr/local/src/mysql-5.5.22/support-files/my-medium.cnf /usr/local/mysql/etc/my.cnf
# chown -R root .
# chown -R mysql:mysql /usr/local/mysql/data
# cd /usr/local/src


MySQL環境変数に登録しておく

# vim ~/.bashrc

以下2行を一番下に追記
---------------------------------------
PATH=$PATH:/usr/local/mysql/bin
export PATH
---------------------------------------

# source ~/.bashrc


MySQL の root ユーザーのパスワードを変更する

# /usr/local/mysql/support-files/mysql.server start
# mysql -u root

root> SET PASSWORD FOR root@localhost=PASSWORD('hoge');
root> exit;

# mysql -u root # これで弾かれることを確認
# /usr/local/mysql/support-files/mysql.server stop # 一応停止しておく
# cd /usr/local/src


Apache のインストール

# wget http://ftp.riken.jp/net/apache//httpd/httpd-2.2.22.tar.gz
# tar xfz httpd-2.2.22.tar.gz
# cd httpd-2.2.22
# ./configure \
--with-libdir=lib64 --prefix=/usr/local/apache2 --with-layout=PHP --with-pear \
--with-apxs2=/usr/local/apache2/bin/apxs --enable-calendar \
--enable-bcmath --with-gmp --enable-exif --with-mcrypt \
--with-mhash --with-zlib --with-bz2 --enable-zip --enable-ftp \
--enable-mbstring --with-iconv --enable-intl --with-icu-dir=/usr \
--with-gettext --with-pspell --enable-sockets --with-openssl \
--with-curl --with-curlwrappers --with-gd --enable-gd-native-ttf \
--with-jpeg-dir=/usr --with-png-dir=/usr --with-zlib-dir=/usr \
--with-xpm-dir=/usr --with-freetype-dir=/usr --with-t1lib=/usr \
--with-libxml-dir=/usr --with-mysql=mysqlnd --with-mysqli=mysqlnd \
--with-pdo-mysql=mysqlnd --enable-soap --with-xmlrpc --with-xsl \
--with-tidy=/usr --with-readline --enable-pcntl --enable-sysvshm \
--enable-sysvmsg --enable-shmop  --enable-ssl=shared --enable-rewrite \
--enable-deflate --enable-headers
# make
# make install
# chown -R apache:apache /usr/local/apache2


Apache の設定ファイル編集

# vim /usr/local/apache2/conf/httpd.conf

# 実行ユーザーを変更
-------------------------------------------------
User daemon
Group daemon
	↓
User apache
Group apache
-------------------------------------------------

# index を html から php に変更
-------------------------------------------------
<IfModule dir_module>
    DirectoryIndex index.html
</IfModule>
	↓
<IfModule dir_module>
    DirectoryIndex index.php
</IfModule>
-------------------------------------------------


PHP のインストール

# wget http://www.php.net/get/php-5.4.0.tar.bz2/from/this/mirror
# tar jxf php-5.4.0.tar.bz2
# cd php-5.4.0
# ./configure --with-libdir=lib64 --prefix=/usr/local/php540 --with-layout=PHP \
--with-pear --with-apxs2=/usr/local/apache2/bin/apxs --enable-calendar \
--enable-bcmath --with-gmp --enable-exif --with-mcrypt --with-mhash \
--with-zlib --with-bz2 --enable-zip --enable-ftp --enable-mbstring --with-iconv \
--enable-intl --with-icu-dir=/usr --with-gettext --with-pspell --enable-sockets \
--with-openssl --with-curl --with-curlwrappers --with-gd --enable-gd-native-ttf \
--with-jpeg-dir=/usr --with-png-dir=/usr --with-zlib-dir=/usr --with-xpm-dir=/usr \
--with-freetype-dir=/usr --with-t1lib=/usr --with-libxml-dir=/usr \
--with-mysql=mysqlnd --with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd \
--enable-soap --with-xmlrpc --with-xsl --with-tidy=/usr --with-readline \
--enable-pcntl --enable-sysvshm --enable-sysvmsg --enable-shmop
# make
# make test
# make install

※2012/05/05追記 CLI 版も必要なので追加 --enable-cli
あと、php 5.4.2 も出ていたので、s/php5.4.0/php5.4.2/g s/540/542/g

Apache にモジュールを読み込ませる

# vim /usr/local/apache2/conf/httpd.conf

下記を追記
----------------------------------------
LoadModule php5_module modules/libphp5.so
AddType application/x-httpd-php .php
----------------------------------------


80番ポートの解放

# vim /etc/sysconfig/iptables

# 下記を追記
-------------------------------
-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
-------------------------------

# /etc/rc.d/init.d/iptables restart