CentOS7 + Apache2.4 + MySQL5.7 + PHP7 で作る最新LAMP環境 on さくらVPS

いわゆるLAMP環境を最新の環境で構築した時の備忘録です。

# 経緯
長くWebサービスを運営していたりすると、CentOS5系をいつまでも使っていたり、Apache2.2系であったり、まだPHP5.3だったり、よくて5.6だったり、、とすべてが最新になっていないことが多々あると思います。運営されているサービスである以上、ユーザーファーストであることが求められるので保守的になってしまうからです。
ということで、個人でさくらVPSを契約して最新環境を構築してみました。

今のトレンドだと、もう一歩先に行っていて、AWSの上にNginx + PHP7(PHP-FPM)、DBは MariaDBであるのかなとも思いますが「これまでのLAMP環境」と比べたかったので、それぞれ最新にして動かしてみたいということを目的としています。
AWSではなく、さくらVPSにしたのも、インストール作業時に悩みながら構築をしたいためです。

# さくらVPSにCentOS7をインストール
さくらVPSのコントロール画面から [OSインストール>カスタムOSインストール] を選択してCentOS7をインストールします。
なお、コントロール画面からの初回起動時は、RPMの更新がかかるので、サーバーへログイン可能となるまで時間がかかるので注意。
VNCコンソールを開くと Updating RPMS on system: と表示されるところで時間がかかる。
![Updating-RPMS-on-system-CentOS.png](https://qiita-image-store.s3.amazonaws.com/0/142172/39c185be-013f-5cad-0b21-6d8145afa207.png)

20分～30分程度待ちVNCコンソールを確認すると、次の処理に進んでいて、最終的に無事 login プロンプトが表示されます。
※TeratermなどのSSHクライアントからの接続もできるようになってるはずです。

# CentOS7
## 1. 一般ユーザ作成

rootしかない状態なので、一般ユーザを作成します(hoge)

```
$ useradd hoge
$ passwd hoge
```

ユーザー一覧確認

```
$ cat /etc/passwd
```

ユーザー名、グループなどの確認

```
$ id hoge
```

グループ名＝ユーザー名となっているので、必要であればグループ名は適宜変更(developer)

```
$ groupmod -n developer hoge
```

## 2. sudo設定
作成した一般ユーザー(hoge)にsudo権限付与
visudoで/etc/sudoersを開き、下記の行のコメントアウトを外す

```
$ visudo

%wheel ALL=(ALL) ALL
```

## 3.ユーザーをwheelグループに追加

```
$ usermod -G wheel hoge
```

## 4. su設定
wheelグループのみにする
下記の行のコメントアウトを外す

```
$ vi /etc/pam.d/su

auth            required        pam_wheel.so use_uid
```

## 5. 日本語化（ロケールの変更）

```
$ localectl set-locale LANG=ja_JP.UTF-8
```
ロケール確認

```
$ localectl status

   System Locale: LANG=ja_JP.UTF-8
       VC Keymap: jp106
      X11 Layout: jp
```

## 6. SELinuxの停止
下記の行を設定する

```
$ vi /etc/selinux/config

SELINUX=disabled
```

## 7. firewalld
CentOS7からファイアウォールの設定が「iptables」から「firewalld」に変更となっています

現在の設定の確認（デフォルト）

```
$ firewall-cmd --list-all

public (default, active)
  interfaces: eth0
  sources:
  services: dhcpv6-client ssh
  ports:
  masquerade: no
  forward-ports:
  icmp-blocks:
  rich rules:
```

httpを追加して、設定反映
(80番ポートを開けたい)

```
$ firewall-cmd --add-service=http --permanent

success

$ firewall-cmd --reload

success
```

再度、確認。

```
$ firewall-cmd --list-all

public (default, active)
  interfaces: eth0
  sources:
  services: dhcpv6-client http ssh
  ports:
  masquerade: no
  forward-ports:
  icmp-blocks:
  rich rules:
```

## 8. 再起動

```
shutdown -r now
```

# リポジトリの設定
インストールに使うリポジトリの設定をします。
CentOSには、公式のリポジトリが用意されていて、通常のyumコマンドで利用可能ですが、保守的で最新のソフトウェアやバージョン更新が行われないので、epelやremiというパッケージをインストールして、各リポジトリにある最新のソフトウェアを利用します。

## 1. epelパッケージのインストール

```
$ yum install epel-release.noarch
```

[epel]の部分のenable=1を、enable=0 に書き換える

```
$ vi /etc/yum.repos.d/epel.repo

[epel]
name=Extra Packages for Enterprise Linux 7 - $basearch
#baseurl=http://download.fedoraproject.org/pub/epel/7/$basearch
mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-7&arch=$basearch
failovermethod=priority
enabled=0
```

## 2. remiのインストール

```
$ rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
```

[remi]の部分のenable=1を、enable=0 に書き換える

```
$ vi /etc/yum.repos.d/remi.repo

[remi]
name=Remi's RPM repository for Enterprise Linux 7 - $basearch
#baseurl=http://rpms.remirepo.net/enterprise/7/remi/$basearch/
mirrorlist=http://rpms.remirepo.net/enterprise/7/remi/mirror
enabled=0
```

# Apache2.4

## 1. インストール

```
$ yum install httpd
```

## 2. 起動

```
$ systemctl start httpd.service
```

※自動起動の設定

```
$ systemctl enable httpd.service
```

# MySQL5.7
CentOS7では、mariaDB(MySQL互換のDB)がデフォルトでインストールされている場合があるので、MySQLと競合を起こさないように削除します。

## 1. mariaDB、既存MySQL削除

```
$ yum remove mariadb-libs
$ yum remove mysql* 
```

## 2. インストール
※適宜URLは最新に変更すること

```
$ yum install http://dev.mysql.com/get/mysql57-community-release-el7-9.noarch.rpm
$ yum -y install mysql-community-server
```

## 3. バージョン確認

```
$ mysqld --version

mysqld  Ver 5.7.15 for Linux on x86_64 (MySQL Community Server (GPL))
```

## 4. 起動

```
systemctl start mysqld.service
```

※自動起動の設定

```
systemctl enable mysqld.service
```

## 5. rootユーザーの初期パスワード
MySQL5.7では、初回起動と同時にrootユーザーにランダム文字列のパスワードが設定され、ログに出力される。

```
$ cat /var/log/mysqld.log | grep 'password is generated'

201*-**-15T09:53:28.904448Z 1 [Note] A temporary password is generated for root@localhost: _aBC12#/dEF:
```

## 6. 初期設定
mysql_secure_installationコマンドで設定していきます。
※新しいルートのパスワードは、大文字、小文字、数字、記号の全てが入っている必要があるので注意

```
$ mysql_secure_installation

Enter password for user root: //ログに出力されていた初期パスワードを入力
Set root password?　//ルートのパスワードを変更しますか？ Yでパスワード設定
Remove anonymous users?　//誰でもログイン可能になっているが消しますか？ Yで消しとく
Disallow root login remotely?　//リモートからrootログインを許可しませんか？ Yでしない
Remove test database and access to it?　//テストデータベース消していいですか？ Yで消す
Reload privilege tables now?　//設定をすぐに反映しますか？ Yで反映
All done!
```

## 7. MySQL接続確認

```
$ mysql -u root -p
Enter password:
```

## 8. my.cnf 設定

```
mysql> SHOW VARIABLES LIKE 'char%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       |
| character_set_connection | utf8                       |
| character_set_database   | latin1                     |
| character_set_filesystem | binary                     |
| character_set_results    | utf8                       |
| character_set_server     | latin1                     |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)
```

my.cnfに以下を設定します

- ストレージエンジンを、InnoDB、データファイル・ログファイルをテーブルごとに設定
- 文字コードをutf8に

```
vi /etc/my.cnf

[mysqld]
default-storage-engine=InnoDB
innodb_file_per_table
 
character-set-server = utf8
collation-server = utf8_general_ci

[mysql]
default-character-set = utf8 
 
[client]
default-character-set = utf8
```

```
mysql> SHOW VARIABLES LIKE 'char%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       |
| character_set_connection | utf8                       |
| character_set_database   | utf8                       |
| character_set_filesystem | binary                     |
| character_set_results    | utf8                       |
| character_set_server     | utf8                       |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.02 sec)

mysql> SHOW VARIABLES LIKE 'innodb_file_per_table';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_file_per_table | ON    |
+-----------------------+-------+
1 row in set (0.00 sec)
```

# PHP7
## 1. libmcrypt
mcryptのインストールに必要なので先にインストール

```
$ yum --enablerepo=epel install libmcrypt
```

## 2. インストール
FastCGIで動かせるPHP-FPM、キャッシュ周りのOPcache、APCuはインストールしておきます（後述）

```
$ yum --enablerepo=remi-php70 install -y php php-cli php-devel php-common php-mbstring php-mysql php-fpm php-gd php-mcrypt php-opcache php-pdo php-xml
```

```
$ php -v
PHP 7.0.17 (cli) (built: Mar 14 2017 15:14:30) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies
    with Zend OPcache v7.0.17, Copyright (c) 1999-2017, by Zend Technologies
```

## 3. php.ini 設定

初期ファイルのバックアップ

```
$ cp /etc/php.ini /etc/php.ini.bk
```

php.iniに以下を設定します

```
$ vi /etc/php.ini

[PHP]
# レスポンスヘッダにPHPのバージョンを表示しない
expose_php = Off
# 全てのログを出力
error_reporting = E_ALL
# ブラウザでエラーを表示しない
display_errors = Off
# エラーをログに残す
log_errors = On
# エラーログの長さを設定
log_errors_max_len = 4096
# エラーログ出力先
error_log = "/var/log/php_errors.log"
# 文字エンコーディング
default_charset = "UTF-8"

[Date]
# タイムゾーン
date.timezone = "Asia/Tokyo"

[mbstring]
# デフォルト言語
mbstring.language = Japanese
# 内部文字エンコーディング
mbstring.internal_encoding = UTF-8
# HTTP入力文字エンコーディングのデフォルト
mbstring.http_input = auto
# 文字エンコーディング検出順序のデフォルト
mbstring.detect_order = auto
```

## 4. 動作確認

ドキュメントルートにphpinfoを出力するphpファイルを作成します。
※/var/www/html/ …ドキュメントルート

```
$ vi /var/www/html/info.php

<?php
	// すべての情報を表示します。デフォルトは INFO_ALL です。
	phpinfo();
```

アクセスして表示されれば、OKです。
![info.png](https://qiita-image-store.s3.amazonaws.com/0/142172/28301a60-efaa-03b6-b20a-0ec9e545831c.png)




# キャッシュ
## APCu
ユーザキャッシュ（データキャッシュ）のこと。
プログラム上で、コードを記述して使う（memcachedのようなイメージ）
参考：
https://icondecotter.jp/blog/2016/03/31/php7%E3%81%A7apcu%E3%82%92%E4%BD%BF%E3%81%86/

## OPcache
オペコードキャッシュ（サーバキャッシュ/アクセラレータ）のこと。
インストールしてあれば、デフォルトで有効。
設定値の最適化は以下参考：
http://php.net/manual/ja/opcache.configuration.php

# PHP-FPM
今回、PHP-FPMは目的としていないですが、簡単に切り替えできるので設定をメモ

## PHP-FPMとは
FPM(FastCGI Process Manager)はPHPのFastCGIでの実装の１つ。

## FastCGIとは
CGIの高速化・負荷を軽減するための動作仕様の１つ。
まず、前提として、webサーバでのPHPの実行環境は、モジュール版とCGI版という二種類があります。
モジュール版は、Webサーバーのプロセスの中でPHPを実行する方法です。 Apacheであれば基本はモジュール版で動作します。
CGI版は、実行ファイル形式で動くので、Webサーバーとは別のプロセスで実行されます。ユーザーからのリクエストの度に、プロセスの生成/破棄が発生するので、大量のリクエストがあると大量のプロセスの生成/破棄が発生し、この事がパフォーマンスを悪化します。それゆえに、モジュール版で動作させるのが定石でした。
FastCGIは、CGIの高速化・負荷軽減を行った実行環境です。初回リクエスト時に実行したプロセスをメモリ上へ保持することで、次回リクエスト時はメモリ上のプロセスを実行し、高速化や、プロセスの生成/破棄に伴うCPUへの負荷を軽減します。
パフォーマンス面は、モジュール版>=FastCGI>>>>>CGIといったところ。
FastCGIの一番のメリットは、CGIのメリットを活かしつつ高速化したところだと思います。（CGIを動かす各ユーザーは、Webサーバーを動かすユーザーとは切り離されているので、他ユーザーに干渉してしまうといった危険がない）
ただし、現在のトレンドとしてapacheではなくnginxと組み合わせて使うことで、apacheモジュール版よりもハイパフォーマンスになります。

## 1. 起動
起動中か確認

```
$ ps ax | grep php-fpm
```

起動/停止

```
$ systemctl start php-fpm
$ systemctl stop php-fpm
```

※永続的に使う場合（自動的に起動）

```
$ systemctl enable php-fpm
```

## 2. apache conf設定

/etc/httpd/conf.d/ 配下にconfファイルを新規作成してhttpd.confで読み込まれるようにする
※/var/www/html/ …ドキュメントルート

```
$ vi /etc/httpd/conf.d/php-fpm.conf

# ProxyPassMatch でPHPファイルはfcgiに流すように指定
ProxyPassMatch ^(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/var/www/html/$1 disablereuse=on
```

## 3. 切り替え
モジュール版への切り替え

```
$ systemctl stop php-fpm
$ mv /etc/httpd/conf.d/php-fpm.conf /etc/httpd/conf.d/php-fpm.conf.bk
$ systemctl reload httpd.service
```

![module.png](https://qiita-image-store.s3.amazonaws.com/0/142172/8470ae5d-1881-9273-181d-ac8c16acdbc7.png)



PHP-FPMへの切り替え

```
$ systemctl start php-fpm
$ mv /etc/httpd/conf.d/php-fpm.conf.bk /etc/httpd/conf.d/php-fpm.conf
$ systemctl reload httpd.service
```

![fpm.png](https://qiita-image-store.s3.amazonaws.com/0/142172/14be1969-4225-46cc-66b1-72253adf2762.png)