Active DirectoryサーバをLDAPサーバとして使っている場合、2026年10月のWindows Updateで接続できなくなる可能性

php2shellのパッチをダウンロードするためにONTAPのダウンロードページにアクセスしたら、phpに関する警告の他に、下記の警告も出ていた

AD-LDAP Authentication Errors After Microsoft October 2026 DC Patch Updates
Microsoft October 2026 domain controller (DCs) patches may affect AD-LDAP authentication requests from ONTAP to DCs resulting in protocol outrages or login disruptions. See SU628 for more details.

Active DirectoryサーバをLDAPサーバとして利用している場合、2026年10月のWindows Updateにより、平文のLDAPアクセスが禁止され、署名ありのLDAPアクセスもしくはLDAPSアクセスが必須となる、という話だった

具体的なWindows Server側のパッチ
 Windows Server 2025 KB5126646
 Windows Server 2022 KB5126655
 Windows Server 2019 KB5126651
 Windows Server 2016 KB5126868

基本的に、Windows Server側に適用されたセキュリティ強化設定を解除することはできない

Windows Server側のLDAP接続に関するドキュメント「Active Directory Domain ServicesのLDAPチャネルバインディング概要」と「Active Directory Domain Services における LDAP 署名の概要」

NetApp側のドキュメント「2026年10月 ドメイン コントローラ更新後のLDAP無効な認証情報 FAQ」(英語版)

まずはLDAPSでアクセスするための「Active Directory Domain Services で SSL 経由で LDAP の証明書を構成する」で、署名などで使用する証明書を用意する

この設定については過去に「Windows Server 2025で作ったActive Directory環境でldapsを使えるようにする」でRHEL からopensslコマンドとldapsearchコマンドを使って確認する方法と共に記載している

次に「Active Directory Domain Services のグループポリシーを使ってLDAP署名を設定する」でクライアントからのアクセス時にLDAP署名を強制する設定を行う、と


クライアントからアクセスする時に確認するべき点のメモ

アクセステスト内容署名不要のDC署名必須のDC
LDAP(389) + Simple bind成功失敗(Strong Auth Required / LDAPエラー8)
LDAP(389) + SASL(署名)成功成功
LDAPS(636)+ Simple bind証明書があれば成功証明書があれば成功

ldapsearch コマンドで挙動を確認する手法のメモ

① 署名必須かどうか(LDAP+Simple bind)

確認コマンド

ldapsearch -x -H ldap://dc01.example.local \
  -D "user@example.local" -W \
  -b "dc=example,dc=local" -s base "(objectClass=*)" dn

署名必須の場合、下記の様なエラー

ldap_bind: Strong(er) authentication required (8)
  additional info: 00002028: LdapErr: DSID-0C09xxxx, The server requires binds to turn on integrity checking if SSL\TLS are not already active on the connection

② LDAP+SASL(Kerberos)+署名での接続

確認コマンド

kinit user@EXAMPLE.LOCAL
ldapsearch -Y GSSAPI -H ldap://dc01.example.local -b "dc=example,dc=local" -s base dn

# 署名なしを強制して失敗するか確認(失敗すれば署名必須)
ldapsearch -Y GSSAPI -O "minssf=0,maxssf=0" -H ldap://dc01.example.local -b "dc=example,dc=local" -s base dn

③ LDAPSでのテスト

確認コマンド

# 証明書・TLSバージョンの確認
openssl s_client -connect dc01.example.local:636 -showcerts </dev/null

# LDAPSでbind
LDAPTLS_CACERT=/path/to/ca.pem \
ldapsearch -x -H ldaps://dc01.example.local \
  -D "user@example.local" -W -b "dc=example,dc=local" -s base dn

# StartTLS(389)
ldapsearch -x -ZZ -H ldap://dc01.example.local -D "user@example.local" -W -b "dc=example,dc=local" -s base dn

自己署名環境の場合、「LDAPTLS_REQCERT=never」を設定することで証明書検証を省略できる

LDAPS上でGSSAPIを使う場合、ADはTLS上のsign/sealを拒否するため「-O maxssf=0」オプションの追加、もしくは ldap.conf に「SASL_SECPROPS maxssf=0」を設定する

Windows環境で確認するためのメモ

PowerShellの場合

Add-Type -AssemblyName System.DirectoryServices.Protocols
$cred = Get-Credential   # user@example.local

# 389 + Simple bind(署名必須なら例外)
$c = New-Object System.DirectoryServices.Protocols.LdapConnection("dc01.example.local:389")
$c.SessionOptions.ProtocolVersion = 3
$c.AuthType = [System.DirectoryServices.Protocols.AuthType]::Basic
try { $c.Bind($cred.GetNetworkCredential()); "389 Simple bind: 成功(署名不要)" }
catch { "389 Simple bind: 失敗 -> $($_.Exception.InnerException.Message)" }

# 636 LDAPS
$s = New-Object System.DirectoryServices.Protocols.LdapConnection("dc01.example.local:636")
$s.SessionOptions.ProtocolVersion = 3
$s.SessionOptions.SecureSocketLayer = $true
$s.AuthType = [System.DirectoryServices.Protocols.AuthType]::Basic
try { $s.Bind($cred.GetNetworkCredential()); "LDAPS: 成功" }
catch { "LDAPS: 失敗 -> $($_.Exception.InnerException.Message)" }

Test-NetConnection dc01 -Port 636 はTCP疎通しか見ないため、TLSが成立するかの確認には上記のbindテストを使う

また、クライアント側でレジストリが設定されているか確認

Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Services\LDAP -Name LDAPClientIntegrity
# 0=なし, 1=ネゴシエート(既定), 2=必須

Active Directoryサーバ側で確認する手法

レジストリ「HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Parameters」を確認

LDAPServerIntegrity が「1」は署名無し、「2」は署名必須

LdapEnforceChannelBinding が「0」無効、「1」サポートしてるなら使う、「2」必須

GPOでの設定項目「ドメイン コントローラー: LDAP サーバー署名必須」

イベントログでの確認

Directory Serviceのイベントログに出てくるイベントID

2886/2887:署名なしbindの存在・件数の警告

2889:署名なしbindを行ったクライアントIPとアカウント(「16 LDAP Interface Events」の診断ログを2に設定して出力)

3039~3041:チャネルバインディング関連

SPAM対応メモ 2026/06/24

メールサーバに新しいメールが入ってこない、というので調査したら、特定ユーザのメールパスワードがばれていてSPAM送信に使われていたという時のメモ

(1) 落ちてるデーモンはいなかった

systemctl --failed

を実行した際に止まっているものはいなかった

(2) メールのキューに異常

postfixのメールキューの状態を確認

# postqueue -p

数万通のメールが滞留していた

差出人はほぼ1ユーザで、宛先は方々にわたる

(3) メール配送停止

ひとまず、postfixのメール配送処理を止める

# postfix abort

(4) ログ確認

/var/log/messagesと/var/log/maillog に対して そのユーザ名でgrepをかけて確認

roudcubeのログにて、roundcube内から多数のメールアドレスを指定してメール送信していることを確認

(5) アクセス者IPアドレス確認

ログから該当する操作のIPアドレスを確認し、そのアドレスがどこなのかを確認

今回は3IPアドレスからきており、どれも海外

(6) あからさまにSPAMを削除

今回特定の時間帯の送信は全部SPAMっぽかったので以下のコマンドで該当ユーザのメールをpostsuper -d queueIDで削除

# for queid in `postqueue -p|grep "Jun 24 04"  |grep ユーザ名|awk '{ print $1 }' | sed s/\*//ig`; do postsuper -d $queid; done

あと、MAILER-DAEMON関連の返送処理も削除

# for queid in `postqueue -p|grep MAILER|awk '{ print $1 }' | sed s/\*//ig`; do postsuper -d $queid; done

(7) とりあえず再開


2026/07/21追記

外部への影響報告

gmailサーバでのメール受信拒否

gmailサーバからメールの受け取り拒否を食らっていました
 https://support.google.com/a/answer/172179

期間は2026/06/23 23:02~2026/07/19ぐらい?(2026/07/21 09:00には問題なかった)

SPFやDMARCなどの設定は正確に実施されているにもかかわらず、gmail側は設定に不備があるから拒否、と言い張る状態でした。

おそらくIPアドレスが同じ場合は、約30日経過しないと許可しないようです・・・

各SPAMレポートサーバでの登録

いくつかのサービスで登録はされましたが、3日程度で削除されていました。

spamcop
GBUdb.com
junkmailfilter.com
https://www.zedsd.net/blacklist.php

2日程度のメール受信拒否を食らったところ

2日程度でSPAM扱いでメール受信拒否を食らったメッセージが帰ってきたところはこんな感じです

意外だったのは、outlook.com 系から受信拒否を食らってなかったことです

hostingシステム系からのエラー
・https://abuse.vadesecure.com/
・https://www.strato-hosting.co.uk/faq/product/why-are-my-emails-not-being-delivered

Apple icloud.comからのエラー
 https://support.apple.com/en-us/102322

postfixのvirtual_transport=dovecot指定時にもvirtual_mailbox_mapsを指定したほうが良い件

postfix/dovecotのメールサーバで、実ドメイン以外のドメインのメールも受け取るようpostfix側にvirtual mailbox domainsの設定を行うことがある

その際、dovecotによるquota制御を行いたい。

その場合の手法は2種類ある。
 ・dovecotドキュメント「Dovecot LDA with Postfix」の「virtual_transport = dovecot」を設定して”Virtual users”にある設定を行う手法
 ・dovecotドキュメント「Postfix and Dovecot LMTP」の「virtual_transport = lmtp:unix:private/dovecot-lmtp」を設定してLMTPを使う手法

LMTPの方は「Dovecot LDAのdeliverでは動作しません」と書いてあるため、dovecot のquotaを使うためにdovecot ldaを使用する場合には使えなさそう。

このため、まずは「virtual_transport = dovecot」の手法を実装

postfixの/etc/postfix/main.cf には以下の設定

dovecot_destination_recipient_limit = 1
virtual_mailbox_domains = your.domain.here
virtual_transport = dovecot

postfixの/etc/postfix/master.cf には以下の設定

dovecot   unix  -       n       n       -       -       pipe
  flags=DRhu user=vmail:vmail argv=/usr/libexec/dovecot/dovecot-lda -f ${sender} -d ${recipient}

しかし、この設定を行った場合、存在しないメールアドレス宛に来たメールを拒否する、という動作をしてくれない

検証方法はこんな感じ

$ telnet メールサーバホスト名 25
Trying 192.168.x.x...
Connected to 192.168.x.x.
Escape character is '^]'
220 メールサーバホスト名 ESMTP Postfix
ehlo testhost
250-メールサーバホスト名
250-<以下省略>
mail from: <>
250 2.1.0 Ok
rcpt to: nothing@your.domain.here
250 2.1.5 Ok

存在しないアドレスを指定した「rcpt to: nothing@your.domain.here」に対する応答として「550 5.1.1 ~」が返ってくることを期待したものの、「250 2.1.5 Ok」という、メールアドレスが存在する場合と同じ応答となっている。

これをなんとか出来ないかを調べてみると、プラグインを独自開発しろ、とかいう話が出てきたものの、意外な解決方法の糸口を発見・・・

/etc/postfix/master.cf の smtpdの起動を「smtpd -v」と詳細ログ出力モードに変えて、上記操作をしてみたところ、rcpt to入力後の動作に気になるところが・・・

「CHECKING Recipient address VALIDATION MAPS」の処理を見てみると以下の順番でメールアドレスの存在確認を行っている模様
 1) recipient_canonical_maps
 2) canonical_maps
 3) virtual_alias_maps

検証環境ではvirtual_mailbox_domains とは別に virtual_alias_domains も設定され、virtual_alias_mapsはhashファイルが指定されている。これにより、virtual_alias_mapsの検索が行われていると判断される

じゃあ、ここにvirtual_mailbox_mapsを設定したら、virtual_mailbox_mapsに対してメールアドレスの存在確認を行ってくれるんじゃないかな?と期待

main.cfに「virtual_mailbox_maps = ldap:/etc/postfix/ldap-mailbox.cf」を追加して、LDAP検索のqueryは「query_filter = (&(objectClass=user)(mail=%s))」で設定した

設定後、「dnf install postfix-ldap」でpostfixのldapサポートを追加し、「systemctl restart postfix」でpostfixを再起動して見ると以下の結果となった

$ telnet メールサーバホスト名 25
Trying 192.168.x.x...
Connected to 192.168.x.x.
Escape character is '^]'
220 メールサーバホスト名 ESMTP Postfix
ehlo testhost
250-メールサーバホスト名
250-<以下省略>
mail from: <>
250 2.1.0 Ok
rcpt to: nothing@your.domain.here
550 5.1.1 <nothing@your.domain.here>: Recipient address rejected: User unknown in virtual mailbox table

期待通りに「550 5.1.1」による拒否を行ってくれるようになった

postfixのdebugログを確認すると、virtual_alias_maps 処理の次に virtual_mailbox_maps処理が追加されていた。
 1) recipient_canonical_maps
 2) canonical_maps
 3) virtual_alias_maps
 4) virtual_mailbox_maps

このことから、postfixで「virtual_transport=dovecot」を設定した場合であっても、virtual_mailbox_maps設定を行い、postfix側でメールアドレスの存在確認を行った方がよい、ということになる

doveadmとjqコマンドを組み合わせて使用率の値だけを取り出す

doveadmとjqコマンドを組み合わせて既定パーセントを超えているユーザを一覧化する、というスクリプトを考えた

前提として、LDAP連携時、1000件を超えるアドレスがある場合、doveadm quota get -A での一括取得ができない、という制約がある。

このため、ldapserchコマンドを使ってユーザ一覧を出力した上で個別に処理を行っていく必要がある。

doveadm quota get -u ユーザ名の通常出力は以下となる

[root@mail ~]# doveadm  quota get -u testuser2
Quota name Type    Value Limit                                                             %
User quota STORAGE     6    50                                                            12
User quota MESSAGE     8     -                                                             0
[root@mail ~]#

doveadmコマンドには-fオプションがあってフォーマットを変えられ、例えばdoveadm -f tab quota get -u ユーザ名を実行するとタブ区切りで処理するためタブが1個だけで表示される

[root@mail ~]# doveadm -f tab quota get -u testuser2
Quota name      Type    Value   Limit   %
User quota      STORAGE 6       50      12
User quota      MESSAGE 8       -       0
[root@mail ~]#

最近のLinuxならjqコマンドがインストールされているのでJSONで形式で出力することにする

[root@mail ~]# doveadm -f json quota get -u testuser2
[{"root":"User quota","type":"STORAGE","value":"6","limit":"50","percent":"12"},{"root":"User quota","type":"MESSAGE","value":"8","limit":"-","percent":"0"}][root@mail ~]#

これを単純にjqコマンドに通す

[root@mail ~]# doveadm -f json quota get -u testuser2 | jq -r
[
  {
    "root": "User quota",
    "type": "STORAGE",
    "value": "6",
    "limit": "50",
    "percent": "12"
  },
  {
    "root": "User quota",
    "type": "MESSAGE",
    "value": "8",
    "limit": "-",
    "percent": "0"
  }
]
[root@mail ~]#

今回は 容量のみ見るので「STORAGE」に関してだけ取得したい。この場合は「.[]」で1段階掘り下げた上で「|」でその下に対する処理を行い、「select」で条件にあうものを選択する、という処理を行う

[root@mail ~]# doveadm -f json quota get -u testuser2 | jq -r '.[] | select(.type =="STORAGE") '
{
  "root": "User quota",
  "type": "STORAGE",
  "value": "6",
  "limit": "50",
  "percent": "12"
}
[root@mail ~]#

selectは複数つなげられる、というのでpercentについても追加するも、90以上なら表示のところ、12なのに表示されている

[root@mail ~]# doveadm -f json quota get -u testuser2 | jq -r '.[] | select(.type =="STORAGE" and .percent>90 ) '
{
  "root": "User quota",
  "type": "STORAGE",
  "value": "6",
  "limit": "50",
  "percent": "12"
}
[root@mail ~]#

じゃあ、percentが12なら表示に変更してみるが、何も表示されない。

[root@mail ~]# doveadm -f json quota get -u testuser2 | jq -r '.[] | select( .percent == 12 ) '
[root@mail ~]#

文字列問題か?ということで、数値を「””」でくくってみると表示される

[root@mail ~]# doveadm -f json quota get -u testuser2 | jq -r '.[] | select( .percent == "12" ) '
{
  "root": "User quota",
  "type": "STORAGE",
  "value": "6",
  "limit": "50",
  "percent": "12"
}
[root@mail ~]#

jqコマンド処理内で、文字列として認識されているものを数値として認識させるのは「tonumber」を通す

[root@mail ~]# doveadm -f json quota get -u testuser2 | jq -r '.[] | select(.type =="STORAGE" and (.percent|tonumber) > 90 ) '
[root@mail ~]#

10より上なら表示に変更

[root@mail ~]# doveadm -f json quota get -u testuser2 | jq -r '.[] | select(.type =="STORAGE" and (.percent|tonumber) > 10 ) '
{
  "root": "User quota",
  "type": "STORAGE",
  "value": "6",
  "limit": "50",
  "percent": "12"
}
[root@mail ~]# 

で、percentの数値だけを出力させるには以下となる

[root@mail ~]# doveadm -f json quota get -u testuser2 | jq -r '(.[] | select(.type =="STORAGE" and (.percent|tonumber) > 10 ) ).percent'
12
[root@mail ~]# doveadm -f json quota get -u testuser2 | jq -r '(.[] | select(.type =="STORAGE" and (.percent|tonumber) > 90 ) ).percent'
[root@mail ~]#

これを環境変数で実行できるように修正を試みるがエラーとなる

[root@mail ~]# limitpercent=10
[root@mail ~]# username=testuser2
[root@mail ~]# doveadm -f json quota get -u $username | jq -r '(.[] | select(.type =="STORAGE" and (.percent|tonumber) > $limitpercent ) ).percent'
jq: error: $limitpercent is not defined at <top-level>, line 1:
(.[] | select(.type =="STORAGE" and (.percent|tonumber) > $limitpercent ) ).percent
jq: 1 compile error
[root@mail ~]#

jqコマンドの–argオプションを使って jqコマンド内部用の$limitpercentを設定する必要があった

[root@mail ~]# doveadm -f json quota get -u $username | jq --arg limitpercent 10 -r '(.[] | select(.type =="STORAGE" and (.percent|tonumber) > $limitper
cent ) ).percent'
[root@mail ~]#

今回も文字列数値問題があるようなのでtonumberを追加

[root@mail ~]# doveadm -f json quota get -u $username | jq --arg limitpercent $limitpercent -r '(.[] | select(.type =="STORAGE" and (.percent|tonumber) > ($limitpercent|tonumber) ) ).percent'
12
[root@mail ~]#

これで、使用率の値だけの取り出しが出来た。

OCI上でローカルユーザベースのメールサーバ構築

postfix/dovecotを使ったIMAPメールサーバをOracle Linux 9.6上でOracle Cloud上のFree Tierで構築してみた

2025/10/30時点の状況としては、以下の問題が出て常用には難しい状態で、限定された用途にしか使えない、という感じとなった。

・OCIのFree TierではIPv4/IPv6アドレスに対する逆引き(PTR)が設定できないため gmailにメールが拒否される
・OCI上の仮想マシンから、外部のIPv4アドレスのポート25に対して通信が通らない。IPv6アドレスのポート25なら通る。(OCIの仕様)

準備1: 一般的な前準備

準備1-1: 日本時間にする

日本に住んでいる場合、日本時間表記の方が使いやすいので、OSも日本時間表示に設定する。

$ sudo timedatectl set-timezone Japan
$ 

手順1-2: swap追加

EPELレポジトリを追加した場合、メモリ1GB構成の場合、swapは5GB程度ないとdnfコマンドが正常に動作しないので、swapを増量する

/var/oled パーテーションに ファイルスワップを作成

$ sudo fallocate -l 4G /var/oled/swapfile
$ ls -l /var/oled/swapfile 
-rw-r--r--. 1 root root 4294967296 Sep  9 13:35 /var/oled/swapfile
$ sudo chmod 600 /var/oled/swapfile 
$ ls -l /var/oled/swapfile 
-rw-------. 1 root root 4294967296 Sep  9 13:35 /var/oled/swapfile
$ sudo mkswap /var/oled/swapfile 
Setting up swapspace version 1, size = 4 GiB (4294963200 bytes)
no label, UUID=bdd4f7a6-1dcc-43c8-bb2d-8f42ac2faf3f
$ 

作成したファイルをスワップとして登録

$ sudo swapon /var/oled/swapfile 
$ swapon --show
NAME               TYPE SIZE   USED PRIO
/.swapfile         file 951M 161.6M   -2
/var/oled/swapfile file   4G   8.2M   -3
$ cat /proc/swaps 
Filename                                Type            Size            Used            Priority
/.swapfile                              file            973820          165524          -2
/var/oled/swapfile                      file            4194300         8412            -3
$ 

/etc/fstab にスワップファイルの記述「/var/oled/swapfile none swap sw 0 0」を追加

$ sudo vi /etc/fstab
$ cat /etc/fstab 
#
# /etc/fstab
# Created by anaconda on Thu Jun 12 01:18:32 2025
#
# Accessible filesystems, by reference, are maintained under '/dev/disk/'.
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
#
# After editing this file, run 'systemctl daemon-reload' to update systemd
# units generated from this file.
#
/dev/mapper/ocivolume-root /                       xfs     defaults        0 0
UUID=dd88872e-0527-4193-8282-b8281f1ae6fd /boot                   xfs     defaults        0 0
UUID=AE3C-806E          /boot/efi               vfat    defaults,uid=0,gid=0,umask=077,shortname=winnt 0 2
/dev/mapper/ocivolume-oled /var/oled               xfs     defaults        0 0
tmpfs                   /dev/shm                tmpfs   defaults,nodev,nosuid,noexec      0 0
######################################
## ORACLE CLOUD INFRASTRUCTURE CUSTOMERS
##
## If you are adding an iSCSI remote block volume to this file you MUST
## include the '_netdev' mount option or your instance will become
## unavailable after the next reboot.
## SCSI device names are not stable across reboots; please use the device UUID instead of /dev path.
##
## Example:
## UUID="94c5aade-8bb1-4d55-ad0c-388bb8aa716a"   /data1    xfs       defaults,noatime,_netdev      0      2
##
## More information:
## https://docs.us-phoenix-1.oraclecloud.com/Content/Block/Tasks/connectingtoavolume.htm
/.swapfile      none    swap    sw      0       0
/var/oled/swapfile      none    swap    sw      0       0
$

準備2-3: パッケージを最新へアップデート

現時点での最新へアップデートする

$ sudo dnf update -y
<略>
$ sudo reboot

手順1-4: 日本語Locale対応

ja_JP.UTF-8など日本語Localeで設定した際、「Failed to set locale, defaulting to C.UTF-8」というメッセージが出力される場合があります。

その場合は日本語Localeを追加インストールします。

$ sudo dnf install langpacks-ja
<略>
$

手順1-5: kdump無効化

どうせ使わないのでkdumpを無効化

$ sudo systemctl disable kdump.service
Removed '/etc/systemd/system/multi-user.target.wants/kdump.service'.
$

手順2: EPELレポジトリの追加

EPELレポジトリを登録

$ sudo dnf config-manager --set-enabled ol10_u0_developer_EPEL
$  dnf repolist --all
repo id                                                                       repo name                                                                                                       status
ol9_MODRHCK                                                                   Latest RHCK with fixes from Oracle for Oracle Linux 9 (x86_64)                                                  disabled
ol9_RDMA                                                                      Oracle Linux 9 (x86_64) RDMA                                                                                    disabled
ol9_UEKR7                                                                     Oracle Linux 9 UEK Release 7 (x86_64)                                                                           disabled
ol9_UEKR8                                                                     Oracle Linux 9 UEK Release 8 (x86_64)                                                                           enabled
ol9_addons                                                                    Oracle Linux 9 Addons (x86_64)                                                                                  enabled
ol9_appstream                                                                 Oracle Linux 9 Application Stream Packages (x86_64)                                                             enabled
ol9_baseos_latest                                                             Oracle Linux 9 BaseOS Latest (x86_64)                                                                           enabled
ol9_codeready_builder                                                         Oracle Linux 9 CodeReady Builder (x86_64) - (Unsupported)                                                       disabled
ol9_developer                                                                 Oracle Linux 9 Development Packages (x86_64)                                                                    disabled
ol9_developer_EPEL                                                            Oracle Linux 9 EPEL Packages for Development (x86_64)                                                           enabled
ol9_developer_UEKR7                                                           Developer Preview of UEK Release 7 (x86_64)                                                                     disabled
ol9_developer_kvm_utils                                                       Oracle Linux 9 KVM Utilities for Development and test (x86_64)                                                  disabled
ol9_distro_builder                                                            Oracle Linux 9 Distro Builder (x86_64) - (Unsupported)                                                          disabled
ol9_ksplice                                                                   Ksplice for Oracle Linux 9 (x86_64)                                                                             enabled
ol9_kvm_utils                                                                 Oracle Linux 9 KVM Utilities (x86_64)                                                                           disabled
ol9_oci_included                                                              Oracle Linux 9 OCI Included Packages (x86_64)                                                                   enabled
ol9_u0_baseos_base                                                            Oracle Linux 9 BaseOS GA (x86_64)                                                                               disabled
ol9_u1_baseos_base                                                            Oracle Linux 9.1 BaseOS (x86_64)                                                                                disabled
ol9_u2_baseos_base                                                            Oracle Linux 9.2 BaseOS (x86_64)                                                                                disabled
ol9_u3_baseos_base                                                            Oracle Linux 9.3 BaseOS (x86_64)                                                                                disabled
ol9_u3_security_validation                                                    Oracle Linux 9 Update 3 (x86_64) Security Validations                                                           disabled
ol9_u4_baseos_base                                                            Oracle Linux 9.4 BaseOS (x86_64)                                                                                disabled
ol9_u5_baseos_base                                                            Oracle Linux 9.5 BaseOS (x86_64)                                                                                disabled
ol9_u6_baseos_base                                                            Oracle Linux 9.6 BaseOS (x86_64)                                                                                disabled
ol9_x86_64_userspace_ksplice                                                  Ksplice aware userspace packages for Oracle Linux 9 (x86_64)                                                    disabled
$

手順3: インターネット公開用設定

手順3-1: fail2ban導入

公開サーバは各種のアタックにさらされます。管理用sshポートにもやってきます。

多少なりとも軽減するためにEPELレポジトリ収録のfail2banを使用します。

$ sudo dnf install fail2ban -y
<略>
$

カスタム設定は/etc/fail2ban/jail.local に対して行います。

$ sudo vi /etc/fail2ban/jail.local 
$ cat /etc/fail2ban/jail.local 
[DEFAULT]
# 86400秒=24時間以内に5回不審なアクセスがあったら24時間BAN
bantime  = 86400
findtime  = 86400
maxretry = 5
# 259200秒=3日以内に5回不審なアクセスがあったら3日間BAN
#bantime  = 259200
#findtime  = 259200
#maxretry = 5
# 除外IP
ignoreip = 127.0.0.1 127.0.0.0/8 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16
[sshd]
enabled = true
banaction = firewallcmd-ipset
$ 

上記設定では24時間BANにしていますが、まぁ、3日BANでもかまわないとは思います。(本当に間違えた場合に困るのでほどほどにしておくとよい)

fail2banをOS起動時に実行する設定と、今すぐfail2banを起動するコマンドを実行します。

$ sudo systemctl enable --now fail2ban
Created symlink '/etc/systemd/system/multi-user.target.wants/fail2ban.service' → '/usr/lib/systemd/system/fail2ban.service'.
$

以降、アタックがあると /var/log/fail2ban.log にログが出ます。

手順3-2: メールサーバ用ポート公開設定

初期設定では dhcpv6-client と ssh が許可されています。

$ sudo firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: ens3
  sources: 
  services: dhcpv6-client ssh
  ports: 
  protocols: 
  forward: yes
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 
$

とりあえずは smtp port 25, smtp-submission 587, imap 143 を開けます

[opc@ocimail ~]$ sudo firewall-cmd --permanent --add-service=smtp
success
[opc@ocimail ~]$ sudo firewall-cmd --permanent --add-service=smtp-submission
success
[opc@ocimail ~]$ sudo firewall-cmd --permanent --add-service=imap
success
[opc@ocimail ~]$ sudo firewall-cmd --reload
success
[opc@ocimail ~]$ sudo firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: ens3
  sources: 
  services: dhcpv6-client imap smtp smtp-submission ssh
  ports: 
  protocols: 
  forward: yes
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 
[opc@ocimail ~]$ 

手順3-3: SSL更新用ポート

後述するのだが、SSLはLet’s Encryptを使う。

その際に、http ポート80と、https ポート 443が必要となるため、設定する

[opc@ocimail ~]$ sudo firewall-cmd --permanent --add-service=http
success
[opc@ocimail ~]$ sudo firewall-cmd --permanent --add-service=https
success
[opc@ocimail ~]$ sudo firewall-cmd --reload
success
[opc@ocimail ~]$ sudo firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: ens3
  sources: 
  services: dhcpv6-client http https imap smtp smtp-submission ssh
  ports: 
  protocols: 
  forward: yes
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 
[opc@ocimail ~]$ 

手順4: ソフトウェアインストール

postfixとdovecotをインストールします。

[opc@ocimail ~]$ sudo dnf install postfix dovecot -y
Last metadata expiration check: 2:15:42 ago on Wed 29 Oct 2025 03:42:39 AM GMT.
Dependencies resolved.
======================================================================================================================================================================================================
 Package                                     Architecture                         Version                                                           Repository                                   Size
======================================================================================================================================================================================================
Installing:
 dovecot                                     x86_64                               1:2.3.16-15.el9                                                   ol9_appstream                               5.2 M
 postfix                                     x86_64                               2:3.5.25-1.el9                                                    ol9_appstream                               1.7 M
Installing dependencies:
 clucene-core                                x86_64                               2.3.3.4-42.20130812.e8e3d20git.el9                                ol9_appstream                               594 k
 libexttextcat                               x86_64                               3.4.5-11.el9                                                      ol9_appstream                               382 k

Transaction Summary
======================================================================================================================================================================================================
Install  4 Packages

Total download size: 7.8 M
Installed size: 24 M
Downloading Packages:
(1/4): libexttextcat-3.4.5-11.el9.x86_64.rpm                                                                                                                          1.9 MB/s | 382 kB     00:00    
(2/4): clucene-core-2.3.3.4-42.20130812.e8e3d20git.el9.x86_64.rpm                                                                                                     1.8 MB/s | 594 kB     00:00    
(3/4): dovecot-2.3.16-15.el9.x86_64.rpm                                                                                                                                12 MB/s | 5.2 MB     00:00    
(4/4): postfix-3.5.25-1.el9.x86_64.rpm                                                                                                                                6.0 MB/s | 1.7 MB     00:00    
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Total                                                                                                                                                                  16 MB/s | 7.8 MB     00:00     
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Preparing        :                                                                                                                                                                              1/1 
  Installing       : libexttextcat-3.4.5-11.el9.x86_64                                                                                                                                            1/4 
  Installing       : clucene-core-2.3.3.4-42.20130812.e8e3d20git.el9.x86_64                                                                                                                       2/4 
  Running scriptlet: dovecot-1:2.3.16-15.el9.x86_64                                                                                                                                               3/4 
  Installing       : dovecot-1:2.3.16-15.el9.x86_64                                                                                                                                               3/4 
  Running scriptlet: dovecot-1:2.3.16-15.el9.x86_64                                                                                                                                               3/4 
  Running scriptlet: postfix-2:3.5.25-1.el9.x86_64                                                                                                                                                4/4 
  Installing       : postfix-2:3.5.25-1.el9.x86_64                                                                                                                                                4/4 
  Running scriptlet: postfix-2:3.5.25-1.el9.x86_64                                                                                                                                                4/4 
  Running scriptlet: dovecot-1:2.3.16-15.el9.x86_64                                                                                                                                               4/4 
  Running scriptlet: postfix-2:3.5.25-1.el9.x86_64                                                                                                                                                4/4 
  Verifying        : clucene-core-2.3.3.4-42.20130812.e8e3d20git.el9.x86_64                                                                                                                       1/4 
  Verifying        : dovecot-1:2.3.16-15.el9.x86_64                                                                                                                                               2/4 
  Verifying        : libexttextcat-3.4.5-11.el9.x86_64                                                                                                                                            3/4 
  Verifying        : postfix-2:3.5.25-1.el9.x86_64                                                                                                                                                4/4 

Installed:
  clucene-core-2.3.3.4-42.20130812.e8e3d20git.el9.x86_64            dovecot-1:2.3.16-15.el9.x86_64            libexttextcat-3.4.5-11.el9.x86_64            postfix-2:3.5.25-1.el9.x86_64           

Complete!
[opc@ocimail ~]$ 

手順5: SSL証明書関連

手順5-1: dhパラメータファイルの作成

diffie-hellman パラメータファイル を /etc/dovecot/conf.d/10-ssl.conf にあるパス /etc/dovecot/dh.pem に作成。なお、30分以上かかる。

[opc@ocimail ~]$ sudo openssl dhparam -out /etc/dovecot/dh.pem 4096
Generating DH parameters, 4096 bit long safe prime
..............................................................................................................+......................................+................................................
<略>

手順5-2: dehydratedによるLet’s Encrypt導入

Let’s EncryptによるSSL証明書導入はcertbotを使うのが一般的ではあるのだが、python環境とあわせてパッケージサイズが大きいので、コンパクトでEPELにも収録されているdehydratedを使用する。

[opc@ocimail ~]$ sudo dnf install dehydrated -y
Last metadata expiration check: 3:29:19 ago on Wed 29 Oct 2025 03:42:39 AM GMT.
Dependencies resolved.
======================================================================================================================================================================================================
 Package                                       Architecture                              Version                                          Repository                                             Size
======================================================================================================================================================================================================
Installing:
 dehydrated                                    noarch                                    0.7.1-6.el9                                      ol9_developer_EPEL                                    154 k
Installing dependencies:
 s-nail                                        x86_64                                    14.9.22-6.el9                                    ol9_appstream                                         626 k

Transaction Summary
======================================================================================================================================================================================================
Install  2 Packages

Total download size: 780 k
Installed size: 1.4 M
<略>
Installed:
  dehydrated-0.7.1-6.el9.noarch                                                                      s-nail-14.9.22-6.el9.x86_64                                                                     

Complete!
[opc@ocimail ~]$

dehydratedによるSSL証明書取得処理にはhttp port80アクセスと /var/www/dehydrated が使用されるためhttpdのインストールとディレクトリを作成します。

[opc@ocimail ~]$ sudo dnf install httpd -y
Last metadata expiration check: 3:31:07 ago on Wed 29 Oct 2025 03:42:39 AM GMT.
Dependencies resolved.
======================================================================================================================================================================================================
 Package                                           Architecture                          Version                                               Repository                                        Size
======================================================================================================================================================================================================
Installing:
 httpd                                             x86_64                                2.4.62-4.0.1.el9_6.4                                  ol9_appstream                                     64 k
Installing dependencies:
 apr                                               x86_64                                1.7.0-12.el9_3                                        ol9_appstream                                    131 k
 apr-util                                          x86_64                                1.6.1-23.el9                                          ol9_appstream                                     99 k
 apr-util-bdb                                      x86_64                                1.6.1-23.el9                                          ol9_appstream                                     12 k
 httpd-core                                        x86_64                                2.4.62-4.0.1.el9_6.4                                  ol9_appstream                                    1.8 M
 httpd-filesystem                                  noarch                                2.4.62-4.0.1.el9_6.4                                  ol9_appstream                                     11 k
 httpd-tools                                       x86_64                                2.4.62-4.0.1.el9_6.4                                  ol9_appstream                                     93 k
 oracle-logos-httpd                                noarch                                90.4-1.0.1.el9                                        ol9_baseos_latest                                 37 k
Installing weak dependencies:
 apr-util-openssl                                  x86_64                                1.6.1-23.el9                                          ol9_appstream                                     14 k
 mod_http2                                         x86_64                                2.0.26-4.el9_6.1                                      ol9_appstream                                    171 k
 mod_lua                                           x86_64                                2.4.62-4.0.1.el9_6.4                                  ol9_appstream                                     58 k

Transaction Summary
======================================================================================================================================================================================================
Install  11 Packages

Total download size: 2.5 M
Installed size: 6.1 M
Downloading Packages:
<略>
Installed:
  apr-1.7.0-12.el9_3.x86_64                  apr-util-1.6.1-23.el9.x86_64                    apr-util-bdb-1.6.1-23.el9.x86_64                      apr-util-openssl-1.6.1-23.el9.x86_64            
  httpd-2.4.62-4.0.1.el9_6.4.x86_64          httpd-core-2.4.62-4.0.1.el9_6.4.x86_64          httpd-filesystem-2.4.62-4.0.1.el9_6.4.noarch          httpd-tools-2.4.62-4.0.1.el9_6.4.x86_64         
  mod_http2-2.0.26-4.el9_6.1.x86_64          mod_lua-2.4.62-4.0.1.el9_6.4.x86_64             oracle-logos-httpd-90.4-1.0.1.el9.noarch             

Complete!
[opc@ocimail ~]$ sudo mkdir /var/www/dehydrated
[opc@ocimail ~]$ 

http://~/.well-known/acme-challenge でアクセスした時に上記ディレクトリが開くようApacheの設定を /etc/httpd/conf.d/dehydrated.conf として作成します。(sudo vi /etc/httpd/conf.d/dehydrated.conf )

[opc@ocimail ~]$ sudo vi /etc/httpd/conf.d/dehydrated.conf 
[opc@ocimail ~]$ cat /etc/httpd/conf.d/dehydrated.conf 
Alias /.well-known/acme-challenge /var/www/dehydrated
<Directory /var/www/dehydrated/>
</Directory>
[opc@ocimail ~]$ 

httpdを起動します

[opc@ocimail ~]$ sudo systemctl enable --now httpd
Created symlink /etc/systemd/system/multi-user.target.wants/httpd.service → /usr/lib/systemd/system/httpd.service.
[opc@ocimail ~]$ 

SSL証明書を発行するホスト名を /etc/dehydrated/domains.txt に記載する。(sudo vi /etc/dehydrated/domains.txt)

$ sudo vi /etc/dehydrated/domains.txt
$ sudo cat /etc/dehydrated/domains.txt
ホスト1名.ドメイン名 ホスト2名.ドメイン名
$

登録操作を開始します。

[opc@ocimail ~]$ sudo dehydrated --register
# INFO: Using main config file /etc/dehydrated/config
# INFO: Using additional config file /etc/dehydrated/conf.d/local.sh

To use dehydrated with this certificate authority you have to agree to their terms of service which you can find here: https://letsencrypt.org/documents/LE-SA-v1.5-February-24-2025.pdf

To accept these terms of service run "/bin/dehydrated --register --accept-terms".
[opc@ocimail ~]$ sudo dehydrated --register --accept-terms
# INFO: Using main config file /etc/dehydrated/config
# INFO: Using additional config file /etc/dehydrated/conf.d/local.sh
+ Generating account key...
+ Registering account key with ACME server...
+ Fetching account URL...
+ Done!
[opc@ocimail ~]$ 

初回のSSL証明書発行処理を実行します。

[opc@ocimail ~]$ sudo dehydrated --cron
# INFO: Using main config file /etc/dehydrated/config
# INFO: Using additional config file /etc/dehydrated/conf.d/local.sh
Processing ocimail.websa.jp
 + Signing domains...
 + Generating private key...
 + Generating signing request...
 + Requesting new certificate order from CA...
 + Received 1 authorizations URLs from the CA
 + Handling authorization for ホスト名
 + 1 pending challenge(s)
 + Deploying challenge tokens...
 + Responding to challenge for ocimail.websa.jp authorization...
 + Challenge is valid!
 + Cleaning challenge tokens...
 + Requesting certificate...
Warning: Will read cert request from stdin since no -in option is given
 + Checking certificate...
 + Done!
 + Creating fullchain.pem...
 + Done!
 + Running automatic cleanup
Moving unused file to archive directory: ホスト名/cert-1761722366.csr
Moving unused file to archive directory: ホスト名/cert-1761722366.pem
Moving unused file to archive directory: ホスト名/privkey-1761722366.pem
[opc@ocimail ~]$ 

これで/etc/dehydrated/certs/ホスト名/ にSSL証明書が作成される

[opc@ocimail ~]$ sudo ls -l /etc/dehydrated/certs/ホスト名/
total 20
-rw-------. 1 root root 1655 Oct 29 07:26 cert-1761722787.csr
-rw-------. 1 root root 2134 Oct 29 07:26 cert-1761722787.pem
lrwxrwxrwx. 1 root root   19 Oct 29 07:26 cert.csr -> cert-1761722787.csr
lrwxrwxrwx. 1 root root   19 Oct 29 07:26 cert.pem -> cert-1761722787.pem
-rw-------. 1 root root 1802 Oct 29 07:26 chain-1761722787.pem
lrwxrwxrwx. 1 root root   20 Oct 29 07:26 chain.pem -> chain-1761722787.pem
-rw-------. 1 root root 3936 Oct 29 07:26 fullchain-1761722787.pem
lrwxrwxrwx. 1 root root   24 Oct 29 07:26 fullchain.pem -> fullchain-1761722787.pem
-rw-------. 1 root root 3272 Oct 29 07:26 privkey-1761722787.pem
lrwxrwxrwx. 1 root root   22 Oct 29 07:26 privkey.pem -> privkey-1761722787.pem
[opc@ocimail ~]$ 

dovecot設定

dovecot ssl設定

/etc/dovecot/conf.d/10-ssl.conf にて

「ssl = required」を「ssl = yes」に変更

# SSL/TLS support: yes, no, required. &lt;doc/wiki/SSL.txt>
# disable plain pop3 and imap, allowed are only pop3+TLS, pop3s, imap+TLS and imaps
# plain imap and pop3 are still allowed for local connections
ssl = yes

ssl_certとssl_keyをdehydratedが出力したファイルに置き換え

# PEM encoded X.509 SSL/TLS certificate and private key. They're opened before
# dropping root privileges, so keep the key file unreadable by anyone but
# root. Included doc/mkcert.sh can be used to easily generate self-signed
# certificate, just make sure to update the domains in dovecot-openssl.cnf
ssl_cert = &lt;/etc/dehydrated/certs/ホスト名/fullchain.pem
ssl_key = &lt;/etc/dehydrated/certs/ホスト名/privkey.pem

dhパラメータのコメントを取る

# SSL DH parameters
# Generate new params with `openssl dhparam -out /etc/dovecot/dh.pem 4096`
# Or migrate from old ssl-parameters.dat file with the command dovecot
# gives on startup when ssl_dh is unset.
ssl_dh = &lt;/etc/dovecot/dh.pem

dovecotのメイン設定ファイル

/etc/dovecot/dovecot.conf に以下の変更

標準だと「imap pop3 lmtp submission」となっているものから、imapとsubmissionとする

# Protocols we want to be serving.
#protocols = imap pop3 lmtp submission
protocols = imap submission

dovecotのメール保存に関するファイル

/etc/dovecot/conf.d/10-mail.conf に以下の変更

maildir形式で各ユーザのホームディレクトリに保存する設定

#   mail_location = maildir:~/Maildir
#   mail_location = mbox:~/mail:INBOX=/var/mail/%u
#   mail_location = mbox:/var/mail/%d/%1n/%n:INDEX=/var/indexes/%d/%1n/%n
#
# &lt;doc/wiki/MailLocation.txt>
#
mail_location = maildir:~/Maildir

quotaを有効化するため、mail_plugins に「$mail_plugins quota」を追加

# Space separated list of plugins to load for all services. Plugins specific to
# IMAP, LDA, etc. are added to this list in their own .conf files.
mail_plugins = $mail_plugins quota

mailboxのindexを有効にする設定「mailbox_list_index = yes」を入れる

##
## Mailbox handling optimizations
##

# Mailbox list indexes can be used to optimize IMAP STATUS commands. They are
# also required for IMAP NOTIFY extension to be enabled.
mailbox_list_index = yes

IMAPログイン時のパスワード取り扱い設定

IMAPログイン時のパスワードを暗号化して送信する、というのが現代の設定となる。

古い仕様のメールクラインとがいたとすると、平文パスワードを許可する設定を /etc/dovecot/conf.d/10-auth.conf に追加する必要がある。

その場合は下記を「disable_plaintext_auth = no」に変更する

# Disable LOGIN command and all other plaintext authentications unless
# SSL/TLS is used (LOGINDISABLED capability). Note that if the remote IP
# matches the local IP (ie. you're connecting from the same computer), the
# connection is considered secure and plaintext authentication is allowed.
# See also ssl=required setting.
#disable_plaintext_auth = yes

また、下記を「auth_mechanism = plain login」に変更する

# Space separated list of wanted authentication mechanisms:
#   plain login digest-md5 cram-md5 ntlm rpa apop anonymous gssapi otp
#   gss-spnego
# NOTE: See also disable_plaintext_auth setting.
auth_mechanisms = plain

dovecotのSMTP-auth動作時の設定

/etc/dovecot/conf.d/10-master.conf でコメントアウトされている smtp-authに関する設定を少し修正して設定する

  # Postfix smtp-auth
  unix_listener /var/spool/postfix/private/auth {
    mode = 0666
    user = postfix
    group = postfix
  }

dovecotのIMAP設定

/etc/dovecot/conf.d/20-imap.conf にて mail_plugin として「imap_quota」を追加

protocol imap {
  # Space separated list of plugins to load (default is global mail_plugins).
  mail_plugins = $mail_plugins imap_quota

  # Maximum number of IMAP connections allowed for a user from each IP address.
  # NOTE: The username is compared case-sensitively.
  #mail_max_userip_connections = 10
}

dovecotのメールボックス取り扱い設定

/etc/dovecot/conf.d/15-mailboxes.conf を修正することで、メールソフトによってフォルダ名に微妙な違いがあるのをある程度吸収できる。

##
## Mailbox definitions
##

# Each mailbox is specified in a separate mailbox section. The section name
# specifies the mailbox name. If it has spaces, you can put the name
# "in quotes". These sections can contain the following mailbox settings:
#
# auto:
#   Indicates whether the mailbox with this name is automatically created
#   implicitly when it is first accessed. The user can also be automatically
#   subscribed to the mailbox after creation. The following values are
#   defined for this setting:
# 
#     no        - Never created automatically.
#     create    - Automatically created, but no automatic subscription.
#     subscribe - Automatically created and subscribed.
#  
# special_use:
#   A space-separated list of SPECIAL-USE flags (RFC 6154) to use for the
#   mailbox. There are no validity checks, so you could specify anything
#   you want in here, but it's not a good idea to use flags other than the
#   standard ones specified in the RFC:
#
#     \All       - This (virtual) mailbox presents all messages in the
#                  user's message store.
#     \Archive   - This mailbox is used to archive messages.
#     \Drafts    - This mailbox is used to hold draft messages.
#     \Flagged   - This (virtual) mailbox presents all messages in the
#                  user's message store marked with the IMAP \Flagged flag.
#     \Important - This (virtual) mailbox presents all messages in the
#                  user's message store deemed important to user.
#     \Junk      - This mailbox is where messages deemed to be junk mail
#                  are held.
#     \Sent      - This mailbox is used to hold copies of messages that
#                  have been sent.
#     \Trash     - This mailbox is used to hold messages that have been
#                  deleted.
#
# comment:
#   Defines a default comment or note associated with the mailbox. This
#   value is accessible through the IMAP METADATA mailbox entries
#   "/shared/comment" and "/private/comment". Users with sufficient
#   privileges can override the default value for entries with a custom
#   value.

# NOTE: Assumes "namespace inbox" has been defined in 10-mail.conf.
namespace inbox {
  # These mailboxes are widely used and could perhaps be created automatically:
  mailbox Drafts {
    special_use = \Drafts
  }
  mailbox "下書き" {
    special_use = \Drafts
  }
  mailbox INBOX.Drafts {
    special_use = \Drafts
  }

  mailbox Junk {
    special_use = \Junk
  }
  mailbox "迷惑メール" {
    special_use = \Junk
  }
  mailbox "Junk Email" {
    special_use = \Junk
  }
  mailbox "INBOX.Junk Email" {
    special_use = \Junk
  }

  mailbox Trash {
    special_use = \Trash
  }
  mailbox "削除済みアイテム" {
    special_use = \Trash
  }
  mailbox "Deleted Items" {
    special_use = \Trash
  }
  mailbox "INBOX.Deleted Items" {
    special_use = \Trash
  }

  # For \Sent mailboxes there are two widely used names. We'll mark both of
  # them as \Sent. User typically deletes one of them if duplicates are created.
  mailbox Sent {
    special_use = \Sent
  }
  mailbox "Sent Messages" {
    special_use = \Sent
  }
  mailbox "送信済みアイテム" {
    special_use = \Sent
  }
  mailbox "Sent Items" {
    special_use = \Sent
  }
  mailbox "INBOX.Sent Items" {
    special_use = \Sent
  }

  # If you have a virtual "All messages" mailbox:
  #mailbox virtual/All {
  #  special_use = \All
  #  comment = All my messages
  #}

  # If you have a virtual "Flagged" mailbox:
  #mailbox virtual/Flagged {
  #  special_use = \Flagged
  #  comment = All my flagged messages
  #}

  # If you have a virtual "Important" mailbox:
  #mailbox virtual/Important {
  #  special_use = \Important
  #  comment = All my important messages
  #}
}

dovecotのquota設定

既存の /etc/dovecot/conf.d/90-quota.conf の最後に下記を追加する

これは100MBで制限する例

mailbox_list_index = yes

# Avoid spending excessive time waiting for the quota calculation to finish
# when mails' vsizes aren't already cached. If this many mails are opened,
# finish the quota calculation on background in indexer-worker process. Mail
# deliveries will be assumed to succeed, and explicit quota lookups will
# return internal error. (v2.2.28+)
protocol !indexer-worker {
  mail_vsize_bg_after_count = 100
}

plugin {
  quota = count:User quota
  quota_rule = *:storage=100M
  #quota_rule2 = Trash:storage=+100M

  # This is required - it uses "virtual sizes" rather than "physical sizes"
  # for quota counting:
  quota_vsizes = yes
}

dovecotのsmtp submission設定

/etc/dovecot/conf.d/20-submission.conf にて設定する

dovecot自体ではメール配送を行わないので、postfix側に引き渡すのだが、同じホスト上にあったとしてもlocalhost指定ではなく、外部から見えるホスト名で指定する。

# Relay server configuration:
#
# The Dovecot SMTP submission service directly proxies the mail transaction
# to the SMTP relay configured here.

# Host name for the relay server (required)
submission_relay_host = ホスト名.ドメン名

postfix側設定

postfix側は /etc/postfix/main.cf へ設定を行う

Oracle Cloud上だとホスト名が内部のみの ホスト名.subnet<数字>.vcn<数字>.oraclevcn.comといったものとなっているので、DNS上のホスト名をmyhostnameで設定する

# INTERNET HOST AND DOMAIN NAMES
# 
# The myhostname parameter specifies the internet hostname of this
# mail system. The default is to use the fully-qualified domain name
# from gethostname(). $myhostname is used as a default value for many
# other configuration parameters.
#
#myhostname = host.domain.tld
#myhostname = virtual.domain.tld
myhostname = ホスト名.ドメイン名

続いてmydomain も 外部で認識させたいドメイン名を入れる

# The mydomain parameter specifies the local internet domain name.
# The default is to use $myhostname minus the first component.
# $mydomain is used as a default value for many other configuration
# parameters.
#
#mydomain = domain.tld
mydomain = ドメイン名

外部に送信するメールの@以降の部分はドメイン名としたいので「myorigin = $mydomain」の方を有効にします。

# SENDING MAIL
# 
# The myorigin parameter specifies the domain that locally-posted
# mail appears to come from. The default is to append $myhostname,
# which is fine for small sites.  If you run a domain with multiple
# machines, you should (1) change this to $mydomain and (2) set up
# a domain-wide alias database that aliases each user to
# user@that.users.mailhost.
#
# For the sake of consistency between sender and recipient addresses,
# myorigin also specifies the default domain name that is appended
# to recipient addresses that have no @domain part.
#
#myorigin = $myhostname
myorigin = $mydomain

外部からpostfixにアクセスする必要があるので「inet_interfaces = all」を有効にします

# The inet_interfaces parameter specifies the network interface
# addresses that this mail system receives mail on.  By default,
# the software claims all active interfaces on the machine. The
# parameter also controls delivery of mail to user@[ip.address].
#
# See also the proxy_interfaces parameter, for network addresses that
# are forwarded to us via a proxy or network address translator.
#
# Note: you need to stop/start Postfix when this parameter changes.
#
inet_interfaces = all
#inet_interfaces = $myhostname
#inet_interfaces = $myhostname, localhost
#inet_interfaces = localhost

# Enable IPv4, and IPv6 if supported
inet_protocols = all

自サーバで受信するメールドメインの設定は2番目のドメイン宛ても受け取るやつにします

# See also below, section "REJECTING MAIL FOR UNKNOWN LOCAL USERS".
#
#mydestination = $myhostname, localhost.$mydomain, localhost
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
#mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain,
#       mail.$mydomain, www.$mydomain, ftp.$mydomain

ローカルユーザとしてメールを受け取りたいので、local_recipient_mapsを明示的に有効にします。

# The right-hand side of the lookup tables is conveniently ignored.
# In the left-hand side, specify a bare username, an @domain.tld
# wild-card, or specify a user@domain.tld address.
# 
local_recipient_maps = unix:passwd.byname $alias_maps
#local_recipient_maps = proxy:unix:passwd.byname $alias_maps
#local_recipient_maps =

postfixでメールを送信できるようにする設定

メール送信を許可するネットワークを mynetworks で行う

#mynetworks = 168.100.189.0/28, 127.0.0.0/8
#mynetworks = $config_directory/mynetworks
#mynetworks = hash:/etc/postfix/network_table

また、以下を追加

# With Postfix version before 2.10, use smtpd_recipient_restrictions
smtpd_relay_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination

postfixのssl証明書設定

/etc/postfix/main.cf の最後の方にSSL関連の設定がある

# The full pathname of a file with the Postfix SMTP server RSA certificate
# in PEM format. Intermediate certificates should be included in general,
# the server certificate first, then the issuing CA(s) (bottom-up order).
#
smtpd_tls_cert_file = /etc/dehydrated/certs/ocimail.websa.jp/fullchain.pem
# The full pathname of a file with the Postfix SMTP server RSA private key
# in PEM format. The private key must be accessible without a pass-phrase,
# i.e. it must not be encrypted.
#
smtpd_tls_key_file = /etc/dehydrated/certs/ocimail.websa.jp/privkey.pem

postfix側からdovecotを起動する設定

/etc/postfix/master.cf の最終行に以下を追加

dovecot   unix  -       n       n       -       -       pipe
  flags=DRhu user=vmail:vmail argv=/usr/libexec/dovecot/dovecot-lda -f ${sender} -d ${recipient}

postfixからSASLを使ってdovecot連携する手法は使わない

今回はsmtp submissionはdovecot側で行うので、SASLを使ってdovecotと連携するための下記設定は行わない。

smtpd_sasl_auth_enable = yes
broken_sasl_auth_clients = yes
# dovecot sasl configuration
smtpd_sasl_type = dovecot
# Can be an absolute path, or relative to $queue_directory
# Debian/Ubuntu users: Postfix is setup by default to run chrooted, so it is best to leave it as-is below
smtpd_sasl_path = private/auth
# and the common settings to enable SASL:
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous 

トラブル対応

gmail宛てがgmail側で受け取り拒否

gmailに送ったところ、メールがなかなか届かないので/var/log/maillogを確認

Oct 30 10:15:28 ocimail postfix/smtp[5898]: AA57A309E87E: to=&lt;アドレス@gmail.com>, relay=gmail-smtp-in.l.google.com[2404:6800:4008:c15::1b]:25, delay=2.6, delays=0.29/0.19/1.2/0.9, dsn=5.7.1, status=bounced (host gmail-
smtp-in.l.google.com[2404:6800:4008:c15::1b] said: 550-5.7.1 [2603:c023:f:9000:0:7a41:2e84:f27f] Gmail has detected that this 550-5.7.1 message does not meet IPv6 sending guidelines regarding PTR records 550-5.7.1 and auth
entication. For more information, go to 550 5.7.1  https://support.google.com/mail/?p=IPv6AuthError 41be03b00d2f7-b71f4ba78c7si7488417a12.1056 - gsmtp (in reply to end of DATA command))

「Gmail has detected that this 550-5.7.1 message does not meet IPv6 sending guidelines regarding PTR records 550-5.7.1 and authentication. For more information, go to 550 5.7.1 https://support.google.com/mail/?p=IPv6AuthError」という形で拒否されていた。

リンク先はGoogleの「メール送信者のガイドライン」の最後のあたりで下記の様に書かれている

IPv6 認証エラーを修正する
送信元サーバーの PTR レコードで IPv6 が使用されていない場合、IPv6 認証エラーが返される場合があります。メールサービス プロバイダを利用している場合は、プロバイダが IPv6 の PTR レコードを使用していることを確認してください。

IPv6 認証エラーの例を次に示します。
550-5.7.1: Message does not meet IPv6 sending guidelines regarding PTR records and authentication.(メールが PTR レコードと認証に関する IPv6 の送信ガイドラインに準拠していません。)

あと、最初の方に書かれているIPアドレスに対する要件も関係している

インフラストラクチャ設定の要件とガイドライン
IP アドレス
重要: 送信元 IP アドレスは、ポインタ(PTR)レコードで指定されたホスト名の IP アドレスと一致している必要があります。

送信元 SMTP サーバーのパブリック IP アドレスには、対応するホスト名を参照する PTR レコードが必要です。これは、リバース DNS ルックアップと呼ばれます。このホスト名には、送信元サーバーと同じパブリック IP アドレスを参照する A レコード(IPv4 の場合)または AAAA レコード(IPv6 の場合)も必要です。これは、フォワード DNS ルックアップと呼ばれます。
送信元サーバーの IP アドレスとドメインを対応付ける有効なリバース DNS レコードを設定します。Google 管理者ツールボックスの Dig ツールを使用して PTR レコードを確認します。
重要: 送信元 IP アドレスは、ポインタ(PTR)レコードで指定されたホスト名の IP アドレスと一致している必要があります。

つまり、IPv6アドレスのPTRレコードに対してちゃんとホスト名を設定する必要があるようだ。

じゃあ、Oracle Cloudの場合、それを設定できるのか?を確認

Oracle Cloud Infrastructureドキュメント:逆引きDNS (PTR)

クラウドIPアドレスに対してPTRレコードを確立するようにリクエストできます:
1. リクエストをオープンする前の完全修飾ドメイン名をIPに示したA (IPv4)またはAAAA (IPv6)フォワード・レコードを作成します。レコードは、Oracle Cloud Infrastructure DNSサービスまたはサードパーティDNSプロバイダを使用して作成できます。
2. サービス・リクエストをオープンして、次の情報を含めます:
a. PTRに必要なIPアドレスおよび完全修飾ドメイン名(FQDN)。
b. ステップ1で作成したフォワード・レコードのFQDN。

サービス・リクエストの受信後、フォワード(AまたはAAAA)レコード情報は、正常に解決できることが検証され、OracleによってPTRレコードが作成されます。

Web UIでは設定できないのでサービスリクエストから申請する必要がある、とのこと。

サービスリクエストのリンクを飛ぶと「サポート・リクエスト」になったが、読むと・・・

サポート・リクエストは有料アカウントでのみ利用可能です。Always Freeリソースのみを使用する顧客およびFree Tierアカウントを使用する顧客はOracle Supportの対象ではありません。サポートが必要な場合は、サポート・チャットおよびCloud Customer Connectを使用します。

とある、サポートチャットで、対応してもらえるんだろうか?

OCI CLIコマンドのdnsオプションで操作できないのか?

パッケージ oci-utils ではなく、パッケージ python39-oci-cli の方だった

[root@ocimail ~]# dnf install python39-oci-cli
Last metadata expiration check: 2:19:30 ago on Thu 30 Oct 2025 08:47:09 AM JST.
Dependencies resolved.
==============================================================================================================================================================================================================================
 Package                                                        Architecture                               Version                                               Repository                                              Size
==============================================================================================================================================================================================================================
Installing:
 python39-oci-cli                                               noarch                                     3.69.0-1.el9                                          ol9_oci_included                                        46 M
Upgrading:
 python39-oci-sdk                                               x86_64                                     2.162.0-1.el9                                         ol9_oci_included                                        91 M
Installing dependencies:
 python3-arrow                                                  noarch                                     1.2.3-5.el9                                           ol9_developer_EPEL                                     166 k
 python3-importlib-metadata                                     noarch                                     4.12.0-2.el9                                          ol9_oci_included                                        75 k
 python3-jmespath                                               noarch                                     0.10.0-4.el9                                          ol9_oci_included                                        78 k
 python3-prompt-toolkit                                         noarch                                     3.0.38-4.el9                                          ol9_oci_included                                       1.0 M
 python3-terminaltables                                         noarch                                     3.1.10-8.0.1.el9                                      ol9_oci_included                                        60 k
 python3-wcwidth                                                noarch                                     0.2.5-8.el9                                           ol9_appstream                                           65 k
 python3-zipp                                                   noarch                                     3.20.1-2.el9                                          ol9_oci_included                                        48 k

Transaction Summary
==============================================================================================================================================================================================================================
Install  8 Packages
Upgrade  1 Package

Total download size: 138 M
Is this ok [y/N]: y
<略>
Upgraded:
  python39-oci-sdk-2.162.0-1.el9.x86_64                                                                                                                                                                                       
Installed:
  python3-arrow-1.2.3-5.el9.noarch     python3-importlib-metadata-4.12.0-2.el9.noarch   python3-jmespath-0.10.0-4.el9.noarch   python3-prompt-toolkit-3.0.38-4.el9.noarch   python3-terminaltables-3.1.10-8.0.1.el9.noarch  
  python3-wcwidth-0.2.5-8.el9.noarch   python3-zipp-3.20.1-2.el9.noarch                 python39-oci-cli-3.69.0-1.el9.noarch  

Complete!
[root@ocimail ~]# 

いれたものの、DNSの逆引き設定ができそうな感じはなかった・・・

とりあえず、IPv6を使わないようにすればごまかせる、という話が「How I Fixed Gmail Rejecting Emails by Disabling IPv6 in Postfix」にあったので /etc/postfix/main.cfの「inet_protocols = all」を「inet_protocols = ipv4」に変更

# Enable IPv4, and IPv6 if supported
inet_protocols = ipv4

ただ、これをやったところ、dovecot submissionで受け取ったメールがpostfixに引き渡されてくれないという問題が発生・・・

「how to set smtp-client -> submission_relay_host for IPv4 only?」で似たような感じで、IPv4だけでつなげたい場合設定はあるのか?という話があるが、/etc/hosts に書くぐらいの対処方法しかないようだ

で・・・さらに原因を調査してみて判明したこと

どうやら、Oracle Cloud内部の仮想マシン上から外部のIPv4アドレスに対してのポート25アクセスができない模様

IPv6アドレスであればいける

[root@ocimail ~]# telnet 外部メールサーバ 25
Trying <IPv6アドレス>...
Connected to 外部メールサーバ.
Escape character is '^]'.
220 外部メールサーバ ESMTP Postfix
quit
221 2.0.0 Bye
Connection closed by foreign host.
[root@ocimail ~]# telnet -4 外部メールサーバ 25
Trying <IPv4アドレス>...
^C
[root@ocimail ~]# 

ポート80だったらIPv4でも問題無いので、IPv4 ポート25に関してだけ規制されている模様

[root@ocimail ~]# telnet -4 外部メールサーバ 80
Trying <IPv4アドレス>...
Connected to 外部メールサーバ.
Escape character is '^]'.
GET / HTTP/1.0

HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Thu, 30 Oct 2025 06:02:36 GMT
Content-Type: text/html
Content-Length: 162
Connection: close
Location: https://_/
X-Frame-Options: sameorigin
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
X-Download-Options: noopen
X-Permitted-Cross-Domain-Policies: none
Content-Security-Policy: default-src https: data: 'unsafe-inline' 'unsafe-eval'
Referrer-Policy: strict-origin

<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>
Connection closed by foreign host.
[root@ocimail ~]# 

試しにOCIのセキュリティリストのセキュリティルールにて、エグレスルールとして、ポート25を追加してみたものの状況は変わりませんでした。(ステートフルのチェックを入れた場合も変化無し)

・・・Oracle Cloudドキュメントにポート25はブロックしてると記載されていました。

「アウトバウンドSMTPがブロックされます」