このガイドで学べること
- Fail2ban が何をしているのかを「なぜ」から理解する
- SSH・メール・Webサーバーを不正アクセスから自動保護する
- 設定の各パラメーターの意味と最適な値を理解する
- トラブル発生時の診断・復旧手順を習得する
- 正規表現フィルターを自分で作れるようになる
目次
第1章:Fail2banの基本概念
なぜ必要か・何をしているか・どう動くか
1-1 なぜFail2banが必要なのか
サーバーをインターネットに公開した瞬間から、世界中のボット(自動プログラム)が24時間365日、不正アクセスを試み続けます。
📖 具体例:実際に記録されるログの例(1時間分)
# /var/log/secure を確認すると以下のような記録が大量に残る
Jan 1 03:12:05 sshd: Failed password for root from 185.234.219.xxx port 43251
Jan 1 03:12:07 sshd: Failed password for admin from 185.234.219.xxx port 43252
Jan 1 03:12:09 sshd: Failed password for user from 185.234.219.xxx port 43253
# 1時間で数百〜数千回の試行が記録されることがある
# 人間が手動で対応することは不可能 → Fail2banが自動対応する
🔍 詳しく解説:Fail2banが解決する3つの問題
| 問題 | 内容 | Fail2banによる解決 |
|---|---|---|
| ① 手動対応の限界 | 攻撃は24時間止まらない。人間が気づいて対応するまでの間も試行が続く。 | 自動でリアルタイム検知・遮断する |
| ② ログファイルの肥大化 | 大量の失敗ログがディスクを圧迫する。 | 遮断することで以後のログ記録自体がなくなる |
| ③ サーバーリソースの浪費 | 認証処理はCPU・メモリを使う。大量の試行はサービス低下につながる。 | 遮断することで認証処理自体が不要になる |
1-2 Fail2banの全体システム図
Fail2banがサーバー内でどのように位置づけられ、各サービスと連携しているかを示します。
1-3 攻撃検知から遮断までのシーケンス(詳細版)
攻撃者がSSH接続を試みてから、firewalldで遮断されるまでの詳細な流れです。
1-4 重要な3つのパラメーターの詳細解説
jail.local の設定で最も重要な3つのパラメーターを、具体的な数値例で解説します。
◆ ① bantime(遮断時間)
攻撃者のIPアドレスを遮断し続ける時間です。この時間が経過すると自動的に解除されます。
| 設定値 | 意味 | 推奨ケース |
|---|---|---|
| 30m | 30分間遮断 | デフォルト値。一時的な誤操作も早めに解除される |
| 1h | 1時間遮断 | 一般的な攻撃ボットへの対策として適切 |
| 24h | 24時間遮断 | 悪質な攻撃者への強い対応 |
| 86400 | 24時間(秒指定) | 秒単位で指定する場合の書き方 |
| -1 | 永久遮断 | apache-badbots など悪質なボット専用(注意が必要) |
⚠️ 注意:bantime=-1(永久遮断)の注意点
永久遮断は一見強力ですが、以下のリスクがあります:
- 自分が誤ってBANされた場合、手動解除が必要になる
- 動的IP(プロバイダが定期的に変更するIP)の場合、次にそのIPを割り当てられた無実のユーザーを巻き込む
使う場合は apache-badbots など明確に悪意があるボットのみに限定する。
◆ ② findtime(監視ウィンドウ)
「この時間内にmaxretry回失敗したらBAN」という時間窓です。
◆ ③ maxretry(許容失敗回数)
BANされるまでに許容される失敗回数です。この回数に到達した次の失敗でBANされます。
| サービス | 推奨設定 | 理由 |
|---|---|---|
| sshd | 5回 | 正当なユーザーが誤入力する可能性を考慮 |
| postfix-sasl | 3回 | メール認証の失敗は不正試行の可能性が高い |
| dovecot | 3回 | 同上 |
| apache-badbots | 1回 | 悪質ボットのユーザーエージェントは1回で確定 |
| apache-404 | 5回 | 存在しないページへの連続アクセスを検知 |
第2章:Fail2banの内部構造
Jail・Filter・Actionの連携を理解する
2-1 3つの構成要素
| 構成要素 | ファイルの場所 | 役割 |
|---|---|---|
| Jail(牢獄の設定) | /etc/fail2ban/jail.local | どのサービスを監視するか、bantime/findtime/maxretryなどを定義 |
| Filter(検知ルール) | /etc/fail2ban/filter.d/*.conf | ログのどの行を「失敗」と判定するか。正規表現(failregex)で定義 |
| Action(実行命令) | /etc/fail2ban/action.d/*.conf | BAN/解除時に何をするか。firewalldへの命令などを定義 |
2-2 Jail・Filter・Actionの連携図
2-3 ipsetを使う理由(パフォーマンスの観点)
なぜ直接firewalldを使わずipsetを経由するのかを解説します。
🔍 詳しく解説:ipsetが必要な理由
【firewalldのみで大量IPを遮断する場合の問題】
- firewalldは遮断ルールを1つずつチェックする(線形探索)
- 遮断IPが1,000件になると → 1,000回チェック
- 遮断IPが10,000件になると → 10,000回チェック
- → パケットが届くたびにこの処理が走るためCPU負荷が増大
【ipsetを使う場合】
- ipsetはハッシュテーブル(辞書)でIPを管理する(定数時間検索)
- 遮断IPが1,000件でも10,000件でも → 同じ速度でチェック
- → IP数に関係なく高速に動作する
第3章:インストールと基本設定
SSH・メールサーバーの保護を設定する
3-1 インストール前の確認
# ── Rocky Linux 9 のバージョン確認 ─────────────────────
cat /etc/os-release
# NAME="Rocky Linux" VERSION="9.x" と表示されればOK
# ── firewalld が稼働しているか確認 ──────────────────────
sudo systemctl is-active firewalld
# "active" と表示されればOK
# "inactive" の場合は以下で起動する
sudo systemctl enable --now firewalld
# ── SELinux の状態確認(Enforcing が推奨) ────────────────
sudo getenforce
# "Enforcing" と表示されればOK
3-2 パッケージのインストール
EPEL(Extended Packages for Enterprise Linux)リポジトリを有効化してからインストールします。EPELはRocky Linuxの標準リポジトリにないパッケージを提供する公式の拡張リポジトリです。
# ── EPELリポジトリの有効化 ──────────────────────────────
sudo dnf install -y epel-release
# ── Fail2banのインストール ──────────────────────────────
# fail2ban: Fail2ban本体
# fail2ban-firewalld: firewalld連携に必要な設定ファイル群
sudo dnf install -y fail2ban fail2ban-firewalld
# ── インストール確認 ──────────────────────────────────────
fail2ban-client --version
# Fail2Ban v1.x.x と表示されれば成功
# ── サービスの有効化と起動 ──────────────────────────────
# enable: OS再起動後も自動起動するよう設定
# now: 今すぐ起動する
sudo systemctl enable --now fail2ban
# ── 起動確認 ────────────────────────────────────────────
sudo systemctl status fail2ban --no-pager
# Active: active (running) と表示されれば成功
3-3 jail.localの作成(全サービス共通設定)
設定のカスタマイズは必ず jail.local で行います。jail.conf を直接編集してはいけません。
💡 ポイント:jail.confを編集してはいけない理由
jail.conf はシステムが管理するデフォルト設定ファイルです。パッケージ更新(dnf update)時に上書きされ、設定が消えます。
正しい方法:jail.local に設定を書く → 更新時も保持される。jail.local の設定は jail.conf より優先される。
sudo tee /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
# ════════════════════════════════════════════
# 全サービス共通のデフォルト設定
# ════════════════════════════════════════════
# ── ホワイトリスト(絶対にBANしないIP) ────────────────
# 127.0.0.1/8 : 自分自身(ローカルホスト)
# ::1 : IPv6のローカルホスト
# 192.168.1.x : LAN内の自分のPC(実際のIPに書き換える)
# 172.16.1.2 : DMZのRocky Linux(必要に応じて追加)
# ★ 自分の固定IPがある場合はここに追加する
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24 172.16.1.0/24
# ── 遮断時間 ────────────────────────────────────────────
# 30m=30分 / 1h=1時間 / 24h=24時間
# -1=永久遮断(apache-badbotsなどの悪質ボット専用)
bantime = 1h
# ── 監視ウィンドウ(この時間内の失敗をカウント) ─────────
# 10m=10分以内にmaxretry回失敗したらBAN
findtime = 10m
# ── 許容失敗回数 ────────────────────────────────────────
# この回数を超えたらBAN(ただし各Jailで上書き可能)
maxretry = 5
# ── 遮断方法(アクション) ──────────────────────────────
# firewallcmd-ipset: firewalld + ipset を使った高速遮断
banaction = firewallcmd-ipset
# ── ログの読み込み方式 ──────────────────────────────────
# systemd: SSH・Postfix・Dovecotなどのsystemd管理サービス向け
# polling: Apacheなどファイルに直接ログを書くサービス向け
# auto: Fail2banが自動判定(迷ったらこれでも可)
backend = systemd
# ════════════════════════════════════════════
# 各サービス(Jail)の設定
# ════════════════════════════════════════════
# ── SSHへの不正ログインを防止 ──────────────────────────
[sshd]
enabled = true
# maxretryはデフォルト値(5回)を使用
# ── メール送信(SMTP認証)の不正試行を防止 ─────────────
[postfix-sasl]
enabled = true
# メール認証失敗は不正試行の可能性が高いため厳しめに設定
maxretry = 3
# ── メール受信(IMAP/POP認証)の不正試行を防止 ─────────
[dovecot]
enabled = true
maxretry = 3
EOF
# ── 設定ファイルの文法チェック ──────────────────────────
sudo fail2ban-client --test
# エラーが表示されなければ文法は正しい
# ── Fail2banを再起動して設定を反映 ──────────────────────
sudo systemctl restart fail2ban
# ── 設定が正しく読み込まれたか確認 ──────────────────────
sudo fail2ban-client status
# Jail listにsshd, postfix-sasl, dovecotが表示されれば成功
第4章:Apache(Webサーバー)の保護
backend=polling の仕組みとカスタムフィルターの作成
4-1 なぜApacheだけbackendが違うのか
SSH・Postfix・Dovecotはsystemdに管理されてログをジャーナルに記録しますが、Apacheは独自のログファイル(access_log)に記録します。この違いがbackend設定の違いを生みます。
💡 ポイント:backendの3種類まとめ
- systemd → systemdのjournal(日記帳)から直接読み取る。SSH/Postfix/Dovecotなどに使用
- polling → ファイルを一定間隔(デフォルト:1秒)で読みに行く。Apache/Nginxなどファイルに独自出力するサービスに使用
- auto → Fail2banが環境を判定して自動選択。どちらか迷う場合に使用(ただし明示的に指定する方が確実)
4-2 Apache保護のjail.local設定追加
/etc/fail2ban/jail.local の最下部に以下を追記します。
sudo tee -a /etc/fail2ban/jail.local << 'EOF'
# ════════════════════════════════════════════
# Apache(Webサーバー)の保護設定
# ════════════════════════════════════════════
# ── [1] 古いプログラム(CGI等)を狙った攻撃の検知 ──────
[apache-noscript]
enabled = true
port = http,https
filter = apache-noscript
logpath = /var/log/httpd/access_log
# Apacheはファイルにログを書くためpollingを使用
backend = polling
maxretry = 3
findtime = 600
bantime = 86400
# ── [2] 悪質ボット・スキャンツールの検知 ───────────────
# maxretry=1:1回検知されただけで即BAN(悪質ボットのため)
# bantime=86400:24時間(1日)遮断
[apache-badbots]
enabled = true
port = http,https
filter = apache-badbots
logpath = /var/log/httpd/access_log
backend = polling
maxretry = 1
findtime = 600
bantime = 86400
# ── [3] 存在しないURLへの連続アクセス(404エラー)検知 ─
# 攻撃者が管理画面・旧システムのURLを探索する行動を検知
[apache-404]
enabled = true
port = http,https
filter = apache-404
logpath = /var/log/httpd/access_log
backend = polling
maxretry = 5
findtime = 600
bantime = 86400
EOF
第5章:カスタムフィルターの作成
正規表現を使って独自の検知ルールを定義する
5-1 正規表現の基礎知識
フィルターは「正規表現(Regular Expression)」という特別な文字列パターンでログ行を解析します。主要な記号だけ覚えれば十分です。
| 記号 | 意味 | 使用例 |
|---|---|---|
. | 任意の1文字 | a.c は「a + 任意の1文字 + c」例: abc, a1c, a-c など |
.* | 任意の文字列(0文字以上) | a.*c は「aで始まりcで終わる任意の文字列」 |
^ | 行の先頭 | ^192 は「192で始まる行」 |
$ | 行の末尾 | html$ は「htmlで終わる行」 |
\[ | [ 文字そのもの | \[.*\] は「[と]で囲まれた任意の文字列」 |
[0-9]+ | 1文字以上の数字 | 404を「[0-9]+」で表現できる |
<HOST> | Fail2banの特殊変数 | IPアドレスを自動的にマッチする |
5-2 apache-404フィルターの作成と解説
Apacheのアクセスログから404エラーを検知するフィルターを作成します。
sudo tee /etc/fail2ban/filter.d/apache-404.conf << 'EOF'
[Definition]
# ────────────────────────────────────────────────────
# 404エラーログ行を検知する正規表現
# ────────────────────────────────────────────────────
# : Fail2banの特殊変数(IPアドレスにマッチ)
# - : Apacheログの固定フォーマット(識別子)
# - : Apacheログの固定フォーマット(ユーザー名)
# \[.*\] : [日時] の部分([で始まり]で終わる任意の文字列)
# ".*" : "GET /xxx HTTP/1.1" の部分("で囲まれた任意の文字列)
# 404 : HTTPステータスコード404(Not Found)
# [0-9]+ : レスポンスサイズ(1文字以上の数字)
# ".*" : Refererヘッダー
# ".*" : User-Agentヘッダー
# $ : 行末
failregex = ^ - - \[.*\] ".*" 404 [0-9]+ ".*" ".*"$
# 検知から除外するパターン(空のままでOK)
ignoreregex =
EOF
📖 具体例:実際のログ行との照合イメージ
【実際のApacheアクセスログの1行】
203.0.113.5 - - [28/Jun/2026:15:30:45 +0900] "GET /wp-login.php HTTP/1.1" 404 283 "-" "Python-urllib/3.8"
【正規表現との対応】
203.0.113.5 ←── <HOST>(IPアドレスを抽出)
- ←── -
- ←── -
[28/Jun/2026:...] ←── \[.*\]
"GET /wp-login.php HTTP/1.1" ←── ".*"
404 ←── 404(ここが一致するかが重要)
283 ←── [0-9]+
"-" ←── ".*"
"Python-urllib/3.8" ←── ".*"
→ すべて一致 → 203.0.113.5 のカウントを+1
5-3 フィルターのテスト方法
作成したフィルターが実際のログファイルに正しくマッチするかテストします。
# fail2ban-regex コマンドでテスト実行
# 書式: fail2ban-regex [ログファイル] [フィルターファイル]
sudo fail2ban-regex /var/log/httpd/access_log /etc/fail2ban/filter.d/apache-404.conf
# ── 成功時の出力例 ─────────────────────────────────────
# Results
# =======
# Failregex: 247 total
# ↑ 0以外の数字が出れば正規表現がマッチしている
# ── 失敗時の出力例(要確認) ───────────────────────────
# Failregex: 0 total
# ↑ 正規表現が一切マッチしていない
# 原因1: 正規表現の書き間違い
# 原因2: ログファイル内にまだ404エラーがない
# → まず curl http://自サーバ/存在しないページ でエラーを生成してから再テスト
5-4 設定の反映と最終確認
# ── 設定ファイルの文法チェック(反映前に必ず実行) ────
sudo fail2ban-client --test
# ── Fail2banを再起動して全設定を反映 ──────────────────
sudo systemctl restart fail2ban
# ── 全体の稼働状況を確認 ──────────────────────────────
sudo fail2ban-client status
# 期待される出力:
# Status
# |- Number of jail: 6
# `- Jail list: apache-404, apache-badbots, apache-noscript,
# dovecot, postfix-sasl, sshd
# ── 各Jailの詳細確認 ──────────────────────────────────
sudo fail2ban-client status apache-404
# 出力の見方:
# |- Filter
# | |- Currently failed: 2 ← 現在カウント中のIP数
# | |- Total failed: 345 ← 累計検知数
# | `- File list: /var/log/httpd/access_log
# `- Actions
# |- Currently banned: 1 ← 現在BAN中のIP数
# |- Total banned: 12 ← 累計BAN数
# `- Banned IP list: 203.0.113.5 ← BAN中のIP一覧
第6章:日常運用と監視
稼働状況の確認・ログの読み方・定期メンテナンス
6-1 日常的な確認コマンド集
# ── Fail2banの稼働状態確認 ──────────────────
sudo systemctl status fail2ban --no-pager
# ── 全Jailの一覧と現在のBAN状況 ─────────────
sudo fail2ban-client status
# ── 特定Jailの詳細(例:sshd) ──────────────
sudo fail2ban-client status sshd
# ── リアルタイムログ監視 ────────────────────
sudo journalctl -u fail2ban -f --no-pager
# ── 今日のBAN件数を数える ───────────────────
sudo journalctl -u fail2ban --since today | grep "Ban " | wc -l
# ── BANされたIPの一覧を全Jailから取得 ───────
sudo fail2ban-client status | grep "Jail list" | sed "s/.*://;s/,/ /g" | \
xargs -I{} sudo fail2ban-client status {} | grep "Banned IP"
6-2 Fail2banのログの読み方
Fail2banはjournaldにログを記録します。主要なログメッセージの意味を解説します。
| ログメッセージ | 意味 | 対応 |
|---|---|---|
| Ban 203.0.113.5 (sshd) | 203.0.113.5をsshdのJailでBANした | 正常動作。攻撃が検知・遮断された |
| Unban 203.0.113.5 (sshd) | 203.0.113.5のBANが解除された(bantime経過) | 正常動作。自動解除 |
| Found 203.0.113.5 - 2026-06-28... | 203.0.113.5の失敗を検知(BANはまだ) | 正常動作。カウント中 |
| ERROR No accessible log files found | ログファイルが見つからない | logpathの設定を確認。Apacheが起動しているか確認 |
| ERROR Failed to execute actionban | BAN命令の実行に失敗 | firewalldが動いているか確認 |
6-3 BANされたIPの管理
# ── 特定のIPを手動でBANする ────────────────────────────
# 書式: fail2ban-client set [Jail名] banip [IPアドレス]
sudo fail2ban-client set sshd banip 203.0.113.5
# ── 特定のIPのBANを解除する ────────────────────────────
# 書式: fail2ban-client set [Jail名] unbanip [IPアドレス]
sudo fail2ban-client set apache-404 unbanip 192.168.1.100
# ── 誤って自分がBANされた場合の緊急対応 ────────────────
# ① 別の接続手段(スマホのLTE等)でサーバにアクセス
# ② 以下を実行して自分のIPを解除
sudo fail2ban-client set sshd unbanip [自分のIPアドレス]
# ── 自分の現在の外部IPを確認する方法 ────────────────────
curl -s https://ifconfig.me
第7章:トラブルシューティング
問題の診断と解決
7-1 トラブルシューティングの基本手順
# Step 1: Fail2ban自体が動いているか確認
sudo systemctl status fail2ban --no-pager
# Step 2: Fail2banのエラーログを確認
sudo journalctl -u fail2ban -n 50 --no-pager
# Step 3: 特定のJailが認識されているか確認
sudo fail2ban-client status
# Step 4: フィルターの文法チェック
sudo fail2ban-client --test
# Step 5: フィルターのテスト実行(特定Jail)
sudo fail2ban-regex /var/log/httpd/access_log \
/etc/fail2ban/filter.d/apache-404.conf
7-2 症状別トラブルシューティング
| 症状 | 考えられる原因 | 確認コマンド・対処方法 |
|---|---|---|
| Fail2banが起動しない | 設定ファイルの文法エラー | sudo fail2ban-client --testsudo journalctl -u fail2ban -n 20 --no-pager |
| JailリストにJailが表示されない | フィルターファイルの文法エラー、またはログファイルが存在しない | sudo journalctl -u fail2ban | grep ERRORls -la /var/log/httpd/access_log |
| BANされているはずなのにアクセスできる | firewalldが止まっている、またはignoreipに含まれている | sudo systemctl status firewalldsudo fail2ban-client get sshd ignoreip |
| 正当なユーザーがBANされた | maxretryが厳しすぎる、またはignoreip未設定 | ignoreipに対象IPを追加sudo fail2ban-client set sshd unbanip [IP] |
| apache-404のカウントが増えない | backend=pollingが未設定、またはログファイルのパスが違う | cat /etc/fail2ban/jail.local | grep -A5 apache-404ls /var/log/httpd/ |
7-3 設定変更後の反映手順(重要)
⚠️ 注意:設定を変更したら必ず以下の手順を実行する
設定ファイルを変更しても、Fail2banを再起動しないと反映されません。
文法チェックを省略すると、文法エラーでFail2ban全体が停止するリスクがあります。
# ─── 設定変更後の必須手順 ───
# 1. 文法チェック(エラーがないことを確認してから再起動)
sudo fail2ban-client --test
# エラーがなければ次のステップへ
# 2. Fail2banを再起動
sudo systemctl restart fail2ban
# 3. 再起動後の状態確認
sudo systemctl status fail2ban --no-pager
sudo fail2ban-client status
# 4. 変更したJailが正しく動いているか確認
sudo fail2ban-client status apache-404
構築完了チェックリスト
- Fail2banがインストールされ起動している:
sudo systemctl is-active fail2ban→ active と表示される - sshd, postfix-sasl, dovecot がJailリストに表示される:
sudo fail2ban-client status→ Jail listに3つが含まれる - Apache用の3つのJailが追加されている:apache-404, apache-badbots, apache-noscript が表示される
- apache-404フィルターがaccess_logにマッチする:
fail2ban-regex /var/log/httpd/access_log /etc/fail2ban/filter.d/apache-404.conf→ Failregex: 0以外 - ignoreipに自分のLANのIPが設定されている:
cat /etc/fail2ban/jail.local | grep ignoreip→ 自分のIPが含まれている - BANされたIPの解除コマンドを把握している:
sudo fail2ban-client set [jail名] unbanip [IP]で解除できる
$ systemctl is-active fail2ban
active
本サイトのRocky Linux 9サーバーで、Fail2banサービスが実際に稼働中であることを確認済みです。
Fail2banの構築・運用が完了しました 🎉
SSH・メール・Webの3層防御が自動化され、サーバーのセキュリティが大幅に向上しました。