自分のApache httpdの設定はいけてるのかなあ?


自分が使い回している設定をさらしてみます

結構がんばって作ったのですが、まだまだできることがありそうです。「こうしたらいいよ!」というご指摘、お待ちしております。

使い回すファイルたち

なにかに依存することを避けて、どの環境でも使えるようにしたファイルたちです。書き換えることはありません。

(ただ Amazon Linux 2 を対象にしているので、場合によってはモジュールが足りないと言われるかもしれません。あと、想定している環境は 2.4 系のみです)

conf/httpd.conf

conf/httpd.conf
Listen 80

Include conf.modules.d/*.conf

User apache
Group apache

ServerName localhost

<Directory "/">
    Require all denied
</Directory>

<Files ".ht*">
    Require all denied
</Files>

<IfModule mod_http2.c>
    Protocols h2 h2c http/1.1
</IfModule>

TypesConfig /etc/mime.types

LogLevel warn
ErrorLog logs/error_log

IncludeOptional conf.d/*.conf
IncludeOptional conf.d/vhosts/*.conf

もともとのファイルからコメントを削っただけのような。

追加の設定は最後の2行で include しているように conf.d/ に書いて、バーチャルホストの定義は cond.d/vhosts/ に書きます。

conf.d/ssl.conf

conf.d/ssl.conf
Listen 443 https

#SSLPassPhraseDialog exec:/usr/libexec/httpd-ssl-pass-dialog
SSLSessionCache         shmcb:/run/httpd/sslcache(512000)
SSLSessionCacheTimeout  300

SSLStaplingCache shmcb:/tmp/stapling_cache(128000)

SSLRandomSeed startup file:/dev/urandom  256
SSLRandomSeed connect builtin

SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite ECDSA+AESGCM
SSLHonorCipherOrder Off

どこかからいろいろコピーしてきて作ったような。

SSLProtocol は TLSv1.2 しか対応していなくても all -SSLv3 -TLSv1 -TLSv1.1 と書いておくと、この先 TLSv1.3 に対応したときでも安心です。

SSLCipherSuite は、セキュリティ事情でいつか変える日が来ると思いますが、2020年7月3日現在では ECDSA+AESGCM だけで問題ないと思います。

openssl ciphers -v ECDSA+AESGCM
TLS_AES_256_GCM_SHA384  TLSv1.3 Kx=any      Au=any  Enc=AESGCM(256) Mac=AEAD
TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any      Au=any  Enc=CHACHA20/POLY1305(256) Mac=AEAD
TLS_AES_128_GCM_SHA256  TLSv1.3 Kx=any      Au=any  Enc=AESGCM(128) Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(128) Mac=AEAD

SSLHonorCipherOrder は、On にするよう書いてあるページが多いですが、ここは Off のままにしていますOff だとブラウザが Cipher を選ぶことになりますが、サーバ側で指定するより日々更新されるブラウザに任せた方が、セキュリティを十分考慮しつつパフォーマンスよくハンドリングしてくれるでしょう。

SSLPassPhraseDialog をコメントアウトしてあるのは、私はTLSv1.3対応のmod_sslを自前でbuildしているので、mod_ssl パッケージに含まれているスクリプトが入っていないからです。鍵の passphrase は気にしない方向で…)

conf.d/vhosts/_default_*.conf

リクエストしたバーチャルホストがないときに使われる定義です。分かりやすいよう、HTTP用とHTTPS用の2つに分けています。

2.4 系では NameVirtualHost は何も処理をしないようになったので書いていません1。(それにともなって _default_* のエイリアス扱いになった2、という変更もありますが、あえて * に変える必要はないと思っています)

_default_80.conf

conf.d/vhosts/_default_80.conf
<VirtualHost _default_:80>
    DocumentRoot /var/www/_default
    <Directory "/var/www/_default">
        Require all granted
    </Directory>
    <If "-f '/var/www/%{HTTP_HOST}/index.html'">
        <If "%{REQUEST_URI} !~ m#^/.well-known/acme-challenge/#">
            RewriteEngine on
            RewriteRule ^.*$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
        </If>
    </If>
    <Else>
        Redirect 403 /
    </Else>

    LogFormat "%{Host}i %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" http_combined
    CustomLog logs/access_log http_combined
</VirtualHost>

HTTP(port 80)は以下のように処理します。

  • HTTP_HOST に該当するバーチャルホストがない場合、すべてのリクエストに 403 Forbidden を返します
  • Let's Encrypt のACMEプロトコルで使うパスだった場合は何もせず、それ以外ならリクエストをそのままHTTPSにリダイレクトします

ACMEプロトコルで使うパスに対応するディレクトリは /var/www/_default/.well-known/acme-challenge になるなので /var/www/_default はアクセスできるようにします。

ここまでやる必要があるのかな、という気は、まあ、あります……。
mod_rewrite の負荷を少しは減らして、全体のレイテンシをあげられるかも……?

log に Host ヘッダを記録しているのは、HSTS preload されているサイトにあえてHTTPでアクセスするのは誰だ、というのを興味本位で知りたいだけです。普通は必要ないです。

_default_443.conf

conf.d/vhosts/_default_443.conf

<VirtualHost _default_:443>
    LogFormat "%{Host}i %h [%{%Y/%m/%d %T}t] %>s %b %{SSL_PROTOCOL}x \"%r\" \"%{Referer}i\" \"%{User-Agent}i\"" all_host_ssl
    CustomLog logs/keys_ssl_access_log all_host_ssl

    LogFormat "%{Host}i %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" https_combined
    CustomLog logs/ssl_access_log https_combined

    Redirect 403 /

    SSLEngine on
    SSLCertificateFile conf.d/dummy.crt
    SSLCertificateKeyFile conf.d/dummy.key
</VirtualHost>

??? という感じの設定ですが、こうしている理由は別の記事(SSL証明書でIPアドレスからホスト名が漏れる)で書きました。

バーチャルホストの定義

以下は、それぞれのバーチャルホストを定義するファイルです。これは、実際に私が使っているWebサーバのものです。

HTTP(port 80)は独自のものは設定せず、デフォルトのものを使います。

conf.d/vhosts/devel.keys.jp.conf
<VirtualHost *:443>
    ServerName devel.keys.jp
    ServerAdmin [email protected]
    DocumentRoot /var/www/devel.keys.jp

    <Directory "/var/www/devel.keys.jp">
        Options All -Indexes
        AllowOverride All
        Require all granted
        SSLOptions +StdEnvVars +StrictRequire
        AddHandler cgi-script .cgi .pl .py
    </Directory>

    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combine_by_host
    CustomLog logs/devel.keys.jp/ssl_access_log combine_by_host

    Header set X-XSS-Protection "1; mode=block"
    Header set X-Content-Type-Options nosniff
    Header append X-Frame-Options SAMEORIGIN
    Header set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"

    SSLEngine on
    SSLUseStapling on
    SSLCertificateFile /opt/dehydrated/certs/devel.keys.jp/fullchain.pem
    SSLCertificateKeyFile /opt/dehydrated/certs/devel.keys.jp/privkey.pem
</VirtualHost>

アクセスログをバーチャルホスト単位で保存するように変更しているほかは、とくに珍しいことはしていないと思います。
Let's EncryptのACMEクライアントには dehydrated を使っています)

今はただ静的コンテンツを提供しているだけなので、これで十分にやれています。重いコンテンツを提供しだすとどうなのかな……。

みなさまは、どういった工夫をされていますか?