Scientific Linux 6 で PHP5.4 Webホスティングサーバ構築

SL6 でWebホスティングサーバを構築する手順メモ
[【CentOS-5.x】レンタルサーバのつくりかた](http://sukobuto.com/archives/147) の SL6 バージョンです。
Symfony2 に適した環境にするため ICU と APC も有効にします。

> 【必読】この構成は 2014.9.25 から話題となっている「ShellShock」というBashの脆弱性の影響をもろに受けます。
Scientific Linux ではまず bash をアップデートしてください。
ShellShock に関するパッチは完全ではないとの報告もあるため、今後の状況を追跡して各自で対応をお願い致します。

## 作業所要時間

順当に行けば1時間以内です。

## この記事でできる環境

+ Web サーバ: Apache2 - ユーザごとの名前ベース仮想ホスト
+ DB サーバ: MySQL - SL6リポジトリの最新版
+ DocRoot: /home/<ユーザ名>/public_html (public_html は変更可能)
+ PHP: 5.4 - suEXEC 環境, アクセラレータ

Apache2 および PHP をソースからビルドするので手間はかかりますが、
ユーザごとのセキュアなホスト環境を容易に追加できるようになります。

※SL6.4 をインストールした直後の状態から検証しています。
※既に Apache2 や PHP がインストール済みの場合は yum remove でアンインストールして下さい。
※記事中で使用する「hoge」「hoge.example.com」はユーザ名やホスト名の例です。逐次置き換えてください。

## 手順

1. Apache2 インストール (suEXEC)
1. MySQL インストール
1. PHP5.4 を CGI モードでインストール
1. Web サーバの設定
1. ホスティングユーザの環境整備 (半自動化)
1. Web サーバ起動・テスト

### Apache2 をインストール

SL6 に Webサーバ (Apache2) を、ソースコード RPM からインストールします。

#### RPMパッケージを取得

ユーザごとの DocRoot (/home/<ユーザ名>/public_html) 配下に設置した CGI を正しく動作させるためには、ソースコード RPM パッケージをダウンロードしてビルド・インストールする必要があります。

```shell-session:RPMパッケージをダウンロードして展開
[root@foo ~]# wget http://ftp1.scientificlinux.org/linux/scientific/6/SRPMS/vendor/httpd-2.2.15-28.sl6.src.rpm
... 省略 ...   

2013-06-16 20:42:27 (160 KB/s) - `httpd-2.2.15-28.sl6.src.rpm' へ保存完了 [6704526/6704526]

[root@foo ~]# rpm -ivh httpd-2.2.15-28.sl6.src.rpm
```

#### コンパイルオプションの修正

suEXEC のオプションを修正します。

```shell-session:SPECファイルを開く
[root@foo ~]# vi rpmbuild/SPECS/httpd.spec
```

先頭行の /var/www を /home に書き換えます

```vim:httpd.spec
%define contentdir /home
```

#### ビルド・インストール

まず、ビルドに必要なパッケージをインストールします。

```shell-session:ビルドに必要なパッケージをyumで一括インストール
[root@foo ~]# yum -y install rpm-build autoconf automake libtool xmlto apr-devel apr-util-devel pcre-devel distcache-devel zlib-devel libselinux-devel openssl-devel apr-util-ldap
```

httpd (Apache2) をビルドします。環境にもよりますが、少し時間がかかります。

```shell-session:Apache2をビルド
[root@foo ~]# rpmbuild -bb rpmbuild/SPECS/httpd.spec
... 省略 ...
書き込み完了: /root/rpmbuild/RPMS/x86_64/httpd-2.2.15-28.sl6.x86_64.rpm
書き込み完了: /root/rpmbuild/RPMS/x86_64/httpd-devel-2.2.15-28.sl6.x86_64.rpm
書き込み完了: /root/rpmbuild/RPMS/noarch/httpd-manual-2.2.15-28.sl6.noarch.rpm
書き込み完了: /root/rpmbuild/RPMS/x86_64/httpd-tools-2.2.15-28.sl6.x86_64.rpm
書き込み完了: /root/rpmbuild/RPMS/x86_64/mod_ssl-2.2.15-28.sl6.x86_64.rpm
書き込み完了: /root/rpmbuild/RPMS/x86_64/httpd-debuginfo-2.2.15-28.sl6.x86_64.rpm
実行中(%clean): /bin/sh -e /var/tmp/rpm-tmp.6RSJY6
+ umask 022
+ cd /root/rpmbuild/BUILD
+ cd httpd-2.2.15
+ rm -rf /root/rpmbuild/BUILDROOT/httpd-2.2.15-28.sl6.x86_64
+ exit 0
```

最後が exit 0 となっていればビルド成功です。
続いてインストールします。

```shell-session:インストール
[root@foo ~]# cd rpmbuild/RPMS/x86_64/
[root@foo x86_64]# ls -l 
合計 3916
-rw-r--r--. 1 root root  840196  6月 16 20:26 2013 httpd-2.2.15-28.sl6.x86_64.rpm
-rw-r--r--. 1 root root 2841500  6月 16 20:26 2013 httpd-debuginfo-2.2.15-28.sl6.x86_64.rpm
-rw-r--r--. 1 root root  152944  6月 16 20:26 2013 httpd-devel-2.2.15-28.sl6.x86_64.rpm
-rw-r--r--. 1 root root   73720  6月 16 20:26 2013 httpd-tools-2.2.15-28.sl6.x86_64.rpm
-rw-r--r--. 1 root root   91824  6月 16 20:26 2013 mod_ssl-2.2.15-28.sl6.x86_64.rpm
[root@foo x86_64]# #表示されたすべてのパッケージをインストールします。
[root@foo x86_64]# rpm -ivh --force httpd-2.2.15-28.sl6.x86_64.rpm \
httpd-debuginfo-2.2.15-28.sl6.x86_64.rpm \
httpd-devel-2.2.15-28.sl6.x86_64.rpm \
httpd-tools-2.2.15-28.sl6.x86_64.rpm \
mod_ssl-2.2.15-28.sl6.x86_64.rpm 
準備中...                ########################################### [100%]
   1:httpd-tools            ########################################### [ 20%]
   2:httpd                  ########################################### [ 40%]
   3:httpd-devel            ########################################### [ 60%]
   4:mod_ssl                ########################################### [ 80%]
   5:httpd-debuginfo        ########################################### [100%]
```

これで Apache2 のインストールは完了です。

### MySQL をインストール

MySQL は yum でインストールします。

```shell-session:MySQLインストール
[root@foo ~]# yum -y install mysql mysql-server mysql-devel
```

### PHP5.4 を CGI モードでインストール

#### 準備

EPEL リポジトリを yum に追加します。（既に追加済みの場合は飛ばして下さい）

```shell-session:EPELをyumに追加
[root@foo ~]# wget http://ftp.riken.jp/Linux/fedora/epel/RPM-GPG-KEY-EPEL-6
... 省略 ...   

2013-06-16 21:48:00 (107 MB/s) - `RPM-GPG-KEY-EPEL-6' へ保存完了 [1649/1649]

[root@foo ~]# rpm --import RPM-GPG-KEY-EPEL-6 
[root@foo ~]# rm -f RPM-GPG-KEY-EPEL-6 
[root@foo ~]# vi /etc/yum.repos.d/epel.repo
```

以下の内容で保存します。

```vim:epel.repo
[epel]
name=EPEL RPM Repository for Red Hat Enterprise Linux
baseurl=http://ftp.riken.jp/Linux/fedora/epel/6/$basearch/
gpgcheck=1
enabled=1
```

yum でライブラリをインストールします。

```shell-session:PHPに必要なライブラリをインストール
[root@foo ~]# yum -y install libxml2-devel libjpeg-devel libpng-devel zlib-devel curl-devel libmcrypt libmcrypt-devel readline readline-devel
```

続いて ICU (Symfonyなどで使われる国際化ライブラリ) をソースからインストール

```shell-session:ICUをインストール
[root@foo ~]# cd /usr/local/src
[root@foo src]# wget http://download.icu-project.org/files/icu4c/51.2/icu4c-51_2-src.tgz
[root@foo src]# tar zxf icu4c-51_2-src.tgz 
[root@foo src]# cd icu/source
[root@foo src]# ./configure
... 省略 ...

ok

[root@foo source]# make
[root@foo source]# make install
```

続いて iconv のインストール
iconv の最新版のURLは [ここ](http://www.gnu.org/software/libiconv/#downloading) からとってきてください。

```shell-session:iconvをインストール
[root@foo source]# cd /usr/local/src
[root@foo src]# wget http://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.14.tar.gz
... 省略 ...   

100%[========================================================================>] 4,984,397    970K/s 時間 6.1s    

2013-06-16 21:38:13 (800 KB/s) - `libiconv-1.14.tar.gz' へ保存完了 [4984397/4984397]

[root@foo src]# tar zxf libiconv-1.14.tar.gz 
[root@foo src]# cd libiconv-1.14
[root@foo libiconv-1.14]# ./configure --prefix=/usr/local
[root@foo libiconv-1.14]# make
[root@foo libiconv-1.14]# make install
```

#### インストール

やっと PHP のインストールです。

```shell-session:PHPのインストール
[root@foo source]# cd /usr/local/src
[root@foo src]# wget http://jp2.php.net/get/php-5.4.16.tar.gz/from/jp1.php.net/mirror
... 省略 ...   

100%[========================================================================>] 14,793,791  2.30M/s 時間 7.1s    

2013-06-16 21:24:58 (2.00 MB/s) - `php-5.4.16.tar.gz' へ保存完了 [14793791/14793791]

[root@foo src]# tar zxf php-5.4.16.tar.gz 
[root@foo src]# cd php-5.4.16
[root@foo php-5.4.16]# ./configure \
--enable-cgi \
--enable-mbstring \
--enable-mbregex \--enable-zip \
--enable-exif \
--with-regex \
--with-curl=/usr \
--with-gd \
--with-mysql \
--with-mysqli \
--with-mysqli=mysqlnd \
--with-pdo-mysql=mysqlnd \
--with-jpeg-dir \
--with-iconv=/usr/local \
--with-tsrm-pthreads \
--with-mcrypt \
--with-openssl \
--enable-gd-native-ttf \
--enable-maintainer-zts \
--enable-intl \
--with-readline
[root@foo php-5.4.16]# make
[root@foo php-5.4.16]# make install
```

PHP の設定ファイルを、テンプレートからコピーして作成します。
テンプレートは開発環境向けと本番環境向けが用意されています。
用途に応じて選んで下さい。（この例では開発環境向けを使用します。）

+ php.ini-development ...開発環境向け
+ php.ini-production ...本番環境向け

```shell-session:php.iniの作成
[root@foo php-5.4.16]# cp php.ini-development /usr/local/lib/php.ini
[root@foo php-5.4.16]# ln -s /usr/local/lib/php.ini /etc/php.ini #リンクを作成
```

PHP を高速化するアクセラレータをインストールします。
いろいろ訊かれますが、すべてそのまま Enter を押下します。

```shell-session:APCをインストール
[root@foo src]# pecl install apc
downloading APC-3.1.13.tar ...
Starting to download APC-3.1.13.tar (Unknown size)
................................done: 970,752 bytes
55 source files, building
running: phpize
Configuring for:
PHP Api Version:         20100412
Zend Module Api No:      20100525
Zend Extension Api No:   220100525
Enable internal debugging in APC [no] : 
Enable per request file info about files used from the APC cache [no] : 
Enable spin locks (EXPERIMENTAL) [no] : 
Enable memory protection (EXPERIMENTAL) [no] : 
Enable pthread mutexes (default) [no] : 
Enable pthread read/write locks (EXPERIMENTAL) [yes] : 
configuration option "php_ini" is not set to php.ini location
You should add "extension=apc.so" to php.ini
```

「You should add "extension=apc.so" to php.ini」と表示された場合は、言わたとおり php.ini に追記します。

```vim:/etc/php.ini
;;;;;;;;;;;;;;;;;;;;;;
; Dynamic Extensions ;
;;;;;;;;;;;;;;;;;;;;;;

extension=apc.so
```

ついでに、デフォルトタイムゾーンの設定もしておきましょう。

```vim:/etc/php.ini
[Date]
; Defines the default timezone used by the date functions
; http://php.net/date.timezone
date.timezone = "Asia/Tokyo"
```
### Webサーバの設定

名前ベースバーチャルホストの設定を行います。
各ホストの設定は別ファイルに切り出します。

```vim:/etc/httpd/conf/httpd.conf#

# AddType allows you to add to or override the MIME configuration
# file mime.types for specific file types.
#
#AddType application/x-tar .tgz
AddType application/x-httpd-php .php
AddType application/x-httpd-php-source .phps

...省略...

#
# AddHandler allows you to map certain file extensions to "handlers":
# actions unrelated to filetype. These can be either built into the server
# or added with the Action directive (see below)
#
# To use CGI scripts outside of ScriptAliased directories:
# (You will also need to add "ExecCGI" to the "Options" directive.)
#
AddHandler cgi-script .cgi .pl

...省略...

#
# Use name-based virtual hosting.
#
NameVirtualHost *:80
Include conf.vh/*.conf
```

```shell-session:バーチャルホスト設定ファイルディレクトリ作成
[root@foo ~]# mkdir /etc/httpd/conf.vh
```

### ホスティングユーザの環境整備 (半自動化)

続いてホスティングユーザを追加するスクリプトを作ります。

```shell-session:ユーザ追加スクリプト作成
[root@foo ~]# vi hostinguseradd.sh
```

```bash:hostinguseradd.sh
#!/bin/bash
USERNAME=$1
HOSTNAME=$2

if [ $# -lt 1 ]
then
	echo "usage: ./hostinguseradd.sh <username> [<hostname>]"
	exit 1
fi

useradd $USERNAME
ret=$?
if [ $ret -ne 0 ]
then
	exit 1
fi

passwd $USERNAME
chmod 710 "/home/$USERNAME"
usermod -a -G $USERNAME apache
mkdir "/home/$USERNAME/public_html"
mkdir "/home/$USERNAME/cgi-bin"
cat << EOS > "/home/$USERNAME/cgi-bin/php-cgi"
#!/bin/sh
exec /usr/local/bin/php-cgi
EOS
chown -R $USERNAME:$USERNAME "/home/$USERNAME/public_html"
chown -R $USERNAME:$USERNAME "/home/$USERNAME/cgi-bin"
chmod 710 "/home/$USERNAME/public_html"
chmod -R 710 "/home/$USERNAME/cgi-bin"

if [ $# -eq 2 ]
then
cat << EOS > "/etc/httpd/conf.vh/${HOSTNAME}.conf"
# ${HOSTNAME}
<VirtualHost *:80>
    ServerName ${HOSTNAME}
    DocumentRoot "/home/${USERNAME}/public_html"
    ServerAdmin root@localhost
    SuexecUserGroup ${USERNAME} ${USERNAME}
    ScriptAlias /php5-${USERNAME} /home/${USERNAME}/cgi-bin/php-cgi
    
    ErrorLog /var/log/httpd/${USERNAME}-error.log
    CustomLog /var/log/httpd/${USERNAME}-access.log combined
    <Directory "/home/${USERNAME}/public_html">
        Options FollowSymLinks ExecCGI
        DirectoryIndex index.php index.html index.htm index.cgi
        AllowOverride All
        Order allow,deny
        Allow from all
        Action php5-cgi /php5-${USERNAME}
        AddHandler php5-cgi .php
    </Directory>
</VirtualHost>
EOS
fi

echo "hostinguseradd success"
exit 0

```

ユーザを追加してみます。
次のように使用します。
./hostinguseradd.sh <ユーザ名> <ホスト名>

```shell-session:ユーザを追加
[root@foo ~]# chmod 700 hostinguseradd.sh #その前に実行権限を付与
[root@foo ~]# ./hostinguseradd.sh hoge hoge.example.com
ユーザー hoge のパスワードを変更。
新しいパスワード:
新しいパスワードを再入力してください:
passwd: 全ての認証トークンが正しく更新できました。
hostinguseradd success
[root@foo ~]# cat /etc/httpd/conf.vh/hoge.example.com #生成されたVH設定ファイルを確認
# hoge.example.com
<VirtualHost *:80>
    ServerName hoge.example.com
    DocumentRoot "/home/hoge/public_html"
    ServerAdmin root@localhost
    SuexecUserGroup hoge hoge
    ScriptAlias /php5-hoge /home/hoge/cgi-bin/php-cgi

    ErrorLog /var/log/httpd/hoge-error.log
    CustomLog /var/log/httpd/hoge-access.log combined
    <Directory "/home/hoge/public_html">
        Options FollowSymLinks ExecCGI
        DirectoryIndex index.php index.html index.htm index.cgi
        AllowOverride All
        Order allow,deny
        Allow from all
        Action php5-cgi /php5-hoge
        AddHandler php5-cgi .php
    </Directory>
</VirtualHost>
```

### Web サーバ起動・テスト

```shell-session:Apache起動
[root@foo ~]# service httpd start #Apache起動
[root@foo ~]# chkconfig httpd on #Apache自動起動ON
```

#### Apache 起動時に警告が出る場合

ここで「Warning: DocumentRoot [/home/hoge/public_html] does not exist」と警告がでる場合、SELinux が有効になっていることが原因です。SELinuxを無効化するには、次のようにします。

```shell-session:SELinuxを無効化
[root@foo ~]# setenforce 0
[root@foo ~]# service httpd restart #Apache再起動を忘れずに
```

もしくは、次のようにすると、httpdがhomedirにアクセスすることを許可できます。

```shell-session:SELinuxでhomeへのアクセスを許可
[root@foo ~]# setsebool -P httpd_enable_homedirs=1
```

/etc/sysconfig/selinux を書き換えておくと、次回ブート時に SELinux が有効にならないように出来ます。

```vim:/etc/sysconfig/selinux
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#     enforcing - SELinux security policy is enforced.
#     permissive - SELinux prints warnings instead of enforcing.
#     disabled - No SELinux policy is loaded.
SELINUX=permissive  # enforcing -> permissive
# SELINUXTYPE= can take one of these two values:
#     targeted - Targeted processes are protected,
#     mls - Multi Level Security protection.
SELINUXTYPE=targeted
```

#### テスト用PHPファイル作成

次の内容で新規作成します。

```php:/home/hoge/public_html/index.php
<?php phpinfo(); ?>
```

以上で作業は完了です。
ブラウザで hoge.example.com にアクセスしてみて下さい。
ローカルからのアクセスやDNSサーバを準備していない場合、一時的に /etc/hosts ファイルにホスト名を追記することでアクセスできます。

hostinguseradd.sh でユーザを追加した後は、必ず Apache を再起動して下さい。
実際には、さらに DNS サーバの構築や設定が必要になりますが、それはまた別の話ということで。