🕊️

【AWS/RHEL9.6/Postfix/Dovecot】初心者向けメールサーバ構築記録 ~前編~

に公開

どうも!新人エンジニアの前歯すきっ歯です🦷
参画している案件でメールサーバを構築することになったので、PostfixとDovecotを用いてメールサーバを構築した備忘録をハンズオン形式で記録します!

⚙️ 0.本記事について

⚙️ 0-1.本記事のゴール

本記事では以下4点を本記事のゴールとして構築していきます💪

  1. AWS内に以下構成図のサービスを構築する。
  2. Certbotを用いて公的証明書を発行する。
  3. PostfixとDovecotの設定を行い、外部(gmail)とメールの送受信をできるようにする。
  4. メールクライアントにThunderbirdをインストールして、Thunderbirdからメールの送受信をできるように設定する。

    構成図

⚙️ 0-2.実行環境や主な設定値

以下が本記事の実行環境です。

  • EC2設定値
    ・EC2(メールサーバ):t2.micro/ディスク8GiB/RHEL9.6
    ・EC2(クライアント):t3.medium/ディスク30GiB/WindowsServer2025
  • ミドルのバージョン
    ・Postfix:postfix-2:3.5.25-1.el9.x86_64
    ・Dovecot:dovecot-2.3.16-15.el9.x86_64
    ・Thunderbird:バージョン141.0(64ビット)
  • ドメイン関連
    ・外部DNSのホストゾーン(購入するドメイン名)/メールアドレスのドメイン:example.com
    ・メールサーバのドメイン(MXレコード):mail.example.com
    ・内部DNSのホストゾーン:mail.example.com

⚙️ 0-3.本記事の大まかな流れ

本記事の流れは以下の通りです。後編のみご覧になりたい方は、以下後編の記事からスタートしてください。
■前編/本記事---------------
 1.メールサーバの役割を理解する
 2.AWS基盤構築
 3.CertbotからのSSL/TLS証明書取得
■後編/次の記事】 ---------------
 4.メールサーバ設定に必要な予備知識と事前準備
 5.Postfixの構築
 6.Dovecotの構築
 7.MTAサーバからのメール送信テスト
 8.Thunderbirdの構築
 9.その他
 10.おわりに

📡 1.メールサーバの役割を理解する

1章では以下2点を抑えていきましょう!

  • メールサーバの基礎的な仕組みや用語を理解する。
  • 構築するメールサーバやメールクライアントがメール送受信の仕組みや用語のどの部分に該当するか理解する。

📡 1-1.メールサーバの内部的な仕組みを理解する

ここでは、実際のEC2の中で各ミドルウェアが持つ役割とよく出てくる「M~A」という用語の意味を抑えてください!

📡 1-1-1.メールを送信するとき

メール送信時は図の流れでメールを送信します。

📡 1-1-2.メールを受信するとき

メール受信時は図の流れでメールを受信します。

📡【発展】[1-1]詳細

より詳しく上記用語を知りたい方は以下リンク先の動画が分かりやすくオススメです!

📡 1-2.メール送信に関わるプロトコル(ポート番号)を理解する

メール送信に関わるプロトコルは数が多く、それらの違いや選ぶ理由を掴みにくいのでここでまとめておきます!

📡 1-2-1.MUAからMTAへ接続するポート ~各種ポートの特徴~

MUAからMTAにメールを転送するときは、以下3つのポートが選択肢としてあります。
接続するプロトコルの名前はSMTPです。 それゆえに、メールサーバは「SMTPサーバ」と呼ばれることもあります。

各ポートの違いは以下の通りです。25番ポートの制限は次項で解説します。

本記事では、「広く普及しているSTARTTLS通信とMUA⇒MTA接続時の認証(別名SMTP-AUTH)を使いたい」という理由から587番ポート(別名サブミッションポート)を利用しています。
※STARTTLS通信や認証は後述する各種ミドル設定の部分で詳細に解説します。現段階では「このポートだとこんなことできるのね」くらいに捉えてください。

📡 1-2-2.MTAサーバからMTAサーバへ接続するポート

MTAサーバからMTAサーバ(メールサーバからメールサーバ)の通信は今でも25番ポートを利用しています。 その理由としては、相手メールサーバのID/PWなどを知ることができず、相手メールサーバにて認証ができないからです。 もちろん、証明書を用いた通信の暗号化は可能です。

📡 1-2-3.25番ポートの制限(OP25B)について

25番ポートはスパムメール等にてメールサーバ悪用の温床となってしまい、25番ポート周りの通信が制限されていることが多々あります。AWSも上記に該当し、25番ポート周りの通信を制限しているので、制限解除の申請が必要です。したがって、本項目ではサブミッションポートが生まれた歴史を通して25番ポートがどの送信経路で制限されるか知り、どのリソースに対して制限解除申請が必要か理解してください!

前提として、以下画像の「メーラ」がMUA、「メールサーバ」がMTAと想定してください。ISPは携帯電話から見ればdocomoやKDDI、EC2から見ればAWSが該当します。
当初はMUA⇒MTAのメール送信依頼も25番ポートを利用していました。25番ポートでは認証ができないので、第三者がMTAサーバを悪用してメールを送り放題になってしまいました。

🔗参考リンク:【#116 CCNA CCNP ネットワークスペシャリスト対策】メール サブミッションポートってなんだ?

第三者の悪用を受けて、ISPは 「自分たちが管理するネットワークから他ISP内サーバの25番ポートへ出ていく通信はできないように設定しよう」 という対策をします。この対策を『OP25B』と呼びます。例外なくAWSも上記通信制限を行っています。これらの背景から、この通信制限があってもメールサーバからメールを送れるようにするために、25番ポートを使わず587番ポートを用いたメール送信と認証の仕組みが生まれます。 この認証のことを "SMTP-AUTH"と呼びます。

🔗参考リンク:【#116 CCNA CCNP ネットワークスペシャリスト対策】メール サブミッションポートってなんだ?

上記通信制限を今回のメールサーバの仕組みや構成図に置き換えると以下の図となります。
したがって、NAT GWから外部サーバ25番ポートへ通信するために、AWSヘ通信制限解除の申請をする必要があります。 申請方法はAWS構築部分で解説します。

メールサーバの仕組みとして通信が遮断される場所

AWS構成図として通信が遮断される場所

📡【発展】[1-2]詳細

[1-2]でご紹介した内容をより詳しく知りたい方は以下リンクが分かりやすかったのでご共有です!

📡 1-3.メール受信に関わるプロトコル(ポート番号)を理解する

メール受信に関わるプロトコルも数が多く、それらの違いや選ぶ理由を掴みにくいのでここでまとめておきます!

📡 1-3-1.MUAからMRAへ接続するポート ~各種ポートの特徴~

MUAからDovecot(MRA)へ接続する時には、以下4つのポートが選択肢としてあります。

各ポートの特徴やプロトコルの名前は以下表の通りです。次項記載の理由から本記事はIMAPS(993番ポート)を使用して通信を行います。

📡 1-3-2.IMAPSの選択理由 ~IMAPとPOP3の違い~

各プロトコルの違いを通して、今回IMAPSを選択した理由をお伝えします。
具体的に、以下2点の理由から今回はIMAPSを選択しました。

  1. ストレージが安い現代でPOP3のメリットはあまりないので、複数台からメールを確認できるIMAPの方が主流となっているから。
    POP3はMUAへメールをダウンロードして管理するので、ストレージ量を節約できるメリットがあります。しかし、それはストレージが高かったり、クラウドのようにストレージのアタッチがすぐにできない時代背景でのメリットです。 現代であまりPOP3のメリットはありません。
    むしろ、POP3の「複数台でメールを管理できない」というデメリットが際立ってしまいます。
    例えば、Outlookに対して携帯とPCからPOP3で接続した場合、携帯にダウンロードされたメールはPCからは見られなくなってしまいます。それでは不便ですよね…?
    上記背景から、IMAPSが現代では主流となっており、本記事でもIMAPを選択しました。

  2. IMAPSの選択理由
    以下RFCの文章です。

    メール送信サーバ(Mail Submission Server)およびメールアクセスサーバ(Mail Access Server)への接続は、「暗黙的TLS(Implicit TLS)」を用いて行うことが望ましい(以下に定義される)。これは、平文ポートに接続して STARTTLS コマンドや類似のコマンドで TLS を交渉する方法よりも推奨される。(🔗参考リンク:RFC 8314 [1.Introduction] ※筆者訳)

📡【発展】[1-3]詳細

以下動画が分かりやすくPOP3とIMAPの挙動を再現してくださっていておすすめです!

📡 1-4.メール送受信とDNSサーバのレコード設定

📡 1-4-1.DNSの基礎とRoute53の機能

DNS関連の資料は沢山あるので、ここではDNSサーバの名前解決の仕組みや基礎的なレコードの書き方は読者の皆さんがご存知の前提として、DNSのメールサーバと関連する部分に焦点をあてます。DNSの仕組みやRoute53の機能について不安がある方はAWSが出しているBlackBeltなどが分かりやすいのでおすすめです。

📡 1-4-2.メール受信に必要なDNSレコード

メールサーバの受信に必要なレコードは一般的には以下3つです。

Route53特有の機能であるALIASレコードを用いて、CNAMEとAレコードを1つのレコードにまとめることができます。

これらのレコードは以下の通り活用されます。

📡 1-4-3.メール送信に必要なDNSレコード ~SPFレコードとは~

SPFレコードを説明した記事は多くあるので、ここでは他記事を引用した簡単な紹介に留めます。
SPFレコードとは 「自ドメインのメール送信元IPアドレスを登録するレコード」 のことです。SPFレコードは、メール受信側がSPFレコード(自ドメインの正しいメール送信元IP)とメール内記載送信元IPアドレスが一致するか調べ第三者からのメール受信を防ぐために使います。

🔗参考リンク:NRIセキュア セキュリティ用語解説 SPF (Sender Policy Framework)

今回の構成の場合は、NAT GWのEIP(送信元IPアドレス)をRoute53にSPFレコード(自ドメインの正しいメール送信元IP)として登録して、メールを受信したサーバはSPFレコードとメール内記載送信元IPアドレスが一致して正しいメール送信者なのか調べるために利用します。

SPFレコードの書き方は以下2つのサイトが分かりやすかったので参考にしてみてください!
詳細なレコードは次項でお伝えします。

📡 1-4-4.メール送信に必要なDNSレコード ~実際のレコード~

前項で紹介したSPFレコードと送信元のPTRレコードを本記事のケースに当てはめると以下レコードとなります。NAT GWのPTRレコードは、メール送信元PTRレコードがないと受信側で迷惑メールと判定されてしまうケースがあるので登録しています。

※NAT GWのEIPはRoute53に直接登録しません。登録方法は後ほどご紹介します。

また、これらの流れを整理すると以下です。

📡 1-4-5.MUA⇒MTAの接続で必要なプライベートDNS

プライベートDNSの設定では、構築VPC内でmail.example.comからメールサーバのIPアドレス(10.0.2.5)を名前解決できる設定を行います。

前提として、クライアント⇒メールサーバ間でもドメイン名mail.example.comのSSL証明書を使い通信(STARTTLSやIMAPS)を行います。そのときにクライアントからメールサーバのIPアドレス10.0.2.5に対してアクセスするとThunderbirdから 「MTAからもらった証明書にmail.example.comって書いてあるから、MUAが通信したい10.0.2.5ではない!SSLハンドシェイク中止!」というエラーが出てしまいます。 (経験者は語る)

Thunderbird上のエラー
また、上記エラーが出た時の/var/log/maillogは以下です。3行目の“SSL alert bad certificate (42)”に注目です。

/var/log/maillog内のログ
Aug 11 17:45:13 mta dovecot[1099]: imap-login: Disconnected: Connection closed:
SSL_accept() failed: error:0A000412:SSL routines::ssl/tls alert bad certificate:
SSL alert number 42 (no auth attempts in 0 secs): user=<>, rip=10.0.128.6,
lip=10.0.128.5, TLS handshaking: SSL_accept() failed: error:0A000412:
SSL routines::ssl/tls alert bad certificate: SSL alert number 42, session=<***********>

🔗参考リンク:IBM Developer for z/OS(SSL アラート・メッセージ)

補足として、検証環境規模なのでクライアントのhostsファイルに書く簡単な対応も考えました。しかし、より実務に近い形で勉強したいと考えて小規模ですが今回はプライベートDNSを作成しています。

☁️ 2.AWS基盤構築

☁️ 2-1.前提

AWS基盤関連の記事は検索すると沢山出てくるので、メールサーバに関係する部分のみピックアップして記載します。それゆえに、下記を「1章 AWS基盤部分」では構築済みの前提とします。

  • VPC、サブネット、IGW、NAT GW、ルーティング設定は構築済みと想定します。
    ※VPCの「DNS 解決」と「DNS ホスト名」は有効化。(内部DNS作成にあたり必須です。)
  • IPアドレスは以下構成図記載のものとします。
  • ルーティングはインターネットに出られるようになっていればOKです。
    <具体例>
    ・プライベートサブネット:①0.0.0.0/0はtargetがNAT GW ②10.0.0.0/16はtargetがlocal
    ・パブリックサブネット:①0.0.0.0/0はtargetがIGW ②10.0.0.0/16はtargetがlocal
  • EC2にはVPC内全ての通信を許可するセキュリティグループ(以後SG)をアタッチ済み
    ※上記SGの名前はPrivate-SGとします。また、他SGは後述します。

    2章で構築済みとする構成図

☁️ 2-2. ドメイン名の取得

以下リンクが分かりやすく解説してくださっていたので、本記事での紹介は割愛します。
ここでは連絡先等の追加登録不要で手間がかからないと思われるRoute53での取得方法をお伝えしますが、お名前ドットコムなど他サイトでの登録も可能です。

🔗参考リンク:Route53でドメインを取得する手順

☁️ 2-3. 25番ポート宛て通信の解除申請

[1-2-3.25番ポートの制限(OP25B)について]でお伝えしたように、NAT GWから外部サーバ25番ポートへ通信するために、AWSヘ通信制限解除の申請をする必要があります。申請はAWSの承認まで時間がかかるので、なるべく早めに行っておいた方が得策です。

☁️ 2-3-1. NAT GWのEIPの逆引き設定

25番ポート宛て通信の解除申請には送信元EIPとその逆引き設定が必要です。
申請の前に送信元EIP(NATGWのEIP)の逆引き設定を行います。

  1. NAT GWのEIPを選択して、[アクション]から[逆引きDNSを更新]を選択する。
  2. メールサーバのドメイン名(mail.example.com.)を入力して更新を押下する。

☁️ 2-3-2. AWSヘの送信制限解除申請

  1. 以下リンクへアクセスする。
    ▷リンク:https://support.console.aws.amazon.com/support/contacts#/rdns-limits

  2. Eメール送信制限解除申請をする。ユースケースの説明は以下3点を入力する。
    (🔗参考リンク:Amazon EC2 インスタンスまたは Lambda 関数のポート 25 の制限を解除するにはどうすればよいですか?)

    • (1)詳細なユースケース。
      <例>検証用に自分のGmailのメールアドレスにのみメールを送信します。送信回数は20~30回程度を想定しています。
    • (2)不要な E メールの送信を確実に防ぐための計画を概説するステートメント。
      <例>NLBの背後にメールサーバを置き、NLBからの通信のみを許可する設定をします。また、メールサーバ内PostfixでSpamhausに登録されたIPからの送信は制限する設定を行います。
    • (3)NAT ゲートウェイの AWS リージョン。
      <例>東京リージョン
  3. AWSからの返信を確認する。追加で質問があった場合は返信する。(日本語返信でもOK)

  4. 最終的にAWSから申請を許可した返信があれば申請完了。

☁️ 2-4. NLBの構築

☁️ 2-4-1. NLB作成にあたり必要なSGの作成

以下画像の通り、NLB周りで必要なSGを作成しておきます。
対象はPostfix-SGNLB-Mail-SGです。Postfix-SGはメールサーバにアタッチしてください。

☁️ 2-4-2. ターゲットグループの作成

ターゲットグループでEC2を選択するにあたりEC2が起動している必要があるので、メールサーバを忘れずに起動させておいてください。 以下手順や設定項目でターゲットグループを作成します。

  1. ターゲットグループの編集画面へ移動して、ターゲットグループの詳細を入力する。
    ターゲットグループ名はMail-TGとする。ヘルスチェックはデフォルト設定。
  2. ターゲットグループに追加するEC2(メールサーバ)を選択する。また、MTAサーバは25番ポートでメールを受信するので[選択したインスタンスのポート]は25を入力し、[保留中として以下を含める]を選択する。 ※メールサーバ名をMailとする。
  3. [ターゲット]に2で選択したサーバが表示されたことを確認して、[ターゲットグループの作成]を選択する。
  4. メールサーバのログにて通信の送信元がNLBにならないようにターゲットグループの設定を確認する。作成したターゲットグループを選択して、[アクション]から[ターゲットグループ属性を編集]を選択する。
  5. [クライアントIPアドレスの保持]が選択されていることを確認する。 ※デフォルトで選択されている。上記設定が選択されていないと、メール受信時のログがTLS通信がNLBと確立しているように表示されてしまう。

☁️ 2-4-3. NLBの構築

  1. ロードバランサーの作成画面へ移動する。Network Load Balancerの[作成]を選択する。
  2. NLBの詳細を入力する。NLBの名前はNLB-Mailとする。
  3. NLBとヘルスチェックが正常に作動していることを確認する。

☁️ 2-5. Route53の構築

☁️ 2-5-1. パブリックDNSの構築

  1. Route53のコンソール内のタブ[ホストゾーン]を開き、右上[ホストゾーンの作成]を選択する。ドメイン名を入力する。
  2. デフォルトでNSレコードとSOAレコードが作成される。[レコードを作成]を選択する。
  3. [1-4.メール送受信とDNSサーバのレコード設定]で紹介したレコードを入力して、レコードを作成する。NAT GWのEIPの逆引きレコードは先に設定しているので、ここでは残り3つのレコードを登録する。
  4. 作成したレコードが正しく登録されていることを確認する。

☁️ 2-5-2. プライベートDNSの構築

プライベートホストゾーンについては以下記事が丁寧に解説してくださっています!詳細が気になる方はご覧ください。

🔗参考リンク:Route53でPrivateHostedZoneを作成しVPC内の名前解決を行う

本記事に必要な設定をここではご共有します。

  1. プライベートホストゾーンを作成する。
  2. デフォルトでNSレコードとSOAレコードが作成される。[レコードを作成]を選択する。
  3. メールサーバのAレコードを作成する。
  4. 作成したレコードが正しく登録されていることを確認する。

🔒 3. CertbotからのSSL/TLS証明書取得

🔒 3-1. 前提 ~Certbot導入方法とその選択理由について~

🔒 3-1-1. EPELとsnapの違いやEPELを選択した理由

この話の前提として、デフォルトでは以下状態です。

  • RHEL標準リポジトリ内にCertbotのパッケージは含まれていない。
    Certbotがないことの確認(デフォルト設定)
    $ sudo dnf install certbot
    Updating Subscription Management repositories.
    Last metadata expiration check: 3:05:19 ago on Mon 21 Jul 2025 08:34:43 AM JST.
    No match for argument: certbot
    Error: Unable to find a match: certbot
    
  • EPEL(Extra Packages for Enterprise Linux)もしくはSnapというリポジトリからCertbotを動かすためのパッケージをインストールする必要がある。 ※EPEL、snapともにRHELのリポジトリとして設定されていない。
    リポジトリの確認(デフォルト設定)
    $ yum repolist
    Not root, Subscription Management repositories not updated
    repo id                                         repo name
    rhel-9-appstream-rhui-rpms                      Red Hat Enterprise Linux 9 for x
    rhel-9-baseos-rhui-rpms                         Red Hat Enterprise Linux 9 for x
    rhui-client-config-server-9                     Red Hat Enterprise Linux 9 Client Configuration
    

したがって、EPELとsnapどちらかを選択してリポジトリとして登録する必要があります。
2つのリポジトリの違いは以下表の通りです。

🔗参考リンク:(Certbot公式)インストール方法 ※Snap推奨の記載あり
🔗参考リンク:(RHEL公式)RHEL および CentOS Stream に EPEL をインストールする方法

自分は以下3つの理由からEPELを用いてCertbotをインストールすることにしました。

  • snapを利用するメリットがない。
    今回Certbotは動作すればよく、最新バージョンであることを求めていない。
  • RHELの通常操作dnfでまとめてパッケージを操作したり、管理したりできることにメリットを感じる。
  • 今後このメールサーバでOpenDKIMの設定をするにあたり、snapにはOpenDKIMのパッケージがないが、EPELにはOpenDKIMのパッケージがある。後ほどEPELが必要となることが見えている。
    ※OpenDKIMについて本記事に記載はしません。

🔒 3-1-2. 検証方法(HTTP検証/DNS検証)の違いとDNS検証選択理由

証明書を渡す人を選ばず誰でも証明書を発行するわけにいかないので、証明書発行過程にはドメイン保持者本人であることを検証する過程が必要です。ここではよく使われるDNS検証とHTTP検証について簡潔にご紹介します。 ※Let'sEncryptの資料では検証をチャレンジと表記されています。

🔗参考リンク:チャレンジの種類(Let'sEncrypt公式)

本記事では以下2つの理由からDNS検証を利用して証明書を発行しています。

  • メールサーバを不必要に外部に公開したくない。
    メールサーバでHTTP検証を行おうとすると、SGにて80番ポートもしくは443番ポートの受信許可設定をする必要があります。
  • メールサーバに不必要なパッケージを残したくない。
    メールサーバでHTTP検証を行う場合、メールサーバにApache等を入れていることが前提となっています。

🔒 3-1-3. Route53を用いたDNS検証方法

[3-1-2]でDNS検証の仕組みを「認証局に指定されたTXTレコードをDNSサーバに追加する。認証局がそのTXTレコードの有無を確認することで所有者確認を行う仕組み。」と紹介しました。しかし、AWSのRoute53を利用する場合、上記TXTレコードの生成/追加に加えてTXTレコード削除まで行ってくれるプラグインがあります! そのプラグインを利用して検証を行い、証明書を発行する手順を本章ではご共有します。

dns_route53 プラグインは、Amazon Web Services の Route 53 API を使用して TXT レコードを作成し、その後削除することで、dns-01 チャレンジ(DNS01)を自動的に処理します。(🔗参考リンク:certbot-dns-route53 のドキュメントへようこそ!)

🔒 3-1-4.【発展】[3-1]詳細と参考リンク

[3-1]の内容について詳細に知りたい方向けにリンクをご共有します。
もしよければご参考にどうぞ!

🔒 3-2. DNS検証用IAMユーザーの作成

いざこの項から証明書のインストールに向けて動き出していきます!

🔒 3-2-1. Route53の権限を付与するIAMポリシーの作成

まずは、CertbotがAWS内を操作するための権限を作成します。

  1. IAMポリシー内に記載が必要なため、パブリックDNSの詳細画面にあるホストゾーンIDを取得する。

  2. IAMのコンソール内[ポリシー]タブからポリシーの作成画面へ移動する。ポリシーエディタで[JSON形式]を選択し、画像下に配置したJSONを貼り付ける。ポリシーの名前はInstall-certbot-policyとしする。画面左下でエラーが出ていないことを確認し[次へ]を選択する。

    IAMポリシー(Install-certbot-policy)
    {
        "Version": "2012-10-17",
        "Id": "Install-certbot-policy",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "route53:ListHostedZones",
                    "route53:GetChange"
                ],
                "Resource": [
                    "*"
                ]
            },
            {
                "Effect": "Allow",
                "Action": [
                    "route53:ChangeResourceRecordSets"
                ],
                "Resource": [
                    "arn:aws:route53:::hostedzone/[パブリックDNSのホストゾーンID]"
                ]
            }
        ]
    }
    

    (🔗参考リンク:certbot-dns-route53 のドキュメントへようこそ!

  3. IAMポリシー名を入力し、許可しているポリシーが正しいことを[このポリシーで定義している許可]で確認する。問題なければ、ポリシーを作成する。

🔒 3-2-2. DNS検証用IAMユーザーの作成

作成したIAMポリシーを使ってIAMユーザーを作成します。

  1. IAMユーザー作成タブに移動して、IAMユーザーの作成画面へ移動する。IAMユーザーの名前をInstall-Certbotとする。
  2. 先程作成したIAMポリシーInstall-certbot-policyを選択する。
  3. 内容を確認してIAMユーザーを作成する。

🔒 3-2-3. IAMユーザーのアクセスキーを作成する。

Certbotが先ほど作ったIAMユーザーとしてAWS内で操作を実行するためにアクセスキー(自分のみ知るPWのイメージ)が必要です。ここではそのアクセスキーを作成します。

  1. 作成したIAMユーザー名を選択してIAMユーザーの詳細へ移動する。右上[アクセスキーを作成する]を選択する。 ※アクセスキー1かアクセスキー2どちらでもOK。機能に差はない。
  2. [サードパーティーサービス]を選択し、確認のチェックボックスを入れる。次へを選択する。
  3. 説明タグを入力してアクセスキーを作成する。 ※任意
  4. 必ずシークレットアクセスキーの文字列をメモする。もしくはCSVをダウンロードして保管しておく。

以上でAWSコンソール側の作業が終了です!!

🔒 3-3.証明書の発行

ここからはメールサーバにアクセスしての作業です。

🔒 3-3-1.EPELのインストール

EPELのインストール
### EPELをインストールする。
$ sudo dnf -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm
Updating Subscription Management repositories.
Last metadata expiration check: 3:35:35 ago on Mon 21 Jul 2025 08:34:43 AM JST.
epel-release-latest-9.noarch.rpm                                                                        20 kB/s |  19 kB     00:00
~~~~~(中略)~~~~~
Complete!

### EPELが追加されていることを確認する。
$ dnf repolist
Not root, Subscription Management repositories not updated
repo id                                        repo name
epel                                           Extra Packages for Enterprise Linux 9 - x86_64
epel-cisco-openh264                            Extra Packages for Enterprise Linux 9 openh264 (From Cisco) - x86_64
rhel-9-appstream-rhui-rpms                     Red Hat Enterprise Linux 9 for x86_64 - AppStream from RHUI (RPMs)
rhel-9-baseos-rhui-rpms                        Red Hat Enterprise Linux 9 for x86_64 - BaseOS from RHUI (RPMs)
rhui-client-config-server-9                    Red Hat Enterprise Linux 9 Client Configuration

🔒 3-3-2.CertbotのインストールとDNS検証の準備

Certbotのインストール
### Certbotをインストールする。
$ sudo dnf -y install certbot
Updating Subscription Management repositories.
Extra Packages for Enterprise Linux 9 - x86_64                                                          12 MB/s |  20 MB     00:01
Extra Packages for Enterprise Linux 9 openh264 (From Cisco) - x86_64                                   1.4 kB/s | 2.5 kB     00:01
~~~~~(中略)~~~~~
Complete!

### Route53でDNS検証を行うパッケージをインストールする。
$ sudo dnf -y install python3-certbot-dns-route53
Updating Subscription Management repositories.
Last metadata expiration check: 1:21:07 ago on Mon 21 Jul 2025 12:38:41 PM JST.
~~~~~(中略)~~~~~
Complete!

### IAMユーザーのアクセスキーが記載されたファイルを作成する。
$ sudo mkdir /root/.aws
$ sudo vi /root/.aws/credentials
    --------------
    ### 以下内容を入力してファイルを保存する。
    [default]
    aws_access_key_id = [IMAユーザーのアクセスキー]
    aws_secret_access_key = [IMAユーザーのシークレットアクセスキー]
    --------------

🔒 3-3-3.証明書の発行

ここからは証明書の発行過程です。
コマンドオプションが詳細に紹介されているリンクは実行コマンドの後にご共有します!

証明書の発行可否の確認テスト
### 証明書が発行できるか確認する。
### "The dry run was successful."と最後に表示されたらOK
$ sudo certbot certonly --dry-run --dns-route53 \
-d mail.example.com \
-m [Let’Encryptと連絡を取るメールアドレス] \
--agree-tos -n
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Simulating a certificate request for mail.example.com
The dry run was successful.
オプション 説明
--dry-run 「更新」または「証明書取得」をテスト実行。証明書をディスクに保存しない。
--dns-route53 Route53パッケージを用いてDNS検証を行う。
-d 証明書の取得を申請するドメイン名を指定する。
-m アカウントの登録や回復などに使用する電子メールアドレスを指定する。
--agree-tos ACMEサーバーのサブスクライバー契約に同意する。
-n 非対話形式でコマンドを実行する。

🔗参考リンク:certbot(Letsecnrypt)コマンド・オプションを真面目に理解する
🔗参考リンク:Let's Encrypt 総合ポータル コマンド解説(コマンドリファレンス)

証明書の発行(本番)
### 証明書を発行する。
$ sudo certbot certonly --dns-route53 \
-d mail.example.com \
-m [Let’Encryptと連絡を取るメールアドレス] \
--agree-tos -n
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Requesting a certificate for mail.example.com

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/mail.example.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/mail.example.com/privkey.pem
This certificate expires on 2025-10-19.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
 * Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
 * Donating to EFF:                    https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

### 【おまけ】サーバ証明書を確認する。(サーバ証明書を見たければ)
$ sudo openssl x509 -in /etc/letsencrypt/live/mail.example.com/fullchain.pem -text

これにてサーバ証明書が無事に発行完了です!
自己証明書を作ったことがあったりすると、簡単すぎてびっくりしちゃいますよね…。

🔒 3-4.証明書自動更新設定

🔒 3-4-1.証明書の自動更新はデフォルトで設定済み

[3-3-3.証明書の発行]の証明書発行時にもThese files will be updated when the certificate renews.Certbot has set up a scheduled task to automatically renew this certificate in the background.と記載があったように、証明書発行時に証明書が自動的に更新されるように設定されています。

ほとんどの Certbot インストールには、自動更新があらかじめ設定されています。これは、certbot renew を定期的に実行するスケジュールタスクによって行われます。(🔗参考リンク:Certbotユーザーガイド 自動更新)

renewは有効期限が近いサーバ証明書を自動的に更新するサブコマンドです。
🔗参考リンク:Let's Encrypt 総合ポータル コマンド解説(コマンドリファレンス)

実際に確認してみます。RHEL9ではSystemd Timerで定期実行するので、systemctl list-timersコマンドで確認します。UNIT列の3行目にcertbot-renew.timerと記載があります。 ※ここではSystemedについて詳しく触れないので、不明な場合は適宜テキスト内リンク先をご覧ください!

Certbotの自動更新設定確認
$ sudo systemctl list-timers
NEXT                        LEFT          LAST                        PASSED       UNIT                         ACTIVATES             >
Sun 2025-08-24 10:39:20 JST 3min 36s left Sun 2025-08-24 10:34:20 JST 1min 23s ago nm-cloud-setup.timer         nm-cloud-setup.service
Sun 2025-08-24 10:50:19 JST 14min left    -                           -            dnf-makecache.timer          dnf-makecache.service
Sun 2025-08-24 13:35:28 JST 2h 59min left Thu 2025-08-21 10:53:25 JST 2 days ago   certbot-renew.timer          certbot-renew.service
Sun 2025-08-24 13:52:00 JST 3h 16min left Thu 2025-08-21 07:02:47 JST 3 days ago   insights-client.timer        insights-client.service
Mon 2025-08-25 00:00:00 JST 13h left      Sun 2025-08-24 10:06:39 JST 29min ago    logrotate.timer              logrotate.service
Mon 2025-08-25 10:21:46 JST 23h left      Sun 2025-08-24 10:21:46 JST 13min ago    systemd-tmpfiles-clean.timer systemd-tmpfiles-clean>

6 timers listed.
Pass --all to see loaded but inactive timers, too.

では、証明書を更新する設定が入っているのか確認していきます。まずは、systemdの設定ファイルがある/usr/lib/systemd/system配下を覗きます。
certbot-renew.servicecertbot-renew.timerの設定ファイルがありますね!

Certbotのサービス
$ sudo ls -l /usr/lib/systemd/system | grep certbot
-rw-r--r--  1 root root  284 Mar 27 07:12 certbot-renew.service
-rw-r--r--  1 root root  195 Mar 27 07:12 certbot-renew.timer

foo.timerで指定した時刻にfoo.serviceが実行される仕組みです。

各タイマーファイルに対して、タイマーが満了したときに起動されるユニットを記述した対応するユニットファイルが存在しなければなりません。既定では、タイマーと同じ名前(拡張子を除く)のサービスが起動されます。
例:foo.timer というタイマーファイルは、対応する foo.service を起動します。
(🔗参考リンク:systemd.timer(5) — Linux manual page/DESCRIPTION) ※筆者訳

では、certbot-renew.timerの設定ファイルの中身を見ていつ定期実行される設定になっているのか確認します。各設定項目の意味は後述します。

certbot-renew.timerの設定値
$ sudo cat /usr/lib/systemd/system/certbot-renew.timer
[Unit]
Description=This is the timer to set the schedule for automated renewals

[Timer]
OnCalendar=*-*-* 00/12:00:00
RandomizedDelaySec=12hours
Persistent=true

[Install]
WantedBy=timers.target

※RHEL9のリンクだけでは伝えることが難しく他ディストリビューションのリンクもありますが、意味は同じなのでご容赦を…。気になる方はman systemd.serviceを実行してみてください…!

項目 説明 リンク
Description このユニットの概要。(設定に関係ない) 1.4. [Unit] セクションの重要なオプション
OnCalendar=*-*-* 00/12:00:00 0時と12時に実行する。(正確には、0時から始めて12時間ごとに実行する) systemd.timer(5) — Linux manual page/OPTIONS/systemd.time(7) — Linux manual page/CALENDAR EVENTS
RandomizedDelaySec=12hours 実行時刻に対して 0〜12時間のランダムな遅延を追加。負荷の集中を緩和。 systemd.timer(5) — Linux manual page/OPTIONS
Persistent=true システムがシャットダウンしている間に実行されるはずだったタスクが、システム起動後直ちに実行される。 systemd.timer(5) — Linux manual page/OPTIONS
WantedBy=timers.target サービスがsystemctl enable設定のとき、タイマーの時間が来たら実行される。 知っておくとちょっと便利!systemd.timer によるタスク管理

※OnCalendarの値にある/は間隔を意味するので、*-*-* 00/12:00:00/12は「0時から始めて12時間ごと」を意味します。すなわち、「毎日0時と12時」に実行される指定です。

"/" を使うと、それは間隔(ステップ値)を意味します。たとえば "Mon..Fri/2" は月曜から金曜の範囲で2日おき、同様に分フィールドで "00/15" と書けば「00, 15, 30, 45」を意味します。(🔗参考リンク:systemd.time(7) — Linux manual page/CALENDAR EVENTS ) ※筆者訳

A.timerで指定された時刻で起動するサービスはA.serviceなので、certbot-renew.serviceを覗いてみます。各設定項目の意味は後述します。

certbot-renew.timerで実行されるcertbot-renew.service
$ sudo cat /usr/lib/systemd/system/certbot-renew.service
[Unit]
Description=This service automatically renews any certbot certificates found

[Service]
EnvironmentFile=/etc/sysconfig/certbot
Type=oneshot
ExecStart=/usr/bin/certbot renew --noninteractive --no-random-sleep-on-renew $PRE_HOOK $POST_HOOK $RENEW_HOOK $DEPLOY_HOOK $CERTBOT_ARGS
項目 説明 リンク
Description このユニットの概要。(設定に関係ない) 1.4. [Unit] セクションの重要なオプション
EnvironmentFile=/etc/sysconfig/certbot ExecStartで指定する変数を格納したファイルを指定する。※/etc/sysconfig/certbot内でExecStart内の変数はデフォルトで設定されていません systemd.service — Service unit configuration/Command lines
Type=oneshot ExecStart= のコマンドが終了した時点でユニットは成功と見なされ、サービスが継続的にactive にはならず終了する。 1.5. [Service] セクションの重要なオプション
ExecStart=/usr/bin/certbot renew --noninteractive --no-random-sleep-on-renew $PRE_HOOK $POST_HOOK $RENEW_HOOK $DEPLOY_HOOK $CERTBOT_ARGS ユニットの開始時に実行するコマンドまたはスクリプトを指定します。certbot renewコマンドと/etc/sysconfig/certbotで指定された$PRE_HOOKなどを実行する。 1.5. [Service] セクションの重要なオプション

これらのことから certbot renewコマンド(証明書更新)は0時と12時に定期実行されていることが分かります。 したがって、よくcronに証明書の更新コマンドcertbot renewを入れる記事を見かけますが、そのような設定は不要かと考えています。しかし、証明書更新時にPostfixとDovecotを再起動させて新しいサーバ証明書を読み込む設定はまだ入っていません。 次項ではその詳細をお伝えします!

🔒 3-4-2.PostfixとDovecotのインストール

「証明書更新時にPostfixとDovecotを再起動させて新しいサーバ証明書を読み込む設定」を入れたいのですが、まだPostfixとDovecotをインストールしてませんでした…。上記設定のために、このタイミングでインストールだけさせてください笑

PostfixとDovecotのインストール
### Postfixをインストールする
$ sudo dnf -y install postfix
~~~~~(中略)~~~~~
Complete!

### Postfixのサービス起動&OS起動時自動起動有効化
$ sudo systemctl enable --now postfix
### 上記設定が反映されているか確認する。
$ sudo systemctl status postfix


### Dovecotをインストールする
$ sudo dnf -y install dovecot
~~~~~(中略)~~~~~
Complete!

### Dovecotのサービス起動&OS起動時自動起動有効化
$ sudo systemctl enable --now dovecot
### 上記設定が反映されているか確認する。
$ sudo systemctl status dovecot

🔒 3-4-3.証明書更新後のPostfixとDovecotのサービス再起動設定

「/etc/letsencrypt/renewal-hooks/deployというディレクトリにファイル(PostfixとDovecotのサービス再起動をするシェルスクリプト)を配置して実現します。注意点として/etc/letsencrypt/renewal-hooks/post配下だと証明書更新を"試みた"後でもよく、更新に"成功した"後ではありません!

Certbot が証明書の更新時期に達したことを検出すると、--pre-hook と --post-hook のフックは、それぞれ更新を試みる前後に実行されます。フックを更新が成功した後にのみ実行したい場合は、以下のように --deploy-hook を使用します。
certbot renew --deploy-hook /path/to/deploy-hook-script
また、Certbot の設定ディレクトリのサブディレクトリにファイルを配置することで、フックを指定することもできます。設定ディレクトリが /etc/letsencrypt である場合、/etc/letsencrypt/renewal-hooks/pre、/etc/letsencrypt/renewal-hooks/deploy、および /etc/letsencrypt/renewal-hooks/post にある実行可能ファイルは、それぞれ pre フック、deploy フック、post フックとして実行されます。(🔗参考リンク:Certbot ユーザーガイド/証明書の更新)

では、実際にやっていきましょう!

証明書の自動更新後のサービス再起動設定
### シェルスクリプトの設定
$ sudo vi /etc/letsencrypt/renewal-hooks/deploy/ReloadService.sh
    ###以下テキストを入力して保存する。
    ---------
    #!/bin/sh
    systemctl restart postfix.service dovecot.service
    ---------

### シェルスクリプトとして実行できるように権限を付ける。
$ sudo chmod 744 /etc/letsencrypt/renewal-hooks/deploy/ReloadService.sh

### 実行権限が付いたことを確認する。
$ sudo ls -l /etc/letsencrypt/renewal-hooks/deploy/ReloadService.sh
-rwxr--r-- 1 root root 59 Aug 24 21:39 /etc/letsencrypt/renewal-hooks/deploy/ReloadService.sh

上記ファイルが起動できたことは証明書更新後にしか分からないので、あしからず…。

🔒 3-4-4.証明書が更新できることを確認する。

更新時期になり証明書が自動更新されないと困るので--dry-runコマンドを使用して、最後に証明書が更新できることを確認しましょう!

証明書の自動更新確認
$ sudo certbot renew --dry-run
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/mail.example.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Simulating renewal of an existing certificate for mail.example.com

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all simulated renewals succeeded:
  /etc/letsencrypt/live/mail.example.com/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

以上がCertbotの設定でした。お疲れ様でした!
続きは以下後編の記事にてお届けします!

https://zenn.dev/gapteeth/articles/6b4111f1f02a7c

Discussion