Table of Contents
はじめに
AWSのインフラエンジニアとして従事して2年以上経過するが、実はApacheというものが何か、というは知っているが、これまでhttpd.confをゼロから作ったことがなく、既に出来上がったものを引き継いで運用していたため、この機会に各パラメータの意味を調べてみようと思いました。
Apacheとは
Webサーバソフトのことです。
PCにApache (httpd)というソフトを入れるとWebサーバとして機能します。
今あなたが見ているこのサイトもリクエストを受けて、Webサーバにあるファイルの内容をレスポンスしてブラウザを通してWebページを見ることができるのです。
httpd.confとは
Apacheの動作を定義する設定ファイルです。
各パラメータについて見ていきましょう
ServerRoot
ServerRoot "/etc/httpd"Apacheが各種関連ファイルを探すときの基準となるディレクトリです。
このhttpd.conf内にInclude conf.d/*.confと記載されていれば、/etc/httpd/conf.d/配下にある設定ファイルをApache起動時に読み込みに行きます。
以下のようなファイルがあれば順番に読みに行きます。
/etc/httpd/conf.d/00-base.conf
/etc/httpd/conf.d/00-mpm.confUser apache
Group apach
User apache
Group apacheApacheがどのユーザー権限で操作を行うかを指定する設定。
権限を設定しておかなとすべてをroot権限で動かすことになるため、仮に、脆弱性をつかれてWebサーバーに侵入された場合、root権限でWebサーバ全体を操作可能になってしまい非常に危険です。
ServerName
Apacheをコンテナで起動している場合、そのコンテナの正式な名前が何か?を定義する場所です。
例えば以下のように定義されている場合、このhttpd.confのファイルを読み取って起動するコンテナの正式名称はdev.example.comであり、ポートは8080で接続する、という設定となります。
ServerName dev.example.com:8080ServerTokens
ひとことで言えばバージョン情報を外部へ見せないための設定。
Apacheサーバに対して、HTTPリクエストが送信されると、HTTPレスポンスヘッダにApacheのバージョン情報が表示されるため、その情報を出力しないように以下を指定している。
ServerTokens: Prod何も指定しない場合はHTTPレスポンスヘッダは以下のように情報を表示する
HTTP/1.1 200 OK
Server: Apache/2.4.68 (Red Hat)Prodを指定することでバージョン情報を出力しないため不要な情報を外部に公開しないためのセキュリティ対策の一つとしての設定です。
ServerSignature
ServerSignatureに関してもServerTokensと似たような設定で、例えば利用者がhttps://example.comでアクセスした場合は正常にブラウザにページが表示されたとします。
しかし、https://example.com/hogeへリクエストし、/hogeというページが見つけられない場合404 Not Foundが返されます。
その際、この設定をonに設定しておくと先ほどの404を返す際に以下のようなエラーページを返します。
404 Not Found
The requested URL was not found on this server.
Apache/2.4.68 Server at example.com/hoge Port 8080つまり、これもバージョン情報やPort番号など余計な情報を返すことになります。
これをoffに設定しておけば以下のように余計な情報を返しません。
404 Not Found
The requested URL was not found on this server.これもセキュリティ対策の一つの設定と思えばよいかと思います。
TraceEnable
HTTP TRACEメソッドの利用可否を制御する設定。
そもそもTRACEメソッドとは?
HTTPにはGET(ページ取得), POST(データ送信)などのメソッドは知っているかと思いますが、それ以外にもHEAD, PUT(更新), DELETE(削除), OPTIONS, TRACE, CONNECTなどのメソッドが存在します。
ここでは徳丸本で有名な徳丸さんが書かれた記事から引用しますが、
TRACEメソッドは、HTTPリクエストを「オウム返しに」HTTPレスポンスとして返すもので、以下のようにGET等の代わりにTRACEとしてWebサーバーにリクエストします。
TRACE /auth/index.php HTTP/1.1
Host: example.jp
User-Agent: Mozilla/5.0 (Windows NT 6.0; rv:18.0) Gecko/20100101 Firefox/18.0
Cookie: PHPSESSID=4lel0hml53u2tbhcd9pmo7pkc4
Authorization: Basic eWFtYWRhOnBhc3N3b3Jk
Connection: keep-alive上記リクエストに対して以下のようなレスポンスが返ります。
HTTP/1.1 200 OK
Date: Tue, 22 Jan 2013 13:51:09 GMT
Server: Apache/2.2.14 (Ubuntu)
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: message/http
Content-Length: 198
TRACE /auth/index.php HTTP/1.1
Host: example.jp
User-Agent: Mozilla/5.0 (Windows NT 6.0; rv:18.0) Gecko/20100101 Firefox/18.0
Cookie: PHPSESSID=4lel0hml53u2tbhcd9pmo7pkc4
Authorization: Basic eWFtYWRhOnBhc3N3b3Jk
Connection: keep-aliveHTTPリクエストの内容がそのまま返されているため、Cookieヘッダ、Autorizationヘッダの内容まで見えてしまっています。
TRACEメソッドはサーバが受信したHTTPリクエストをそのまま返す診断用機能です。
過去にはXSS (Cross-Site Scripting)と組み合わせたXST (Cross-Site Tracing)攻撃に利用されたため、無効化が推奨されることが多い。
ただ、現在の主要ブラウザではXST対策が実装されており、TRACE自体が重大な脆弱性というわけではない。
それでも通常のWebシステムでは利用用途がほとんどなく、無効化によるデメリットも少ないためTraceEnable Off設定がされていると考えられる。
Header unset X-Powered-By
まず、X-Powered-Byとは、HTTPレスポンスヘッダの一種です。
X-Powered-Byによってレスポンスされるヘッダ情報をunsetとすることで、削除する設定です。
例えばcurl -I https://example.comを実行すると、以下のような情報が返ってくることがあります。
X-Powered-By PHP/8.2.10つまり、このサイトはPHPで動いている、バージョンは8.2.10かということがわかり、対象バージョンの脆弱性をついて攻撃されるリスクがあるということです。
あえてそんなリスクを取る必要はないので、Header unset X-Powered-Byとしておくことで、余計な情報を表示しないようにするわけです。
Time out
Time outについては例えば60秒と設定していた場合、ユーザからリクエストを受信後、60秒経過しても処理が完了しない場合はタイムアウトとして接続を終了する設定です。
例えば以下のような構成でリクエストを受け取る場合、Apache が後続のアプリケーションサーバへトラフィックを転送し、アプリケーションサーバからの応答を待ちます。
その際、アプリケーションサーバがなんらかの原因で60秒経過しても応答がない場合、Apacheがユーザに対してエラーを返します。
ユーザ -> Apache Webサーバ -> アプリケーションサーバKeepAlive
HTTP通信を行う際に、TCP 3-way handshakeによって接続が確立されます。
KeepAliveを有効化しておくと、HTTPリクエストごとにTCP接続を切断せず、確立済みのTCP接続を利用して複数回HTTP通信を行うことができます。
具体的にどういうことか見ていきましょう。
KeepAliveがOffの場合
TCP 3way handshake
↓
HTTP GET /index.html
↓
HTTPレスポンス
↓
TCP切断
TCP 3way handshake
↓
HTTP GET /index.html
↓
HTTPレスポンス
↓
TCP切断毎回TCP接続を張り直します。
KeepAlive Onの場合
TCP 3way handshake
↓
HTTP GET /index.html
↓
HTTP レスポンス
HTTP GET /style.css
↓
HTTPレスポンス
HTTP GET /image.jpg
↓
HTTPレスポンス
TCP切断上記のようにTCP接続が使いまわされます。
この設定はデフォルトではKeepAlive onになっています。
RemoteIPProxyProtocol
一言でいうとApacheがアクセス元のIPアドレスを確認するための設定です。
どういうことかというと、例えば以下のように間にALBを挟む場合、ユーザのIPアドレスが203.0.113.10だった場合、ApacheとしてはユーザのIPアドレスである203.0.113.10からのアクセスだということを知りたいわけですが、この場合だとALBを経由してApacheに来るため、Apacheで確認できるIPアドレスはALBのIPアドレスになります。
ユーザ
↓
ALB
↓
Apache Webサーバこの元のアクセスIPを知りたい場合にRemoteIPProxyProtocolをOnにしておくことでApacheはProxy Protocol付の通信を受け取ることができるようになります。
RemoteIPHeader X-Forwarded-For
一言で言うとHTTPヘッダーの一種で、X-Forwarded-ForはALBやリーバスプロキシを経由した際に、元のクライアントIPアドレスを後続のサーバ伝えるために付与されるヘッダーのことです。
例えば以下のようにX-Forwarded-Forヘッダを付与します。
GET / HTTP/1.1
Host example.com
X-Forwarded-For: 203.0.113.10DocumentRoot “/var/www/html”
一言で言うと、Apacheが公開するWebコンテンツの配置場所です。
一般的にはDocumentRootは/var/www/htmlで設定し、この配下配置されたファイルがWebコンテンツとなる。
/var/www/html/index.htmlを配置し、ユーザがhttps://example.comにアクセスするとindex.htmlが返される。
DirectoryInex index.html
この設定は正確には以下のディレクティブのようになっています。
<IfModule dir_module>
DirectoryIndex index.html
</IfModule>DirectoryIndexはディレクトリへのアクセス時にデフォルトで表示するファイルを指定する設定です。
流れとしては、ユーザがhttps://example.com にアクセスするとDocumentRootの/var/www/htmlが参照され、その後DirectoryIndex index.htmlにより/var/www/html/index.htmlが返される。
ErrorLog
Apacheのエラーログ出力先を指定します。
例えば以下のように設定の場合、
/var/log/httpd/error_log/var/log/httpd/配下にerror_logが出力されます。
CustomLog
Apacheのアクセスログの出力先を指定します。
エラーログと同様に以下のような設定になります。
/var/log/httpd/access_logProxyRequests ProxyPass ProxyPassReverse
ProxyRequests: フォワードプロキシにする設定、Onならフォワードプロキシとして機能、Offならリバースプロキシとして機能。
フォワードプロキシとは
ユーザの代わりにが外部サイトへアクセスする
会社のネットワークなどは以下の流れでインターネットに接続します。
ユーザ
↓
社内Proxy
↓
外部サイトhttps://google.comへアクセスすると、上記の流れになるため、Googleからみたら、アクセス元はProxyサーバからのアクセスということになります。
これがどういうことか?
- データをキャッシュできる
- 許可されていない不正サイトへのアクセスをブロックする
- アクセス元を一元管理するため、誰がどのサイトにアクセスしたのかを記録できる
リバースプロキシとは
Webサーバの代わりにリクエストを受ける
ユーザ
↓
Apache
↓
ALB
↓
バックエンドサーバ上記のような構成で、ALBがリバースプロキシとして動作し、ユーザからのリクエストを後続へ振り分ける役割を担います。
負荷分散やアクセスログの取得、ヘルスチェックなどの機能も提供します。
フォワードプロキシとリバースプロキシをまとめると
フォワードプロキシ
ユーザ (クライアント)の前段に配置され、ユーザに変わって外部サイトへアクセスする。
リバースプロキシ
サーバの前段に配置され、ユーザ (クライアント)からのアクセスを受け付けて、後続のサーバへ転送する。
ここまでを理解した上で、ProxyPassにProxyPass / http://internal-alb-123456.ap-northeast-1.elb.amazoaws.comのように設定されていたら、Apacheに到着したリクエストを後続のALBへ転送する設定と理解します。
ユーザ
↓
Apache
↓
ALB実際にローカル環境にApacheコンテナとバックエンドコンテナを構築して試してみましょう。
以下のディレクトリ構成でファイルを準備します。
apache-sandbox
├ apache
│ └ httpd.conf
├ backend
│ └ index.html
└ docker-compose.yamlServerName localhost
LoadModule mpm_event_module modules/mod_mpm_event.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule unixd_module modules/mod_unixd.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
User daemon
Group daemon
ErrorLog /proc/self/fd/2
LogFormat "%h %l %u %t \"%r\" %>s %b" common
CustomLog /proc/self/fd/1 common
Listen 80
<VirtualHost *:80>
ProxyPass / http://backend/
ProxyPassReverse / http://backend/
</VirtualHost><h1>Backend Server</h1>services:
apache:
image: httpd:2.4
container_name: apache
ports:
- "8080:80"
volumes:
- ./apache/httpd.conf:/usr/local/apache2/conf/httpd.conf
depends_on:
- backend
backend:
image: nginx:latest
container_name: backend
volumes:
- ./backend/index.html:/usr/share/nginx/html/index.html上記ファイルを準備し、以下コマンドでコンテナを立ち上げます。
docker compose up -d
[+] Running 14/14
✔ apache Pulled 12.0s
✔ backend Pulled 10.3s
[+] Running 3/3
✔ Network apache-sandbox_default Created 0.1s
✔ Container backend Started 0.6s
✔ Container apache Started コンテナが問題なく起動しhttp://localhost:8080にアクセスするとBackend Serverと画面に表示されれば、Apacheが後続のコンテナへ転送できているということになります。
クライアント
↓
Apache
↓
BackendProxyPassについてにはこれで理解できたかと思います。
次にProxyPassReverseについてですが、これはなぜ必要なのでしょうか?これが非常にわかりづらいのですが、
上記で構築したbackendコンテナがリダイレクトを返すケースが問題になってきます。
例えば、http://localhost:8080/loginにアクセスした場合、以下のように転送します。
ブラウザ
↓
localhost::8080/login
Apache
↓
backend/loginBackendが仮に以下を返したとします。
HTTP/1.1 302 Found
Location: http://backend/topProxyPassReverseがない場合
ブラウザは
Location: http://backend/top上記を受け取ります。
ブラウザは
http://backend/topへアクセスしようとします。
ただ、backendはDockerネットワーク内部の名前なのでブラウザから上記でアクセスしてもエラーとなります。
ProxyPassReverseがある場合
Apacheはレスポンスを見て、
Location: http://backend/top上記を以下に書き換えます。
Location: http://localhost:8080/topその結果ブラウザは以下へアクセスします。
http://localhost:8080/topまとめると、
ProxyPassReverseは後続サーバから返却されたリダイレクト先のURLを利用者向けのURLへ書き換えるための設定です。
ここまでhttpd.confについて諸々調べて書き起こしてみました。
いまだにApacheを使っているシステムはまだまだあるので、今後保守案件などで必要になった際の備忘として使用できればと思います。