小規模サイトを沢山持つWeb制作会社向けのテスト環境を構築してみた

そこまで大きくない大きくても50ページ位のサイトを沢山制作・運営サポートをしているWeb制作会社向けのテスト環境として、下記のようなモノを用意してみました。

* 絶対パス使ってるサイトもある
  * テスト環境だとは言っても**サブディレクトリは嫌だ**
* お客様の環境によってPHPのバージョンが違う
  * マイナーバージョンはしょうがないにしても、ある程度**PHPのバージョンを併せたい**
* ただ、テスト環境にはそこまでお金を掛けたくない
  * **サーバは一つにしたい**

ということで、サーバ一つで上記仕様が解決出来る環境を考えてみました。
（OSはAmazon Linux、Apacheは2.2の環境です）

## TL;DR

PHPを複数インストールして、Apacheの設定を頑張ったら、

```
http://p56.client.example.com/
 -> /var/www/vhosts/client/p56/htdocs
 -> PHP5.6が動く！

http://p53.client.example.com/
 -> /var/www/vhosts/client/p53/htdocs
 -> PHP5.3が動く！
```

という環境が出来た。


## サブディレクトリは嫌だ

取り敢えず簡単にテスト環境を用意しようとすると、例えば

```
http://example.com/client_name/20170804/
```

みたいなコトになるかと思いますが、この様な環境下で絶対パスが前提として制作された案件があったとすると、このテスト環境下では動かなくなってしまいます…。

そこで、せめて案件ごとにサブディレクトリを簡単に切れる環境を用意してみます。

### ApacheのVirtualDocumentRootが便利

これは、Apacheの`VirtualDocumentRoot`を利用することで簡単に実現することが出来ます。

```apache:virtual.conf
<VirtualHost *:80>
  ServerName example.com
  ServerAlias *.example.com
  VirtualDocumentRoot /var/www/vhosts/%1/htdocs

  <Directory /var/www/vhosts/*/htdocs/>
    Options +ExecCGI +FollowSymlinks
    AllowOverride All
    Allow from all
  </Directory>
</VirtualHost>
```

上記の様に`ServerAlias`にワイルドカードを渡すと、`VirtualDocumentRoot`に`%1`, `%2`...という形で値を渡すことが可能です。

つまり上記のように記述すると、

```
http://clienta.example.com/ -> /var/www/vhosts/clienta/htdocs
http://clientb.example.com/ -> /var/www/vhosts/clientb/htdocs
```

と、一つの設定でサブドメインを振り分けることが出来ます。

また、コチラの設定は複数の階層を設定することが出来るため、例えば下記のようにすることも可能です。

```apache:virtual.conf
<VirtualHost *:80>
  ServerName example.com
  ServerAlias *.*.example.com
  VirtualDocumentRoot /var/www/vhosts/%2/%1/htdocs

  <Directory /var/www/vhosts/*/*/htdocs/>
    Options +ExecCGI +FollowSymlinks
    AllowOverride All
    Allow from all
  </Directory>
</VirtualHost>
```

```
http://recruit.clienta.example.com/ -> /var/www/vhosts/clienta/recruit/htdocs
http://company.clienta.example.com/ -> /var/www/vhosts/clienta/company/htdocs

http://company.clientb.example.com/ -> /var/www/vhosts/clientb/company/htdocs
```


### DNSも設定する

ドメイン側も追加する度にレコードを増やすのが大変なので、コチラもワイルドカードを使って、毎回追加しなくても良いようにします。

```
example.com.       1800    IN  A     0.0.0.0
*.example.com.     18000   IN  CNAME example.com
```

と言うかたちで設定しておけば、複数階層のサブドメインまで全て`example.com`と同じサーバに繋がるようになります。

### 問題点

ログをドメインごとに分けることが出来ず、一つに集約されてしまうため、ログを確認しないといけないときには面倒な時があります…。


## PHPのバージョンを併せたい

続いて、案件ごとにPHPのバージョンを変えるための設定を行います。

今回はphpenvで複数バージョンのPHPをインストールを行いました。（最近の流行りはanyenv経由なのだと思いますが…）

### phpenv + php-buildを用意する

マニュアルのとおりにphpenvとphp-buildをインストールします。

```bash
# phpenv
git clone https://github.com/CHH/phpenv.git
phpenv/bin/phpenv-install.sh

# php-build
curl -L http://git.io/phpenv-installer \
    | bash
```

php-buildのバージョンをアップした時に戻ってしまいそうですが…default_configure_optionsを書き換えてコンパイル時のオプションを変更します。

```bash
cd ~/.phpenv/plugins/php-build/share/php-build/
# 念のため残しておく
cp default_configure_options default_configure_options.orig
vi default_configure_options
```

変更点は下記の通り

```diff:default_configure_options
# バージョンによってphp-cgiが作られない事があったのでfpmを無効化
- --enable-fpm
# intlが上手く入らなかったため無効化、どこか足りないライブラリがあったのだと思いますが…
- --enable-intl
# 設定しておかないとmysql.sockへのパスが空になってしまったので追加
# パスは適宜変更すること
+ --with-mysql-sock=/var/lib/mysql/mysql.sock
```

### ビルドに必要なライブラリをインストール

PHPをビルドするためのライブラリを沢山インストールします。

```bash
# まずはC, C++周り
sudo yum install gcc
sudo yum install gcc-c++

# 足りないと怒られた諸々
sudo yum install libxml2-devel bzip2-devel libcurl-devel libjpeg-devel libpng-devel libicu-devel libmcrypt-devel readline-devel libtidy-devel bison-devel re2c libxslt-devel

# 最後のコンパイル時に下記がないと通らなかったため追加
sudo yum install autoconf
sudo yum install automake
```

### PHPのインストール

これで準備は整いました、ということで幾つかのバージョンをインストールしてみます。

```
phpenv install 7.1.7
phpenv install 5.6.31
phpenv install 5.3.29
phpenv install 5.2.17
```

> 5.2.17はそのままだと上手くインストールされず、下記のパッチを当てています。
> https://code.google.com/archive/p/php52-backports/issues/16
> 
> ただ、それでもちょっと動作が不安定なので使用を見送り中…。

コンパイルにやたら時間がかかりますが、インストールが完了すると、

```
~/.phpenv/versions/(バージョン番号)/bin/php-cgi
```

に、CGIモジュールが作成されているはずです。


### Apacheで使える様に設定する

最後にApacheで使えるように設定を行います。
まずは、httpd.confの`ScriptArias`に指定されているディレクトリにコピーします。

```bash
# /var/www/cgi-binは環境によって適宜変更すること
sudo cp ~/.phpenv/versions/7.1.7/bin/php-cgi /var/www/cgi-bin/php71
sudo cp ~/.phpenv/versions/5.6.31/bin/php-cgi /var/www/cgi-bin/php56
sudo cp ~/.phpenv/versions/5.3.29/bin/php-cgi /var/www/cgi-bin/php53
sudo cp ~/.phpenv/versions/5.2.17/bin/php-cgi /var/www/cgi-bin/php52
```

> シンボリックリンクでも出来ると思うのですが、イマイチ上手く行かなかったので、今回は見送りました。

次にhttpd.confに上記までのパスを追記します。

```apache:httpd.conf
Action php56 /cgi-bin/php56
Action php53 /cgi-bin/php53
Action php52 /cgi-bin/php52
Action php71 /cgi-bin/php71
```

これで、.htaccessに

```
AddHandler php71 .php
```

と記述することで、PHP7.1が実行される様になりますので、ディレクトリ毎に異なったバージョンのPHPを実行出来るようになります。


### でも.htaccessも案件独自のモノがあるんだけど…

ただ、案件によっては.htaccessが既にあったりするので、それに追記するのはミスに繋がったりしそうで嫌ですよね。

そこで、**VirtualDocumentRoot**が再び登場します。今回は先の例を応用して、下記のように追記を行い特定の命名規則のフォルダにある場合にPHPのバージョンが切り替わるように設定しました。

```apache:virtual.conf
<VirtualHost *:80>
  ServerName example.com
  ServerAlias *.*.example.com
  VirtualDocumentRoot /var/www/vhosts/%2/%1/htdocs

  <Directory /var/www/vhosts/*/*/htdocs/>
    Options +ExecCGI +FollowSymlinks
    AllowOverride All
    Allow from all
  </Directory>

  # p56フォルダ内はPHP5.6
  <Directory /var/www/vhosts/*/p56/htdocs/>
    AddHandler php56 .php
  </Directory>

  # p53フォルダ内はPHP5.3
  <Directory /var/www/vhosts/*/p53/htdocs/>
    AddHandler php53 .php
  </Directory>

  # p52フォルダ内はPHP5.2
  <Directory /var/www/vhosts/*/p52/htdocs/>
    AddHandler php52 .php
  </Directory>

  # p71フォルダ内はPHP7.1
  <Directory /var/www/vhosts/*/p71/htdocs/>
    AddHandler php71 .php
  </Directory>
</VirtualHost>
```

これで、

```
http://p56.client.example.com/
 -> /var/www/vhosts/client/p56/htdocs
 -> PHP5.6が動く！

http://p53.client.example.com/
 -> /var/www/vhosts/client/p53/htdocs
 -> PHP5.3が動く！
```

という形で、特定のフォルダに入れるとバージョンが切り替わる様になりました。


## 長い雑感

テストで動かしていて、本番に持っていくとPHPのバージョンが違って動かない、といったことがあり、仮想サーバを何個か立ち上げて対応したこともありましたが、毎回Webサーバを立てたりするのが面倒で、何とか出来ないか考えていました。

ansibleとか使えば仮想環境の構築自体も自動化出来ると思いますが、今回は**ある程度近い環境をお手軽に用意する**というのを目指していますので、vagrantやらdockerやらの仮想環境の構築は見送りました。

本来的にはApacheやMySQLなども合ってる方が良いんですが…特定バージョンに依存するような特殊な処理も行っていないですし、小さな案件の場合は**どうしても引っかかるのはPHP**という状態でした。

この設定でアップロードする場所を選ぶだけど、それなりに近い環境を選択できる様になったため、ある程度解消出来るようになるのを期待しています、*が、PHP5.2が上手く動いていないのに気づいて、他のバージョンでも起きていないか内心ビクビクしていたりします。*

後はGitからの簡単な自動デプロイ機能を予定しています。あー楽したい。