Apache について纏めてみる

Linuc2の学習のために、Apache について纏めてみる。
正直今まで、yum でインストールすれば利用できてしまうため、細かな設定はあまり気にしたことがなかった。
httpd.conf を編集し、apache configtest などで確認すると基本 AH〜始まるエラーが表示されるので、比較的とっつきやすい。


# インストール

## ソースからコンパイルする

個人的にはいつも、yum でしかインストールしないため、↓の記事を参考にしていただきたい。
[コンフィグ,コンパイル,インストール](https://qiita.com/mocha_xx/items/66ffedbeb3f98db5a6b1)

なお、ソースからコンパイルするには、APR および APR-util のインストールも必要です。

## パッケージを利用する

```
# yum install -y httpd
```

# 設定ファイル

|ディレクティブ|説明|
|---|---|
|/etc/httpd/conf/httpd.conf|メイン設定ファイル|
|/etc/httpd/conf.d|補助設定ファイルを格納するディレクトリ|
|ssl.conf|SSL/TLSの設定|
|php.conf|PHPモジュールの設定|
|perl.conf|Perlモジュールの設定|

# htpd.conf

- 基本的な書式

`ディレクティブ名 設定値`

- 適用範囲を指定する場合

`<Files ファイル名>... </Files>`
`<Directory ディレクトリ名>...</Directory>`
`<Location URL>...</Location>`

|ディレクティブ|説明|
|---|---|
|ServerTokens|バージョン情報|
|ServerRoot|トップディレクトリ|
|ServerName|ホスト名|
|ServerAdmin|メールアドレス|
|StartServers|起動時の数|
|MinSpareServers|待機子プロセスの最小数|
|MaxSpareServers|待機子プロセスの最大数|
|ServerLimits|子プロセスの設定可能な上限数|
|Timeout|クライアントからの接続がタイムアウトになる時間|
|KeepAlive|キープアライブの有効/無効|
|KeepAliveRequests|1回のTCP接続における上限リクエスト数|
|KeepAliveTimeout|1回のTCP接続におけるタイムアウト時間|
|Listen|待ち受けポート|
|User|子プロセスの実行ユーザー|
|Group|子プロセスの実行グループ|
|DocumentRoot|ドキュメントルートとなるディレクトリ|
|UserDir|一般ユーザーの公開ディレクトリ|
|DirectoryIndex|ディレクトリのインデックスとして返すファイル名|
|ErrorLog|エラーを記録するログファイル|
|LogLevel|エラーログのログレベル|
|LogFormat|ログに記録する項目と書式|
|CustomLog|アクセスログ|
|HostnameLookups|DNSの逆引きを行い、アクセス元のIPアドレスからホスト名を取得する|
|Alias|ドキュメントルートツリー以外の場所を参照できるようになります。|
|ScliptAlias|CGIスクリプト用ディレクトリ|
|ErrorDocument|エラーが発生した場合の処理を指定する|

# 外部設定ファイル

外部ファイル（.htaccess）を使って、httpd.conf の設定を上書きするには、**AccessFileName**ディレクトリブを使います。

```conf
AccessFileName .htaccess
```

外部設定ファイルの利用を許可するには、**AllowOverride**ディレクトリブで指定する。

次の例は、.htaccess で認証とアクセス制御を利用可能にする。

```conf
AllowOverride AuthConfig Limit
```

|サブコマンド|説明|
|---|---|
|AuthConfig|認証|
|Indexes|DirectoryIndex|
|Fileinfo|ファイルタイプの制御|
|Limit|Order,Allow,Deny|
|Options|Options|
|None|.htaccessでの変更を無効|
|All|.htaccessで変更可能なすべての設定を有効にする|

# apachectl

|サブコマンド|説明|
|---|---|
|start|起動|
|stop|停止|
|restart|再起動|
|graceful|停止中なら起動し、リクエストを再起動中なら再起動を待つ|
|reload|設定ファイルを読み込む|
|configtest|設定ファイルの構文をチェックする|

# モジュール

[モジュール一覧](https://httpd.apache.org/docs/2.4/ja/mod/)

|主な認証モジュール|説明|使用可能な認証プロバイダ|
|---|---|---|
|mod_authz_core|コア認証|env,all,method,expr|
|mod_authz_user|ユーザ認証|user,valid-user|
|mod_authz_host|ホスト認証|ip,host,forward-dns,local|
|mod_authz_groupfile|プレーンテキストファイルを用いたグループ認証を提供||

モジュールをロードするには、次のように指定します。

```conf
LoadModule perl_module modules/mod_perl.so
```

Apache のインストール後に、モジュールを組み込むには、**apxs** を利用します。
その後、↑と同じように LoadModuleディレクトリブで追加します。
なお、apxs のインストールには、httpd-develパッケージをインストールする。

```
# yum install httpd-devel
```

```
# apxs -i -c mod_foobar.c
```

組み込み済みモジュールは、**httpd -l**
組み込み済みモジュールとDSOモジュールの一覧を表示し、設定ファイルの文法もチェックするには、**httpd -M**
を利用します。

```
# httpd -l
# httpd -M
```

# スクリプト言語

WEBアプリケーションとして良く使われている php を取り上げます。

```
# yum install -y php
```

`/etc/httpd/conf.d/php.conf` ファイルが追加されます。

以下のようなファイルを作成し、Apacheを再起動させると、表示されます。

```/var/www/html/phpinfo.php
<?php
  phpinfo();
?>
```

# クライアントアクセスの認証

## BASIC認証

BASIC認証を利用するには、httpd.conf にユーザー認証設定を追加し、専用のパスワードファイルを用意する。

|ディレクティブ|説明|
|---|---|
|AuthType|Basic|
|AuthName|認証の際にダイアログボックスに出力させるメッセージ|
|AuthUserfile|パスワードファイル名|
|AuthGroupfile|認証するグループファイル名|
|require|**valid-user**:パスワードファイルにエントリのあるユーザーがアクセスを許可されます。<br>**user**:ユーザ名のリストにに指定されたユーザだけを許可<br>**group**:グループ名のリスト指定されたグループのユーザだけを許可|
|Order|**Deny,Allow**：DenyされないクライアントとAllowされたクライアントを許可。それ以外は拒否。<br> **Allow,Deny**：AllowされないクライアントとDenyされたクライアントを拒否。それ以外は許可。|
|Deny|アクセスを拒否するホストを指定。|
|Allow|アクセスを許可するホストを指定。|
|Satisfy|ホストのアクセス制御とユーザー認証の両方が指定されている時のアクセスポリシーを指定。<br>＊＊Any＊＊:AllowとRequireのどちらかを満たせば許可。<br>**All**:Allowとrequire両方を満たせば許可。|

```conf
<Directory "/var/www/html/private-area">
AuthType Basic
AuthName "Please enter your ID and password"
AuthUserfile /etc/httpd/conf/.htpasswd
require valid-user
</Directory>
```

認証に用いられるユーザーとパスワードを設定するには、**htpasswd** を利用します。

```
# htpasswd -c /etc/httpd/conf/.htpasswd linuc1
New password: 
Re-type new password: 
Adding password for user linuc

# cat /etc/httpd/conf/.htpasswd
linuc:$apr1$szHx1lmc$PVMPwHwo/7T0bnlbRhAFP0
```

グループ単位で、BASIC認証を設定するには、AuthGroupfile でグループパスワードファイルを指定します。

パスワードファイルの書式は次の通りです。
`グループ名: ユーザー名1 ユーザー名2...`

指定したユーザーは、それぞれ htpasswd でパスワードを設定しておきます。

require では、次の書式でグループ名を指定します。
`require group グループ名`

## ダイジェスト認証

|ディレクティブ|説明|
|---|---|
|AuthType|Digest|
|AuthName|認証の領域|
|AuthUserfile|パスワードファイル名|
|AuthDigestGroupfile|認証するグループファイル名|
|require|アクセス可能なユーザー、**valid-user** を指定するとパスワードファイルにエントリのあるユーザーがアクセスを許可されます。|

```conf
<Directory "/var/www/html/secret-area">
AuthType Digest
AuthName "secret-area"
AuthUserfile /etc/httpd/conf/.htdigestfile
require valid-user
</Directory>
```

ダイジェスト認証のためのユーザー作成やパスワード変更には、**htdigest** を利用します。

```
# htdigest -c /etc/httpd/conf/.htdigest secret-area linuc2
Adding password for linuc2 in realm secret-area.
New password: 
Re-type new password: 

# cat /etc/httpd/conf/.htdigest
linuc2:secret-area:2b2b3ade579cc9e0121b4f1df227db6b
```

## ホストベースのアクセス制御

IPアドレスやホスト名、ドメイン名などでアクセス制御をしたい場合は、**require**ディレクティブをを使います。
この機能は、**authz_host_module** で提供されます。

例えば、172.31.0.0/16 からのアクセスは拒否し、それ以外のホストからのアクセスを許可させるには次の通り指定します。

```conf
require all granted
require not ip 172.31.0.0/16
```

# バーチャルホスト機能

1つのホストで複数のWebサイトを管理することができます。

## 名前ベースのバーチャルホスト

1つのホストに1つのIPアドレスと複数のドメインを設定する。
**VirtualHost**ディレクティブ内に記述します。
DNSを適切に設定すれば、それぞれのWebサイトを独立して運用することができます。

```conf
<VirtualHost *:80>
  ServerName web.example.com
  DocumentRoot /var/www/virtual/web
</VirtualHost>

<VirtualHost *:80>
  ServerName www.example.net
  DocumentRoot /var/www/virtual/example
</VirtualHost>
```

**SNI**
- SSLハンドシェイク時にクライアントがアクセスしたいホスト名を平文で伝える仕組みです。
- SSLでは、接続するサーバが決まってから復号化が行われますが、名前ベースのバーチャルホストの場合、ホスト名が指定されたHTTPプロトコルヘッダが、SSLによって暗号化されているため、接続するサーバを決定することができません。この問題を解決したのがSNIです。
- SNIは、サーバだけでなく、クライアントも対応している必要があります。

## IPベースのバーチャルホスト

1つのホストに複数のIPアドレスと複数のドメインを設定する。
**VirtualHost**ディレクティブ内に記述します。
**Listen**ディレクティブでそれぞれのIPアドレスを指定しておく必要があります。

```
Listen 192.168.1.10:80
Listen 192.168.1.11:80

<VirtualHost 192.168.1.10:80>
  ServerName web.example.com
  DocumentRoot /var/www/virtual/web
</VirtualHost>

<VirtualHost 192.168.1.11:80>
  ServerName www.example.net
  DocumentRoot /var/www/virtual/example
</VirtualHost>
```

# 監視とメンテナンス

**mod_status** : サーバの稼働状況についての情報

```conf
LoadModule status_module modules/mod_status.so

<Location /server-status>
  SetHandler server-status
</Location>
```

**mod_info** : サーバの設定に関する情報

```conf
LoadModule info_module modules/mod_info.so

<Location /server-info>
  SetHandler server-info
</Location>
```

##SSL/TLS

**mod_ssl** を利用することで、SSLに対応します。

サイト証明書を認証局から入手する必要があります。

①公開鍵と暗号鍵を作成する。
②作成した公開鍵を、利用企業の身元を証明する書類などとともに、認証局（CA）へ送付する。
③CAでは証明書を発行して返送する。（この証明書を使って、Webサーバーは、Webブラウザに対して身元を明らかにする。）
④送られてきた証明書を、Webサーバーにインストールする。

サーバー証明書は、IPアドレスまたはドメイン名に対して発行されます。
ここでは、自己署名証明書（自身を独自の認証局として、その認証局によって証明書に署名を行う方法）を取り上げます。
CentOSでは、SSLがインストールされたディレクトリ内にCA.shというスクリプトが用意されているので、それをコピーして対話的に作成します。

```
# cd /etc/pki/tls/misc
# ./CA -newca
```

秘密鍵：`/etc/pki/CA/private/cakey.pem`
公開鍵：`/etc/pki/CA/cacert.pem`
のように作成されます。

SSL対応HTTPサーバーを構築するために必要となるサーバー秘密鍵 **server.key** を作成します。

```
# openssl genrsa -out server.key 2048
```

認証局に対して証明書の発行を要求する証明書発行要求書（CSR） **server.csr** を作成します。

```
# openssl req -new -key server.key -out server.csr
```

証明書発行要求ファイルに対して証明書が署名を行いサーバー証明書 **server.crt** を作成します。

```
# openssl ca -out server.crt -infiles server.csr
```

サーバー秘密鍵とサーバー証明書を適切なディレクトリに移動し、httpd.conf に必要な設定を記述します。

|SSL/TLS関連のディレクティブ|説明|
|---|---|
|SSLEngine|有効/無効|
|SSLProtocol|バージョン|
|SSLCipherSuite|暗号アルゴリズム|
|SSLCertificateFile|サーバー証明書ファイル|
|SSLCertificateKeyFile|サーバー秘密鍵ファイル|
|SSLCertificateChainFile|中間CA証明書ファイル<br>Apache2.4.8以降：サーバ証明書と中間CA証明書を1つに纏めたファイルを作成し、SSLCertificateFileに記載する。<br>Apache2.4.8以前：サーバ証明書をSSLCertificateKeyFile、中間CA証明書をSSLCertificateChainFileに記載する。|
|SSLCACertificateFile|クラアイント証明書発行のCA証明書発行ファイル|
|SSLCACertificatePath|クラアイント証明書発行のCA証明書発行ディレクトリ|
|SSLVerifyClient|クライアント認証のレベル<br>[ApacheでIP制限とクライアント認証をor条件で運用する](https://qiita.com/kite_999/items/0638e750da69105b598c)|

```
LoadModule ssl_module modules/mod_ssl.so
Listen 443 https

<VirtualHost _default_:443>
  ServerName www.example.net:443
  DocumentRoot "/var/www/html"
  ErrorLog logs/ssl_errorlog
  TransferLog logs/ssl_access_log
  LogLevel warn
  SSLEngine on
  SSLProtocol all -SSLv2 -SSLv3
  SSLCipherSuite HIGH:3DES:!aNULL:!MD5:!SEED:!IDEA:!DH
  SSLCertificateFile /etc/httpd/conf/ssl.crt/server.crt
  SSLCertificateKeyFile /etc/httpd/conf/ssl.key/server.key
</VirtualHost>
```

※検証などで、試したい場合は、[Let's Encrypt](https://letsencrypt.org/ja/) で、無償でデジタル証明書を発行してもらえます。

# ログファイル

## アクセスログファイル

`/var/log/httpd/access_log`

**LogFormat** ディレクティブでフォーマットを指定し、
**CustomLog** ディレクティブでログファイル名とフォーマットを結びつけます。

```conf
LogFormat

CustomLog logs/access_log combined
```

## エラーログファイル

`/var/log/httpd/error_log`

LogLevel ディレクティブで、記録するログレベルを指定することができます。

```conf
LogLevel warn
```