サーバーセキュリティ (Fail2ban)

ネット上に公開されているサーバーは常に何らかのスキャンを受けています。ほとんどは無害なものが多いと思われますが、中には踏み台探しや、設定ミスによる API キーやデータベースのパスワード漏洩等を狙ったアクセスなどもあります。
このブログでは開発手法に関する記事が多いためか、そのようなアクセスがだんだん増えてきましたので何らかの対応をする必要性が出てきました。
結論から言うと、これらのアクセスを完全になくすことはできませんが、ある程度制限することで不要な負荷やリスクを減らすことは可能です。今回は備忘録も兼ねて「Fail2ban」というパケットフィルタリングツールを使用した動的防御の設定方法と、Apache・UFW などを組み合わせた多層防御の構成方法をメモとして残します。Fail2ban は VPS だけではなく、AWS などでも使用可能です。
この記事ではおもに
- Fail2ban の基本設定
- WordPress ログイン攻撃の遮断方法
- .env スキャン対策
- メールブルートフォース防御
- recidive の実運用設定
などについてご説明しています。
Fail2ban とは
Fail2ban は、サーバーやシステムのログを監視して攻撃パターンを検出し、nftables などのファイアウォールに自動で Ban ルールを追加することで、不正アクセスを抑止するセキュリティツールです。

デフォルト設定では SSH の不正アクセスを検知できるようになっていますが、Web サーバーやメールサーバーに限らず、以下の条件を満たすログファイルであれば、どのようなものでも監視することが可能です。
- 「テキスト形式のファイルであること」
- 「IP アドレスが記録されていること」
- 「正規表現で攻撃パターンを判別できること」
次のセクションからはインストールと設定方法をご説明します。
※このブログサイトにはすでに設定済みなので、記事作成用に WSL2 上の Ubuntu 24.04 を使用してご説明しています。
Fail2ban のインストール
以下のコマンドをコンソール画面で入力して Fail2ban をインストールします。
sudo apt update
sudo apt install -y fail2banインストールが完了すると以下の位置にフォルダとファイルが作成されます。「filter.d」フォルダ内には正規表現の検知条件が書かれたフィルターファイルがいくつも登録されています。必要であれば自分でオリジナルの検知用ファイルを追加することもできます。
「jail.conf」設定ファイルで使用する検知用ファイルを有効化できますが、バージョンアップなどで更新される可能性がありますので、新たに「jail.local」というファイルを作成してこちらに設定を記述していきます。
etc/
└─ fail2ban/
├── action.d/
├── fail2ban.d/
├── filter.d/ ← ※検知用のファイルが保存されています
├── jail.d/
├── fail2ban.conf
├── jail.conf
├── jail.local ← ※新たにファイルを作成します
├── paths-arch.conf
├── paths-common.conf
├── paths-debian.conf
└── paths-opensuse.confフィルターファイルは以下のように記述されています。各設定項目の意味は次の通りです。どちらも正規表現で記述できます。
- failregex・・・検知条件を記述します。
- ignoreregex・・・除外条件を記述します。
検知条件にマッチしてもこの条件にマッチした場合は除外されます。
[Definition]
failregex = ^<HOST> - - \[.*\] "(GET|POST) (?:/[^"]*)?wp-login\.php(?:\?.*)? HTTP/[^"]+" 403 .*
ignoreregex =「jail.local」ファイルの記述例は以下のようになります。各セクションと設定値の意味については後ほどご説明いたします。
[DEFAULT]
backend = auto
maxretry = 3
findtime = 10m
bantime = 1h
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 7d
banaction = nftables
ignoreip = 127.0.0.1/8 ::1
[sshd]
enabled = true
backend = systemd
[apache-botsearch]
enabled = true
port = http,https
filter = apache-botsearch
logpath = /var/log/apache2/access.log
maxretry = 5
findtime = 5m
bantime = 24hFail2ban の設定方法
このセクションからは実際の攻撃パターン毎の設定方法についてご説明していきます。Fail2ban の設定方法だけではなく、WordPress や Apache との連携についてもご説明します。
・jail.local ファイルのひな型を作成
まずは「jail.local」というファイルを作成して、以下の設定を書き込みます。[DEFAULT] セクションは各セクションのデフォルト値を定義しています。各セクションで特に指定がない場合はこのセクションの設定値が使用されます。
[DEFAULT]
backend = auto
maxretry = 3
findtime = 10m
bantime = 1h
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 7d
banaction = nftables各設定項目の意味は以下のようになっています。
| 設定項目 | 意味 |
|---|---|
| backend | ログの監視方法を設定します。以下の種類があります。 ・auto : 自動判別 (通常はこれでOK) ・systemd : systemd-journald から直接読む ・polling : ファイルを定期スキャン ・pyinotify : inotifyでリアルタイム監視 |
| maxretry | findtime 内に maxretry 回失敗すると Ban |
| findtime | 失敗回数をカウントする時間範囲 |
| bantime | 初回 Ban 時間 以下の指定が可能です。 ・指定なし : 秒 (bantime = 600 の場合は 10 分) ・m : 分 ・h : 時間 ・d : 日 ・w : 週 ・mo : 月 (概算) ・y : 年 ・-1 または permanent : 永久 Ban (手動解除まで) |
| bantime.increment | 再遮断時に Ban 時間を延長する (true = 有効) |
| bantime.factor | 再遮断時の延長倍率 (例:1h → 2h → 4h → 8h …) |
| bantime.maxtime | Ban の最大時間 (これ以上は延長しない) |
| banaction | IP の遮断方法を設定します。以下の種類が代表的です。 ・nftables : 近代的な Linux 標準ファイアウォール ・iptables-multiport : 従来の iptables を使用 |
以下の設定も追加して自分が Ban されないようにします。必要に応じてリモート設定用の IP アドレスなども除外しておきます。
# ローカルや管理用 IP を誤って Ban しないよう除外する
# 複数指定する場合はスペース区切り
ignoreip = 127.0.0.1/8 ::1一応念のために SSH のセクション (フィルター) も追加しておきます。
[sshd]
enabled = true
backend = systemd設定が完了したら以下のコマンドを実行して設定ファイルのチェックを行います。
sudo fail2ban-client -tファイルの文字コードなどが合っていないと以下のようなエラーが出ることがあります。
user01@DESKTOP-CQEA49P:~$ sudo fail2ban-client -t
2026-02-20 11:46:41,130 fail2ban [2862]: ERROR Failed during configuration: File contains no section headers.
file: '/etc/fail2ban/jail.local', line: 1
'\ufeff[DEFAULT]\n'
2026-02-20 11:46:41,130 fail2ban [2862]: ERROR ERROR: test configuration failedそのような場合は設定ファイル (jail.local) を削除してから、以下のコマンドをターミナル画面にコピー&ペーストしてください。(ターミナル画面でマウスを右クリックするとペースト可能です。)
sudo tee /etc/fail2ban/jail.local > /dev/null << 'EOF'
[DEFAULT]
backend = auto
maxretry = 3
findtime = 10m
bantime = 1h
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 7d
banaction = nftables
ignoreip = 127.0.0.1/8 ::1
[sshd]
enabled = true
backend = systemd
EOF特に問題なければ Fail2ban を再起動します。
sudo systemctl restart fail2ban「sudo fail2ban-client status」コマンドを実行すると現在のステータスが表示されます。
user01@DESKTOP-CQEA49P:~$ sudo fail2ban-client status
Status
|- Number of jail: 1
`- Jail list: sshd
user01@DESKTOP-CQEA49P:~$・WordPress へのログインを試みるアクセスを検知
WordPress へのログインを試みるアクセスを検知して遮断するように設定します。Apache のログファイル (/var/log/apache2/access.log) を見てみると、私の場合は以下のように記録されていました。(実際の IP アドレスはマスクしています。) 短時間に何回もログインを試みています。
xxx.xxx.xxx.xxx - - [01/Feb/2026:13:53:55 +0900] "GET /wp-login.php HTTP/1.1" 302 3419 "https://twitter.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.6045.159 Safari/537.36"
xxx.xxx.xxx.xxx - - [01/Feb/2026:13:53:56 +0900] "GET /blog/wp-login.php HTTP/1.1" 403 486 "https://twitter.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.6045.159 Safari/537.36"
xxx.xxx.xxx.xxx - - [01/Feb/2026:13:54:29 +0900] "POST /wp-login.php HTTP/1.1" 302 920 "https://mimura-soft.jp/wp-login.php" "Mozilla/5.0 (Windows NT 11.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.5993.88 Safari/537.36"
xxx.xxx.xxx.xxx - - [01/Feb/2026:13:54:30 +0900] "GET /blog/wp-login.php HTTP/1.1" 403 486 "https://mimura-soft.jp/wp-login.php" "Mozilla/5.0 (Windows NT 11.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.5993.88 Safari/537.36"
xxx.xxx.xxx.xxx - - [01/Feb/2026:13:54:30 +0900] "POST /wp-login.php HTTP/1.1" 302 920 "https://mimura-soft.jp/wp-login.php" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.2210.133"
xxx.xxx.xxx.xxx - - [01/Feb/2026:13:54:30 +0900] "GET /blog/wp-login.php HTTP/1.1" 403 486 "https://mimura-soft.jp/wp-login.php" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.2210.133"
xxx.xxx.xxx.xxx - - [01/Feb/2026:13:54:30 +0900] "POST /wp-login.php HTTP/1.1" 302 920 "https://mimura-soft.jp/wp-login.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.5993.88 Safari/537.36"
xxx.xxx.xxx.xxx - - [01/Feb/2026:13:54:31 +0900] "GET /blog/wp-login.php HTTP/1.1" 403 486 "https://mimura-soft.jp/wp-login.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.5993.88 Safari/537.36"
xxx.xxx.xxx.xxx - - [01/Feb/2026:13:54:31 +0900] "POST /wp-login.php HTTP/1.1" 302 920 "https://mimura-soft.jp/wp-login.php" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.130 Safari/537.36"
...このアクセスを検知するフィルターは標準では用意されていないようなので自分で作成します。
まず「/etc/fail2ban/filter.d/」フォルダ内に「wordpress-auth.conf」というファイルを作成して以下の内容を書き込みます。正規表現の中にある <HOST> は Fail2ban が内部的に展開する特別なマクロになっています。IPv4、IPv6、ホスト名などにマッチするようです。それ以降は GET または POST でログインが失敗 (403 Forbidden) した場合にマッチします。
[Definition]
failregex = ^<HOST> - - \[.*\] "(GET|POST) (?:/[^"]*)?wp-login\.php(?:\?.*)? HTTP/[^"]+" 403 .*
ignoreregex =「jail.local」ファイルに以下のセクションを追加します。セクション名は任意の名称が使用できます。
[wordpress-auth]
enabled = true
port = http,https
filter = wordpress-auth
logpath = /var/log/apache2/access.log
maxretry = 3
findtime = 10m
bantime = 24h各設定項目の意味は以下のようになっています。
| 設定項目 | 意味 |
|---|---|
| enabled | フィルターの有効化フラグ |
| port | 遮断対象ポート 数値またはプロトコル名 (小文字) で指定します。複数ある場合はカンマで区切ります。 ・http : 80 ・https : 443 ・smtp : 25 ・smtps : 465 ・submission : 587 など /etc/services 内にあるサービス名が使用できます。 |
| filter | 使用するフィルター名 (フォルダ名と拡張子を除いたもの) |
| logpath | 監視対象ログファイル名 |
それ以外は 10 分以内に 3 回失敗した IP アドレスを 24 時間 Ban するように設定しておきます。3 回目で Ban されます。
設定が完了したら「sudo fail2ban-client -t」と入力してエラーが無いか確認します。OK の場合は以下のように入力して正常に検知できるかチェックします。
sudo fail2ban-regex /var/log/apache2/access.log /etc/fail2ban/filter.d/wordpress-auth.conf実際のログファイルを使用して確認したところ以下のようになりました。155 件マッチしたようです。
user01@DESKTOP-CQEA49P:~$ sudo fail2ban-regex /var/log/apache2/access.log /etc/fail2ban/filter.d/wordpress-auth.conf
Running tests
=============
Use failregex filter file : wordpress-auth, basedir: /etc/fail2ban
Use log file : /var/log/apache2/access.log
Use encoding : UTF-8
Results
=======
Failregex: 155 total
|- #) [# of hits] regular expression
| 1) [155] ^<HOST> - - \[.*\] "(GET|POST) (?:/[^"]*)?wp-login\.php(?:\?.*)? HTTP/[^"]+" 403 .*
`-
Ignoreregex: 0 total
Date template hits:
|- [# of hits] date format
| [6295] Day(?P<_sep>[-/])MON(?P=_sep)ExYear[ :]?24hour:Minute:Second(?:\.Microseconds)?(?: Zone offset)?
`-
Lines: 6295 lines, 0 ignored, 155 matched, 6140 missed
[processed in 0.36 sec]
Missed line(s): too many to print. Use --print-all-missed to print all 6140 lines
user01@DESKTOP-CQEA49P:~$特に問題なければ Fail2ban を再起動します。
sudo systemctl restart fail2ban「sudo fail2ban-client status wordpress-auth」と入力すると現在の状態が表示されます。
user01@DESKTOP-CQEA49P:~$ sudo fail2ban-client status wordpress-auth
Status for the jail: wordpress-auth
|- Filter
| |- Currently failed: 0
| |- Total failed: 0
| `- File list: /var/log/apache2/access.log
`- Actions
|- Currently banned: 1
|- Total banned: 1
`- Banned IP list: xxx.xxx.xxx.xxx
user01@DESKTOP-CQEA49P:~$「sudo nft list table inet f2b-table」と入力すると現在のすべてのフィルターの状態が一覧表示されます。(まだ何も遮断されていない場合はエラーが表示されます)
user01@DESKTOP-CQEA49P:~$ sudo nft list table inet f2b-table
table inet f2b-table {
set addr-set-wordpress-auth {
type ipv4_addr
elements = { xxx.xxx.xxx.xxx }
}
chain f2b-chain {
type filter hook input priority filter - 1; policy accept;
tcp dport { 80, 443 } ip saddr @addr-set-wordpress-auth reject with icmp port-unreachable
}
}
user01@DESKTOP-CQEA49P:~$手動で Ban、Unban したい場合は以下のように入力します。
# 手動 Ban
sudo fail2ban-client set wordpress-auth banip xxx.xxx.xxx.xxx
# 解除
sudo fail2ban-client set wordpress-auth unbanip xxx.xxx.xxx.xxxWordPress のログイン検知ですが、ログインに失敗しても通常は 403 などのエラーコードは返りません。
xxx.xxx.xxx.xxx - - [01/Feb/2026:13:54:30 +0900] "GET /blog/wp-login.php HTTP/1.1" 403 486 "https://mimura-soft.jp/wp-login.php" "Mozilla/5.0 (Windows NT 11.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.5993.88 Safari/537.36"これはログインに失敗したからではなくて、Apache の .htaccess ファイルで管理用のファイルにアクセスできる IP を制限しているために 403 (Forbidden) エラーが返っています。
<FilesMatch "^(wp-config\.php|wp-cron\.php|xmlrpc\.php|wp-login\.php)">
order deny,allow
deny from all
allow from 127.0.0.1
allow from xxx.xxx.xxx.xxx
</FilesMatch>このような設定ができない環境の場合は、ログインの失敗をログファイルから判定するのは非常に困難です。(ログイン失敗でも 302 や 200 が返ってしまうため) WordPress のプラグインでログイン失敗時にアクセス制限できるものもありますが、簡単なプラグインを作成して Fail2ban で判定する方法を次にご紹介します。
・WordPress へのログイン試行を検知 (自作プラグイン使用)
まず WordPress のプラグインフォルダ 「wp-content/plugins/」フォルダ内に「my-fail2ban」フォルダを作成して、「my-fail2ban.php」というファイルを作成します。(任意の名称に変更できますが「wp-fail2ban」という名称はすでに公開されているプラグインがあるため使用できないようです。)
<wordpress>/
└─ wp-content/
└─ plugins/
└─ my-fail2ban/
└─ my-fail2ban.php「my-fail2ban.php」ファイルに以下の内容を記述して保存します。WordPress のログインが失敗した時に発生する「wp_login_failed」イベントをフックしてエラーログに記録するようになっています。
<?php
/*
Plugin Name: My Fail2ban
Author: <your name>
Description: Log WordPress login failures to syslog for fail2ban
Version: 1.0
*/
add_action('wp_login_failed', function ($username) {
$ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
$ua = $_SERVER['HTTP_USER_AGENT'] ?? 'unknown';
error_log("WP-LOGIN-FAIL user={$username} ip={$ip} ua={$ua}");
});ターミナル画面などでプラグインフォルダ (plugins) に移動してから、以下のコマンドで自作プラグインの所有者を変更します。
sudo chown -R www-data:www-data ./my-fail2banあとは WordPress で「My Fail2ban」プラグインを有効化しておきます。以降はログインに失敗するたびに「/var/log/apache2/error.log」ファイルに以下のような内容が記録されます。
[Mon Feb 23 10:49:04.192500 2026] [php:notice] [pid 425] [client 172.29.112.1:51660] WP-LOGIN-FAIL user=@yuuji_mimura ip=172.29.112.1 ua=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36, referer: http://mimura-soft.jp/blog/wp-login.php?loggedout=true&wp_lang=ja次に「/etc/fail2ban/filter.d/」フォルダ内に「wordpress-auth-hook.conf」というファイルを作成して以下の内容を書き込みます。
[Definition]
failregex = WP-LOGIN-FAIL user=.* ip=<HOST> .*
ignoreregex =「jail.local」ファイルに以下のセクションを追加します。セクション名は任意の名称が使用できます。
[wordpress-auth-hook]
enabled = true
port = http,https
filter = wordpress-auth-hook
logpath = /var/log/apache2/error.log
maxretry = 3
findtime = 10m
bantime = 24h作成が終了したら設定チェックを行い、さらにフィルターが実際にヒットするか確認します。
sudo fail2ban-client -t
sudo fail2ban-regex /var/log/apache2/error.log /etc/fail2ban/filter.d/wordpress-auth-hook.conf特に問題なければ Fail2ban を再起動しておきます。
sudo systemctl restart fail2ban実際にログインに失敗して「/var/log/fail2ban.log」というログファイルに以下のようなメッセージが表示されたら正常に動作しています。
2026-02-23 11:08:21,934 fail2ban.filter [2919]: INFO [wordpress-auth-hook] Found 172.29.112.1 - 2026-02-23 11:08:21・設定ミスを狙ったスキャンを検知
次に危険度が高そうなスキャンを検知します。ときどき以下のような「本物」のスキャンをされることがあります。長いので折りたたんで表示します。(IP アドレスはマスクしてあります。)
以下のような攻撃を試みています。
- .env 全バリエーションの読み取り
- docker-compose.yml
- application.yml / properties (Spring)
- appsettings.json (.NET)
- wp-config.php.*
- serverless.yml
- actuator/env
- proc/self/environ : 環境変数の読み取り
- @fs/… (Vite / Dev Server系)
- パストラバーサル など
まだどれも成功した形跡がないので早速フィルターを書きたいですが、その前に 1 つ問題があります。「.env」ファイルの読み取りで何かにリダイレクト (301) されています。おそらく WordPress の 404 ページが表示されていると思われますが、実際にサーバールート以下に「.env」ファイルなどがあった場合は、一回目のアクセスで情報を取得されてしまう可能性があります。ドットファイルなどは Web サーバー側で 403 または 404 を返すように修正しておいた方が安全です。
xxx.xxx.xxx.xxx - - [08/Feb/2026:09:46:43 +0900] "GET / HTTP/1.1" 200 73639 "-" "Mozilla/5.0"
xxx.xxx.xxx.xxx - - [08/Feb/2026:09:46:44 +0900] "GET /.env HTTP/1.1" 301 3278 "-" "Mozilla/5.0"
xxx.xxx.xxx.xxx - - [08/Feb/2026:09:46:45 +0900] "GET /.env.local HTTP/1.1" 301 3284 "-" "Mozilla/5.0"
xxx.xxx.xxx.xxx - - [08/Feb/2026:09:46:46 +0900] "GET /.env.production HTTP/1.1" 301 3288 "-" "Mozilla/5.0"
xxx.xxx.xxx.xxx - - [08/Feb/2026:09:46:47 +0900] "GET /.env.development HTTP/1.1" 301 3291 "-" "Mozilla/5.0"
xxx.xxx.xxx.xxx - - [08/Feb/2026:09:46:48 +0900] "GET /.env.dev HTTP/1.1" 301 3283 "-" "Mozilla/5.0"
xxx.xxx.xxx.xxx - - [08/Feb/2026:09:46:48 +0900] "GET /.env.prod HTTP/1.1" 301 3282 "-" "Mozilla/5.0"
...以降は Ubuntu 24.04 上の Apache2 を使用している前提でご説明します。他の環境でもおおまかな設定方法は同じと思われます。
まず「/etc/apache2/conf-available/」フォルダ内に「hardening-scans.conf」というファイルを作成して以下の設定を書き込みます。
# Block common secret files / bot scans early
<IfModule mod_rewrite.c>
RewriteEngine On
# Allow .well-known (Let's Encrypt etc.)
RewriteRule "^/\.well-known(/.*)?$" "-" [L]
# Block Vite/Dev Server abuse
RewriteRule "^/@fs(/|$)" "-" [F,L,NC]
# Block environ leak path
RewriteRule "proc/self/environ" "-" [F,L,NC]
# Block dotfiles and dot directories anywhere (/.env, /.git, /.aws, /.streamlit, etc.)
RewriteRule "(^|/)\." "-" [F,L]
# Block non-dot secret/config filenames often leaked accidentally
RewriteRule "(?i)(^|/)(docker-compose(\..*)?\.ya?ml|serverless\.ya?ml|secrets(\..*)?\.(json|ya?ml|toml)|credentials\.json|appsettings(\..*)?\.json|application(-.*)?\.(properties|ya?ml)|wp-config\.php(\..*)?)$" "-" [F,L]
# Block traversal-like encoded patterns
RewriteCond %{THE_REQUEST} "(?i)(\.\./|%2e%2e%2f|%2f\.\.|%252f)" [OR]
RewriteCond %{REQUEST_URI} "(?i)(\.\./|%2e%2e%2f|%2f\.\.|%252f)"
RewriteRule ".*" "-" [F,L]
</IfModule>rewrite モジュールが入っていない場合は有効化します。
sudo a2enmod rewrite作成した conf ファイルを有効化して Apache 再読込みします。
sudo a2enconf hardening-scans
sudo apachectl configtest
sudo systemctl reload apache2ブラウザーを起動して URL 欄に「<ホスト名>/.env」と入力するか、WSL2 などから以下のコマンドを実行して 403 または 404 が返ってきたら正常に設定されています。(自分のサーバーからも実行できます。)
curl -i http://<ホスト名>/.env
curl -i http://<ホスト名>/@fs/
curl -i http://<ホスト名>/proc/self/environ
curl -i "http://<ホスト名>/%2e%2e%2f"環境によっては (ローカル環境の WSL2 などでは) ブロックされないようなので、その場合は「hardening-scans.conf」ファイルを以下のように変更するとブロックされるようです。
# Block common secret files / bot scans early
# URLとして来る攻撃パスをブロック (静的 / WordPress / リバースプロキシ 全部に対応)
<LocationMatch "(?i)^/(?:@fs(?:/|$)|@vite(?:/|$)|vite-client$|proc/self/environ$)">
Require all denied
</LocationMatch>
# パストラバーサルをブロック
<LocationMatch "(?i)(?:\.\./|%2e%2e%2f|%2f\.\.|%252f)">
Require all denied
</LocationMatch>
#ファイル実体の漏えいをブロック (/var/www/html 配下のサブフォルダ内のファイルにも有効)
<Directory /var/www/html>
# dotfiles: .env, .git, .aws, ...
<FilesMatch "(?i)^\.(?!well-known$).+">
Require all denied
</FilesMatch>
# 狙われやすい設定ファイルへのアクセスをブロック
<FilesMatch "(?i)^(wp-config\.php(?:\..*)?|docker-compose(\..*)?\.ya?ml|compose\.ya?ml|serverless\.ya?ml|credentials\.json|appsettings(\..*)?\.json|application(-.*)?\.(properties|ya?ml|yaml)|secrets(\..*)?\.(json|ya?ml|yaml|toml))$">
Require all denied
</FilesMatch>
</Directory>
# Let's Encrypt などを使用している場合は .well-known を許可
<Directory "/var/www/html/.well-known">
Require all granted
</Directory>以上で Web サーバー側の設定は終了です。続いて Fail2ban 側の設定を行います。
「/etc/fail2ban/filter.d/」フォルダ内に「apache-envscan.conf」というファイルを作成して以下の内容を書き込みます。ドットファイルや設定ファイルに対して読み取りなどが失敗した (400、403、404 が返った) 場合にマッチします。
[Definition]
allowipv6 = auto
failregex = ^<HOST> .* "(GET|POST|HEAD) (?:https?://[^ ]+)?/(?:@fs(?:/|$)|.*proc/self/environ|.*\.env(?:[^ ]*)?|.*\.git|.*\.aws|.*\.streamlit|docker-compose(?:\..*)?\.ya?ml).*" (?:400|403|404) .*$
ignoreregex =「jail.local」ファイルに以下のセクションを追加します。セクション名は任意の名称が使用できます。危険なアクセスなので、24 時間以内に 1 回アクセスすると 1 週間 (7 日間) Ban します。その後に再度遮断されるたびに、2 週間 → 4 週間と伸びてゆき最終的には最大で 30 日間 Ban されます。
[apache-envscan]
enabled = true
port = http,https
filter = apache-envscan
logpath = /var/log/apache2/access.log
maxretry = 1
findtime = 24h
bantime = 7d
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 30d・メールサーバーへのブルートフォースを検知
このサイトではメールサーバーも運用しているので以下のようなアクセスもあります。
2026-02-08T00:00:12.443401+09:00 mimura-soft postfix/smtpd[17033]: warning: unknown[xxx.xxx.xxx.xxx]: SASL LOGIN authentication failed: (reason unavailable), sasl_username=thunder@mimura-soft.jp
2026-02-08T00:00:13.594634+09:00 mimura-soft postfix/smtpd[17033]: disconnect from unknown[xxx.xxx.xxx.xxx] ehlo=1 auth=0/1 rset=1 quit=1 commands=3/4
2026-02-08T00:00:29.857238+09:00 mimura-soft postfix/smtpd[17033]: connect from unknown[xxx.xxx.xxx.xxx]
2026-02-08T00:00:36.498676+09:00 mimura-soft postfix/smtpd[17033]: warning: unknown[xxx.xxx.xxx.xxx]: SASL LOGIN authentication failed: (reason unavailable), sasl_username=tiger@mimura-soft.jp
2026-02-08T00:00:37.556327+09:00 mimura-soft postfix/smtpd[17033]: disconnect from unknown[xxx.xxx.xxx.xxx] ehlo=1 auth=0/1 rset=1 quit=1 commands=3/4
2026-02-08T00:00:55.107838+09:00 mimura-soft postfix/smtpd[17237]: connect from unknown[xxx.xxx.xxx.xxx]
2026-02-08T00:01:01.121826+09:00 mimura-soft postfix/smtpd[17237]: warning: unknown[xxx.xxx.xxx.xxx]: SASL LOGIN authentication failed: (reason unavailable), sasl_username=tmbecker@mimura-soft.jp
2026-02-08T00:01:01.814733+09:00 mimura-soft postfix/smtpd[17237]: disconnect from unknown[xxx.xxx.xxx.xxx] ehlo=1 auth=0/1 rset=1 quit=1 commands=3/4
2026-02-08T00:01:20.852168+09:00 mimura-soft postfix/smtpd[17033]: connect from unknown[xxx.xxx.xxx.xxx]
2026-02-08T00:01:26.264459+09:00 mimura-soft postfix/smtpd[17033]: warning: unknown[xxx.xxx.xxx.xxx]: SASL LOGIN authentication failed: (reason unavailable), sasl_username=tmp@mimura-soft.jp
2026-02-08T00:01:27.561799+09:00 mimura-soft postfix/smtpd[17033]: disconnect from unknown[xxx.xxx.xxx.xxx] ehlo=1 auth=0/1 rset=1 quit=1 commands=3/4
2026-02-08T00:01:46.084281+09:00 mimura-soft postfix/smtpd[17237]: connect from unknown[xxx.xxx.xxx.xxx]
2026-02-08T00:01:52.016981+09:00 mimura-soft postfix/smtpd[17237]: warning: unknown[xxx.xxx.xxx.xxx]: SASL LOGIN authentication failed: (reason unavailable), sasl_username=tomcat4@mimura-soft.jp
2026-02-08T00:01:52.305199+09:00 mimura-soft postfix/smtpd[17237]: disconnect from unknown[xxx.xxx.xxx.xxx] ehlo=1 auth=0/1 rset=1 quit=1 commands=3/4
...典型的なメール認証ブルートフォースと思われますが、放置しておくとスパムメールの踏み台にされかねませんので、こちらのアクセスも検知できるように設定していきます。
メール送信に Postfix を使用する構成であれば、標準で「postfix」というフィルターが用意されていますのでこれを使用します。「jail.local」ファイルを開いて以下の設定を追加します。
[postfix]
enabled = true
port = smtp,submission,smtps
filter = postfix
logpath = /var/log/mail.log
maxretry = 2
findtime = 1h
bantime = 24hまた標準のフィルターでは「sasl_username=server」などのように、メールアドレス形式ではないユーザー名にマッチしないので「/etc/fail2ban/filter.d」フォルダ内に「postfix-sasl.conf」というファイルを作成して以下の内容を書き込みます。
[Definition]
failregex = ^.*warning: .*\[<HOST>\]: SASL (?:LOGIN|PLAIN) authentication failed:.*$
ignoreregex =「jail.local」ファイルに以下のセクションを追加します。
[postfix-sasl]
enabled = true
filter = postfix-sasl
logpath = /var/log/mail.log
maxretry = 2
findtime = 1h
bantime = 24hさらに通信手順を無視して直接バイナリデータを送り込んでくる以下のようなアクセスも多数ありましたので、追加のフィルターを作成します。
2026-02-08T11:27:52.614220+09:00 mimura-soft postfix/submission/smtpd[21771]: improper command pipelining after CONNECT from xxxx [xxx.xxx.xxx.xxx]: \026\003\001\000{\001\000\000w\003\003\344\027\261o\204ca\222~\353\306\026p\207\374H>N\361\032\330\226mAa&\301\366\2411\365r\000\000\032\300/\300+\300\021\300\a\300\023\300\t\300\024\300\n\000\005\000/\0005\300\022\000\n\001\000\0004\000\005\000\005\001\000\000\000\000\000\n\000\b\000\006\000\027\000\030\000\031\000\v\000
2026-02-08T11:27:52.614557+09:00 mimura-soft postfix/submission/smtpd[21771]: warning: non-SMTP command from xxxx [xxx.xxx.xxx.xxx]: \001\000\0004\000\005\000\005\001\000\000\000\000\000「/etc/fail2ban/filter.d」フォルダ内に「postfix-protocol.conf」というファイルを作成して以下の内容を書き込みます。failregex に 2 つ以上の条件がある場合は、いずれかの条件にマッチすると一致したとみなされます。
[Definition]
failregex =
^.* postfix/(?:submission/)?smtpd\[\d+\]: warning: non-SMTP command from \S*\[<HOST>\].*$
^.* postfix/(?:submission/)?smtpd\[\d+\]: improper command pipelining after CONNECT from \S*\[<HOST>\]:.*$
ignoreregex =「jail.local」ファイルに以下のセクションを追加します。
[postfix-protocol]
enabled = true
port = smtp,submission,smtps
filter = postfix-protocol
logpath = /var/log/mail.log
maxretry = 3
findtime = 1h
bantime = 24h・繰り返し Ban される IP アドレスがある場合 (recidive)
Fail2ban は設定されている「bantime」を過ぎると制限を解除 (Unban) します。しかし何度も同じ IP が Ban されるような場合は「recidive (レシディブ)」という特別なセクションを用意します。
通常の Ban 動作が Web やメールサーバーのログを監視しているのに対して、recidive は自分のログファイル (fail2ban.log) を監視します。他のログファイルを指定することも可能ですが、recidive のフィルタは 「Ban」を含む行を検知するのであまり意味がありません。
「jail.local」ファイルに以下のように記述すると有効になります。検知条件や bantime は自由に設定できます。用途を考えると少し長め (30d ~ 90d くらい) に設定しておいても良いかもしれません。
[recidive]
enabled = true
logpath = /var/log/fail2ban.log
maxretry = 2
findtime = 1d
bantime = 30d設定が完了したら Fail2ban をリロード (または再起動) します。
sudo fail2ban-client reloadFail2ban の主な機能のご説明はここで終了です。次のセクションからは UFW やメールサーバーの設定で、もう少し制限をかける方法を考察します。
UFW で不要なポートを閉じる
Fail2ban を使用すると動的にアクセス制限できましたが、「UFW」と呼ばれるファイアウォールを使用すると静的にアクセス制限をかけることが可能です。デフォルトですべてのポートを閉じて、使用するポートのみを開放または制限をかける方式で設定していきます。
まずはターミナル画面に以下のコマンドを入力してバージョンを確認します。
ufw --versionインストールされていない場合は、以下のコマンドを入力して UFW パッケージをインストールします。
sudo apt update
sudo apt install ufw次に以下のコマンドを入力して、デフォルトで外部からの接続をすべて拒否します。内側からの発信は許可します。(UFW を起動するまで設定は有効になりません。)
sudo ufw default deny incoming
sudo ufw default allow outgoingIPv6 を使用しない場合は「/etc/default/ufw」ファイルを開いて「IPV6=no」に設定します。
# Set to yes to apply rules to support IPv6 (no means only IPv6 on loopback
# accepted). You will need to 'disable' and then 'enable' the firewall for
# the changes to take affect.
IPV6=noSSH を使用している場合は以下のように設定します。アクセスできる IP アドレスを制限しない場合は、安全のためにこちらの記事などでご紹介している、公開鍵で認証する方法をおすすめします。
# すべてのアドレスに公開する場合
sudo ufw allow 22/tcp
# アクセスできる IP アドレスを指定する場合
sudo ufw allow from xxx.xxx.xxx.xxx to any port 22 proto tcp
# アクセスできる IP アドレスの範囲を指定する場合
sudo ufw allow from xxx.xxx.xxx.xxx/24 to any port 22 proto tcpあとは必要に応じて開放するポートを追加していきます。
# Web サーバー
sudo ufw allow 80/tcp # 必要に応じて
sudo ufw allow 443/tcp
# メールサーバー
sudo ufw allow 25/tcp # smtp (MTA 受信用)
sudo ufw allow 465/tcp # smtps (送信用)
sudo ufw allow 587/tcp # submission (送信用)
sudo ufw allow 993/tcp # imaps (受信用)
# など必要に応じてすべて設定したら以下のように入力して UFW を有効化します。(SSH を使用している場合は締め出されていないか確認するため、現在のターミナルを閉じる前に他のターミナルからも接続できるか確認してください。)
sudo ufw enable無効化するには以下のように入力します。
sudo ufw disable現在の状態を調べるには以下のように入力します。
sudo ufw status
# 番号付きで見たい場合は以下のように入力します
sudo ufw status numberedルールは最後尾に追加されていくため、任意の場所に追加したい場合は「insert」オプションを使用します。
# 先頭に追加したい場合
sudo ufw insert 1 allow 80/tcpルールを削除したい場合は以下のように入力します。
sudo ufw delete <ルール番号>余談ですが、このサイトでは管理やメールの送受信は固定 IP からしか行わないため、以下のような設定になっています。(SSL 経由で VPN 接続するように設定すれば、3 番目以降のルールも不要になります。)
root@mimura-soft:/# ufw status numbered
Status: active
To Action From
-- ------ ----
[ 1] 25/tcp ALLOW IN Anywhere
[ 2] 443/tcp ALLOW IN Anywhere
[ 3] 22/tcp ALLOW IN xxx.xxx.xxx.xxx
[ 4] 465/tcp ALLOW IN xxx.xxx.xxx.xxx
[ 5] 993/tcp ALLOW IN xxx.xxx.xxx.xxx
root@mimura-soft:/#メールサーバーの設定を変更する
自前でメールを受信するサーバーである以上 25 番ポートを塞ぐことは不可能なので、このポートのセキュリティについて考察していきます。
・25 番ポートの AUTH を停止する
実際にメールサーバーに Telnet などで接続すると、「250-AUTH」などと表示されることがあります。これはこのポートで認証 (ユーザー名とパスワードでログインする) 機能が有効であることを示しています。
user01@DESKTOP-CQEA49P:~$ telnet localhost 25
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 mail.mimura-soft.jp ESMTP
EHLO test
250-mail.mimura-soft.jp
250-PIPELINING
250-SIZE 10240000
250-ETRN
250-AUTH PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250-SMTPUTF8
250 CHUNKING
QUIT
221 2.0.0 Bye
Connection closed by foreign host.
user01@DESKTOP-CQEA49P:~$この機能が有効になっていると以下のようなアクセスが増える場合があります。
2026-02-23T05:56:21.419105+09:00 mimura-soft postfix/smtpd[61963]: connect from unknown[xxx.xxx.xxx.xxx]
2026-02-23T05:56:24.389950+09:00 mimura-soft postfix/smtpd[61963]: disconnect from unknown[xxx.xxx.xxx.xxx] ehlo=1 auth=0/1 rset=1 quit=1 commands=3/4
2026-02-23T05:56:51.159511+09:00 mimura-soft postfix/smtpd[61963]: connect from unknown[xxx.xxx.xxx.xxx]
2026-02-23T05:56:53.785480+09:00 mimura-soft postfix/smtpd[61963]: disconnect from unknown[xxx.xxx.xxx.xxx] ehlo=1 auth=0/1 rset=1 quit=1 commands=3/4
2026-02-23T05:57:17.946607+09:00 mimura-soft postfix/smtpd[61963]: connect from unknown[xxx.xxx.xxx.xxx]
2026-02-23T05:57:20.962418+09:00 mimura-soft postfix/smtpd[61963]: disconnect from unknown[xxx.xxx.xxx.xxx] ehlo=1 auth=0/1 rset=1 quit=1 commands=3/4
2026-02-23T05:57:44.731129+09:00 mimura-soft postfix/smtpd[61963]: connect from unknown[xxx.xxx.xxx.xxx]
2026-02-23T05:57:48.503407+09:00 mimura-soft postfix/smtpd[61963]: disconnect from unknown[xxx.xxx.xxx.xxx] ehlo=1 auth=0/1 rset=1 quit=1 commands=3/4
2026-02-23T05:58:12.698825+09:00 mimura-soft postfix/smtpd[61963]: connect from unknown[xxx.xxx.xxx.xxx]
2026-02-23T05:58:15.407663+09:00 mimura-soft postfix/smtpd[61963]: disconnect from unknown[xxx.xxx.xxx.xxx] ehlo=1 auth=0/1 rset=1 quit=1 commands=3/4
2026-02-23T05:58:39.791862+09:00 mimura-soft postfix/smtpd[61963]: connect from unknown[xxx.xxx.xxx.xxx]
2026-02-23T05:58:42.506298+09:00 mimura-soft postfix/smtpd[61963]: disconnect from unknown[xxx.xxx.xxx.xxx] ehlo=1 auth=0/1 rset=1 quit=1 commands=3/4
...仮にこの認証を突破されると、そのセッションで任意のメールが転送可能になります。直ちに危険ではありません (他の送信用ポートも危険度は同じです) が、適切に設定されているメールサーバーであればオープンリレーなどは出来ないようになっていると思われますので、不要な攻撃の糸口を塞ぐためにこの機能を停止します。
Postfix + Dovecot + SASL という構成を前提にしてご説明します。
まず初めにオープンリレーになっていないか確認します。「/etc/postfix/main.cf」というファイルを開いて「smtpd_recipient_restrictions」項目に「reject_unauth_destination」という設定があればリレーされません。(設定が他の場所で上書きされていない場合)
smtpd_recipient_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_unauth_destination実際に確認したい場合は、「telnet <ホスト名> 25」などと外部から接続して、以下の順番で入力します。
- EHLO test
- MAIL FROM:<test@example.com>
- RCPT TO:<someone@gmail.com>
- QUIT と入力して終了します。
554 5.7.1 <someone@gmail.com>: Relay access denied などの応答が返ってくれば中継されていません。(WSL2 の場合は 454 で返ってくるようです。)
220 mail.mimura-soft.jp ESMTP
EHLO test
250-mail.mimura-soft.jp
250-PIPELINING
250-SIZE 10240000
250-ETRN
250-AUTH PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250-SMTPUTF8
250 CHUNKING
MAIL FROM:<test@example.com>
250 2.1.0 Ok
RCPT TO:<someone@gmail.com>
454 4.7.1 <someone@gmail.com>: Relay access denied次に AUTH 機能を停止します。「/etc/postfix/master.cf」というファイルを開いて smtp 設定の 13 行目辺りに以下の設定を追加します。
# ==========================================================================
# service type private unpriv chroot wakeup maxproc command + args
# (yes) (yes) (no) (never) (100)
# ==========================================================================
smtp inet n - y - - smtpd
-o smtpd_sasl_auth_enable=no
#smtp inet n - y - 1 postscreen
#smtpd pass - - y - - smtpd
#dnsblog unix - - y - 0 dnsblog
#tlsproxy unix - - y - 0 tlsproxy設定が完了したらメールサーバーの設定を更新します。
sudo postfix reload設定が反映されたか確認します。Telnet などでメールサーバーにログインして、「EHLO test」などと入力すると使用可能な機能や情報が表示されますので、「250-AUTH」項目がない事を確認します。「QUIT」と入力すると終了します。
user01@DESKTOP-CQEA49P:~$ telnet localhost 25
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 mail.mimura-soft.jp ESMTP
EHLO test
250-mail.mimura-soft.jp
250-PIPELINING
250-SIZE 10240000
250-ETRN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250-SMTPUTF8
250 CHUNKING
QUIT
221 2.0.0 Bye
Connection closed by foreign host.
user01@DESKTOP-CQEA49P:~$・Postscreen と DNSBL (RBL) を有効化する
Postfix には「Postscreen」という接続前フィルターが組み込まれています。この機能を有効化すると、メールサーバーに接続するスパムメールなどのあやしい接続をセッションが開始する前に切断してくれます。同様に DNSBL (DNS-based Blackhole List) と呼ばれる仕組みを使用すると、接続してきた IP アドレスを外部の専用サイトに DNS 形式で問い合わせて、ブラック度合いのスコアを取得します。取得されたスコアが設定した基準値を越えた場合はセッションを切断します。どちらも有効化する設定はそれほど難しくありません。
設定を有効化するには「/etc/postfix/master.cf」というファイルを開いて smtp 設定の 14 ~ 18 行目辺りのコメントをはずして以下のように設定します。AUTH 機能をオフにする設定「smtpd_sasl_auth_enable=no」も smtpd の下に追加します。元々あった smtp 設定 (12 と 13 行目) はコメントアウトします。
# ==========================================================================
# service type private unpriv chroot wakeup maxproc command + args
# (yes) (yes) (no) (never) (100)
# ==========================================================================
#smtp inet n - y - - smtpd
# -o smtpd_sasl_auth_enable=no
smtp inet n - y - 1 postscreen
smtpd pass - - y - - smtpd
-o smtpd_sasl_auth_enable=no
dnsblog unix - - y - 0 dnsblog
tlsproxy unix - - y - 0 tlsproxy次に「/etc/postfix/main.cf」ファイルを開いて、ファイルの最後に以下の設定を追加します。
# --- postscreen hardening (safe baseline) ---
postscreen_greet_action = enforce
postscreen_greet_wait = 6s
postscreen_pipelining_action = enforce
postscreen_non_smtp_command_action = enforce
postscreen_bare_newline_action = enforce
postscreen_cache_map = btree:/var/lib/postfix/postscreen_cache
postscreen_cache_retention_time = 7d
# --- DNSBL (optional but very effective) ---
postscreen_dnsbl_action = enforce
postscreen_dnsbl_sites =
zen.spamhaus.org=127.0.0.[2..11]*3
bl.spamcop.net=127.0.0.2*2
postscreen_dnsbl_threshold = 3設定が完了したらメールサーバーの設定を更新または再起動します。
# 更新
sudo postfix reload
# 再起動
sudo systemctl restart postfix実際のログを見てみると設定通りに動作しているようです。
2026-02-23T16:55:31.708828+09:00 mimura-soft postfix/postscreen[68523]: CONNECT from [xxx.xxx.xxx.xxx]:36690 to [153.126.131.65]:25
2026-02-23T16:55:31.999334+09:00 mimura-soft postfix/postscreen[68523]: PREGREET 11 after 0.29 from [xxx.xxx.xxx.xxx]:36690: EHLO User\r\n
2026-02-23T16:55:32.041153+09:00 mimura-soft postfix/smtpd[68524]: connect from unknown[xxx.xxx.xxx.xxx]
2026-02-23T16:55:32.335457+09:00 mimura-soft postfix/smtpd[68524]: disconnect from unknown[xxx.xxx.xxx.xxx] ehlo=1 quit=1 commands=2
2026-02-23T16:55:58.639234+09:00 mimura-soft postfix/postscreen[68523]: CONNECT from [xxx.xxx.xxx.xxx]:44170 to [153.126.131.65]:25
2026-02-23T16:55:58.928043+09:00 mimura-soft postfix/postscreen[68523]: PREGREET 11 after 0.29 from [xxx.xxx.xxx.xxx]:44170: EHLO User\r\n
2026-02-23T16:55:58.929398+09:00 mimura-soft postfix/smtpd[68524]: connect from unknown[xxx.xxx.xxx.xxx]
2026-02-23T16:55:59.326516+09:00 mimura-soft postfix/smtpd[68524]: disconnect from unknown[xxx.xxx.xxx.xxx] ehlo=1 quit=1 commands=2
2026-02-23T16:56:25.059487+09:00 mimura-soft postfix/postscreen[68523]: CONNECT from [xxx.xxx.xxx.xxx]:51454 to [153.126.131.65]:25
2026-02-23T16:56:25.349104+09:00 mimura-soft postfix/postscreen[68523]: PREGREET 11 after 0.29 from [xxx.xxx.xxx.xxx]:51454: EHLO User\r\n
2026-02-23T16:56:25.350193+09:00 mimura-soft postfix/smtpd[68524]: connect from unknown[xxx.xxx.xxx.xxx]
2026-02-23T16:56:25.789270+09:00 mimura-soft postfix/smtpd[68524]: disconnect from unknown[xxx.xxx.xxx.xxx] ehlo=1 quit=1 commands=2
2026-02-23T16:56:52.042468+09:00 mimura-soft postfix/postscreen[68523]: CONNECT from [xxx.xxx.xxx.xxx]:58582 to [153.126.131.65]:25
2026-02-23T16:56:52.332820+09:00 mimura-soft postfix/postscreen[68523]: PREGREET 11 after 0.29 from [xxx.xxx.xxx.xxx]:58582: EHLO User\r\n
2026-02-23T16:56:52.333892+09:00 mimura-soft postfix/smtpd[68524]: connect from unknown[xxx.xxx.xxx.xxx]
2026-02-23T16:56:52.750680+09:00 mimura-soft postfix/smtpd[68524]: disconnect from unknown[xxx.xxx.xxx.xxx] ehlo=1 quit=1 commands=2
2026-02-23T16:57:19.065611+09:00 mimura-soft postfix/postscreen[68523]: CONNECT from [xxx.xxx.xxx.xxx]:37512 to [153.126.131.65]:25
2026-02-23T16:57:19.757749+09:00 mimura-soft postfix/postscreen[68523]: PREGREET 11 after 0.69 from [xxx.xxx.xxx.xxx]:37512: EHLO User\r\n
...ただこの機能はセッションを切断してくれますが、IP 接続そのものを遮断する訳ではないのでログファイルには延々と切断されたログが記録されます。
そこで Fail2ban と連携して、メールサーバーの通信ログに切断情報が記録されたら IP アドレスを Ban するように設定します。
まず「/etc/fail2ban/filter.d/」フォルダ内に「postfix-postscreen.conf」というファイルを作成して以下の内容を書き込みます。
[Definition]
failregex =
^.*\spostfix/postscreen\[\d+\]:\s+PREGREET\s+\d+\s+after\s+[0-9.]+\s+from\s+\[<HOST>\](?::\d+)?:
^.*\spostfix/postscreen\[\d+\]:\s+HANGUP\s+after\s+\d+\s+from\s+\[<HOST>\](?::\d+)?
^.*\spostfix/postscreen\[\d+\]:\s+DNSBL\s+rank\s+\d+\s+for\s+\[<HOST>\]:
^.*\spostfix/postscreen\[\d+\]:\s+(?:NON-SMTP command|BARE NEWLINE|COMMAND PIPELINING)\s+from\s+\[<HOST>\](?::\d+)?
ignoreregex =「jail.local」ファイルに以下のセクションを追加します。セクション名は任意の名称が使用できます。
[postfix-postscreen]
enabled = true
port = smtp
filter = postfix-postscreen
logpath = /var/log/mail.log
maxretry = 2
findtime = 2h
bantime = 24h設定が完了したら Fail2ban をリロード (または再起動) します。
sudo fail2ban-client reload以上で設定は完了です。実際にそれぞれの遮断を開始すると攻撃パターンもどんどん変化していきますので、ログなどを見ながら新しいフィルターを追加する必要が出てくるかもしれません。
まとめ
今回は Fail2ban というセキュリティツールの設定方法についてご説明しました。
それ以外にも
- Web サーバー設定
- メールサーバー側でのブロック
- ファイアウォール
などとの連携方法についても考察しました。
Fail2ban は単体でも非常に強力なツールですが、他の機能を組み合わせることによりさらに強固なセキュリティ機能を構築することが可能です。
以上です。







