王道Webサーバ構成を構築する

# 【概要】
この記事は王道Webサーバ構成であるLAMP環境をローカル開発環境であるVagrantを使って構築してみる記事となります。また、構築しないまでもWebプログラミングの学習をされている初学者の方は参考程度に読んでいただければと思います。

# 【対象者】
- Webプログラミングを始めて数ヶ月から一年程度の初学者
- WebサーバをLAMP環境で構築したい方

# 【事前知識】
- VirtualBox/Vagrantのインストールと基礎知識 [参考記事](https://weblabo.oscasierra.net/vagrant/)
- LAMP環境の基礎知識 [参考記事](https://furien.jp/columns/90/)
- UNIXコマンドの基礎知識 [参考記事](https://techacademy.jp/magazine/6406)
- Webサーバ概略図

Webサーバはクライアントから情報処理の依頼を受け付けたりクライアントへ情報を提供することが主な役割となる。下の配置図のようにAPサーバがリクエストを受け付けプログラムを実行し、データの取得や加工をする。その後リクエスト元にレスポンスとしてデータを返却する。
<img src="http://drive.google.com/uc?export=view&id=1QfOw7QgYJ9q6oNW8upnWdB6x1gy7pdxi" >

具体的な名称を上げると下記のような技術が分類されます。

- OS ... Linux Windowsサーバ
- APサーバ ... ApacheHTTPServer NginX Tomcat
- 実行プログラム ... PHP Java C++
- データベース ... MySQL Oracle NoSQL

<details>
<summary><font color="OrangeRed">**注意点**</font></summary>
実際に運用されているWebサービスのサーバにおいて、上記図のようなアプリケーションとデータベースが同居するような構成となっていることはほぼないと思います。外部から接続があった場合、セキュリティや負荷分散を考慮してProxyやロードバランサを経由して受信しますし、DBもアプリケーションとは切り離した別のサーバでマスター/スレーブ構成などで運用されると思います。飽くまで開発環境や低可用性を許容した小規模システムを構築する場合などの参考にしてください。
</details>

# 【環境構築】
Vagrantを使ってWebサーバを立て、そこにApacheやMySQLをインストールしアプリケーションプログラムと連携できるよう設定します。最後にローカルPCのブラウザから画面表示とデータ検索ができれば構築完了となります。アプリケーションプログラムは[こちら](https://github.com/hys-rabbit/FindWiki)のサンプルコードを使用します。

## VMの起動
まずはVagrantでLinuxのVMを起動します。今回ディストリビューションはCentOS7でBOXは[こちら](https://app.vagrantup.com/bento/boxes/centos-7)を使用します。起動したらログインして環境を作っていきます。

```console:
[vagrant@localhost ~]$ cat /etc/centos-release
CentOS Linux release 7.5.1804 (Core) 
```
後にyum経由でPKGをいくつかインストールするのでepelとiusのrpmをインストールしておきます。

```console:
[vagrant@localhost ~]$ sudo rpm -ivh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm https://centos7.iuscommunity.org/ius-release.rpm
.
.
.

// インストールされたことを確認
[vagrant@localhost ~]$ rpm -aq | grep -E "(epel-release|ius-release)"
ius-release-1.0-15.ius.centos7.noarch
epel-release-7-11.noarch
```

VMの起動が完了したらログインして必要となるPKGをインストールしていきますが、まずはその前に[サンプルコード](https://github.com/hys-rabbit/FindWiki)をダウンロードして解凍します。

```console:
// 50MB強あるのでdownloadに5分ほどかかる
[vagrant@localhost ~]$ wget https://github.com/hys-rabbit/FindWiki/archive/master.zip
.
.
.

// zipもunzipも入ってないと思うのでインストールする
[vagrant@localhost ~]$ sudo yum install -y zip unzip
.
.
.

// ダウンロードしたzipを解凍する
[vagrant@localhost ~]$ unzip master.zip 
.
.
.
```
上記まで終わると`FindWiki-master`というディレクトリができていると思います。
ちなみにgitでcloneする場合は下記ととなります。

```console:
// git2.0系であるgit2u-2が候補にあることを確認してインストール（git1.0系でも問題ない）
[vagrant@localhost ~]$ yum --showduplicates search git | grep -E "^git2u-2"
git2u-2.16.2-1.ius.centos7.x86_64 : Fast Version Control System
git2u-2.16.4-1.ius.centos7.x86_64 : Fast Version Control System
git2u-2.16.5-1.ius.centos7.x86_64 : Fast Version Control System

[vagrant@localhost ~]$ sudo yum install git2u-2.16.5-1.ius.centos7.x86_64 -y
.
.
.

[vagrant@localhost ~]$ git --version
git version 2.16.5 

// サンプルコードのリポジトリをフォークしてクローンする
// 50MB強あるのでクローンに5分ほどかかる
[vagrant@localhost ~]$ git clone https://github.com/<yourname>/FindWiki.git
.
.
.
```
上記まで終わると`FindWiki`というディレクトリができていると思います。

## MySQLの準備
今回使用するサンプルコードではデータベースとしてMySQLを使うのでWebサーバにMySQL5.7をインストールします。手順としては[公式サイト](https://dev.mysql.com/downloads/repo/yum/)を参考にrpmをインストールした後yumでmysql-community-serverをインストールします。

```console:
// rpmをインストールする
[vagrant@localhost ~]$ sudo rpm -ivh https://dev.mysql.com/get/mysql80-community-release-el7-2.noarch.rpm
.
.
.

// インストールされたことを確認する
[vagrant@localhost ~]$ rpm -aq | grep mysql                                                                                                                                       
mysql80-community-release-el7-2.noarch  

// yumリポジトリで有効となっているmysql-community-serverを確認するとMySQL8.0が有効となっている
// 今回は5.7を使用するので8.0を無効化し5.7を有効化する。
[vagrant@localhost ~]$ yum repolist all | grep -E "mysql.[00-99]-community"
mysql55-community/x86_64           MySQL 5.5 Community Server       無効
mysql55-community-source           MySQL 5.5 Community Server - Sou 無効
mysql56-community/x86_64           MySQL 5.6 Community Server       無効
mysql56-community-source           MySQL 5.6 Community Server - Sou 無効
mysql57-community/x86_64           MySQL 5.7 Community Server       無効
mysql57-community-source           MySQL 5.7 Community Server - Sou 無効
mysql80-community/x86_64           MySQL 8.0 Community Server       有効:     82
mysql80-community-source           MySQL 8.0 Community Server - Sou 無効
[vagrant@localhost ~]$ sudo yum-config-manager --disable mysql80-community
.
.
.
[vagrant@localhost ~]$ sudo yum-config-manager --enable mysql57-community
.
.
.
[vagrant@localhost ~]$ yum repolist all | grep -E "mysql.[00-99]-community"
mysql55-community/x86_64           MySQL 5.5 Community Server       無効
mysql55-community-source           MySQL 5.5 Community Server - Sou 無効
mysql56-community/x86_64           MySQL 5.6 Community Server       無効
mysql56-community-source           MySQL 5.6 Community Server - Sou 無効
mysql57-community/x86_64           MySQL 5.7 Community Server       有効:    327
mysql57-community-source           MySQL 5.7 Community Server - Sou 無効
mysql80-community/x86_64           MySQL 8.0 Community Server       無効
mysql80-community-source           MySQL 8.0 Community Server - Sou 無効

// mysql-community-serverをインストール
[vagrant@localhost ~]$ sudo yum install mysql-community-server -y
.
.
.
[vagrant@localhost ~]$ mysql --version
mysql  Ver 14.14 Distrib 5.7.25, for Linux (x86_64) using  EditLine wrapper
```
これでMySQL5.7をインストールすることができたので、これからはデータベースを構築していきます。

```console:
// MySQLが起動していないことを確認する
[vagrant@localhost ~]$ systemctl status mysqld.service
● mysqld.service - MySQL Server
   Loaded: loaded (/usr/lib/systemd/system/mysqld.service; enabled; vendor preset: disabled)
   Active: inactive (dead)
     Docs: man:mysqld(8)
           http://dev.mysql.com/doc/refman/en/using-systemd.html

// MySQLを起動する
[vagrant@localhost ~]$ systemctl start mysqld.service
==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ===
Authentication is required to manage system services or units.
Authenticating as: root
Password: 
==== AUTHENTICATION COMPLETE ===
[vagrant@localhost ~]$ systemctl status mysqld.service
● mysqld.service - MySQL Server
   Loaded: loaded (/usr/lib/systemd/system/mysqld.service; enabled; vendor preset: disabled)
   Active: active (running) since 土 2019-03-16 12:48:19 UTC; 33s ago
     Docs: man:mysqld(8)
           http://dev.mysql.com/doc/refman/en/using-systemd.html
  Process: 6479 ExecStart=/usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid $MYSQLD_OPTS (code=exited, status=0/SUCCESS)
  Process: 6402 ExecStartPre=/usr/bin/mysqld_pre_systemd (code=exited, status=0/SUCCESS)
 Main PID: 6482 (mysqld)
   CGroup: /system.slice/mysqld.service
           └─6482 /usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid

// LISTENプロセスの確認に便利なlsofをインストールする
[vagrant@localhost ~]$ sudo yum install lsof -y
.
.
.

// MySQLのデフォルトポート3306とそのPIDを見てMySQLが起動していることを確認する
[vagrant@localhost ~]$ sudo lsof -i:3306
COMMAND  PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
mysqld  6482 mysql   22u  IPv6  39113      0t0  TCP *:mysql (LISTEN)
[vagrant@localhost ~]$ ps uf 6482
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
mysql     6482  0.0 16.8 1119708 171608 ?      Sl   12:48   0:00 /usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid

// MySQLの初期パスワードを確認する
[vagrant@localhost ~]$ sudo grep 'temporary password' /var/log/mysqld.log
2019-03-16T12:48:17.038108Z 1 [Note] A temporary password is generated for root@localhost: <初期パスワード>

// MySQLにログインする
[vagrant@localhost ~]$ mysql -u root -p
Enter password: // ↑で確認した初期パスワードを入力する
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.25

Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> 

// パスワードを初期パスワードから変更する（rootパスワードなので忘れないようにする）
mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY '新パスワード';
Query OK, 0 rows affected (0.00 sec)

// データベースを作成する
mysql> create database wiki;
Query OK, 1 row affected (0.00 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| wiki               |
+--------------------+
5 rows in set (0.00 sec)
```
データベースを用意したら、サンプルコードにあるDDLを実行してデータを作る。
まずはDDLのzipを解凍しよう。

```console:
// サンプルコードディレクトリに移動しDDLを解凍する。
[vagrant@localhost FindWiki-master]$ gunzip sql/ddl.sql.gz 
[vagrant@localhost FindWiki-master]$ ll sql/ddl.sql 
-rw-rw-r--. 1 vagrant vagrant 231879465  3月 15 12:54 sql/ddl.sql

// 早速DDLを投入する
// データ量が多いので投入完了まで数分かかる
[vagrant@localhost FindWiki-master]$ mysql -u root -p wiki < sql/ddl.sql 
Enter password: // 先ほど決めたパスワード

// 最後にMySQLにログインしてデータができていることを確認する
[vagrant@localhost FindWiki-master]$ mysql -u root -p
.
.
.
mysql> use wiki
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
+----------------+
| Tables_in_wiki |
+----------------+
| namespace      |
| page           |
+----------------+
2 rows in set (0.00 sec)

// 263万レコードある
mysql> select count(1) from page;
+----------+
| count(1) |
+----------+
|  2637675 |
+----------+
1 row in set (0.58 sec)
```
これでデータベースの準備は完了です。

## Apacheの準備
APサーバとなるApache2.4をインストールして起動します。ApacheはPKG名としては`httpd`となっています。

```console:
// 一番新しいのをインストールする
[vagrant@localhost ~]$ yum --showduplicates list | grep "httpd24u\."
httpd24u.x86_64                         2.4.35-1.ius.centos7           ius
httpd24u.x86_64                         2.4.37-1.ius.centos7           ius
httpd24u.x86_64                         2.4.38-1.ius.centos7           ius
[vagrant@localhost ~]$ sudo yum install httpd24u.x86_64 -y 
.
.
.

// Apacheが停止していることを確認
[vagrant@localhost ~]$ systemctl status httpd.service
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)
   Active: inactive (dead)
     Docs: man:httpd.service(8)

// DocumentRootにviなどで下記の確認用HTMLファイルを作成する
[vagrant@localhost ~]$ cat /etc/httpd/conf/httpd.conf | grep -v "#" | grep DocumentRoot
DocumentRoot "/var/www/html"
[vagrant@localhost ~]$ cat /var/www/html/index.html
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <title>My Page</title>
    </head>
    <body>
        <h1>Welcome to my page.</h1>
    </body>
</html>

// Apacheを起動する
[vagrant@localhost ~]$ systemctl start httpd.service
==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ===
Authentication is required to manage system services or units.
Authenticating as: root
Password:
==== AUTHENTICATION COMPLETE === 

// 6プロセス起動している（rootは親プロセス）
[vagrant@localhost ~]$ sudo lsof -i:80
COMMAND   PID   USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
httpd   14626   root    4u  IPv6  54971      0t0  TCP *:http (LISTEN)
httpd   14627 apache    4u  IPv6  54971      0t0  TCP *:http (LISTEN)
httpd   14628 apache    4u  IPv6  54971      0t0  TCP *:http (LISTEN)
httpd   14629 apache    4u  IPv6  54971      0t0  TCP *:http (LISTEN)
httpd   14630 apache    4u  IPv6  54971      0t0  TCP *:http (LISTEN)
httpd   14631 apache    4u  IPv6  54971      0t0  TCP *:http (LISTEN)
httpd   14688 apache    4u  IPv6  54971      0t0  TCP *:http (LISTEN)
```
ブラウザのアドレスバーにIPを入力し閲覧してみると、確認用のHTMLファイルを参照していることがわかる。簡単だがApacheのインストールはこれまで。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/169092/d0379153-a242-16aa-f660-83a3b55028d0.png)

### PHP関連PKGのインストール
HTMLは表示できたが、このままではPHPを読み込まないのでPHP用のPKGをインストールしていきます。

```console:
// ApacheがPHPの実行やDB接続するために下記三つのPKGをインストールする
[vagrant@localhost ~]$ yum list | grep -E "(mod_php72u|php72u-pdo|php72u-mysqlnd)\."
mod_php72u.x86_64                       7.2.16-1.ius.centos7           @ius     
php72u-mysqlnd.x86_64                   7.2.16-1.ius.centos7           @ius     
php72u-pdo.x86_64                       7.2.16-1.ius.centos7           @ius   
[vagrant@localhost ~]$ sudo yum install -y mod_php72u.x86_64 php72u-pdo.x86_64 php72u-mysqlnd.x86_64
.
.
.
[vagrant@localhost ~]$ sudo yum list installed | grep php72u
mod_php72u.x86_64                    7.2.16-1.ius.centos7           @ius        
php72u-common.x86_64                 7.2.16-1.ius.centos7           @ius        
php72u-mysqlnd.x86_64                7.2.16-1.ius.centos7           @ius        
php72u-pdo.x86_64                    7.2.16-1.ius.centos7           @ius 

// 下記のlibphpをApacheの設定に追加する必要があるので覚えておく
[vagrant@localhost ~]$ rpm -ql mod_php72u.x86_64
/etc/httpd/conf.d/php.conf
/etc/httpd/conf.modules.d/15-php.conf
/usr/lib64/httpd/modules/libphp7-zts.so
/usr/lib64/httpd/modules/libphp7.so // ← これ
/usr/share/httpd/icons/php.gif
/var/lib/php/mod_php
/var/lib/php/mod_php/opcache
/var/lib/php/mod_php/session
/var/lib/php/mod_php/wsdlcache
```

### httpd.confの設定
```console:
// FindWiki直下のappディレクトリをusr下に移動して所有者をrootにする
[vagrant@localhost ~]$ sudo cp -pr FindWiki-master/app/ /usr/lib/app/
[vagrant@localhost ~]$ sudo chown root:root -R /usr/lib/app/

// 設定ファイルをコピーしバックアップとしておく
[vagrant@localhost ~]$ cd /etc/httpd/conf/
[vagrant@localhost conf]$ 
[vagrant@localhost conf]$ sudo cp -p httpd.conf  httpd.conf.org

// viで編集し設定を追加していく
[vagrant@localhost conf]$ sudo vi httpd.conf
↓↓↓ ここからは編集する内容を記載 ↓↓↓

// mod_phpを読み込む
LoadModule php7_module /usr/lib64/httpd/modules/libphp7.so

// MySQLの設定値を記載
SetEnv DB_HOST 127.0.0.1
SetEnv DB_PORT 3306
SetEnv DB_USER <username> // 特にユーザを作っていなければroot
SetEnv DB_PASS <password> // rootユーザのパスワード

// アプリケーションディレクトリの設定する
DocumentRoot "/usr/lib/app" // /var/www/htmlだったところ

<Directory "/usr/lib/app"> // /var/www/htmlだったところ

<IfModule dir_module>
    DirectoryIndex index.php // index.htmlだったところ
</IfModule>

↑↑↑ ここまでは編集する内容を記載 ↑↑↑
```
最終的に下記の変更ができていれば良いかと思います。

```
[vagrant@localhost conf]$ diff httpd.conf httpd.conf.org 
59,64d58
< # php7.2
< #
< 
< LoadModule php7_module /usr/lib64/httpd/modules/libphp7.so
< 
< #
121,128d114
< # Configuration value for MySQL.
< #
< SetEnv DB_HOST 127.0.0.1
< SetEnv DB_PORT 3306
< SetEnv DB_USER <username>
< SetEnv DB_PASS <password>
< 
< #
133c119
< DocumentRoot "/usr/lib/app"
---
> DocumentRoot "/var/www/html"
145c131
< <Directory "/usr/lib/app">
---
> <Directory "/var/www/html">
178c164
<     DirectoryIndex index.php
---
>     DirectoryIndex index.html
```
最後にApacheを再起動してブラウザをリロードすると画面が表示されるはずです。
検索ができればDB接続もできていることとなり構築完了となります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/169092/53e18419-bf5a-d3a2-18b3-0e73915a8e60.png)

# まとめ
下記図はブラウザからリクエストを投げてレスポンスが返ってくるまでの簡単なシーケンス図となる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/169092/e241ef34-a83e-a0d1-7c63-5d990276e613.png)
本記事は環境構築のみでプログラムの実装はなかったが、今後LAMP環境アプリのプログラムを実装することがあったら、先に記した配置図や上記のシーケンス図を思い出してほしい。自分がアプリケーションのどこで何をするプログラムを書くのかイメージすることで、本質的なプログラムの実装や課題の解決に繋げることができると思います。