CentOS 8 StreamでWebサーバを構築する

# Webサーバ構築

## 「ターミナル」からssh接続

### ゲストPCのIPアドレス確認

```sh
$ nmcli device  # 全インタフェースの状態を確認 -> STATEが「接続済み」の物理NIC名を確認
DEVICE      TYPE      STATE            CONNECTION 
enp0s3      ethernet  接続済み         enp0s3     
virbr0      bridge    接続済み (外部)  virbr0     
lo          loopback  管理無し         --         
virbr0-nic  tun       管理無し         -- 

$ nmcli device show enp0s3  # 指定インタフェースのNIC情報を表示 -> ゲストPCのIPアドレスを確認
...
IP4.ADDRESS[1]:                         10.0.2.15/24
...
```

#### nmcliコマンドについて
NetworkManagerをCLIで管理するコマンド。
操作対象はDeviceとConnectionの2つ。

##### Device
「物理/論理NIC」を指す。

##### Connection
物理/論理NICに紐付けされた「ネットワーク接続設定情報」を指す。

### ポートフォワーディングの設定

VirtualBox「設定」
→「ネットワーク」
→「高度」
→「ポートフォワーディング」

ホストIP: ホストPCのIPアドレス
ホストポート: 1024~65535(0~1023のWell-knownポート番号以外)を指定
ゲストIP: ゲストPCのIPアドレス
ゲストポート: 22(SSH接続)

### ホストPC(Mac)からゲストPC(CentOS)に「ターミナル」でssh接続

```sh:構文
% ssh -p <ホストポート番号> <ログインユーザ名>@<ホストPCアドレス>  # ポート番号を指定してSSH接続
% ssh -p 1024 admin@192.168.1.2
```

***

## Apacheのインストール

### Apacheとは
正式名称は`Apache HTTP Server`。
ゲストPCに「Webサーバ」として機能させるソフトウェア。

※サーバ = ハードウェア × OS × `ソフトウェア`
-> `ソフトウェア`によってサーバが変わる

### httpdパッケージのインストール
-> `httpd`パッケージが`Apache HTTP Server`を提供。

#### デーモン(daemon)とは
特定の機能をバックグラウンドで提供するプログラム。

#### パッケージとは
特定の機能拡張に必要なプログラム・ファイルを一まとめにしたもの。

#### 設定手順

```sh
$ dnf list installed | grep httpd  # インストール済のRPMパッケージを一覧で表示 -> 現時点ではhttpdに関するパッケージは未インストール

$ dnf list | grep httpd  # 利用可能なRPMパッケージを一覧で表示 | 文字列を指定して検索
centos-logos-httpd.noarch                              82.0-2.el8                                        appstream 
httpd.x86_64                                           2.4.37-30.module_el8.3.0+462+ba287492.0.1         appstream 
httpd-devel.x86_64                                     2.4.37-30.module_el8.3.0+462+ba287492.0.1         appstream 
httpd-filesystem.noarch                                2.4.37-30.module_el8.3.0+462+ba287492.0.1         appstream 
httpd-manual.noarch                                    2.4.37-30.module_el8.3.0+462+ba287492.0.1         appstream 
httpd-tools.x86_64                                     2.4.37-30.module_el8.3.0+462+ba287492.0.1         appstream 
keycloak-httpd-client-install.noarch                   1.0-2.el8                                         appstream 
libmicrohttpd.i686                                     1:0.9.59-2.el8                                    baseos    
libmicrohttpd.x86_64                                   1:0.9.59-2.el8                                    baseos    
python3-keycloak-httpd-client-install.noarch           1.0-2.el8                                         appstream 

$ su -  # rootユーザに移行
# dnf -y install httpd httpd-tools httpd-devel httpd-manual# 依存パッケージ含めRPMパッケージを指定してインストール(すべて「はい」)
...(中略)...

# dnf list installed | grep httpd  # インストール済のRPMパッケージを一覧で表示 -> httpdパッケージのインストールを確認
centos-logos-httpd.noarch                          82.0-2.el8                                    @appstream
httpd.x86_64                                       2.4.37-30.module_el8.3.0+462+ba287492.0.1     @appstream
httpd-devel.x86_64                                 2.4.37-30.module_el8.3.0+462+ba287492.0.1     @appstream
httpd-filesystem.noarch                            2.4.37-30.module_el8.3.0+462+ba287492.0.1     @appstream
httpd-manual.noarch                                2.4.37-30.module_el8.3.0+462+ba287492.0.1     @appstream
httpd-tools.x86_64                                 2.4.37-30.module_el8.3.0+462+ba287492.0.1     @appstream
```

#### インストールするhttpdパッケージ
httpd.x86_64  # httpd Web Server本体
httpd-devel.x86_64  # httpd開発ツール/モジュール
httpd-manual.noarch  # httpdマニュアル
httpd-tools.x86_64  # httpd関連ツール群

#### dnfコマンドについて
2大パッケージ管理システム`RPM`・`Yum(Dandified Yum)`のうち、`Yum`でパッケージを管理するコマンド。
`RPM`は個々にパッケージを扱うのに対し、
`Yum`はパッケージ間の依存関係を含めてパッケージを扱う。

***

## httpdの起動

### systemctlコマンドについて
`デーモン`を管理する`systemd`を操作するコマンド。サービスの起動や停止、状態確認を実行できる。

### httpdユニットの状態確認

```sh
$ systemctl status httpd  # httpdユニットの状態確認 -> 現時点ではinactive
● 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)

# systemctl start httpd  # httpdユニットの起動
# systemctl status httpd  # httpdユニットの状態確認 -> active(running)を確認
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)
   Active: active (running) since Wed 2021-03-03 22:41:20 JST; 1min 39s ago
     Docs: man:httpd.service(8)
 Main PID: 38552 (httpd)
   Status: "Running, listening on: port 80"
    Tasks: 213 (limit: 100840)
   Memory: 44.3M
...(中略)
```

### httpdユニットの自動起動を有効化

```sh
$ systemctl is-enabled httpd  # httpdユニットの自動起動が有効状態であるか確認 -> 現時点ではdisabled
disabled

# systemctl enable httpd  # httpdユニットの自動起動を有効化
$ systemctl is-enabled httpd  # httpdユニットの自動起動が有効状態であるか確認 -> enabledを確認
enabled
```

***

## Firewallの設定

### Firewalldとは

CentOS 7から採用されたパケットフィルタリング機構。
Inputチェインのパケットフィルタリングルールを「ゾーン」と呼ぶ。
publicゾーンは「サーバとして最低限必要な受信許可ルール」であり、全てのインタフェースはデフォルトでpublicゾーンに所属する。

### firewall-cmdコマンドについて
firewalldサービスを設定・確認するコマンド。

### firewalldのパケットフィルタリング(=ゾーン)設定

```sh
$ firewall-cmd --get-default-zone  # デフォルトのゾーン名を表示
public  # デフォルトはpublicゾーン

# firewall-cmd --list-all  # デフォルトゾーン(public)の設定を表示
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: enp0s3  # ゾーンが適用されるインタフェース名
  sources: 
  services: cockpit dhcpv6-client ssh  # 許可されたサービス一覧 -> publicでssh接続が許可されている状態
  ports: 
  protocols: 
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

# firewall-cmd --new-zone=manage --permanent  # ゾーンを恒久的に新規作成
success
# firewall-cmd --zone=manage --set-target=ACCEPT --permanent  # manageゾーンに対して通信を許可
success
# firewall-cmd --zone=manage --add-service=ssh --permanent  # manageゾーンに対してsshサービスの通信を許可
success
# firewall-cmd --zone=manage --add-service=http --permanent  # manageゾーンに対してhttpサービスの通信を許可
success

# firewall-cmd --zone=manage --add-source=192.168.1.2/32 --permanent  # manageゾーンに対して通信を許可する接続元IPアドレス(=ホストPCアドレス)を設定
success
# firewall-cmd --reload  # firewalldサービスの設定を再読み込み
success

# firewall-cmd --get-active-zones  # 現在activeなゾーンを表示
manage
  sources: 192.168.1.2/32
public
  interfaces: enp0s3

# nmcli connection modify enp0s3 connection.zone manage  # 指定NIC(enp0s3)に対してmanageゾーンを適用
# firewall-cmd --set-default-zone=manage  # デフォルトゾーンをmanageに設定
success

# firewall-cmd --remove-service=ssh --zone=public --permanent  # publicゾーンからsshサービスの通信を削除
success
# firewall-cmd --reload  # firewalldサービスの設定を再読み込み
success

# firewall-cmd --list-all  # デフォルトゾーン(manage)の設定を表示
manage (active)
  target: ACCEPT
  icmp-block-inversion: no
  interfaces: enp0s3  # 物理NIC(enp0s3)に対してmanageゾーンが適用されている
  sources: 192.168.1.2/32  # 接続元ホストアドレスが192.168.1.2/32のみ接続を許可
  services: http ssh  # manageゾーンではhttpd, sshサービスを許可
  ports: 
  protocols: 
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

# firewall-cmd --list-all --zone=public  # publicゾーンの設定を表示
public
  target: default
  icmp-block-inversion: no
  interfaces:   # publicゾーンが適用されるインタフェースが存在しない
  sources: 
  services: cockpit dhcpv6-client
  ports: 
  protocols: 
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 
```

### 不要サービスを無効化 -> 不要ポートの開放/サーバリソースの無駄遣いを防止

```sh
# systemctl disable auditd.service  # 不要サービス(auditd)の無効化
Removed /etc/systemd/system/multi-user.target.wants/auditd.service.
# systemctl disable smartd.service  # 不要サービス(smartd)の無効化
Removed /etc/systemd/system/multi-user.target.wants/smartd.service.
# systemctl disable mdmonitor.service  # 不要サービス(mdmonitor)の無効化
Removed /etc/systemd/system/multi-user.target.wants/mdmonitor.service.
# reboot  # サーバの再起動(設定の反映)
Connection to 192.168.1.2 closed by remote host.
Connection to 192.168.1.2 closed.
```

***

## htmlページ作成前の事前設定

### Welcomeページの表示確認
CentOS内ブラウザ(FireFox)で「10.0.2.15(ゲストPCアドレス)」を入力
![スクリーンショット 2021-03-04 9.56.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673880/e483485b-385b-90e5-afd7-1f38c8771ab5.png)
 -> 現時点ではWelcome Pageが表示

### httpd.confファイルのバックアップ

```sh
# cd /etc/httpd/conf  # httpd.confファイルがあるディレクトリに移動
# cp -p httpd.conf httpd.conf.org  # コピー元ファイルの属性を保持してコピー
# vi httpd.conf  # httpd.confをviエディタで開く -> :set numberで行数を表示

# -----<httpd.conf>-----
# 動作ユーザ・グループの変更
69 User apache -> User admin
70 Group apache -> Group admin

# サーバ管理者のメールアドレスを変更
89 ServerAdmin root@localhost -> ServerAdmin n-ito@clinks.jp

# サーバのホスト名を変更
98 #ServerName www.example.com:80 -> ServerName test-clinks.jp:80

# ドキュメントルートの変更
122 DocumentRoot "/var/www/html" -> DocumentRoot "/home/admin/html"

# ディレクトリの変更①
127 <Directory "/var/www"> -> <Directory "/home/admin">

# ディレクトリの変更②
134 <Directory "/var/www/html"> -> <Directory "/home/admin/html">

# Optionsパラメータの変更
147     Options Indexes FollowSymLinks -> Options FollowSymLinks  # ファイルが存在しない場合にエラーを返すようにする

# スクリプトエイリアスの変更
250     ScriptAlias /cgi-bin/ "/var/www/cgi-bin/" -> ScriptAlias /cgi-bin/ "/home/admin/cgi-bin/"

# CGI用ディレクトリの変更
258 <Directory "/var/www/cgi-bin"> -> <Directory "/home/admin/cgi-bin">
# -----<httpd.conf>-----

# httpd -t  # サービス(httpd)設定ファイルの構文チェック -> 現時点では構文エラー(上で記載したディレクトリが存在しない)
AH00526: Syntax error on line 122 of /etc/httpd/conf/httpd.conf:
DocumentRoot '/home/admin/html' is not a directory, or is not readable
```

### ドキュメントルート用ディレクトリの作成

```sh
# cd /home/admin/  # ドキュメントルートディレクトリを作成するディレクトリに移動
# mkdir html  # htmlディレクトリの作成
# mkdir cgi-bin  # cgi-binディレクトリの作成

# ll  # カレントディレクトリ内のファイルを詳細情報表示(ls -l)
合計 0
drwxr-xr-x. 2 root  root  6  3月  4 10:14 cgi-bin  # フォルダの所有権がrootユーザになっている
drwxr-xr-x. 2 root  root  6  3月  4 10:14 html  # フォルダの所有権がrootユーザになっている
drwxr-xr-x. 2 admin admin 6  3月  3 22:02 ダウンロード  # フォルダの所有権はadminユーザ(本環境では一般&管理者ユーザ)
...(中略)

# chown admin:admin html  # htmlディレクトリの所有ユーザ・ユーザグループをadmin:adminに設定
# chown admin:admin cgi-bin  # cgi-binディレクトリの所有ユーザ・ユーザグループをadmin:adminに設定

# ll  # カレントディレクトリ内のファイルを詳細情報表示(ls -l)
合計 0
drwxr-xr-x. 2 admin admin 6  3月  4 10:14 cgi-bin
drwxr-xr-x. 2 admin admin 6  3月  4 10:14 html
drwxr-xr-x. 2 admin admin 6  3月  3 22:02 ダウンロード
...(中略)

# httpd -t  # サービス(httpd)設定ファイルの構文チェック -> 構文OK
Syntax OK
```

### 不要な設定ファイルの無効化

```sh
# cd /etc/httpd/conf.d  # 不要ファイルが含まれるディレクトリに移動
# mv autoindex.conf autoindex.conf.org  # autoindexファイルの名前を変更
# mv welcome.conf welcome.conf.org  # welcome.confファイルの名前を変更
```

### SELinuxの無効化

```sh
# getenforce  # SELinuxの状態確認 -> 現時点ではEnforcing
Enforcing

# vi /etc/selinux/config  # SELinuxの設定ファイルをviエディタで開く
SELINUX=enforcing -> SELINUX=disabled
# shutdown -r now  # サーバをシャットダウン後、再起動

# getenforce  # SELinuxの状態確認 -> Disabledに変更済
Disabled
```

### 設定変更の反映

```sh
# systemctl restart httpd  # httpdユニットの再起動

# systemctl status httpd  # httpdユニットの状態確認
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor prese>
   Active: active (running) since Thu 2021-03-04 10:26:21 JST; 53s ago
     Docs: man:httpd.service(8)
 Main PID: 4764 (httpd)
   Status: "Running, listening on: port 80"
    Tasks: 213 (limit: 100840)
   Memory: 39.7M
...(中略)
```

### Welcomeページの表示確認
CentOS内ブラウザ(FireFox)で「10.0.2.15(ゲストPCアドレス)」を入力
![スクリーンショット 2021-03-04 10.28.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673880/6cc118bd-27ee-98da-2fc2-f7829b1ba7c1.png)
 -> Welcome Pageが表示されず、HTTP 403エラーが表示(welcome.confが名前変更により読み込まれていない)

***

## htmlページの作成

### htmlファイルの作成

```sh
# cd /home/admin/html  # htmlファイルが読み込まれるディレクトリに移動
# vi index.html  # index.htmlファイルの生成・編集

# -----<index.html>-----
<!DOCTYPE html>
<html>
<body>
test page
</body>
</html>
# -----<index.html>-----

# ll  # カレントディレクトリ内のファイルを詳細情報表示(ls -l)
合計 4
-rw-r--r--. 1 root root 56  3月  4 10:39 index.html

# chown admin:admin index.html  # index.htmlファイルの所有ユーザ・ユーザグループをadmin:adminに設定

# ll  # カレントディレクトリ内のファイルを詳細情報表示(ls -l)
合計 4
-rw-r--r--. 1 admin admin 56  3月  4 10:39 index.html
```

### テストページの表示確認
CentOS内ブラウザ(FireFox)で「10.0.2.15(ゲストPCアドレス)」を入力
![スクリーンショット 2021-03-04 12.34.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673880/ab0ce383-5bc7-00b0-ca74-6df48b974bad.png)
 -> 作成したテストページが表示される。

### トラブルシューティング
[Apacheで403 Forbiddenが表示された時のチェックポイント5選](https://engineers.weddingpark.co.jp/apache-403-forbidden/)

#### Apacheの再起動が未実施

```sh
# systemctl restart httpd  # httpdユニットの再起動
```

#### index.htmlファイルの「その他ユーザ」での読み取り権限がない

```sh
# cd /home/admin/  # ドキュメントルートディレクトリを設定したディレクトリに移動
# chown admin:admin html  # htmlディレクトリの所有ユーザ・ユーザグループをadmin:adminに設定
# chown admin:admin cgi-bin  # cgi-binディレクトリの所有ユーザ・ユーザグループをadmin:adminに設定
# cd /home/admin/html  # htmlファイルが読み込まれるディレクトリに移動
# chown admin:admin index.html  # index.htmlファイルの所有ユーザ・ユーザグループをadmin:adminに設定
```

※ここでの「admin」は管理者ユーザ 兼 一般ユーザ。

#### DocumentRootまでに「その他ユーザ」からの実行権がないディレクトリが存在

```sh
# cd /home  #対象ディレクトリが存在するディレクトリに移動
# ll  # カレントディレクトリ内のファイルを詳細情報表示(ls -l)
合計 4
drwx------. 17 admin admin 4096  3月  4 10:45 admin  # その他ユーザでの実行権がない

# chmod o+x /home/admin  # その他ユーザ(o)に対して実行権限(x)を付与
# ll  # カレントディレクトリ内のファイルを詳細情報表示(ls -l)
合計 4
drwx-----x. 17 admin admin 4096  3月  4 10:45 admin  # その他ユーザでの実行権が付与された
```

#### SELinuxが有効

##### SELinuxを無効にする場合

```sh
$ getenforce  # SELinuxの状態確認 -> 現時点ではEnforcing
Enforcing

# vi /etc/selinux/config  # SELinuxの設定ファイルをviエディタで開く
SELINUX=enforcing -> SELINUX=disabled
# shutdown -r now  # サーバをシャットダウン後、再起動

# getenforce  # SELinuxの状態確認 -> Disabledに変更済
Disabled
```

##### SELinuxを有効のまま運用する場合

```sh
# ls -ld --context /var/www/html  # 元のDocumentRootのSELinuxラベルを確認
drwxr-xr-x. 2 root root system_u:object_r:httpd_sys_content_t:s0 6  8月  1  2020 /var/www/html

# chcon system_u:object_r:httpd_sys_content_t:s0 /home/admin/html -R  # 新しいDocumentRootに対して同じSELinuxラベルを付与
# ls -ld --context /home/admin/html  # 新しいDocumentRootのSELinuxラベルが元DocumentRootと同じであることを確認
drwxr-xr-x. 2 root root system_u:object_r:httpd_sys_content_t:s0 24  3月  4 11:03 /home/admin/html
```

***

## ホストOSから閲覧できるように設定

### ネットワークアダプタの作成
「VirtualBox」→「ファイル」→「ホストネットワークマネージャ」→「作成」  # DHCPサーバは「有効」

### ネットワークアダプタの追加
「設定」→「ネットワーク」→「アダプター2」
割り当て: ホストオンリーアダプター
※ネットワークアダプタのIPアドレス: 192.168.56.1/24
DHCPサーバアドレス: 192.168.56.100
サーバアドレス範囲: 192.168.56.101-192.168.56.254

### 新規追加したネットワークアダプタの設定
IPv4メソッドは「手動」
アドレス: 192.168.56.2(ネットワークアダプタIPアドレスの同一セグメントかつサーバアドレス範囲外であればOK)
ネットマスク: 255.255.255.0
ゲートウェイ: 192.168.56.1(ネットワークアダプタのIPアドレス)

### ホストOSからテストページを表示
ホストOSのブラウザで、新規追加したネットワークアダプタのIPアドレスを入力(ここでは「192.168.56.2」)
![スクリーンショット 2021-03-04 13.34.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673880/eaec9b8b-5008-1658-2870-2dad7dee2e62.png)

***

## サーバ名(ドメイン名)からテストページを表示

### hostsファイルの編集

```sh
# cd /etc  # 名前解決を行うhostsファイルが存在するディレクトリに移動
# vi hosts  # hostsファイルをviエディタで開く

# -----<hosts>-----
10.0.2.15   test-clinks.jp  # 最終行に追加
# -----<hosts>-----
```

### ゲストOSのブラウザ(FireFox)のURLにサーバ名(ドメイン名)を入力
![スクリーンショット 2021-03-04 13.51.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673880/65afd2bd-ccdb-7ee7-526f-c3485dc9790d.png)

-> ホストOSブラウザでも同様にhostsファイルを編集することで、ドメイン名によるテストページへのアクセスが可能になる。