287
308

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Apache 2.4 設定ファイルの記述例

Last updated at Posted at 2013-11-24

導入

CentOS 7の公式Yumリポジトリから提供されているApacheで動作を確認しています。それ以外のOSでは、設定ファイルが置かれている場所 (英語)ドキュメントルートの初期値が異なる場合があるのでご注意ください。

Apache設定ファイル (*.conf) のシンタックスハイライト

CentOS標準のYumリポジトリで提供されているテキストエディタのうちVimEmacs以外のエディタは、初期状態で.confファイルのシンタックスハイライトが機能しません。以下のように設定ファイルの編集などを行い、シンタックスハイライトを有効にします。

gedit

Bug 612368 – Language definition for Apache configuration filesで公開されているファイルを利用します。

# Apache設定ファイル用の言語設定ファイルをダウンロード
wget https://bug612368.bugzilla-attachments.gnome.org/attachment.cgi?id=195525 --output-document=apache.lang
# 言語設定ファイル中のclass属性、class-disabled属性を削除。「*.conf」をハイライトするように
sed --in-place --regexp-extended --expression 's/\sclass(-disabled)?="[^"]+"//g' --expression 's/httpd\.conf;httpd2\.conf;apache\.conf;apache2\.conf/*.conf/' apache.lang
# GtkSourceViewのユーザー定義ディレクトリに移動
sudo mv apache.lang /usr/share/gtksourceview-*/language-specs/

nano

Arch Linuxnano-syntax-highlighting-gitパッケージを利用します。1 2

# INIファイルのシンタックスハイライトを行う設定ファイルをダウンロード
wget https://raw.githubusercontent.com/scopatz/nanorc/master/apacheconf.nanorc
# .conf で終わるファイルをApache設定ファイルとして扱うようにする
sed --in-place 's/httpd\\\.conf/.conf$/' apacheconf.nanorc
# シンタックスハイライトを行う設定ファイル保管場所に移動
sudo mv apacheconf.nanorc /usr/share/nano/
# nanoの個人設定ファイルから読み込むようにする
echo $'\n\n'## INI files$'\n'include "/usr/share/nano/apacheconf.nanorc" >> ~/.nanorc

Kate

ファイル名が.confで終わるファイルをApache設定ファイルとして開くようにします。

/usr/share/kde*/apps/katepart/syntax/.xml
<language name="Apache Configuration" section="Configuration"
          version="1.11" kateversion="2.0"
          extensions="*.conf;.htaccess*;.htpasswd*"
          mimetype=""
          author="Jan Janssen (medhefgo@googlemail.com)" license="LGPL">
<!-- ↑extensions属性値の「httpd.conf;httpd2.conf;apache.conf;apache2.conf」を「*.conf」に置換 -->

                    <!--##############
                        ## 以下省略 ##
                        ##############-->

基本設定

/etc/httpd/conf/httpd.conf
                        ##############
                        ## 以上省略 ##
                        ##############

<IfModule unixd_module>
#
# If you wish httpd to run as a different user or group, you must run
# httpd as root initially and it will switch.  
#
# User/Group: The name (or #number) of the user/group to run httpd as.
# It is usually good practice to create a dedicated user and group for
# running httpd, as with most system services.
#
User apache
Group apache
## ↑両方とも daemon から apache に変更する (CentOS7標準のApacheでは設定済み) ##

</IfModule>

# 'Main' server configuration
#
# The directives in this section set up the values used by the 'main'
# server, which responds to any requests that aren't handled by a
# <VirtualHost> definition.  These values also provide defaults for
# any <VirtualHost> containers you may define later in the file.
#
# All of these directives may appear inside <VirtualHost> containers,
# in which case these default settings will be overridden for the
# virtual host being defined.
#

#
# ServerAdmin: Your address, where problems with the server should be
# e-mailed.  This address appears on some server-generated pages, such
# as error documents.  e.g. admin@your-domain.com
#
ServerAdmin webmaster@example.jp
## ↑サーバー管理者への問い合わせ先メールアドレスに変更する ##

#
# ServerName gives the name and port that the server uses to identify itself.
# This can often be determined automatically, but we recommend you specify
# it explicitly to prevent problems during startup.
#
# If your host doesn't have a registered DNS name, enter its IP address here.
#
ServerName example.jp:80
## ↑サーバーのホスト名を指定する ##

                        ##############
                        ##   中略   ##
                        ##############
#
# Relax access to content within /var/www.
#
#<Directory "/var/www">
#    AllowOverride None
#    # Allow open access:
#    Require all granted
#</Directory>
## ↑<Directory "/var/www"> セクションをコメントアウトする (CentOS7標準のApacheの場合) ##

## ↓一つ上のディレクトリに変更する ##
<Directory "/var/www">
    #
    # Possible values for the Options directive are "None", "All",
    # or any combination of:
    #   Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
    #
    # Note that "MultiViews" must be named *explicitly* --- "Options All"
    # doesn't give it to you.
    #
    # The Options directive is both complicated and important.  Please see
    # https://httpd.apache.org/docs/2.4/mod/core.html#options
    # for more information.
    #
    Options FollowSymLinks
    ## ↑ Indexes を削除する ##

    #
    # AllowOverride controls what directives may be placed in .htaccess files.
    # It can be "All", "None", or any combination of the keywords:
    #   AllowOverride FileInfo AuthConfig Limit
    #
    AllowOverride None
    
    #
    # Controls who can get stuff from this server.
    #
    #Require all granted
    ## ↑コメントアウトする ##
</Directory>

#
# DirectoryIndex: sets the file that Apache will serve if a directory
# is requested.
#
<IfModule dir_module>
    DirectoryIndex index.html
</IfModule>

                        ##############
                        ##   中略   ##
                        ##############
#
# LogLevel: Control the number of messages logged to the error_log.
# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
#
#LogLevel warn
## ↑コメントアウトする ##

                        ##############
                        ##   中略   ##
                        ##############
#
# Customizable error responses come in three flavors:
# 1) plain text 2) local redirects 3) external redirects
#
# Some examples:
#ErrorDocument 500 "The server made a boo boo."
#ErrorDocument 404 /missing.html
#ErrorDocument 404 "/cgi-bin/missing_handler.pl"
#ErrorDocument 402 http://www.example.com/subscription_info.html
#
ErrorDocument 403 /not-found
ErrorDocument 404 /not-found
ErrorDocument 503 /internal-server-error
## ↑それぞれのエラーコードに対応するファイルを指定する ##

                        ##############
                        ## 以下省略 ##
                        ##############

[User ディレクティブ] \([旧バージョンの翻訳][user-old])
[Group ディレクティブ] \([旧バージョンの翻訳][group-old])
`User apache`
`Group apache`
root権限で起動したApacheの親プロセスが子プロセスを生成する際に使用するユーザー名とグループ名を指定します。ここでは、`daemon`から、Apacheインストール時に自動作成されたユーザー (グループ) `apache`に変更します。
[ServerAdmin ディレクティブ]
`ServerAdmin webmaster@example.jp`
サーバー管理者への問い合わせ先メールアドレス (または別サーバーのURL) を指定します。 **`webmaster@example.jp`は例示用のアドレスなので、自分が管理するメールアドレスに置き換えてください。**
[ServerName ディレクティブ]
`ServerName example.jp:80`
サーバーのホスト名とポート番号を指定します。サーバーのIPアドレスに対して、DNSのPTRレコード (逆引きレコード) で設定したホスト名を指定しておくと良いでしょう。このディレクティブが欠けていると、「正確なホスト名を決定できなかった」という旨のエラーが発生します。 **`example.jp`は例示用のホスト名なので、自分のサーバーのホスト名に置き換えてください。** このディレクティブは、後述する[<VirtualHost> セクション]内でも設定します。
[Option ディレクティブ]
利用できる機能の制限を強化、または緩和します。最初から記述されている`Options Indexes FollowSymLinks`は、Indexes機能FollowSymLinks機能が有効です。スラッシュで終わるURLにアクセスがあった場合、 [DirectoryIndex ディレクティブ]で指定したファイルがディレクトリに存在しなければ、ディレクトリ内のファイル一覧を返すのがIndexes機能です。このディレクティブが欠けていると、デフォルト値である`Options All`に設定されるので注意してください。
[Require ディレクティブ] \(リンク先英語)
サーバーのディレクトリに接続してくるクライアントについて、許可・拒否する条件を指定するディレクティブです。昔は[Allow ディレクティブやDeny ディレクティブ]を利用していました。`Require all granted`は、すべてのクライアントからの接続を許可します。`Require all denied`は、すべてのクライアントからの接続を拒否します。
[<Directory> セクション]
ディレクティブを適用するディレクトリを指定します。ファイルシステムのパス絶対URL (ドキュメントルートではなくOSのルートディレクトリをルートとするスラッシュで始まるURL) で指定します。`*` `?` `[` `]`をワイルドカードとして使用できます。パス区分 (ディレクトリ名など) を`/`以外 (Windowsの`\\`など) で区切るOSであっても、このセクションの引数では`/`を用います。
記述できるディレクティブの制限などはありますが、``内に記述するのと、`/var/www/html/.htaccess`に記述するのは同義です。
最初は``にドキュメントルートの設定が記述されています。`html`以外のディレクトリへのアクセスがあるなら、``に変更し、`Require all granted`をコメントアウトしておきます。
[Redirect ディレクティブ]
第2引数で指定したURLを、第3引数で指定したURLにリダイレクトします。第1引数にはHTTPステータスコードを指定します。第1引数は省略可能で、省略した場合`302`になります。URLは前方一致で、`Redirect /foo /bar`と記述すると、https://example.com/foo/test が https://example.com/bar/test にリダイレクトされます。この場合、https://example.com/foo2 などには一致しません。
第1引数に[300〜399]以外の数値を指定することもでき、この場合第3引数は指定しません。
第1引数において、`301` `302` `303` `410`は、それぞれ`permanent` `temp` `seeother` `gone`とキーワードで指定することもできます。なお、古いHTTP仕様で`302`はこのキーワード通り`Moved Temporarily`でしたが、仕様が変更され[302 (Found)]となっており、一時的なリダイレクトには現在[307 (Temporary Redirect)]を使うことになっています。
[RedirectMatch ディレクティブ]
第2引数に正規表現を指定すること以外は、[Redirect ディレクティブ]と同じです。正規表現内の後方参照は、第3引数で`$1`などと数字に`$`を前置して利用できます。たとえば、`RedirectMatch ^/foo(/.*)?$ /bar$1`は`Redirect /foo /bar`と同じ意味になります。
[ErrorDocument ディレクティブ]
`ErrorDocument 404 /not-found`
エラーが発生したときに返す文書等を指定します。第2引数でファイルを指定する場合は、パス絶対URL (ドキュメントルートをルートとするスラッシュで始まるパス) で指定する必要があります。
ここでは、[ファイルの存在自体を隠蔽するなどの理由で、エラーコードが403の場合でも404の場合と同じ文書を返す]ようにしています。この場合第2引数に、`404`を返すプログラムを指定したり、[RewriteRule ディレクティブ]の[\[R|redirect\]フラグ][R]で`404`を返したりする必要があります。

TLS (俗称: SSL) の設定

サーバー証明書をインストール済みであればこの項は読み飛ばしてください。この記事では、無料でDV証明書を取得できるLet’s Encryptを利用する場合について解説します。Let’s Encryptは証明書を自動発行するACMEプロトコルを採用しており、CertbotなどのACMEクライアントで簡単に導入できます。

Certbotのインストール

この記事では、サーバー設定も自動で行えるCertbotをACMEクライアントとして使用します。

Let’s Encrypt の使い方 — Let’s Encrypt 総合ポータル

各OSごとの取得方法は上記ページをご覧ください。以下はCentOS7の場合における例です。

# 【インストールしていない場合】EPELリポジトリとmod_sslのインストール
sudo yum install epel-release mod_ssl

# Certbotのインストール
sudo yum install certbot python-certbot-apache
# ↑EPEL7のGPG公開鍵を取り込んでも良いか訊ねられた場合、
#   Fingerprintが https://getfedora.org/ja/keys/ の指紋と大文字小文字無視で一致するか確認します。

# 【未設定の場合】443ポートを開ける
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

証明書の取得・インストール

途中でApacheが再起動される際にエラーが出るため、先にApacheを起動しておきます。

sudo apachectl start
sudo certbot --apache --must-staple --hsts --redirect

途中で証明書を発行するドメイン名の入力 (複数の場合は空白かカンマ区切り)、緊急連絡などに使うメールアドレスの入力、およびLet’s Encrypt利用規約への同意を求められます。また、設定の保存先として ssl.conf (CentOSの場合) が提示されるので、そのままそれを <Select> します。

後述の設定で複数のドメインを扱う場合、--redirect の代わりに一旦 --no-redirect を指定しておきます。

Apacheの設定

/etc/httpd/conf.d/ssl.conf
                        ##############
                        ## 以上省略 ##
                        ##############

# Use separate log files for the SSL virtual host; note that LogLevel
# is not inherited from httpd.conf.
#ErrorLog logs/ssl_error_log
#TransferLog logs/ssl_access_log
#LogLevel warn
## ↑3行ともコメントアウトする ##

#   SSL Engine Switch:
#   Enable/Disable SSL for this virtual host.
#SSLEngine on
## ↑コメントアウトする ##

                        ##############
                        ##   中略   ##
                        ##############

#   Server Certificate:
# Point SSLCertificateFile at a PEM encoded certificate.  If
# the certificate is encrypted, then you will be prompted for a
# pass phrase.  Note that a kill -HUP will prompt again.  A new
# certificate can be generated using the genkey(1) command.
SSLCertificateFile /etc/letsencrypt/live/example.jp/cert.pem
## ↑CertbotのApacheプラグインによって自動的に修正された行 ##

#   Server Private Key:
#   If the key is not combined with the certificate, use this
#   directive to point at the key file.  Keep in mind that if
#   you've both a RSA and a DSA private key you can configure
#   both in parallel (to also allow the use of DSA ciphers, etc.)
SSLCertificateKeyFile /etc/letsencrypt/live/example.jp/privkey.pem
## ↑CertbotのApacheプラグインによって自動的に修正された行 ##

                        ##############
                        ##   中略   ##
                        ##############

#   Per-Server Logging:
#   The home of a custom SSL log file. Use this when you want a
#   compact non-error SSL logfile on a virtual host basis.
CustomLog logs/ssl_request_log \
          "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"

# TLSの基本設定を読み込み
Include /etc/letsencrypt/options-ssl-apache.conf
## ↑この行を追加 ##

## ↓これ以降の行が、CertbotのApacheプラグインによって追記された文字列 ##
ServerName example.jp
ServerAlias sub1.example.jp sub2.example.jp
Header always set Strict-Transport-Security "max-age=31536000"
SSLUseStapling on
SSLCertificateChainFile /etc/letsencrypt/live/example.jp/chain.pem
</VirtualHost>                                  

<IfModule mod_ssl.c>
SSLStaplingCache shmcb:/var/run/apache2/stapling_cache(128000)
</IfModule>

[SSLProtocol ディレクティブ] \(リンク先英語)
`SSLProtocol all -SSLv2 -SSLv3`
使用するSSL/TLSのバージョンを制御します。各引数の先頭に `+` `-` を付け、手前で指定したバージョンに追加するか除外するかを表します。
ここでは、サポートされるすべてのバージョンから、(SSL 2.0)、SSL 3.0 を除外しています。なお、CentOS 7 の `ssl.conf` には最初 `SSLProtocol all -SSLv2` と記述されているものの、Apache 2.4 では SSL 2.0 をすでにサポートしていないので、エラーこそ出ませんがこの指定は無意味です。
もともと SSL 3.0 は標準化されていませんでしたが、[RFC 7568によって使用が禁止されました]。TLS 1.0、およびTLS 1.1は、実装間でより新しいバージョンがある場合は使用すべきでないと[RFC 7525に書かれています]。NetReaderなどのIEコンポーネントブラウザは、Windows VistaだとTLS 1.1に対応していない[^vista]ので、2017年4月11日まではTLS 1.0を有効にしておく必要があるかと思います。[^NetReader]
[SSLCipherSuite ディレクティブ] \(リンク先英語)
`SSLCipherSuite !DSS:EECDH+HIGH:EDH+HIGH:HIGH:MEDIUM:!aNULL:!MD5:!SEED:!IDEA`
使用する暗号化方式を制御します。各引数の先頭に `+` `-` `!` を付け、手前で指定したバージョンに追加するか除外するかを表します。引数の意味については、[ApacheでOpenSSLのセキュリティを強化する]をご覧ください。
[SSLHonorCipherOrder ディレクティブ] \(リンク先英語)
`SSLHonorCipherOrder on`
使用する暗号化方式の決定について、クライアントよりサーバーのリストを優先します。既定では無効になっています。
[SSLCertificateFile ディレクティブ] \(リンク先英語)
`SSLCertificateFile /etc/letsencrypt/live/example.jp/cert.pem`
Apache 2.4.7以下ではサーバー証明書 (Certbotで取得した場合は `cert.pem`) を、Apache 2.4.8以上ではサーバー証明書と中間証明書を結合したファイル (Certbotで取得した場合は `fullchain.pem`) のパスを指定します。 **2.4.7/2.4.8をまたいでバージョンを変更する際は修正する必要があるので注意してください。**
この例はApache 2.4.6のものなので、Certbotによってサーバー証明書のパスが設定されています。
[SSLCertificateKeyFile ディレクティブ] \(リンク先英語)
`SSLCertificateKeyFile /etc/letsencrypt/live/example.jp/privkey.pem`
秘密鍵を指定します。
[SSLCertificateChainFile ディレクティブ] \(リンク先英語)
`SSLCertificateChainFile /etc/letsencrypt/live/example.jp/chain.pem`
Apache 2.4.7以下において、中間証明書 (Certbotで取得した場合は `chain.pem`) を指定します。Apache 2.4.8以降、[SSLCertificateFile ディレクティブ]に統合する形で廃止されました。 **2.4.7/2.4.8をまたいでバージョンを変更する際は修正する必要があるので注意してください。**
この例はApache 2.4.6のものなので、Certbotによってこのディレクティブが追加されています。
[SSLUseStapling ディレクティブ] \(リンク先英語)
`SSLUseStapling on`
[OCSP Stapling]を有効化します。
[SSLStaplingCache ディレクティブ] \(リンク先英語)
`SSLStaplingCache shmcb:/var/run/apache2/stapling_cache(128000)`
[OCSP Stapling]におけるキャッシュの保存先と容量を指定します。

証明書の自動更新例 (systemd)

certbot renew で期限切れが近い証明書を更新できます。systemdを採用しているCentOS 7などでは、certbotパッケージに同梱のcertbot-renew.timerを利用します。3

# certbot.timerの有効化 (OS起動時に自動的に起動させる) と起動
sudo systemctl enable --now certbot-renew.timer

直近のログは次のようなコマンドで調べます。

  • sudo cat /var/log/letsencrypt/letsencrypt.log
  • systemctl status certbot-renew --full --lines 50
  • systemctl status certbot-renew.timer --full

HTTP応答ヘッダの設定

/etc/httpd/conf/httpd.conf
# XHTMLに対応していないブラウザ
SetEnvIfExpr "!(%{HTTP_ACCEPT} -strcmatch '*application/xhtml+xml*') || %{HTTP_USER_AGENT} =~ m#UP\\.Browser/6\\.2|Nintendo 3DS| NX/1\\.|Trident/5\\.#" LEGACY_BROWSER
## ↑ファイルの先頭に挿入 ##

                        ##############
                        ##   中略   ##
                        ##############

<IfModule mime_module>

                        ##############
                        ##   中略   ##
                        ##############

    #
    # Filters allow you to process content before it is sent to the client.
    #
    # To parse .shtml files for server-side includes (SSI):
    # (You will also need to add "Includes" to the "Options" directive.)
    #
    #AddType text/html .shtml
    #AddOutputFilter INCLUDES .shtml
    ## ↑この2行をコメントアウトする (CentOS7標準のApacheの場合) ##
    
    ## ↓<IfModule mime_module> セクションの末尾に追記 ##
    <If "-n reqenv('LEGACY_BROWSER')">
        # XHTMLに対応していなければ
        AddType text/html .xhtml
    </If>
</IfModule>

#
# Specify a default charset for all content served; this enables
# interpretation of all content as UTF-8 by default.  To use the 
# default browser choice (ISO-8859-1), or to allow the META tags
# in HTML content to override this choice, comment out this
# directive:
#
#AddDefaultCharset UTF-8
## ↑コメントアウトする ##

# content-typeヘッダにcharsetパラメータを付加する
AddCharset utf-8 .xhtml .html .css .es .js .txt .json .xml .csv
## ↑この行を追加 ##

# content-languageヘッダを送出する
AddLanguage ja .xhtml .html
## ↑この行を追加 ##

                        ##############
                        ##   中略   ##
                        ##############

## ↓ファイルの末尾に追記 ##
ServerTokens ProductOnly
Header always set x-content-type-options nosniff
<If "%{HTTP_USER_AGENT} =~ m#Trident/5\\.#">
    # Internet Explorer 9 の互換表示ボタンを消す
    Header always set x-ua-compatible IE=edge
</If>
/etc/httpd/conf.d/ssl.conf
                        ##############
                        ## 以上省略 ##
                        ##############

ServerName example.jp
ServerAlias sub1.example.jp sub2.example.jp
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
## ↑「includeSubDomains」「preload」パラメータを追加 ##
SSLUseStapling on
SSLCertificateChainFile /etc/letsencrypt/live/example.jp/chain.pem
</VirtualHost>                                  

<IfModule mod_ssl.c>
SSLStaplingCache shmcb:/var/run/apache2/stapling_cache(128000)
</IfModule>
/etc/httpd/conf.d/autoindex.conf (CentOS7標準のApacheの場合)
#
# Directives controlling the display of server-generated directory listings.
#
# Required modules: mod_authz_core, mod_authz_host,
#                   mod_autoindex, mod_alias
#
# To see the listing of a directory, the Options directive for the
# directory must include "Indexes", and the directory must not contain
# a file matching those listed in the DirectoryIndex directive.
#

#
# IndexOptions: Controls the appearance of server-generated directory
# listings.
#
#IndexOptions FancyIndexing HTMLTable VersionSort
## ↑コメントアウトする ##

# We include the /icons/ alias for FancyIndexed directory listings.  If
# you do not use FancyIndexing, you may comment this out.
#
#Alias /icons/ "/usr/share/httpd/icons/"
## ↑コメントアウトする ##

                        ##############
                        ## 以下省略 ##
                        ##############
/etc/httpd/conf.d/welcome.conf (CentOS7標準のApacheの場合)
# 
# This configuration file enables the default "Welcome" page if there
# is no default index page present for the root URL.  To disable the
# Welcome page, comment out all the lines below. 
#
# NOTE: if this file is removed, it will be restored on upgrades.
#
#<LocationMatch "^/+$">
#    Options -Indexes
#    ErrorDocument 403 /.noindex.html
#</LocationMatch>

#<Directory /usr/share/httpd/noindex>
#    AllowOverride None
#    Require all granted
#</Directory>

#Alias /.noindex.html /usr/share/httpd/noindex/index.html
#Alias /css/bootstrap.min.css /usr/share/httpd/noindex/css/bootstrap.min.css
#Alias /css/open-sans.css /usr/share/httpd/noindex/css/open-sans.css
#Alias /images/apache_pb.gif /usr/share/httpd/noindex/images/apache_pb.gif
#Alias /images/poweredby.png /usr/share/httpd/noindex/images/poweredby.png
## ↑すべてコメントアウトする ##

[SetEnvIfExpr ディレクティブ] \([SetEvnIf ディレクティブの日本語訳])
`SetEnvIfExpr "!(%{HTTP_ACCEPT} -strcmatch '*application/xhtml+xml*') || %{HTTP_USER_AGENT} =~ m#UP\\.Browser/6\\.2|Nintendo 3DS| NX/1\\.|Trident/5\\.#" LEGACY_BROWSER`
第1引数の条件式が真なら、第2引数の環境変数を設定します。条件式の構文は[Expressions in Apache HTTP Server]に載っています。この構文は[<If> セクション]や[RewriteCond ディレクティブ]でも利用できます。`LEGACY_BROWSER`のように変数値を省略することは、`LEGACY_BROWSER=1`のように変数値として`1`を指定することと同義です。
[accept要求ヘッダ]に`application/xhtml+xml`が含まれていれば、基本的にそれはXHTML文書に対応しているWebブラウザからのアクセスです。しかしその中には、XHTML文書を正常に扱えず、HTML文書を返した方が良いブラウザもあります。httpd.confの先頭に上記のような[SetEnvIfExpr ディレクティブ]を記述することで、XHTML文書に対応していないブラウザからのアクセスに対し、`LEGACY_BROWSER`という環境変数が設定されるようにしています。ここでXHTML文書に対応していないブラウザとして扱っているのは、[accept要求ヘッダ]に`application/xhtml+xml`が含まれないブラウザ、Openwave Mobile Browser 6.2 (古い[EZブラウザ])、[NetFront Browser NX 1] \([ニンテンドー3DS用インターネットブラウザー])[^3ds]、Internet Explorer 9[^ie9-xhtml] [^ie9] です。
[AddType ディレクティブ]
`AddType image/vnd.microsoft.icon .ico .cur`
どの拡張子がどのファイル形式に対応するか指定します。`mime.types`ファイルに登録されている情報を元に[content-type応答ヘッダ][content-type]が返されるので、基本的には必要はありません。登録されていなかったり、登録されていても情報が古かったりする場合に、このディレクティブを使用して`mime.types`の設定を上書きします。
[<If> セクション]
[<ElseIf> セクション] \(リンク先英語)
[<Else> セクション] \(リンク先英語)
``〜``
ディレクティブを適用する条件式を指定します。ドキュメンテーションにそのような説明がなくエラーも出ませんが、 **これらのセクションを入れ子にすると、内側のセクションが中身ごと無視されます** 。(Apache 2.4.7 現在)
`-n reqenv('LEGACY_BROWSER')`は、`LEGACY_BROWSER`という環境変数が空でなければ真を返す式です。
[Include ディレクティブ]
[IncludeOptional ディレクティブ] \(リンク先英語)
`Include /etc/httpd/conf/extra/httpd-languages.conf`
サーバー設定ファイルから他の設定ファイルを読み込みます。ファイル、またはディレクトリをファイルシステムのパス絶対URLか、[サーバールート] \(CentOS7標準のApacheの場合、デフォルトでは`ServerRoot "/etc/httpd"`が記述されている) からのパス相対URLで指定します。ワイルドカードも使用可能です。
[IncludeOptional ディレクティブ]はほぼ[Include ディレクティブ]と同じですが、ファイル、またはディレクトリが存在しない場合でもエラーが発生しません。
[ServerTokens ディレクティブ]
[server応答ヘッダ][server]とサーバーが生成するドキュメントのフッターに表示されるサーバー情報を制御します。デフォルト値は`ServerTokens Full`で、`Server: Apache/2.4.7 (Unix)`のように出力されます。`ServerTokens ProductOnly`を指定すると、`Server: Apache`と出力されます。
[Header ディレクティブ]
`Header always set x-content-type-options nosniff`
HTTP応答ヘッダを制御します。内部ヘッダテーブルにはヘッダの一覧が格納されており、[2xxレスポンス]の場合のみ利用されるonsuccessテーブルと、2xxレスポンスを含むすべての場合で利用されるalwaysテーブルのどちらを書き換えるか、第1引数で指定します。第1引数は省略可能で、省略した場合`onsuccess`になります。第2引数で内部ヘッダテーブルに対してどのような操作を行うか指定します。
第2引数について、`set`は新しくヘッダを設定しますが、同じ名前のヘッダが既に存在すればそれを置き換えます。`edit`は既存のヘッダの置換を行う設定で、第3引数に正規表現、第4引数に置換後の文字列を指定します。
[AddLanguage ディレクティブ]
`AddLanguage ja .xhtml .html`
どの拡張子がどの言語に対応するか指定します。上記の指定では、拡張子が`.xhtml` `.html`であるファイルが、HTTP応答ヘッダで`Content-Language: ja`を送出するようになります。
[AddCharset ディレクティブ]
`AddCharset UTF-8 .xhtml .html .css .es .js .txt .json .csv .xml`
どの拡張子がどの文字コードに対応するか指定します。上記の指定では、拡張子が`.xhtml` `.html` `.css` `.es` `.txt` `.json` `.csv`であるファイルの応答ヘッダに、`Content-Type: application/xhtml+xml; charset=UTF-8`のように`charset`パラメータが付加されます。`.htm`や`.xht`等、これ以外の拡張子を持つテキストファイルが自分のサーバーに存在していれば、それらも追加しておきましょう。文字化けは[XSS]につながる可能性もあるので、設定漏れが無いように注意してください。
なお、`application/json` に `charset` パラメータは存在せず、例の通り記述した場合 `Content-Type: application/json; charset=UTF-8` のような不正なヘッダが出力されます。しかしながら、`Content-Type: application/json` を出力すると、ファイルの中身とブラウザの組み合わせによっては文字化けします。[^json]
HTTP応答ヘッダフィールド名
content-type application/xhtml+xmltext/cssなどのファイルの種類と、文字コードを示します。このヘッダが間違っていると、XSSの発生につながります。
content-language HTML文書、XHTML文書 (以下、HTML) では、このヘッダやlang属性によって文章や単語の言語が決定されます。これらの指定が間違っていると、意図したフォントで表示されないといった弊害も起きます。なお、これらの値に指定する言語タグについて、ja-JP (言語と地域を-で繋いでいる) は正しい値ですが、ja_JP (言語と地域を_で繋いでいる) と書くのは誤りです。
link HTMLのlink要素と同じ意味を持ちます。例えば、link: </common/development>; rel=stylesheetは、head要素内に記述した<link href="/common/development" rel="stylesheet" />と同じ効果があります。2013年11月現在、Firefoxのみrel=stylesheetに対応しており、HTML以外のファイルを開いた場合にもスタイルシートが適用されます。rel=iconには対応していません。
x-content-type-options Internet Explorerのcontent-type応答ヘッダ無視を防ぎます。XSSを防止するためにも、このヘッダは必ず送出しなければなりません。
x-ua-compatible 本来はmeta要素で使う属性値で、HTTPヘッダとしては非標準です。 Internet Explorer 94 の互換表示ボタンを消します。
strict-transport-security HTTPS接続を強制する HTTP Strict Transport Security (HSTS) を有効化します。この指定は、同一ドメインに対し max-age パラメータで指定した秒数だけ記憶されます。includeSubDomains を指定すると、サブドメインに対してもHTTPS接続を強制できます。次のような条件を満たせば、ブラウザが初めてアクセスするときもHTTPSを矯正するHSTS Preloadが利用できます。
  • http://〜 から https://〜 にリダイレクトしている
  • すべてのサブドメインにHTTPS接続できる
  • max-age パラメータの値が18週間 (10886400秒) 以上
  • includeSubDomains パラメータを指定している
  • 非標準の preload パラメータを指定している
HSTS Preload List SubmissionからHSTS Preloadを利用するドメインを登録します。リストはGoogleが管理しています。
content-security-policy
x-frame-options
(後述)

Content Security Policy

サイト製作者の意図しないスクリプトの実行などをブラウザ側でブロックし、XSSなどを防ぎます。

Internet Explorer は対応していません。

以下にcontent-security-policy応答ヘッダの設定例を示します。

/etc/httpd/conf/httpd.conf
                        ##############
                        ## 以上省略 ##
                        ##############

# サーバー全体で共通のポリシー
Header always set content-security-policy "default-src 'none'; disown-opener; frame-ancestors 'none'; style-src 'self'; img-src 'self'; upgrade-insecure-requests; report-uri [レポートの送信先URL]"
<If "%{HTTP_USER_AGENT} -strmatch '*Trident/*'">
    # Internet Explorer で frame-ancestors 'none' を機能させる
    Header always set x-frame-options DENY
</If>

<DirectoryMatch ^/var/www/html/index$>
    # トップページへのSVG画像の埋め込み
    Header always edit content-security-policy $ "; object-src 'self'; frame-src 'self'"
</DirectoryMatch>
<DirectoryMatch ^/var/www/html/chat/index$>
    # チャットのstyle属性、スクリプト、EventSource、XMLHttpRequest、およびベル音
    Header always edit content-security-policy "style-src 'self'" "style-src 'self' 'unsafe-inline'; script-src 'self'; connect-src 'self'; media-src 'self'"
</DirectoryMatch>
<Directory /var/www/html/link>
    # リンク集のバナー
    Header always edit content-security-policy "img-src 'self'" "img-src 'self' example.com example.jp example.co.jp example.ne.jp"
</Directory>
<Directory /var/www/html/phpMyAdmin>
    # phpMyAdmin
    Header always edit content-security-policy "style-src 'self'" "style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; connect-src 'self'"
</Directory>
<DirectoryMatch ^/var/www/html/phpinfo$>
    # phpinfo()関数の結果を表示するページ
    Header always edit content-security-policy "style-src 'self'" "style-src 'self' 'unsafe-inline'"
    Header always edit content-security-policy "img-src 'self'" "img-src 'self' data:"
</DirectoryMatch>

以上のコード例のcontent-security-policy応答ヘッダ値は、以下のような意味になります (disown-opener frame-ancestors upgrade-insecure-requests report-to 省略)。

`default-src 'none'; style-src 'self'; img-src 'self'`
サーバー全体に適用するポリシー。同一生成元のスタイルシートと同一生成元の画像のみ許可している。
`default-src 'none'; style-src 'self'; img-src 'self'; object-src 'self'; frame-src 'self'`
object要素でSVG画像を埋め込む場合。Firefoxはobject、OperaとGoogle Chromeはframeと認識するため、両方のディレクティブで許可している。
`default-src 'none'; style-src 'self' 'unsafe-inline'; script-src 'self'; connect-src 'self'; media-src 'self'; img-src 'self'`
同一生成元のスタイルシート、style要素とstyle属性による指定を許可。同一生成元のスクリプトを許可。XMLHttpRequestやEventSourceからの同一生成元に対するアクセスを許可。audio要素とvideo要素で同一生成元のファイルを許可。同一生成元の画像を許可。
`default-src 'none'; style-src 'self'; img-src 'self' example.com example.jp example.co.jp example.ne.jp`
リンク集に適用するポリシー。同一生成元と直リンクしているバナーの生成元の画像を許可している。
`default-src 'none'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; connect-src 'self'; img-src 'self'`
[phpMyAdmin]に適用するポリシー。phpMyAdminではインラインスクリプトやeval関数が使用されているため、Content Security Policyが有効に活用できない。
`default-src 'none'; style-src 'self' 'unsafe-inline'; img-src 'self' data:`
[PHPのphpinfo関数]の実行結果に適用するポリシー。同一生成元のスタイルシート、style要素とstyle属性による指定を許可。同一生成元と[dataスキーム]の画像を許可。

主なディレクティブ (指令)

ディレクティブ名 構文、作用
default-src 以下のディレクティブが省略されていたときの既定値を指定します。
  • child-src
  • connect-src
  • font-src
  • img-src
  • media-src
  • object-src
  • script-src
  • style-src
これらのディレクティブでは、次のような値を空白区切りで指定します。
  • 'none' (何も許可しない)
  • 'self' (生成元5 が同じものを許可)
  • https://maxcdn.bootstrapcdn.com/bootstrap/ (ホストソース式)
以上のような値はソースリストと呼ばれます。
style-src スタイルシートの許可。'unsafe-inline'を指定すると、あらゆるstyle要素、style属性が許可されますが、完全に避けるのが最善とされています。style要素に関しては、hash-sourceを使えば決まった中身のstyle要素のみ許可できますが、2016年11月現在Microsoft Edgeが未対応です。'unsafe-hashed-attributes'を使えばstyle属性値もhash-sourceにより制御できますが、2016年11月現在まだ仕様が不安定です。
img-src 画像の許可。
media-src 音声、動画、字幕の許可。
script-src スクリプトの許可。'unsafe-inline' 周りの事情は、上記 style-src と大体同じです。'strict-dynamic' を指定すれば、(ライブラリなどによって) 後から挿入されたscript要素はブロックされなくなりますが、2016年11月現在ブラウザのサポートが進んでいません。
connect-src 次のようなAPIにおける接続先の許可。
frame-src iframe要素などで埋め込むページの許可。6
font-src フォントの許可。
object-src SWFファイルなどのプラグイン内容の許可。
plugin-types 許可するプラグインのMIME型を指定します。SWFファイルのMIME型はapplication/vnd.adobe.flash-movieですがAdobe Flash Playerが対応していないので、同ファイルを埋め込む場合はとりあえず plugin-types application/vnd.adobe.flash-movie application/x-shockwave-flash のように指定しておきます。このディレクティブを指定した場合、object要素などのtype属性が必須となります。7
disown-opener 移動先のWindow#openernull にします。フィッシング詐欺の手法である[Tabnabbing]対策になりますが、2016年11月現在まだ仕様が不安定です。a要素の場合は rel=noopener を付加することで、該当のリンクに対しては同様の効果を持たせられますが、2016年11月現在OperaとGoogle Chromeしか対応していません。そこで、rel="noopener noreferrer" と併記する必要があります。8
[frame-ancestors] 現在のページを埋め込める先祖ウィンドウのURLを指定します。[クリックジャッキング]対策などに役立ちます。Internet Explorer は CSP 自体に対応していませんが、x-frame-options応答ヘッダで似たような対策が可能です。たとえば frame-ancestors 'none' に対応する値は DENY です。
[report-uri] CSP違反が発生したときの報告先。[report-uri.ioというサービスが便利]です。
[upgrade-insecure-requests] [混在コンテンツ]になりそうな画像などに対して、自動的にセキュアなURLから取得します。たとえば <link src="http://example.jp/lib.css" rel="stylesheet" /> のような記述があれば、http://example.jp/lib.css ではなく https://example.jp/lib.css にアクセスします。2016年11月現在、Firefox、Opera、Google Chromeが対応しており、Safariの開発版には実装されているようです。

[Tabnabbing]: https://blog.jxck.io/entries/2016-06-12/noopener.html "本サイト以下全ての target=_blank 付きのリンクに rel="noopener noreferrer" の付与を実施した。このプロパティの意味と、これが無い場合のフィッシング詐欺攻撃の可能性について解説する。"
[frame-ancestors]: https://triple-underscore.github.io/CSP3-ja.html#directive-frame-ancestors "frame-ancestors 指令は、[ frame / iframe / object / embed / applet ] 要素を利用して埋め込めるリソースの URL を制約する。 この指令を利用すれば、敵対的になり得る文脈の中にリソースが埋め込まれるリスクを避けることで、多くの UI Redressing 【 UI の着せ替え】 攻撃避けることができる。"
[クリックジャッキング]: https://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AA%E3%83%83%E3%82%AF%E3%82%B8%E3%83%A3%E3%83%83%E3%82%AD%E3%83%B3%E3%82%B0 "クリックジャッキング(クリックジャック攻撃、Clickjacking、User Interface redress attack、UI redress attack、UI redressing)は、ウェブページの利用者に対し悪意をもって使用される技術の一種で、リンクやボタンなどの要素を隠蔽・偽装してクリックを誘い、利用者の意図しない動作をさせようとする手法である。"
[report-uri]: https://triple-underscore.github.io/CSP3-ja.html#directive-report-uri "report-uri 指令は、報告先 — ある特定のふるまいが防止されたとき, 違反報告の送信先になるネットワーク端点 — の集合を定義する。"
[report-uri.ioというサービスが便利]: https://blog.jxck.io/entries/2016-03-30/content-security-policy.html#report-uri.io "このレポートの収集と解析を行うサービスとして、 report-uri.io というサービスが最近登場した。"
[upgrade-insecure-requests]: https://triple-underscore.github.io/webappsec-upgrade-insecure-requests-ja.html#delivery "サーバは、[ upgrade-insecure-requests 指令を包含する Content-Security-Policy ヘッダ ] を送信することにより, [ ある特定の被保護リソースに対する非セキュア要請 ] を昇格するよう, UA に指図してよい。"
[混在コンテンツ]: https://developer.mozilla.org/docs/Security/%E6%B7%B7%E5%9C%A8%E3%82%B3%E3%83%B3%E3%83%86%E3%83%B3%E3%83%84 "もし HTTPS のページの中に通常の平文の HTTP で送られてくるコンテンツが含まれる場合、その接続は部分的に暗号化されたものにすぎなくなります。すなわち、暗号化されていないコンテンツは盗聴可能であり、中間者攻撃の攻撃者によってコンテンツの中身は操作可能となり、もはや接続は保護されません。そのような web ページは「混在コンテンツ」を含むページと呼ばれます。"
[CSP2でconnect-srcに置き換える形で非推奨にされた]: https://triple-underscore.github.io/CSP-ja.html#changes-from-level-1 "child-src は、 frame-src を非推奨にして, それを置き換える — それは、[ 被保護リソースが フレームを埋め込む / worker を読み込む ] 機能を制御する。"
[CSP3でconnect-srcframe-src worker-srcに分割される形で非推奨ではなくなった]: https://triple-underscore.github.io/CSP3-ja.html#changes-from-level-2 "CSP Level 2 で非推奨にされた frame-src 指令は, 非推奨でなくなり、 worker-src が追加された。 両者とも無い場合は child-src に先送りする(それも無い場合は default-src に先送りする)。"

一つのApacheで複数のドメインを扱う (仮想ホスト)

/etc/httpd/conf.modules.d/00-base.conf
                        ##############
                        ## 以上省略 ##
                        ##############

#LoadModule request_module modules/mod_request.so
#LoadModule sed_module modules/mod_sed.so
#LoadModule speling_module modules/mod_speling.so
LoadModule macro_module modules/mod_macro.so
# ↑ファイルの末尾にこの行を追記

/etc/httpd/conf/httpd.conf#LoadModule macro_module lib64/httpd/modules/mod_macro.soのような行があれば、/etc/httpd/conf.modules.d/00-base.confに追記する代わりにそちらのコメントアウトを外してください。

[LoadModule ディレクティブ]
`LoadModule macro_module modules/mod_macro.so`
指定した動的共有モジュールをApache起動時に読み込みます。
/etc/httpd/conf.d/ssl.conf
                        ##############
                        ## 以上省略 ##
                        ##############

##
## SSL Virtual Host Context
##

#<VirtualHost _default_:443>
## ↑この行をコメントアウト ##

# General setup for the virtual host, inherited from global configuration
#DocumentRoot "/var/www/html"
#ServerName www.example.com:443

                        ##############
                        ##   中略   ##
                        ##############

#   Per-Server Logging:
#   The home of a custom SSL log file. Use this when you want a
#   compact non-error SSL logfile on a virtual host basis.
CustomLog logs/ssl_request_log \
          "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"

# TLSの基本設定を読み込み
#Include /etc/letsencrypt/options-ssl-apache.conf
## ↑この行をコメントアウト ##

#ServerName example.jp
#ServerAlias sub1.example.jp sub2.example.jp
## ↑この2行をコメントアウト ##
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
SSLUseStapling on
SSLCertificateChainFile /etc/letsencrypt/live/example.jp/chain.pem
#</VirtualHost>                       
## ↑この行をコメントアウト ##           

<IfModule mod_ssl.c>
SSLStaplingCache shmcb:/var/run/apache2/stapling_cache(128000)
</IfModule>
/etc/httpd/conf.d/vhosts.conf
# すべての仮想ホストから読み込まれるファイル
AliasMatch ^/((?:common|polyfill)/.+) /var/www/common/$1
<DirectoryMatch ^/var/www/common/(?:common|polyfill)/.+$>
    Require all granted
</DirectoryMatch>

# すべての仮想ホストで共通の設定
<Macro CommonHost $subdomain $directory>
    ServerName $subdomainexample.jp
    Include /etc/letsencrypt/options-ssl-apache.conf
    DocumentRoot /var/www/$directory
    <Directory /var/www/$directory>
        Require all granted
    </Directory>
</Macro>

<VirtualHost *:80>
    # 80番ポートへのアクセス
    ServerName default-virtual-host.invalid

    # 正規のサブドメインに一致するなら、https://%{HTTP_HOST}/ にリダイレクト
    RewriteEngine on
    RewriteCond %{HTTP_HOST} ^(?:sub1|sub2).example.jp$
    RewriteRule .* https://%{HTTP_HOST}$0 [redirect=permanent,last]

    # それ以外の場合は、https://example.jp/ にリダイレクト
    RewriteRule .* https://example.jp$0 [redirect=permanent,last]
</VirtualHost>

<VirtualHost *:443>
    Use CommonHost " " html
    # アップロードされたデータ
    Alias /oekaki/data /var/www/share/html/uploader/data
    <Directory /var/www/share/html/uploader/data>
        Require all granted
    </Directory>
</VirtualHost>

<VirtualHost *:443>
    Use CommonHost sub1. sub1
    AliasMatch ^/((?:index|style)(?:\.[^/]+)?)$ /var/www/share/sub1/core/$1
    <Directory /var/www/share/sub1/core>
        Require all granted
    </Directory>
</VirtualHost>

<VirtualHost *:443>
    Use CommonHost sub2. sub2
</VirtualHost>

/etc/httpd/conf/httpd.confIncludeOptional conf.d/*.confのような行が無ければ、追記しておきます。

/etc/httpd/conf/httpd.conf
                        ##############
                        ## 以上省略 ##
                        ##############

<IfModule log_config_module>
    #
    # The following directives define some format nicknames for use with
    # a CustomLog directive (see below).
    #
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
    LogFormat "%h %l %u %t \"%r\" %>s %b" common

    <IfModule logio_module>
      # You need to enable mod_logio.c to use %I and %O
      LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
    </IfModule>

    #
    # The location and format of the access logfile (Common Logfile Format).
    # If you do not define any access logfiles within a <VirtualHost>
    # container, they will be logged here.  Contrariwise, if you *do*
    # define per-<VirtualHost> access logfiles, transactions will be
    # logged therein and *not* in this file.
    #
    #CustomLog "logs/access_log" common

    #
    # If you prefer a logfile with access, agent, and referer information
    # (Combined Logfile Format) you can use the following directive.
    #
    #CustomLog "logs/access_log" combined
    ## ↑コメントアウトする ##
    CustomLog "logs/access_log" "%v %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
    ## ↑この行を追加 ##
</IfModule>

                        ##############
                        ## 以下省略 ##
                        ##############

[Alias ディレクティブ]
第1引数で指定したURLを、第2引数で指定したファイルシステムのパス絶対URLと結び付けます。URLは[Redirect ディレクティブ]と同じく前方一致で、`Alias /foo /var/www/foo/bar`と記述すると、https://example.com/foo/test が`/var/www/foo/bar/test`と結び付けられます。
[AliasMatch ディレクティブ]
第1引数に正規表現を指定すること以外は、[Alias ディレクティブ]と同じです。正規表現内の後方参照は、第3引数で`$1`などと数字に`$`を前置して利用できます。`AliasMatch ^/((?:common|polyfill)/.*) /var/www/common/$1`は`Alias /common/ /var/www/common/common/` `Alias /polyfill/ /var/www/common/polyfill/`と同じ意味になります。
[<DirectoryMatch> セクション]
``〜``
ディレクティブを適用する **ファイルを** 正規表現で指定します。[<Directory> セクション]と同じくファイルシステムのパス絶対URLで指定します。[<Directory> セクション]よりは[<FilesMatch> セクション]に近く、[AllowOverride ディレクティブ]が使えず、[RewriteBase ディレクティブ]もエラーは出ませんが正しく機能しません。どのOSであっても、パス区分を区切る文字は必ず`/`であるものとして正規表現を記述します。
[DocumentRoot ディレクティブ]
ファイルシステムのパス絶対URL、またはサーバールートからの相対パスでドキュメントルートを設定します。例えば、`ServerName example.jp`と`DocumentRoot /var/www/html`が指定されていた場合、https://example.jp/foo/bar.html にアクセスされたときに`/var/www/html/foo/bar.html`を返します。
[<VirtualHost> セクション]
``〜``
サーバーのIPアドレスとポート番号の組み合わせごとにディレクティブを適用します。IPアドレスとポート番号の間には`:`を挟み、その組は第2引数以降で複数指定することもできます。ポート番号を省略した場合、どのポート番号にも一致するようになります。ポート番号を省略したセクションより、ポート番号が省略されていないセクションの方が優先されます。
値の同じ[<VirtualHost> セクション]を複数作成し、それぞれに[ServerName ディレクティブ]でドメインを設定すれば、ドキュメントルートなどをドメインごとに設定できます ([名前ベースのバーチャルホスト])。
サーバーにアクセスしたときのドメインが、どの[ServerName ディレクティブ]の設定とも一致しない場合は、IPアドレスとポート番号の条件が一致する[<VirtualHost> セクション]の中で最初に記述したもの (デフォルトの仮想ホスト) が適用されます。デフォルトの仮想ホストの選択も、ポート番号が省略されていないセクションの方が優先されます。
[CustomLog ディレクティブ]
`"CustomLog logs/access_log" "%v %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""`
第1引数に保存先、第2引数に書式を指定します。
最初に記述されていた `CustomLog "logs/access_log" combined` は、直前の `LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined` から `CustomLog "logs/access_log" "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""` と展開できます。つまり記述例で書き直した書式は、最初に記述されていた書式の先頭に `%v` を追加したものです。`%v` は、サーバーのホスト名に置き換えられます。
[<Macro> セクション] \(リンク先英語)
``〜``
設定ファイルマクロを定義します。設定ファイルマクロは、複数の箇所で同じ設定が必要な場合に使います。プログラミングにおける関数宣言のように、第1引数にマクロ名、第2引数以降に仮引数を記述します。引数の数の違いによる多重定義はできません。
[Use ディレクティブ] \(リンク先英語)
定義しておいた設定ファイルマクロを使用します。プログラミングにおける関数呼び出しのように、第1引数にマクロ名、第2引数以降に実引数を記述します。`Use ExampleMacro ""`のように、実引数に空文字列を指定すると、警告が発生します。

例えば上記コードの最後の<VirtualHost> セクションは、設定ファイルマクロによって以下のように置換されます。

置換前
<VirtualHost *:80>
    Use CommonHost sub2. sub2
</VirtualHost>
置換後
<VirtualHost *:80>
    ServerName sub2.example.jp
    DocumentRoot /var/www/sub2
    <Directory /var/www/sub2>
        Require all granted
    </Directory>
</VirtualHost>

URLの末尾に拡張子を表示しない

ここではRewriteMap ディレクティブを利用していますが、mod_negotiationモジュールRewriteCond ディレクティブを利用して実現できる場合もあります。

/etc/httpd/conf.d/vhosts.conf
# Virtual Hosts
#
# If you want to maintain multiple domains/hostnames on your
# machine you can setup VirtualHost containers for them. Most configurations
# use only name-based virtual hosts so the server doesn't need to worry about
# IP addresses. This is indicated by the asterisks in the directives below.
#
# Please see the documentation at 
# <URL:https://httpd.apache.org/docs/2.4/vhosts/>
# for further details before you try to setup virtual hosts.
#
# You may use the command line option '-S' to verify your virtual host
# configuration.

## ↓ここから追記 ##
RewriteEngine on

# rewriteモジュールに関するログをすべて記録する
#LogLevel alert rewrite:trace8

# 標準入力の「フルパス,プレフィックスを取り除いたパス」から拡張子付きのファイルを探し、最初に見つかったファイルのパスからプレフィックスを取り除いて返す
RewriteMap adjust-extension "prg:/usr/bin/perl -e '$| = 1; while (<STDIN>) { chomp($_); my @params = split(/,/, $_); my $path; if ($#params == 1) { ($path) = glob(@params[0] . \\'.*\\'); if ($path) { $path = substr($path, length(@params[0]) - length(@params[1])); } } print(($path || \\'NULL\\') . \"\\\\x0A\"); }'"

<Directory /var/www>
    # 拡張子無しのURLでアクセスできるようにする
    RewriteOptions Inherit
    RewriteRule ^([^.]+)(?<!/)$ ${adjust-extension:%{REQUEST_FILENAME},$1|$1}
</Directory>

<If "unescape(%{THE_REQUEST}) =~ /\\..*\\s/">
    # 要求行の最後の空白より前にピリオドが含まれていれば
    # Favicon、robots.txt、phpMyAdminディレクトリを除く拡張子付きのURLを拡張子無しのURLにリダイレクト
    RedirectMatch permanent ^(/(?!(?:favicon\.ico|robots\.txt)$|phpMyAdmin/)[^.]+)\. $1
</If>
## ↑ここまで追記 ##

# すべての仮想ホストから読み込まれるファイル
AliasMatch ^/((?:common|polyfill)/.+) /var/www/common/$1
<Directory /var/www/common>
    RewriteBase /
</Directory>
## ↑この<Directory>セクションを追加 ##
<DirectoryMatch ^/var/www/common/(?:common|polyfill)/.+$>
    Require all granted
</DirectoryMatch>

# すべての仮想ホストで共通の設定
<Macro CommonHost $subdomain $directory>
    ServerName $subdomainexample.jp
    Include /etc/letsencrypt/options-ssl-apache.conf
    DocumentRoot /var/www/$directory
    RewriteOptions Inherit
    ## ↑この行を追加 ##
    <Directory /var/www/$directory>
        Require all granted
    </Directory>
</Macro>

<VirtualHost *:80>
    # 80番ポートへのアクセス
    ServerName default-virtual-host.invalid

    # 正規のサブドメインに一致するなら、https://%{HTTP_HOST}/ にリダイレクト
    RewriteEngine on
    RewriteCond %{HTTP_HOST} ^(?:sub1|sub2).example.jp$
    RewriteRule .* https://%{HTTP_HOST}$0 [redirect=permanent,last]

    # それ以外の場合は、https://example.jp/ にリダイレクト
    RewriteRule .* https://example.jp$0 [redirect=permanent,last]
</VirtualHost>

<VirtualHost *:443>
    Use " " html
    # アップロードされたデータ
    Alias /oekaki/data /var/www/share/html/uploader/data
    <Directory /var/www/share/html/uploader/data>
        RewriteBase /uploader/data/
        ## ↑この行を追加 ##
        Require all granted
    </Directory>
</VirtualHost>

<VirtualHost *:443>
    Use sub1. sub1
    AliasMatch ^/((?:index|style)(?:\.[^/]+)?)$ /var/www/share/sub1/core/$1
    <Directory /var/www/share/sub1/core>
        RewriteBase /
        ## ↑この行を追加 ##
        Require all granted
    </Directory>
</VirtualHost>

<VirtualHost *:443>
    Use sub2. sub2
</VirtualHost>

/etc/httpd/conf/httpd.conf#LoadModule rewrite_module lib64/httpd/modules/mod_rewrite.soのような行があれば、コメントアウトを外しておきます。

[RewriteEngine ディレクティブ] \(リンク先英語)
`RewriteEngine on`
rewriteエンジンの有効と無効を切り替えます。初期設定では無効になっています。無効の場合、[RewriteRule ディレクティブ]などが無視されるだけで、エラーは発生しません。
[RewriteRule ディレクティブ] \(リンク先英語)
RewriteRule ^([^.]+)(?<!/)$ ${adjust-extension:%{REQUEST_FILENAME},$1|$1}
第1引数の正規表現に一致したパスを第2引数で指定した文字列に置き換えます。一度でも置き換えが行われていると、全てのRewriteRuleが処理された後、内部リダイレクトによってリクエスト処理がやり直されます。`%{REQUEST_URL}`等もURL書き換え後のものになっているので、無限ループが起こらないように注意する必要があります。
rewriteはファイルシステムのパスではなくURLを書き換える処理なので、[Alias ディレクティブ]のようにドキュメントルート外に書き換えることはできません。
引数にワイルドカードを含む[<Directory> セクション]では期待通りに動かないことがあります (per-dirにワイルドカードが含まれたままrewrite処理が行われるため)。

上記コードのような設定をして https://example.jp/file にアクセスしたときのrewrite処理を、例として示します。この場合、ReqriteRuleを記述したディレクトリのパス絶対URLper-dir)は/var/www/です。

処理前 処理後 処理内容
1 /var/www/html/file html/file ファイルシステムのパス絶対URLからper-dirを取り除く
2 html/file html/file.xhtml ^([^.]+)(?<!/)$に一致するので、${adjust-extension:%{REQUEST_FILENAME},$1|$1}に書き換える
3 html/file.xhtml /var/www/html/file.xhtml per-dirを前置する
4 /var/www/html/file.xhtml /file.xhtml ドキュメントルートを取り除き、内部リダイレクト
5 /var/www/html/file.xhtml html/file.xhtml ファイルシステムのパス絶対URLからper-dirを取り除く
6 html/file.xhtml html/file.xhtml ^([^.]+)(?<!/)$に一致しないので、何もしない
7 html/file.xhtml /var/www/html/file.xhtml 書き換えが行われなかったので、ファイルシステムのパス絶対URLを返してrewrite処理終了

[RewriteBase ディレクティブ] \(リンク先英語)
`RewriteBase /`
[Alias ディレクティブ]によってURLがドキュメントルート外のパスと結び付けられていると、そのままでは内部リダイレクト前のドキュメントルートを取り除く処理が行えません。そこで、ドキュメントルートの絶対パスを取り除く代わりに、per-dirを第1引数で指定した基底URLに置き換えます。[^qa@it-alias-rewrite]

上記コードのような設定をして https://example.jp/polyfill/main にアクセスしたときのrewrite処理を、例として示します。この場合、per-dir/var/www/common基底URL/です。

処理前 処理後 処理内容
1 /polyfill/main /var/www/common/polyfill/main AliasMatch ディレクティブによって、絶対URLファイルシステムの絶対パス相対URLが結び付けられている
2 /var/www/common/polyfill/main polyfill/main ファイルシステムのパス絶対URLからper-dirを取り除く
3 polyfill/main polyfill/main.js ^([^.]+)(?<!/)$に一致するので、${adjust-extension:%{REQUEST_FILENAME},$1|$1}に書き換える
4 polyfill/main.js /var/www/common/polyfill/main.js per-dirを前置する
5 /var/www/common/polyfill/main.js /polyfill/main.js per-dir基底URLに置き換え、内部リダイレクト
6 /polyfill/main.js /var/www/common/polyfill/main.js AliasMatch ディレクティブによって、絶対URLファイルシステムのパス絶対URLが結び付けられている
7 /var/www/common/polyfill/main.js polyfill/main.js ファイルシステムのパス絶対URLからper-dirを取り除く
8 polyfill/main.js polyfill/main.js ^([^.]+)(?<!/)$に一致しないので、何もしない
9 polyfill/main.js /var/www/common/polyfill/main.js 書き換えが行われなかったので、ファイルシステムのパス絶対URLを返してrewrite処理終了

[RewriteCond ディレクティブ] \(リンク先英語)
[RewriteRule ディレクティブ]を適用する条件を設定します。RewriteRule1つに付き、複数のRewriteCondを設定できます。RewriteCondは対象のRewriteRuleよりも前に記述しますが、RewriteCondよりも先にRewriteRuleの条件がチェックされます。
[RewriteMap ディレクティブ] \(リンク先英語)
`RewriteMap adjust-extension "prg:/usr/bin/perl -e '$| = 1; while () { chomp($_); my @params = split(/,/, $_); my $path; if ($#params == 1) { ($path) = glob(@params[0] . \\\\'.*\\\\'); if ($path) { $path = substr($path, length(@params[0]) - length(@params[1])); } } print(($path || \\\\'NULL\\\\') . \\"\\\\\\\\x0A\\"); }'"`
第1引数にマップ名 (関数名)、第2引数にマップタイプマップソースを`:`区切りで指定し、[RewriteCond ディレクティブ]と[RewriteRule ディレクティブ]で利用できるマッピング関数を定義します。[RewriteMap ディレクティブ]は、サーバ設定ファイルコンテキスト (設定ファイルの中で[<Directory> セクション]や[<VirtualHost> セクション]の外) か仮想ホストコンテキスト ([<VirtualHost> セクション]の中で[<Directory> セクション]などの外) にしか記述できません。[RewriteMap ディレクティブ]を記述した場所でrewriteエンジンが無効になっている場合、関数は定義されません。`${マップ名:引数|デフォルト値}`のように関数を呼び出します。`${関数名:引数}`のようにデフォルト値を書かなかった場合、引数に対応する戻り値が見つからなかった場合 (`map lookup FAILED`) は空文字列が返ります。
マップタイプが`prg`の場合、マップソースは標準入力から引数を受け取り標準出力へ戻り値を書きだすプログラムファイルへのパスです。[User ディレクティブ]で設定したユーザーが、このプログラムファイルの実行権限を持っている必要があります。このプログラムはApache起動時に一度だけ起動されるため、標準入力を受け取るまで処理をブロックし、戻り値を書きだした後はまた標準入力を受け取るまで処理をブロックする無限ループ構造にしておきます。入出力バッファの無効化も必要です。戻り値の末尾に改行 (LF) を1つだけ置きます。文字列`NULL` (+改行) を返せば、`map lookup FAILED`を示すことができます。
プログラムが期待通りの動作をしない場合、SELinuxによってブロックされている場合もあるので、[SELinuxのログの確認]もしてみてください。また、プログラムの標準エラー出力は無視され、Apacheのログには残りません。
第2引数全体を`"`で囲み、プログラムへのパスの後に空白区切りでコマンドライン引数を書いた場合、各コマンドライン引数は文字列としてプログラムに渡されます。シングルクォートで囲むことで、コマンドライン引数に空白を含めることができます。コマンドライン引数の中で`'` `"` `\\`を使う場合は、それぞれ`\\\\'` `\\"` `\\\\\\\\` とエスケープします。
[RewriteOptions ディレクティブ] \(リンク先英語)
`RewriteOptions Inherit`
rewriteエンジンの追加設定を有効にします。この設定有効化は、サブディレクトリで[RewriteRule ディレクティブ]などを記述した場合にも引き継がれます。`Inherit`は、現在のディレクトリのルールの後に、親ディレクトリのルールをコピーするというオプションです。`Inherit`オプションを仮想ホストコンテキストで有効にした場合は意味が変わり、メインサーバ設定 ([<VirtualHost> セクション]の外) に記述したルールを継承するオプションとなります。[^qa@it-rewriterule]
[LogLevel ディレクティブ]
`LogLevel alert rewrite:trace8`
エラーログに記録するログの種類を指定します。モジュールレベルを`:`区切りで指定します。第1引数以降で複数記述することができます。第1引数のモジュールは省略することができ、その場合すべてのモジュールについて同じレベルを指定したことになります。既定は `LogLevel warn` です。

開発環境向けの設定

/etc/httpd/conf/httpd.conf
                        ##############
                        ## 以上省略 ##
                        ##############

#
# EnableMMAP and EnableSendfile: On systems that support it, 
# memory-mapping or the sendfile syscall may be used to deliver
# files.  This usually improves server performance, but must
# be turned off when serving from networked-mounted 
# filesystems or if support for these functions is otherwise
# broken on your system.
# Defaults if commented: EnableMMAP On, EnableSendfile Off
#
#EnableMMAP off
#EnableSendfile on
## ↑仮想マシンで共有ディレクトリを使用している場合、この行をコメントアウトする ##

                        ##############
                        ##   中略   ##
                        ##############

# 開発環境

# 403と404を区別する
ErrorDocument 403 /forbidden

# 開発環境用のスタイルシート
Header always set link "</common/development>; rel=stylesheet"

# Faviconを変える
Alias /favicon.ico /var/www/html/favicon-development.ico

# 開発環境へのCSRFを防止する
<If "-n %{HTTP_REFERER} && !(%{HTTP_REFERER} -strmatch %{REQUEST_SCHEME} . '://' . %{SERVER_NAME} . '/*')">
    # リファラが存在し、かつリファラのホスト名がサーバーのホスト名と一致しなければ
    Require all denied
</If>

ブラウザでリファラを変更している場合は、ターゲットのホワイトリストに開発環境のドメインを追加しておきます。

[EnableSendfile ディレクティブ]
「sendfile」というシステムコールを使って静的ファイルを返す時の性能を向上しようとする機能の有効と無効を切り替えます。
Apache 2.4の既定は`EnableSendfile Off`ですが、CentOS7標準のパッケージでは設定ファイルに`EnableSendfile On`が記述されており有効化されています。 **[VirtualBox]などで[仮想マシン]を作成して共有ディレクトリ機能を利用している場合、ファイルの更新が反映されないことがあります。** そのようなときは、`EnableSendfile On`をコメントアウトしてこの機能を無効化します。[^sf]
/var/www/common/common/development.css
/*====================================
	表示領域の右端に縦書きで文字を表示する
*/
body::after {
	font-size: 10vmin;
	width: 1em;
	line-height: 2.3;
	content: "開発環境";
	display: block;
	color: #FFFFFF;
	font-weight: bold;
	background: rgba(127, 127, 127, 0.7);
	border: solid #FFFFFF 0.2em;
	position: fixed;
	top: 0;
	bottom: 0;
	right: 0;
	opacity: 0.5;
}

link応答ヘッダによるCSSの設定は、前述のようにFirefoxでしか使えません。開発環境を表すCSSの設定はユーザースタイルシートを使っても良いと思います。

参考ページ・脚注

  1. シンタックスハイライト | 設定 | nano — ArchWiki

  2. 37.nanoエディタの設定ファイル、nanorcをいじる — Linuxゲリラ戦記

  3. let’s Encryptの証明書更新 CentOS7編 — Qiita

  4. Internet Explorer 9 は Windows Vista でしか利用できないが、Windows Vista のセキュリティアップデートは2017年4月11日で終了する。

  5. httpsなどの「スキーム」、example.comなどの「ホスト」、「ポート番号」の組み合わせ。

  6. frame-src は、[CSP2でconnect-srcに置き換える形で非推奨にされた]が、[CSP3でconnect-srcframe-src worker-srcに分割される形で非推奨ではなくなった]。

  7. plugin-types が指定されていない場合でも、Opera、Google Chromeはtype属性がないobject要素に child-src を適用しようとするため、どちらにしても必須である。

  8. [リンクのへの rel=noopener 付与による Tabnabbing 対策 | blog.jxck.io][Tabnabbing]

287
308
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
287
308

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?