2026年7月6日
2026年7月6日
ClamAVでメールのウイルスチェックをする方法(clamav-milterでPostfixと連携)
自分で運用しているPostfixのメールサーバーで、届いたメールの添付ファイルをウイルス検査するには、ClamAVの常駐プロセス(clamd)とclamav-milterを入れ、Postfixのmilterとして登録する方法が手軽です。この記事では、Ubuntu/Debianを例に、インストール、定義ファイルの自動更新、clamav-milterの設定、Postfixとの連携、テスト用ファイルでの動作確認、運用上の注意までを説明します。ウイルスを含むメールは受信の段階で拒否できるため、利用者の受信箱に届く前に止められます。
構成と、先に知っておくこと
ClamAVは、オープンソースのウイルス検査エンジンです。メールの検査では、次の3つが連携して動きます。
- clamd: ウイルス定義を読み込んで常駐し、検査を受け持つプロセス。
- freshclam: ウイルス定義(シグネチャ)を定期的に取得して更新するプロセス。
- clamav-milter: Postfixから受け取ったメールをclamdに渡し、結果に応じて受信を許可・拒否する橋渡し役。
始める前に、次の点を把握しておきます。
- メモリ: clamdはウイルス定義をメモリに読み込むため、1GB以上の空きメモリを見込んでおくと安心です。定義を更新して読み込み直す間は、一時的にさらに多くのメモリを使います。小さなVPSでは、ほかのサービスとのメモリの取り合いになっていないかを最初に確かめます。
- 検出できる範囲: ClamAVは既知のマルウェアの検出が中心で、出回り始めたばかりのものや、巧妙なフィッシングメールまでは防げません。ウイルス検査は対策の一部と考え、迷惑メール対策や、危険な種類の添付ファイルの制限と組み合わせます。
- 作業前のバックアップ:
/etc/postfix/と/etc/clamav/の設定をコピーしておきます。milterの設定を誤るとメールの受信が止まることがあるため、利用者の少ない時間帯に作業します。
インストールと定義ファイルの更新
sudo apt update
sudo apt install clamav-daemon clamav-freshclam clamav-milter
sudo systemctl status clamav-freshclam
インストール直後は、freshclamが最初のウイルス定義をダウンロードするまでclamdが起動できないことがあります。/var/lib/clamav/ に定義ファイル(main.cvd、daily.cvd など)ができたことを確かめてから、clamdを起動します。
ls -lh /var/lib/clamav/
sudo systemctl enable --now clamav-daemon
sudo systemctl status clamav-daemon
freshclamはサービスとして常駐し、一定間隔で定義を更新します。注意したいのは、手動の freshclam の実行やcronでの短い間隔の更新を重ねないことです。ClamAVの配布元は、短時間に繰り返しアクセスする利用者を一時的に遮断することがあり、そうなると定義が更新されなくなります。ログ(/var/log/clamav/freshclam.log や journalctl -u clamav-freshclam)で、更新が成功しているかを定期的に見ます。
clamav-milterを設定する
/etc/clamav/clamav-milter.conf の主な項目を次のようにします。既存の行がある場合は書き換えます。
MilterSocket inet:7357@127.0.0.1
ClamdSocket unix:/var/run/clamav/clamd.ctl
OnClean Accept
OnInfected Reject
OnFail Defer
RejectMsg Message rejected: virus detected (%v)
AddHeader Replace
LogSyslog true
LogInfected Basic
MilterSocket inet:7357@127.0.0.1は、Postfixとローカルの7357番ポートで通信する指定です。Unixソケットも使えますが、Postfixのchroot環境から参照できる場所と権限を合わせる手間があるため、ここではローカルのTCPにしています。ClamdSocketは、clamdの待ち受け先です。/etc/clamav/clamd.confのLocalSocketの値と一致させます。OnInfected Rejectは、ウイルスが見つかったメールを受信の段階で拒否する指定です。送信元のサーバーにエラーが返るため、受け取ってから捨てる方法と違い、こちらから無関係な相手にエラーメールを送ってしまうことがありません。OnFail Deferは、clamdが応答しないなど検査できなかったときに、一時エラーを返して送信元に再送してもらう指定です。Acceptにすると、clamdが止まっている間は検査なしでメールが届きます。どちらを優先するかは運用方針で決めます。AddHeader Replaceは、検査したメールに結果のヘッダー(X-Virus-Scannedなど)を付け、外部から付けられた同名のヘッダーは置き換える指定です。RejectMsgの%vには、検出されたウイルス名が入ります。
OnInfected には、拒否せずにPostfixの保留キュー(hold queue)に移す Quarantine もあります。誤検知が心配な場合は、最初は Quarantine にして保留されたメールの内容を確かめ、問題がないと分かってから Reject に切り替える方法も取れます。保留されたメールは postqueue -p で一覧でき、postsuper -H で保留を解除、postsuper -d で削除できます。
sudo systemctl restart clamav-milter
sudo ss -ltnp | grep 7357
待ち受けが 127.0.0.1:7357 になっていることを確認します。
Postfixにmilterを登録する
sudo postconf -e 'milter_default_action = tempfail'
sudo postconf -e 'smtpd_milters = inet:127.0.0.1:7357'
sudo systemctl reload postfix
OpenDKIMなどほかのmilterをすでに使っている場合は、既存の値を消さずにカンマ区切りで追加します。
postconf smtpd_milters
sudo postconf -e 'smtpd_milters = inet:localhost:8891, inet:127.0.0.1:7357'
milter_default_action は、Postfixがmilterに接続できないときの動作で、すべてのmilterに共通です。tempfail はメールを一時エラーにして再送を待ち、accept は検査や署名を飛ばして通します。OpenDKIMの記事などで accept にしている場合は、ウイルス検査を通さずに受信してしまう可能性とのどちらを取るかを考えて決めます。
ここでは smtpd_milters だけに登録しています。外部から届くメールの検査が目的なので、サーバー内のWordPressが sendmail 経由で送るメール(non_smtpd_milters の対象)まで検査する必要は通常ありません。
テスト用ファイルで動作を確かめる
EICARテストファイルは、ウイルス対策ソフトの動作確認のために作られた無害な文字列で、多くの検査エンジンが検出対象として扱います。まず、clamd単体で検出できるかを確かめます。
printf '%s' 'X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*' > /tmp/eicar.com.txt
clamdscan --fdpass /tmp/eicar.com.txt
結果にEICARを示すシグネチャ名と FOUND が出れば、clamdは動いています。--fdpass は、ファイルを開く権限をclamdに渡す指定です。Ubuntuでは、AppArmorによってclamdが読めるディレクトリが制限されているため、これを付けないと権限エラーになることがあります。
次に、メール経由で確かめます。このファイルを添付したメールを、外部のアドレスから自分のサーバー宛てに送ります。大手のメールサービスは送信時点でEICARを含む添付を止めることがあるため、別のサーバーからswaksなどのテストツールで送ると確かめやすくなります(swaksの添付の指定方法は版によって違うため、swaks --help で確認します)。
成功していれば、送信側にはエラーが返り、受信サーバーの /var/log/mail.log に次のような記録が残ります(細部は版によって異なります)。
postfix/cleanup[...]: ...: milter-reject: END-OF-MESSAGE from ...: 5.7.1 Message rejected: virus detected (検出名)
通常のメールが届いたときは、ヘッダーに X-Virus-Scanned と X-Virus-Status: Clean が付いていることも確認します。
うまくいかないときの確認順
- メールがすべて一時エラーで届かない: Postfixがclamav-milterに接続できていないか、clamav-milterがclamdに接続できていません。
mail.logにconnect to Milter service ... Connection refusedが出ていないか、systemctl status clamav-milter clamav-daemonで両方が動いているかを確認します。 - clamdが起動しない、または途中で止まる: 定義ファイルがまだない、またはメモリ不足が多い原因です。
journalctl -u clamav-daemonと、dmesgにOOM Killerの記録がないかを見ます。メモリが足りない場合は、clamd.confのConcurrentDatabaseReload noで、定義の読み込み直しのときに新旧を同時にメモリに置かないようにできます(その間は検査が止まります)。 - 大きな添付が検査されない: clamdとclamav-milterには、検査するファイルの大きさの上限(
MaxFileSize、StreamMaxLengthなど)があり、上限を超えたものは検査されずに通ることがあります。上限を上げるとメモリと処理時間が増えるため、受け付けるメールの大きさ(Postfixのmessage_size_limit)とあわせて決めます。 - 定義が古いまま:
freshclam.logで更新の失敗や、配布元からの一時的な遮断の記録がないかを見ます。
あわせて設定したいこと
- 危険な拡張子の添付を拒否する: 実行ファイルなど、通常のやり取りで使わない種類の添付は、Postfixの
mime_header_checksで拡張子を見て拒否できます。ClamAVの検出に頼らずに防げる範囲が広がります。 - 迷惑メール対策との組み合わせ: ClamAVはフィッシングの検出が得意ではないため、SpamAssassinやRspamdで迷惑メールの判定も行います。
- 監視: clamdとfreshclamが止まっていないか、定義の更新日時が古くなっていないかを監視の対象に入れます。
ClamAVは1.x系が配布されており、長期サポート版とそれ以外の版でサポート期間が違います。ディストリビューションのパッケージがどの版かを clamd --version で確認し、サポートが終わった版を使い続けないようにします(2026年10月現在)。
まとめ
- clamdが検査し、freshclamが定義を更新し、clamav-milterがPostfixとの橋渡しをします。
- freshclamの更新を短い間隔で重ねると、配布元に一時遮断されることがあります。ログで更新の成否を確認します。
OnInfected Rejectで、ウイルスを含むメールを受信の段階で拒否できます。不安なときはQuarantineから始めます。milter_default_actionとOnFailで、検査できないときに「止める」か「通す」かを決めます。- EICARテストファイルで、clamd単体とメール経由の両方を確かめます。