Ubuntu 24.04 Apache2 設定手順

はじめに(背景知識)

本手順を実施する前提として、以下の基礎知識を整理する。既知の内容は読み飛ばしてよい。

Apache HTTP Server とは

Apache HTTP Server(以下 Apache)は、オープンソースの Web サーバーソフトウェアである。リクエスト処理機能をモジュール(共有ライブラリ)として組み込む構造を持ち、必要な機能のみを有効化して使用する。Ubuntu でのパッケージ名は apache2 であり、サービス名およびコマンド名もこれに準じる。Apache のプロセスは既定で www-data という権限の限定された専用ユーザーで動作する。

HTTP と HTTPS

HTTP は Web の通信プロトコルであり、平文で通信する。途中経路で内容が傍受・改ざんされる可能性があるため、現在は HTTP を TLS(Transport Layer Security)で暗号化した HTTPS の使用が標準である。TLS は通信の暗号化に加え、サーバー証明書による接続先サーバーの真正性検証も担う。本手順では HTTPS を有効化したうえで、HTTP アクセスは HTTPS へリダイレクトする構成とする。

Let's Encrypt と ACME / certbot

Let's Encrypt は、無料で SSL/TLS 証明書を発行する認証局である。証明書発行は ACME(Automatic Certificate Management Environment)という標準プロトコルで自動化されており、certbot は ACME クライアントの代表的な実装である。本手順では certbot をコマンドラインから使用する。

ACME のドメイン所有権認証には主に二方式がある。

方式仕組み長所短所
HTTP-01(webroot 方式)Let's Encrypt が HTTP(80番ポート)経由で /.well-known/acme-challenge/ 配下のトークンファイルを取得し検証するWeb サーバー稼働中のまま取得できる。設定が簡素80 番ポートを外部公開する必要がある。ワイルドカード証明書には対応しない
DNS-01指定された TXT レコードを DNS に登録し検証するポート公開が不要。ワイルドカード証明書(*.example.jp)を取得できるDNS 操作が必要。自動化には DNS プロバイダーの API が必要

本手順では既に 80 番ポートを Web 公開する構成のため、HTTP-01(webroot 方式)を標準として採用する。

証明書ファイルの構成

certbot による取得後、/etc/letsencrypt/live/<ドメイン名>/ に複数のファイルが配置される。本手順で参照する主要なファイルを以下に示す。

本手順におけるドキュメントルートの選択

Ubuntu 標準のドキュメントルートは /var/www/html であるが、本手順では学習目的でパスを短縮した /www を採用する。本番運用では、サイトごとに /var/www/<サイト名>/ のように分離する構成が一般的である。読者の環境ポリシーに合わせて読み替えてよい。

systemctl reload と restart の違い

本手順では設定変更後に reload または restart を使い分ける。

本手順では原則 reload を使用し、restart が必要な箇所では明示する。

1分で読めるサマリー

この手順で達成できること:Ubuntu 24.04 上に、HTTPS 対応の Web サーバーを構築する。SSL 証明書は無料で取得でき、自動更新されるため運用負荷を抑えられる。

前提条件

主要な手順

  1. Apache2 をインストールし、基本設定を実施(手順 1〜5)
  2. Let's Encrypt で SSL 証明書を取得(手順 6〜7)
  3. HTTPS を有効化し、HTTP からのリダイレクトを設定(手順 8〜10)
  4. 証明書の自動更新を確認(手順 11)
  5. 動作確認(手順 12)
  6. オプション:高速化設定(Deflate 圧縮、KeepAlive、ブラウザキャッシュ)(手順 13〜15)
  7. オプション:不正アクセス自動遮断(fail2ban)(手順 16〜18)
  8. 総合的な動作確認(手順 19)
  9. オプション:ページインクルード(SSI)の有効化(手順 21)

注意事項

費用:すべて無料(Let's Encrypt の SSL 証明書は無料で取得でき、更新も無料)

本手順の設定値(例)

目次

セキュリティに関する注意事項

本手順には基本的なセキュリティ設定を含むが、以下の点に留意する必要がある。

事前に決定しておく事項

本手順を実施する前に、以下の項目を決定しておく。

項目本手順での設定値説明
ドメイン名www.example.jpWeb サイトの URL に使用するドメイン
ドキュメントルート/wwwWeb コンテンツを配置するディレクトリ
アクセスログのパス/var/log/apache2/www.example.jp-access.logアクセス記録の保存先
エラーログのパス/var/log/apache2/www.example.jp-error.logエラー記録の保存先
ログ形式commonIP アドレス、日時、リクエスト内容、ステータスコード、転送バイト数を記録

注意:上記の値は自身の環境に合わせて読み替える。本手順中の www.example.jp は、すべて自身のドメイン名に置き換える。

前提条件

本手順を実施する前に、以下の条件を満たしていることを確認する。

補足:ファイアウォール設定は本手順の範囲外である。使用しているファイアウォールソフトウェア(ufw、iptables 等)のマニュアルを参照し、事前に設定を完了させる。

用語説明

用語説明
ドキュメントルートWeb サーバーが公開するファイルを配置するディレクトリ
仮想ホスト1 台のサーバーで複数のドメインを運用するための設定単位
SSL/TLS通信を暗号化するプロトコル。HTTPS はこれを使用する
Let's Encrypt無料で SSL 証明書を発行する認証局。証明書の有効期間は 90 日間
webroot 方式既存の Web サーバーを利用して Let's Encrypt の認証を実施する方式。Web サーバーを停止せずに証明書を取得できる
common 形式Apache のログ形式の一つ。IP アドレス、日時、リクエスト内容、ステータスコード、転送バイト数を記録する
HSTSHTTP Strict Transport Security の略。ブラウザに HTTPS 接続を強制する仕組み
暗号スイートSSL/TLS 通信で使用する暗号化アルゴリズムの組み合わせ。安全性と互換性を考慮して選択する

設定手順の流れ

本手順は以下の順序で進める。

段階作業内容HTTP(80番)HTTPS(443番)
手順 1〜5Apache 導入と HTTP 設定通常公開未設定
手順 6HTTP 動作確認通常公開未設定
手順 7証明書取得認証に使用未設定
手順 8〜10HTTPS 設定とリダイレクトリダイレクト公開
手順 11〜12自動更新確認と動作確認リダイレクト公開
手順 13〜15高速化設定(オプション)リダイレクト公開
手順 16〜18不正アクセス対策(オプション)リダイレクト公開
手順 19総合的な動作確認リダイレクト公開
手順 21ページインクルード(オプション)リダイレクト公開

この順序で作業する理由:Let's Encrypt は HTTP(80番ポート)経由で認証を実施する。証明書取得前は HTTP で通常公開し、証明書取得後に HTTPS を有効化してリダイレクトを設定する必要がある。

1. Apache2 のインストール

目的:Web サーバーソフトウェアをシステムに導入する。

sudo apt update
sudo apt install -y apache2

確認

sudo systemctl status apache2

「active (running)」と表示されれば成功である。インストール後、Apache は自動的に起動し、OS 起動時にも自動起動する。

2. Apache セキュリティ基本設定

目的:バージョン情報を非表示にし、攻撃者による脆弱性特定を困難にする。

設定ファイルを開く。

sudo nano /etc/apache2/conf-available/security.conf

以下の項目を変更する。

# 変更前:ServerTokens OS
# 変更後:
ServerTokens Prod

# 変更前:ServerSignature On
# 変更後:
ServerSignature Off

設定を有効化する。

sudo a2enconf security
sudo systemctl reload apache2

設定項目の説明

3. ドキュメントルートの作成

目的:Web コンテンツを配置する専用ディレクトリを作成し、適切な権限を設定する。

sudo mkdir -p /www
sudo chown -R www-data:www-data /www
sudo chmod -R 755 /www

権限設定の理由:Apache は www-data という権限の限定されたユーザーとして動作する。パーミッション 755 は、所有者が読み書き実行可能、その他は読み取りと実行のみ可能な設定である。

確認

ls -ld /www

drwxr-xr-x」と表示され、所有者が www-data であれば成功である。

4. HTTP 用仮想ホスト設定の作成

目的:HTTP(80番ポート)でアクセス可能な Web サイトの基本設定を作成する。この設定は証明書取得に必要である。

注記:この段階ではリダイレクト設定を含めない。Let's Encrypt の証明書取得には HTTP(80番ポート)でのアクセスが必要である。リダイレクト設定は手順 9 で実施する。

sudo nano /etc/apache2/sites-available/www.example.jp.conf

以下を記述する。

<VirtualHost *:80>
    ServerName www.example.jp
    DocumentRoot /www

    <Directory /www>
        Options -Indexes +FollowSymLinks
        AllowOverride None
        Require all granted
    </Directory>

    # .well-known ディレクトリへのアクセスを原則禁止
    <Directory "/www/.well-known">
        Require all denied
    </Directory>

    # ACME 認証用ディレクトリのみ許可
    <Directory "/www/.well-known/acme-challenge">
        Require all granted
    </Directory>

    # ログ設定
    ErrorLog ${APACHE_LOG_DIR}/www.example.jp-error.log
    CustomLog ${APACHE_LOG_DIR}/www.example.jp-access.log common
</VirtualHost>

設定項目の説明

5. HTTP サイトの有効化

目的:作成した設定を有効化し、デフォルト設定を無効化する。

sudo a2dissite 000-default.conf
sudo a2ensite www.example.jp.conf
sudo systemctl reload apache2

デフォルトサイトを無効化する理由:デフォルト設定は、ドメイン名を指定しないアクセスに応答するため、意図しない情報漏洩のリスクがある。

確認

apache2ctl -S

www.example.jp.conf」が表示され、「000-default.conf」が表示されなければ成功である。

6. HTTP アクセスの確認

目的:証明書取得の前に、HTTP でアクセスできることを確認する。これにより、DNS 設定とファイアウォール設定の正常性を検証できる。

# テスト用ファイルの作成
echo "test" | sudo tee /www/index.html

# アクセス確認
curl -I http://www.example.jp

成功の判定HTTP/1.1 200 OK が表示されれば成功である。

失敗した場合の確認事項

7. Let's Encrypt 証明書の取得

目的:HTTPS 通信に必要な SSL 証明書を取得する。

認証方式の選択:本手順では HTTP-01(webroot 方式)を標準とする。80 番ポートが外部公開されており、ワイルドカード証明書を必要としない場合に適する。80 番ポートを公開できない場合、またはワイルドカード証明書が必要な場合は DNS-01 方式を選択する。本手順の以降の記述は webroot 方式を前提とする。

DNS 認証を行う場合は、次のコマンドを実行する。

sudo certbot certonly --manual --preferred-challenges dns -d www.example.jp

webroot 方式で取得する場合は、次のコマンドを実行する。

sudo apt install -y certbot
sudo mkdir -p /www/.well-known/acme-challenge
sudo chown www-data:www-data /www/.well-known/acme-challenge
sudo certbot certonly --webroot -w /www -d www.example.jp

webroot 方式の仕組み:certbot は /www/.well-known/acme-challenge/ に認証用ファイルを配置する。Let's Encrypt のサーバーは HTTP 経由でこのファイルにアクセスし、ドメインの所有権を確認する。Web サーバーを停止する必要はない。

成功の判定:以下のディレクトリに証明書ファイルが作成される。

/etc/letsencrypt/live/www.example.jp/

確認

sudo ls -l /etc/letsencrypt/live/www.example.jp/

fullchain.pemprivkey.pem が存在すれば成功である。

主要ファイルの役割

失敗した場合の確認事項

8. HTTPS 用仮想ホスト設定の作成

目的:HTTPS(443番ポート)での暗号化通信を有効化し、セキュリティヘッダーとログ記録を設定する。

注記:セキュリティヘッダーの設定には headers モジュールが必要である。このモジュールは手順 10 で有効化する。

sudo nano /etc/apache2/sites-available/www.example.jp-ssl.conf

以下を記述する。

<VirtualHost *:443>
    ServerName www.example.jp
    DocumentRoot /www

    # SSL 設定
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/www.example.jp/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/www.example.jp/privkey.pem

    # SSL プロトコル設定(古い脆弱なプロトコルを無効化。TLSv1.2 と TLSv1.3 のみ有効)
    SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1

    # 暗号スイート設定
    SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
    SSLHonorCipherOrder off

    # セキュリティヘッダー
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set X-Content-Type-Options "nosniff"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"

    # ドキュメントルート設定
    <Directory /www>
        Options -Indexes +FollowSymLinks
        AllowOverride None
        Require all granted
    </Directory>

    # ログ設定
    ErrorLog ${APACHE_LOG_DIR}/www.example.jp-error.log
    CustomLog ${APACHE_LOG_DIR}/www.example.jp-access.log common
</VirtualHost>

注記:HTTPS 仮想ホストには .well-known/acme-challenge 用のブロックを置かない。HTTP-01 認証は 80 番ポートで完結するためである。

セキュリティ設定の説明

設定項目目的詳細
SSLProtocol安全なプロトコルのみ使用SSLv3、TLSv1、TLSv1.1 を無効化し、TLSv1.2 以上のみ許可する
SSLCipherSuite安全な暗号化方式のみ使用ECDHE と GCM を使用した暗号スイートを選択する
SSLHonorCipherOrder暗号スイート選択の制御off に設定する。TLS 1.3 では順序指定の意義が薄いためクライアント側の優先順位を採用する。TLS 1.2 までを厳密に統制する組織では on を推奨する場合がある
Strict-Transport-SecurityHTTPS 接続を強制ブラウザに HTTPS 接続を強制する(HSTS)。max-age=31536000 は 1 年間有効
X-Frame-Optionsクリックジャッキング攻撃を防止他のサイトから iframe で埋め込まれることを防止する
X-Content-Type-OptionsMIME タイプスニッフィングを防止ブラウザが独自にファイル種別を判定することを防止する
Referrer-Policyリファラー情報の送信を制御同一サイト内ではフルパスを送信、外部サイトへはオリジンのみ送信する

ログ形式 common の出力例

192.168.1.100 - - [20/Jan/2026:12:34:56 +0900] "GET /index.html HTTP/1.1" 200 1234

この形式は、IP アドレス、日時、リクエスト内容、ステータスコード、転送バイト数を記録する。

9. HTTP 設定をリダイレクトに変更

目的:HTTP アクセスを HTTPS へ自動転送し、すべての通信を暗号化する。

HTTPS の準備が整ったため、手順 4 で作成した HTTP 設定ファイルを書き換え、HTTPS へリダイレクトするよう変更する。

sudo nano /etc/apache2/sites-available/www.example.jp.conf

内容を以下に変更する。

<VirtualHost *:80>
    ServerName www.example.jp
    DocumentRoot /www

    # ACME 認証(証明書更新)用パスはリダイレクト対象外とする
    Alias "/.well-known/acme-challenge/" "/www/.well-known/acme-challenge/"
    <Directory "/www/.well-known/acme-challenge">
        Require all granted
    </Directory>

    # 上記以外はすべて HTTPS にリダイレクト
    RewriteEngine On
    RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/
    RewriteRule ^(.*)$ https://www.example.jp$1 [R=301,L]

    # ログ設定
    ErrorLog ${APACHE_LOG_DIR}/www.example.jp-error.log
    CustomLog ${APACHE_LOG_DIR}/www.example.jp-access.log common
</VirtualHost>

R=301 の意味:HTTP ステータスコード 301(恒久的な移動)を返す。ブラウザと検索エンジンは、このサイトが HTTPS に移行したことを認識する。

acme-challenge を除外する理由:Let's Encrypt の証明書自動更新は HTTP(80番)経由で /.well-known/acme-challenge/ 配下のファイルを取得して認証する。全リクエストを HTTPS にリダイレクトすると、証明書未取得や期限切れ等の状況で更新が失敗する可能性がある。除外設定により、認証経路を常に確保する。

必要なモジュール:上記の RewriteEngine を使用するため、rewrite モジュールを有効化する必要がある(手順 10 で他のモジュールとあわせて有効化する)。

10. 必要なモジュールの有効化と設定の反映

目的:SSL 通信、セキュリティヘッダー、リダイレクトに必要なモジュールを有効化し、HTTPS 設定を反映する。

sudo a2enmod ssl
sudo a2enmod headers
sudo a2enmod rewrite
sudo a2ensite www.example.jp-ssl.conf
sudo systemctl restart apache2

モジュール追加にはプロセスの再起動が必要なため、reload ではなく restart を使用する。

各モジュールの役割

確認

apache2ctl -M | grep -E 'ssl|headers|rewrite'

ssl_module」「headers_module」「rewrite_module」が表示されれば成功である。

11. 証明書自動更新の確認

目的:証明書の自動更新が正常に動作することを検証する。

sudo certbot renew --dry-run

--dry-run オプションの意味:テスト実行であり、実際の更新は実施されない。エラーが出なければ自動更新が機能する。

確認

sudo systemctl list-timers | grep certbot

certbot.timer」が表示され、次回実行時刻が表示されれば成功である。

証明書自動更新の仕組み

certbot のインストール時に systemd タイマーが設定され、定期的に更新確認が実行される。証明書の有効期限の残りが 30 日未満になると、更新対象として処理される。

自動更新が失敗する主な原因

定期的な手動確認を実施する(運用上の注意事項を参照)。

12. 動作確認

目的:すべての設定が正しく機能していることを確認する。

12.1 基本動作の確認

# HTTP から HTTPS へのリダイレクトを確認
curl -I http://www.example.jp

# HTTPS でのアクセスを確認
curl -I https://www.example.jp

成功の判定

12.2 セキュリティヘッダーの確認

curl -I https://www.example.jp

以下のヘッダーが含まれていることを確認する。

Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin

ヘッダーが表示されない場合:headers モジュールが有効化されているか確認する(手順 10 を再実行する)。

12.3 サーバー情報の非表示確認

curl -I https://www.example.jp

レスポンスヘッダーの Server:Apache のみとなり、バージョン番号が表示されていないことを確認する。

バージョン番号が表示される場合:手順 2 の設定が正しく反映されているか確認する。

高速化設定(オプション)

本セクションでは、Web サーバーのレスポンス速度を向上させる設定を実施する。

13. Deflate 圧縮の有効化

目的:テキストベースのファイル(HTML、CSS、JavaScript 等)を圧縮して転送し、転送量を削減する。

期待される効果:テキストファイルの転送量が削減される(圧縮率はファイル内容に依存する)。

sudo a2enmod deflate
sudo systemctl restart apache2

圧縮対象の設定

sudo cat /etc/apache2/mods-available/deflate.conf

圧縮対象の MIME タイプが以下のように指定されていることを確認する(環境により記載内容は若干異なる場合がある)。

<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript
    AddOutputFilterByType DEFLATE application/x-javascript application/javascript application/ecmascript
    AddOutputFilterByType DEFLATE application/rss+xml
    AddOutputFilterByType DEFLATE application/wasm
    AddOutputFilterByType DEFLATE application/xml
</IfModule>

確認

curl -H "Accept-Encoding: gzip" -I https://www.example.jp

Content-Encoding: gzip」が表示されれば成功である。

注記:画像ファイル(JPEG、PNG、GIF)や動画ファイルは既に圧縮されているため、対象に含めない。

14. KeepAlive の最適化

目的:HTTP コネクションを再利用し、接続確立のオーバーヘッドを削減する。

期待される効果:複数のファイルを読み込むページで、接続確立処理の繰り返しが省略される。

sudo nano /etc/apache2/apache2.conf

以下の項目を確認する。

# KeepAlive を有効化
KeepAlive On

# 1 つのコネクションで処理できるリクエスト数
MaxKeepAliveRequests 100

# KeepAlive タイムアウト(秒)
KeepAliveTimeout 5

設定項目の説明

設定変更を行った場合は、次のコマンドにより反映する。

sudo systemctl restart apache2

確認

curl -v -I https://www.example.jp 2>&1 | grep -i "connection"

Connection #0 to host ... left intact が表示されれば、接続が維持されており KeepAlive が有効であることを確認できる。

15. ブラウザキャッシュの設定

目的:静的ファイルをブラウザにキャッシュさせ、再訪問時の読み込み速度を向上させる。

期待される効果:再訪問時に、キャッシュ対象のファイルはサーバーから再取得されない。

本設定のキャッシュポリシー

1 時間キャッシュを採用する理由

sudo a2enmod expires
sudo a2enmod headers
sudo systemctl restart apache2

キャッシュ設定の追加

sudo nano /etc/apache2/sites-available/www.example.jp-ssl.conf

</VirtualHost> の直前に以下を追加する。

    # ブラウザキャッシュ設定(静的ファイルは 1 時間キャッシュ)
    <IfModule mod_expires.c>
        ExpiresActive On

        # 画像:1 時間キャッシュ
        ExpiresByType image/jpeg "access plus 1 hour"
        ExpiresByType image/png "access plus 1 hour"
        ExpiresByType image/gif "access plus 1 hour"
        ExpiresByType image/webp "access plus 1 hour"
        ExpiresByType image/svg+xml "access plus 1 hour"
        ExpiresByType image/x-icon "access plus 1 hour"

        # CSS:1 時間キャッシュ
        ExpiresByType text/css "access plus 1 hour"

        # JavaScript:1 時間キャッシュ
        ExpiresByType application/javascript "access plus 1 hour"
        ExpiresByType application/x-javascript "access plus 1 hour"
        ExpiresByType text/javascript "access plus 1 hour"

        # フォント:1 時間キャッシュ
        ExpiresByType font/woff2 "access plus 1 hour"
        ExpiresByType font/woff "access plus 1 hour"
        ExpiresByType font/ttf "access plus 1 hour"

        # HTML:キャッシュしない
        ExpiresByType text/html "access plus 0 seconds"
    </IfModule>

    # Cache-Control ヘッダーの設定
    <IfModule mod_headers.c>
        # 画像、CSS、JavaScript、フォント(1 時間キャッシュ)
        <FilesMatch "\.(jpg|jpeg|png|gif|webp|svg|ico|css|js|woff2|woff|ttf|eot)$">
            Header set Cache-Control "max-age=3600, public"
        </FilesMatch>

        # HTML(キャッシュしない)
        <FilesMatch "\.(html|htm)$">
            Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
            Header set Pragma "no-cache"
            Header set Expires "0"
        </FilesMatch>
    </IfModule>

設定を反映する。

sudo systemctl restart apache2

キャッシュ設定の説明

確認

# 画像、CSS、JavaScript が 1 時間キャッシュされることを確認
curl -I https://www.example.jp/sample.jpg
curl -I https://www.example.jp/style.css
curl -I https://www.example.jp/script.js

# HTML がキャッシュされないことを確認
curl -I https://www.example.jp

期待される出力

ファイル更新後の反映時間

即時更新が必要な場合の対処法:ファイル名にバージョン番号を付加する(例:logo.pnglogo-v2.png)ことで、キャッシュを回避できる。

不正アクセス自動遮断の設定(オプション)

本セクションでは、fail2ban を使用して不正アクセスを自動的に検知し、一時的にアクセスを遮断する設定を実施する。

16. fail2ban のインストールと基本設定

目的:ログファイルを監視し、不正なアクセスパターンを検知して自動的にファイアウォールで遮断する。

期待される効果:パスワード総当たり攻撃、スキャン攻撃、DoS 攻撃の初期段階を自動的に検知し遮断する。

sudo apt install -y fail2ban

基本設定ファイルの作成

sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local

以下の項目を確認し、必要に応じて設定を変更する。

[DEFAULT]
# 遮断時間(秒)デフォルトは 10 分
bantime = 600

# 監視期間(秒)デフォルトは 10 分
findtime = 600

# 遮断対象から除外する IP アドレス(自分の IP を追加)
ignoreip = 127.0.0.1/8 ::1

設定項目の説明

17. Apache 用フィルターの有効化

目的:Apache のアクセスログとエラーログを監視し、不正なアクセスを検知する。

同じファイル(/etc/fail2ban/jail.local)内で、以下のセクションを有効化する。

# Apache 認証失敗を検知
[apache-auth]
enabled = true
port = http,https
logpath = /var/log/apache2/*error.log

# 存在しないスクリプトへのアクセスを検知(スキャン攻撃対策)
[apache-noscript]
enabled = true
port = http,https
logpath = /var/log/apache2/*error.log

# .htaccess や .htpasswd へのアクセスを検知
[apache-overflows]
enabled = true
port = http,https
logpath = /var/log/apache2/*error.log

各フィルターの説明

fail2ban を再起動して設定を反映する。

sudo systemctl restart fail2ban
sudo systemctl enable fail2ban

確認

# fail2ban のステータスを確認
sudo fail2ban-client status

# 特定の jail のステータスを確認
sudo fail2ban-client status apache-auth

有効化した jail が表示され、「Currently banned」の数値が確認できれば成功である。

18. 遮断状況の確認とメンテナンス

目的:fail2ban の動作状況を確認し、必要に応じて設定を調整する。

遮断状況の確認

# 現在遮断されている IP アドレスを確認
sudo fail2ban-client status apache-auth

# すべての jail の統計情報を確認
sudo fail2ban-client status

手動での IP アドレス遮断解除

# 特定の IP アドレスを遮断解除
sudo fail2ban-client set apache-auth unbanip 192.168.1.100

ログの確認

# fail2ban のログを確認
sudo tail -f /var/log/fail2ban.log

運用上の確認事項

注記:fail2ban はファイアウォール(iptables または nftables)を介してアクセスを遮断する。ファイアウォール設定を手動で変更する場合、fail2ban の動作に影響を与えないよう注意する。

19. 総合的な動作確認

目的:手順 13〜18 で実施した高速化設定と不正アクセス対策が正常に動作していることを総合的に確認する。

19-1. 高速化設定の動作確認

Deflate 圧縮の確認

curl -H "Accept-Encoding: gzip" -I https://www.example.jp
curl -H "Accept-Encoding: gzip" -I https://www.example.jp/style.css

期待される出力:すべてのレスポンスに「Content-Encoding: gzip」が含まれている。

KeepAlive の確認

curl -I https://www.example.jp

期待される出力:「Connection: Keep-Alive」が含まれている。

ブラウザキャッシュの確認

curl -I https://www.example.jp/sample.jpg
curl -I https://www.example.jp/style.css
curl -I https://www.example.jp

期待される出力

19-2. ブラウザでの実際の動作確認

開発者ツールでの確認手順(Chrome / Edge)

  1. ブラウザで https://www.example.jp にアクセスする
  2. F12 キーを押して開発者ツールを開く
  3. 「Network」タブを選択する
  4. ページを再読み込み(F5)する

確認ポイント 1:Deflate 圧縮

確認ポイント 2:KeepAlive

確認ポイント 3:ブラウザキャッシュ

ファイル更新の反映確認

確認手順

  1. サーバー上で CSS、JavaScript、または画像ファイルを編集する
  2. ブラウザで通常の再読み込み(F5)を実行する

期待される動作

19-3. 不正アクセス対策の動作確認

fail2ban の基本動作確認

# fail2ban のステータスを確認
sudo systemctl status fail2ban

# 有効な jail を確認
sudo fail2ban-client status

期待される出力:「active (running)」と表示され、有効化した jail(apache-authapache-noscriptapache-overflows)が表示される。

19-4. Apache の総合ステータス確認

設定ファイルの文法チェック

sudo apache2ctl configtest

期待される出力:「Syntax OK」が表示される。

有効なモジュールの確認

apache2ctl -M | grep -E 'ssl|headers|deflate|expires|rewrite'

期待される出力

deflate_module (shared)
expires_module (shared)
headers_module (shared)
rewrite_module (shared)
ssl_module (shared)

有効な仮想ホストの確認

apache2ctl -S

期待される出力

VirtualHost configuration:
*:443                  www.example.jp (/etc/apache2/sites-enabled/www.example.jp-ssl.conf:1)
*:80                   www.example.jp (/etc/apache2/sites-enabled/www.example.jp.conf:1)

19-5. セキュリティ設定の総合確認

HTTPS リダイレクトの確認

curl -I http://www.example.jp

期待される出力

HTTP/1.1 301 Moved Permanently
Location: https://www.example.jp/

セキュリティヘッダーの確認

curl -I https://www.example.jp

期待される出力:以下のヘッダーがすべて含まれている。

Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Server: Apache

SSL 証明書の確認

sudo certbot certificates

期待される出力

Certificate Name: www.example.jp
  Domains: www.example.jp
  Expiry Date: 2026-04-20 12:34:56+00:00 (VALID: 89 days)

有効期限が 30 日以上残っていることを確認する。

19-6. 外部ツールによる総合診断

SSL/TLS 設定の診断

使用ツール:SSL Labs(https://www.ssllabs.com/ssltest/

目標評価:A 評価以上。

ページ速度の診断

使用ツール:Google PageSpeed Insights(https://pagespeed.web.dev/

目標スコア:パフォーマンス 70 点以上。

セキュリティヘッダーの診断

使用ツール:Security Headers(https://securityheaders.com/

目標評価:B 評価以上。

19-7. 総合確認チェックリスト

カテゴリ確認項目確認方法期待される結果
高速化設定Deflate 圧縮curl -H "Accept-Encoding: gzip" -I https://www.example.jpContent-Encoding: gzip が表示
KeepAlivecurl -I https://www.example.jpConnection: Keep-Alive が表示
ブラウザキャッシュcurl -I https://www.example.jp/sample.jpgCache-Control: max-age=3600 が表示
不正アクセス対策fail2ban 動作sudo systemctl status fail2banactive (running) と表示
jail 有効化sudo fail2ban-client status有効化した jail が表示
セキュリティ設定HTTPS リダイレクトcurl -I http://www.example.jp301 Moved Permanently が返される
HSTS ヘッダーcurl -I https://www.example.jpStrict-Transport-Security が表示
バージョン隠蔽curl -I https://www.example.jpServer: Apache のみが表示
SSL 証明書sudo certbot certificates有効期限が 30 日以上
Apache 設定設定ファイルsudo apache2ctl configtestSyntax OK が表示
モジュールapache2ctl -M | grep -E 'ssl|headers|deflate|expires|rewrite'5 つのモジュールが表示
仮想ホストapache2ctl -Sポート 80 と 443 が表示
外部診断SSL/TLSSSL Labs で診断A 評価以上
ページ速度PageSpeed Insights で診断パフォーマンス 70 点以上
セキュリティヘッダーSecurity Headers で診断B 評価以上

すべての項目が期待される結果となっていれば、設定は完了である。

20. トラブルシューティング

本セクションでは、代表的な失敗パターンとその対処法をまとめる。問題が発生した場合、該当する項目を参照し、段階的に対処する。

20-1. 証明書取得失敗

症状sudo certbot certonly --webroot -w /www -d www.example.jp を実行すると、以下のエラーが表示される。

Failed authorization procedure. www.example.jp (http-01): urn:ietf:params:acme:error:unauthorized

主な原因と対処法

原因確認方法対処法
DNS 設定が正しくないdig www.example.jp でサーバー IP が表示されるか確認DNS 設定を修正し、反映を待つ(数分〜数時間)
80 番ポートが閉じられているsudo ufw status で 80 番ポートの状態を確認sudo ufw allow 80/tcp で開放
HTTP でアクセスできないcurl -I http://www.example.jp で確認手順 6 を再実行し、HTTP アクセスが成功することを確認
ドキュメントルートのパスが間違っているls -ld /www でディレクトリの存在を確認certbot コマンドの -w オプションで指定したパスを確認

診断コマンド

dig www.example.jp
curl -I http://www.example.jp
sudo systemctl status apache2
sudo tail -n 50 /var/log/letsencrypt/letsencrypt.log

20-2. HTTPS 接続エラー

症状:ブラウザで https://www.example.jp にアクセスすると、「接続がタイムアウトしました」「証明書が無効です」などのエラーが表示される。

主な原因と対処法

原因確認方法対処法
443 番ポートが閉じられているsudo ufw status で 443 番ポートの状態を確認sudo ufw allow 443/tcp で開放
SSL モジュールが有効化されていないapache2ctl -M | grep ssl で確認sudo a2enmod ssl で有効化し、sudo systemctl reload apache2
HTTPS 用仮想ホストが有効化されていないapache2ctl -S で 443 番ポートの仮想ホストを確認sudo a2ensite www.example.jp-ssl.conf で有効化し、sudo systemctl reload apache2
設定ファイルに文法エラーがあるsudo apache2ctl configtest で確認エラーメッセージに表示されたファイルと行番号を確認し、修正
証明書ファイルのパスが間違っているsudo ls -l /etc/letsencrypt/live/www.example.jp/ で確認手順 8 の SSL 設定でパスが正しいか確認

診断コマンド

curl -I https://www.example.jp
apache2ctl -M | grep ssl
apache2ctl -S
sudo apache2ctl configtest
sudo ls -l /etc/letsencrypt/live/www.example.jp/

20-3. HTTP から HTTPS へのリダイレクトが動作しない

症状http://www.example.jp にアクセスしても、https://www.example.jp にリダイレクトされない。

主な原因と対処法

原因確認方法対処法
HTTP 用設定にリダイレクトが記述されていないsudo cat /etc/apache2/sites-available/www.example.jp.conf で確認手順 9 を再実行し、RewriteRule が記述されているか確認
rewrite モジュールが有効化されていないapache2ctl -M | grep rewrite で確認sudo a2enmod rewrite で有効化し、sudo systemctl restart apache2
ブラウザのキャッシュが残っている別のブラウザまたはシークレットモードでアクセスブラウザのキャッシュをクリアするか、スーパーリロード(Ctrl+F5)を実行

診断コマンド

curl -I http://www.example.jp
# 期待される出力:HTTP/1.1 301 Moved Permanently
# 期待される出力:Location: https://www.example.jp/

20-4. セキュリティヘッダーが表示されない

症状curl -I https://www.example.jp を実行しても、Strict-Transport-Security などのセキュリティヘッダーが表示されない。

主な原因と対処法

原因確認方法対処法
headers モジュールが有効化されていないapache2ctl -M | grep headers で確認sudo a2enmod headers で有効化し、sudo systemctl reload apache2
HTTPS 用設定にヘッダー設定が記述されていないsudo cat /etc/apache2/sites-available/www.example.jp-ssl.conf | grep "Header always set" で確認手順 8 を再実行し、Header always set の行が記述されているか確認

20-5. Deflate 圧縮が動作しない

症状curl -H "Accept-Encoding: gzip" -I https://www.example.jp を実行しても、Content-Encoding: gzip が表示されない。

主な原因と対処法

原因確認方法対処法
deflate モジュールが有効化されていないapache2ctl -M | grep deflate で確認sudo a2enmod deflate で有効化し、sudo systemctl restart apache2
アクセスしているファイルが圧縮対象外HTML、CSS、JavaScript ファイルでテスト画像ファイルは既に圧縮されているため対象外。HTML または CSS ファイルでテスト

20-6. ブラウザキャッシュが動作しない

症状curl -I https://www.example.jp/sample.jpg を実行しても、Cache-Control: max-age=3600 が表示されない。

主な原因と対処法

原因確認方法対処法
expires/headers モジュールが有効化されていないapache2ctl -M | grep -E 'expires|headers' で確認sudo a2enmod expiressudo a2enmod headers で有効化し、sudo systemctl restart apache2
HTTPS 用設定にキャッシュ設定が記述されていないsudo cat /etc/apache2/sites-available/www.example.jp-ssl.conf | grep "ExpiresActive" で確認手順 15 を再実行し、ExpiresActive OnExpiresByType が記述されているか確認

20-7. fail2ban が不正アクセスを検知しない

症状:明らかに不正なアクセスがログに記録されているが、sudo fail2ban-client status で「Currently banned」が 0 のまま。

主な原因と対処法

原因確認方法対処法
fail2ban が起動していないsudo systemctl status fail2ban で確認sudo systemctl start fail2ban で起動し、sudo systemctl enable fail2ban で自動起動を有効化
jail が有効化されていないsudo fail2ban-client status で jail リストを確認/etc/fail2ban/jail.local で該当する jail の enabled = true を確認
ログファイルのパスが間違っているsudo fail2ban-client get apache-auth logpath で確認/etc/fail2ban/jail.locallogpath が正しいか確認

20-8. Apache のパフォーマンスが低い

症状:ページの読み込みが遅い。同時アクセス数が増えるとサーバーが応答しなくなる。

主な原因と対処法

原因確認方法対処法
Deflate 圧縮が有効化されていないcurl -H "Accept-Encoding: gzip" -I https://www.example.jp で確認手順 13 を実施
KeepAlive が無効化されているsudo cat /etc/apache2/apache2.conf | grep KeepAlive で確認手順 14 を実施
ブラウザキャッシュが設定されていないcurl -I https://www.example.jp/sample.jpg で確認手順 15 を実施
メモリ不足free -h でメモリ使用状況を確認不要なサービスを停止するか、サーバーのメモリを増設

20-9. Apache が起動しない

症状sudo systemctl start apache2 を実行しても、Apache が起動しない。sudo systemctl status apache2 で「failed」と表示される。

主な原因と対処法

原因確認方法対処法
設定ファイルに文法エラーがあるsudo apache2ctl configtest で確認エラーメッセージに表示されたファイルと行番号を確認し、修正
80 番または 443 番ポートが既に使用されているsudo lsof -i :80sudo lsof -i :443 で確認他のプロセスが使用している場合、そのプロセスを停止
証明書ファイルが見つからないsudo ls -l /etc/letsencrypt/live/www.example.jp/ で確認証明書が存在しない場合、手順 7 を再実行

診断コマンド

sudo systemctl status apache2
sudo apache2ctl configtest
sudo lsof -i :80
sudo lsof -i :443
sudo tail -n 50 /var/log/apache2/error.log

20-10. ログファイルが見つからない、またはログが記録されない

症状sudo tail -f /var/log/apache2/www.example.jp-access.log を実行しても、「No such file or directory」と表示される。または、アクセスしてもログが記録されない。

主な原因と対処法

原因確認方法対処法
ログファイルのパスが間違っているsudo cat /etc/apache2/sites-available/www.example.jp-ssl.conf | grep Log で確認手順 8 で指定したログパスを確認。${APACHE_LOG_DIR}/var/log/apache2 に展開される
仮想ホスト設定が有効化されていないapache2ctl -S で仮想ホストの一覧を確認sudo a2ensite www.example.jp-ssl.conf で有効化し、sudo systemctl reload apache2

トラブルシューティングの一般的な手順

上記の個別の問題に該当しない場合、以下の手順で問題を特定する。

  1. エラーログを確認する:sudo tail -n 100 /var/log/apache2/error.log
  2. 設定ファイルの文法をチェックする:sudo apache2ctl configtest
  3. Apache の状態を確認する:sudo systemctl status apache2
  4. 仮想ホストの設定を確認する:apache2ctl -S
  5. モジュールの有効化を確認する:apache2ctl -M
  6. ファイアウォールの設定を確認する:sudo ufw status
  7. DNS 設定を確認する:dig www.example.jp
  8. 再起動を試行する:sudo systemctl restart apache2

それでも解決しない場合

21. ページインクルード(SSI)の有効化(オプション)

目的:複数ページで共通するヘッダー・フッター等を別ファイル化し、各ページから取り込む構成を可能にする。Apache の標準機能 mod_include(SSI: Server Side Includes)を使用する。

SSI とは:HTML ファイル内に専用のディレクティブを記述し、サーバー側でその箇所を別ファイルの内容に置換してからクライアントへ送信する仕組みである。共通部分の変更を 1 ファイルの編集で全ページに反映できる。

採用する設計

21-1. モジュールの有効化

sudo a2enmod include
sudo systemctl restart apache2

モジュール追加にはプロセスの再起動が必要なため、reload ではなく restart を使用する。

確認

apache2ctl -M | grep include

include_module」が表示されれば成功である。

21-2. 仮想ホスト設定への追加

HTTPS 用設定ファイル /etc/apache2/sites-available/www.example.jp-ssl.conf を開き、<Directory /www> ブロックを以下のように変更する。

    <Directory /www>
        Options -Indexes +FollowSymLinks +IncludesNOEXEC
        AllowOverride None
        Require all granted

        # .shtml を SSI 処理対象に追加
        AddType text/html .shtml
        AddOutputFilter INCLUDES .shtml
    </Directory>

    # ディレクトリ既定ファイルに index.shtml を追加
    DirectoryIndex index.html index.shtml

変更点の説明

外部コマンド実行が必要な場合は +IncludesNOEXEC+Includes に変更する(セキュリティ上のリスクが高まるため、必要性が明確な場合のみ採用する)。

21-3. ブラウザキャッシュ設定との整合

SSI で生成されるページは動的に組み立てられる。HTML と同様にブラウザキャッシュの対象から除外することが望ましい。手順 15 で設定した FilesMatch パターンに shtml を追加する。

        <FilesMatch "\.(html|htm|shtml)$">
            Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
            Header set Pragma "no-cache"
            Header set Expires "0"
        </FilesMatch>

21-4. 設定の反映

sudo apache2ctl configtest
sudo systemctl reload apache2

Syntax OK」が表示され、reload が成功すれば反映完了である。

21-5. 動作確認

共通ヘッダーと、それを取り込むページを作成する。

# 共通ヘッダー(インクルードされる側のファイル)
sudo tee /www/header.html > /dev/null <<'EOF'
<header>
  <h1>サイト共通ヘッダー</h1>
</header>
EOF

# 共通ヘッダーを取り込むページ
sudo tee /www/sample.shtml > /dev/null <<'EOF'
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>SSI テスト</title></head>
<body>
<!--#include virtual="/header.html" -->
<p>本文です。</p>
</body>
</html>
EOF

sudo chown www-data:www-data /www/header.html /www/sample.shtml

tee は標準入力をファイルに書き込むコマンドであり、sudo と組み合わせることで管理者権限でファイルを作成できる。<<'EOF' ... EOF はヒアドキュメントと呼ばれる構文で、EOF までの内容を標準入力として渡す。

確認

curl https://www.example.jp/sample.shtml

レスポンス本文に <header> ブロックが展開された状態で含まれていれば成功である。<!--#include ... --> がそのまま残っている場合、SSI が処理されていないため、モジュールの有効化(手順 21-1)と AddOutputFilter 設定(手順 21-2)を確認する。

21-6. include の主な書式

書式意味
<!--#include virtual="/header.html" -->ドキュメントルートからの URL パスで指定する
<!--#include file="header.html" -->現在のファイルからの相対パスで指定する(親ディレクトリへの遡及は不可)

ログファイルの場所

ログ種別パス用途
アクセスログ/var/log/apache2/www.example.jp-access.logアクセス解析、トラフィック監視、不正アクセスの検知
エラーログ/var/log/apache2/www.example.jp-error.logトラブルシューティング、設定ミスの発見、アプリケーションエラーの検知

ログの確認方法

# 最新のアクセスログを表示
sudo tail -n 20 /var/log/apache2/www.example.jp-access.log

# エラーログをリアルタイムで監視
sudo tail -f /var/log/apache2/www.example.jp-error.log

運用上の注意事項

定期的なセキュリティアップデート

目的:セキュリティ脆弱性への対策を適用し、システムの安全性を維持する。

以下のコマンドを定期的に実行し、システムを最新の状態に保つ。

sudo apt update
sudo apt upgrade -y

実施頻度:最低でも月 1 回、可能であれば週 1 回実施する。セキュリティ上の重大な脆弱性が公表された場合は直ちに実施する。

アップデート後の確認

sudo systemctl restart apache2
sudo systemctl status apache2

Apache が正常に起動することを確認する。

ログの監視

目的:不正アクセスや攻撃の兆候を早期に検知する。

監視すべき項目

SSL 設定の検証

目的:SSL/TLS 設定の安全性を第三者の視点で評価し、脆弱性を発見する。

SSL Labs(https://www.ssllabs.com/ssltest/)などの外部サービスを利用して、SSL/TLS 設定の安全性を定期的に検証する。

実施頻度:初回設定後、および Apache や OpenSSL の大幅なアップデート後に実施する。

目標評価:A 評価以上を目指す。B 評価以下の場合、暗号スイートや SSL プロトコルの設定を見直す必要がある。

証明書の有効期限確認と自動更新の健全性確認

目的:自動更新が正常に機能していることを定期的に検証する。

certbot は systemd タイマーにより 1 日 2 回程度のペースで更新確認を実行し、有効期限の残りが 30 日未満になった証明書を自動更新する。健全な状態であれば残り日数は概ね 30〜90 日の範囲を維持する。

月 1 回の確認手順

sudo certbot certificates

判定基準

自動更新失敗時の対応

# 手動更新を試みる
sudo certbot renew

# 直近のログを確認
sudo tail -n 100 /var/log/letsencrypt/letsencrypt.log

# systemd タイマーの状態を確認
sudo systemctl list-timers | grep certbot

失敗の主な原因は、80 番ポートの閉塞、/.well-known/acme-challenge/ へのアクセス不可、DNS 設定の変更などである。手順 9 のリダイレクト除外設定が崩れていないかも確認する。