diff --git a/deployments/services/email/Proxmox Mail Gateway.md b/deployments/services/email/Proxmox Mail Gateway.md index 5fd257c..2d772ac 100644 --- a/deployments/services/email/Proxmox Mail Gateway.md +++ b/deployments/services/email/Proxmox Mail Gateway.md @@ -1,418 +1,159 @@ --- tags: -- Proxmox Mail Gateway -- PMG -- Mailcow -- Email -- SMTP -- Gateway -- Spam Filtering + +* Proxmox Mail Gateway +* PMG +* Mailcow +* Email +* SMTP +* Gateway +* Spam Filtering --- +# Proxmox Mail Gateway Inbound Filtering for Mailcow + ## Purpose -The purpose of this document is to illustrate how to place Proxmox Mail Gateway in front of an existing Mailcow email server for inbound SMTP filtering. -This document assumes that Mailcow has already been deployed using the companion Mailcow deployment document, and that Mailcow is already functional for mailbox hosting, webmail, SMTP submission, IMAP, POP3, and certificate handling. +This document defines the procedure for placing `Proxmox Mail Gateway` in front of an existing `Mailcow` server for inbound SMTP filtering. -!!! note "Assumptions" - It is assumed that you are deploying Proxmox Mail Gateway into an existing homelab or small production environment where Mailcow is already deployed internally. +PMG will handle inbound SMTP inspection before delivering accepted mail to Mailcow. - This document uses the following example IP addresses: +This document covers **inbound SMTP filtering only**. - ```text - Proxmox Mail Gateway: 192.168.3.15 - Mailcow Server: 192.168.3.61 - Mail Hostname: mail.bunny-lab.io - Mail Domain: bunny-lab.io - ``` +It does not move: - The intent is for Proxmox Mail Gateway to filter inbound SMTP traffic before delivering accepted mail to Mailcow. +* Outbound SMTP delivery +* DKIM signing +* SMTP submission +* IMAP +* POP3 +* ManageSieve +* Mailcow certificates +* Mailcow web access +* Roundcube access -## Target Mail Flow +## Assumptions -Before deploying Proxmox Mail Gateway, inbound SMTP traffic is sent directly to Mailcow: +Mailcow is already deployed and functional. + +Mailcow already handles: + +* Mailbox hosting +* User authentication +* Webmail +* Mailcow admin interface +* IMAP +* POP3 +* SMTP submission +* Outbound delivery +* DKIM signing +* TLS certificates for `mail.bunny-lab.io` + +Example environment: + +```text +Proxmox Mail Gateway: 192.168.3.15 +Mailcow Server: 192.168.3.61 +Mail Hostname: mail.bunny-lab.io +Mail Domain: bunny-lab.io +Firewall: pfSense +Reverse Proxy: Traefik +``` + +!!! warning "Inbound SMTP Only" + Only move public inbound SMTP port `25` to PMG during this stage. + +``` +Do not move mail client ports, outbound relay behavior, DKIM signing, or Mailcow web access. +``` + +## Architecture + +### Existing Mail Flow ```text Internet - ↓ + | + v pfSense WAN :25 - ↓ + | + v Mailcow 192.168.3.61:25 ``` -After deploying Proxmox Mail Gateway, inbound SMTP traffic should be sent to PMG first: +### Target Mail Flow ```text Internet - ↓ + | + v pfSense WAN :25 - ↓ -Proxmox Mail Gateway 192.168.3.15:25 - ↓ + | + v +PMG 192.168.3.15:25 + | + v Mailcow 192.168.3.61:25 ``` -!!! note "Inbound Filtering Only" - This document only covers inbound SMTP filtering. - - Outbound mail flow, DKIM signing, SMTP submission, IMAP, POP3, webmail, and Mailcow certificates should remain unchanged for now. - -## What PMG Will Handle - -Proxmox Mail Gateway will handle: +### Final Service Ownership ```text -Inbound SMTP on port 25 -Spam filtering -Virus filtering -Mail gateway tracking -Quarantine handling -Delivery of accepted inbound mail to Mailcow +PMG + - Inbound SMTP on port 25 + - Spam filtering + - Virus filtering + - Tracking Center + - Quarantine + - Delivery of accepted inbound mail to Mailcow + +Mailcow + - Mailbox hosting + - User authentication + - Webmail + - Mailcow admin interface + - IMAP + - POP3 + - SMTP submission + - Outbound mail delivery + - DKIM signing + - TLS certificates for mail.bunny-lab.io + +Traefik + - Public HTTP + - Public HTTPS + - Mailcow / Roundcube frontend routing ``` -Mailcow will continue to handle: +## DNS -```text -Mailbox hosting -User authentication -Webmail -Mailcow admin interface -IMAP -POP3 -SMTP submission -Outbound mail delivery -DKIM signing -TLS certificates for mail.bunny-lab.io -``` - -!!! warning "Do Not Move Everything at Once" - For the first deployment, only move inbound SMTP port `25` to Proxmox Mail Gateway. - - Do not change outbound mail routing, DKIM signing, or authenticated submission until inbound mail flow has been confirmed stable. - -## Firewall / NAT Configuration - -Update the firewall rules so that inbound SMTP traffic is sent to Proxmox Mail Gateway instead of directly to Mailcow. - -Change this: - -```text -WAN :25 -> Mailcow 192.168.3.61:25 -``` - -To this: - -```text -WAN :25 -> Proxmox Mail Gateway 192.168.3.15:25 -``` - -Using the example IP addresses in this document: - -```text -WAN :25 -> 192.168.3.15:25 -``` - -Leave the existing Mailcow client access ports pointed directly at Mailcow: - -```text -WAN :465 -> Mailcow 192.168.3.61:465 -WAN :587 -> Mailcow 192.168.3.61:587 -WAN :993 -> Mailcow 192.168.3.61:993 -WAN :995 -> Mailcow 192.168.3.61:995 -WAN :110 -> Mailcow 192.168.3.61:110 -WAN :143 -> Mailcow 192.168.3.61:143 -WAN :4190 -> Mailcow 192.168.3.61:4190 -``` - -Web traffic should remain on the existing reverse proxy path: - -```text -WAN :80 -> Traefik :80 -WAN :443 -> Traefik :443 -``` - -!!! warning "Do Not Move Mail Client Ports to PMG" - Do not forward IMAP, POP3, SMTPS, Submission, or ManageSieve ports to Proxmox Mail Gateway. - - Proxmox Mail Gateway should handle inbound SMTP gateway traffic. Mailcow should still handle mailbox access and authenticated mail client traffic. - -## DNS Configuration - -Your public MX record should continue pointing to the public mail hostname. - -Example: +Public DNS remains unchanged. ```text bunny-lab.io MX 10 mail.bunny-lab.io -``` - -The mail hostname should continue pointing to the public WAN IP: - -```text mail.bunny-lab.io A ``` -The firewall then controls where inbound SMTP traffic is delivered internally: +The public DNS records continue pointing to the WAN IP. + +The firewall determines where inbound SMTP is delivered internally. ```text pfSense WAN :25 -> PMG 192.168.3.15:25 ``` -!!! note "DNS Does Not Need to Change" - The public DNS records do not need to point directly to the internal PMG IP. +!!! note "DNS Does Not Point to PMG Directly" + The public MX and A records do not point to the internal PMG IP. - DNS should continue pointing to the public WAN IP. The firewall NAT rule determines whether port `25` goes to Mailcow or PMG. - -## Initial PMG Login - -After installing Proxmox Mail Gateway, log into the web interface: - -```text -https://192.168.3.15:8006 +``` +NAT controls the internal SMTP destination. ``` -Use the root credentials configured during installation. +## Firewall and NAT Design -!!! note "Certificate Warning" - You may receive a browser certificate warning when accessing the PMG web interface by IP address. This is expected unless a trusted certificate has already been configured for the PMG management interface. - -## Confirm PMG Can Reach Mailcow - -Before changing public NAT, confirm that PMG can reach Mailcow on SMTP port `25`. - -From the PMG shell, run: - -```bash -nc -vz 192.168.3.61 25 -``` - -A successful result should look similar to: - -```text -(UNKNOWN) [192.168.3.61] 25 (smtp) open -``` - -!!! note "Reverse DNS Warning" - When testing with `nc`, you may see a message like this: - - ```text - inverse host lookup failed: Unknown host - ``` - - This does not necessarily indicate a problem. - - If the final result still shows port `25` as open, SMTP connectivity to Mailcow is working. - -## Confirm Mailcow's SMTP Banner - -From the PMG shell, connect directly to Mailcow on SMTP port `25`: - -```bash -nc 192.168.3.61 25 -``` - -You should receive an SMTP banner from Mailcow. - -Example: - -```text -220-mail.bunny-lab.io ESMTP Postcow -220 mail.bunny-lab.io ESMTP Postcow -``` - -After confirming the banner, type: - -```text -quit -``` - -Then press **Enter**. - -!!! note "Mailcow SMTP Banner" - Mailcow commonly presents itself as `Postcow`. - - This is expected and confirms that Mailcow's SMTP service is responding. - -## Configure PMG SMTP Ports - -In the Proxmox Mail Gateway web interface, navigate to: - -```text -Configuration > Mail Proxy > Ports -``` - -Confirm the following value: - -```text -External SMTP Port: 25 -``` - -For this inbound-only deployment, external mail servers should connect to PMG on port `25`. - -!!! note "Internal SMTP Port" - Proxmox Mail Gateway also has an internal SMTP port, which is commonly used for outbound filtering from an internal mail server. - - This document does not use outbound filtering yet, so do not change outbound mail routing at this stage. - -## Configure Relay Domains - -In the Proxmox Mail Gateway web interface, navigate to: - -```text -Configuration > Mail Proxy -``` - -Then select the: - -```text -Relay Domains -``` - -tab. - -!!! note "PMG Tab Layout" - PMG may open the Mail Proxy section on the `Relaying` tab by default. - - `Relay Domains` is a tab inside the Mail Proxy configuration area, not a separate left-side menu item. - -Add the mail domain that PMG should accept mail for: - -```text -bunny-lab.io -``` - -This tells PMG that it is allowed to receive mail for the domain. - -!!! warning "Do Not Skip Relay Domains" - If the domain is not listed as a relay domain, PMG may reject inbound mail because it does not know that it is responsible for accepting mail for that domain. - -## Configure Mailcow as the Default Relay - -In the Proxmox Mail Gateway web interface, navigate to: - -```text -Configuration > Mail Proxy > Relaying -``` - -Configure the default relay as follows: - -```text -Default Relay: 192.168.3.61 -Relay Port: 25 -Relay Protocol: smtp -Disable MX Lookup: Yes -Smarthost: none -``` - -This tells PMG to deliver accepted inbound mail directly to Mailcow. - -```text -PMG 192.168.3.15 - ↓ -Mailcow 192.168.3.61:25 -``` - -!!! note "Why Disable MX Lookup?" - PMG should not perform a public MX lookup for your own domain when delivering mail internally. - - Since Mailcow is the internal destination server, PMG should deliver directly to `192.168.3.61`. - -!!! note "No Smarthost for Inbound-Only" - For this inbound-only deployment, leave `Smarthost` unset or set to `none`. - - Smarthost configuration is normally used for outbound relay behavior, which is not being configured in this document. - -## Configure Mailcow to Trust PMG - -Because inbound mail will now arrive at Mailcow from PMG, Mailcow should be configured to trust PMG as a forwarding host. - -In Mailcow, navigate to: - -```text -System > Configuration Dropdown > Options > Forwarding Hosts Dropdown -``` - -Add the PMG IP address: - -```text -192.168.3.15 -``` - -When adding the PMG IP as a forwarding host, Mailcow may ask whether spam filtering should be enabled for that forwarding host. - -For this design, set the spam filter option to: - -```text -Inactive -``` - -!!! note "Why This Matters" - Without this step, Mailcow may see PMG as the immediate sender for inbound mail. - - Trusting PMG helps Mailcow correctly interpret forwarded mail and reduces the chance of incorrect spam handling or delivery problems. - -!!! note "Why Spam Filtering Is Inactive" - PMG is intended to be the primary inbound spam and virus filtering system. - - Setting the Mailcow forwarding-host spam filter to `Inactive` avoids double-filtering mail that PMG has already inspected. - -## Leave Outbound Mail Unchanged - -For this first deployment, do not change outbound mail flow. - -Mailcow should continue sending outbound mail the same way it did before PMG was introduced. - -```text -Mailcow 192.168.3.61 - ↓ -Internet -``` - -Do not configure Mailcow to relay outbound mail through PMG yet. - -!!! recommendation "Stage the Deployment" - First, confirm that inbound mail filtering works correctly. - - After inbound mail flow is stable, outbound filtering can be planned as a separate change. - -## Leave DKIM, SPF, and DMARC Unchanged - -For this inbound-only deployment, leave the existing DKIM, SPF, and DMARC configuration unchanged. - -Mailcow should continue handling outbound signing if it was already doing so. - -```text -DKIM: Mailcow / existing configuration -SPF: Existing public DNS record -DMARC: Existing public DNS record -``` - -!!! warning "Do Not Move DKIM Yet" - Do not move DKIM signing to Proxmox Mail Gateway during the inbound-only phase. - - DKIM applies to outbound mail, and this document is only moving inbound SMTP filtering. - -## Filtering Policy - -With this design, PMG should be the primary inbound spam and virus filtering system. - -Recommended behavior: - -```text -PMG = inbound SMTP filtering, tracking, quarantine -Mailcow = mailbox hosting, authentication, webmail, IMAP, POP3, SMTP submission -``` - -!!! recommendation "Simplify Filtering" - Avoid making Mailcow and PMG both aggressively quarantine inbound mail at the same time. - - Let PMG own the inbound edge filtering role so message tracking and quarantine behavior are easier to understand. - -## Change pfSense NAT for Inbound SMTP - -After PMG and Mailcow have both been configured, update the pfSense NAT rule for inbound SMTP. +Only public inbound SMTP changes. Change this: @@ -426,9 +167,281 @@ To this: WAN :25 -> PMG 192.168.3.15:25 ``` -Do not change the other Mailcow port forwards. +Leave Mailcow client access ports pointed directly at Mailcow. -These should remain pointed at Mailcow: +```text +WAN :465 -> Mailcow 192.168.3.61:465 +WAN :587 -> Mailcow 192.168.3.61:587 +WAN :993 -> Mailcow 192.168.3.61:993 +WAN :995 -> Mailcow 192.168.3.61:995 +WAN :110 -> Mailcow 192.168.3.61:110 +WAN :143 -> Mailcow 192.168.3.61:143 +WAN :4190 -> Mailcow 192.168.3.61:4190 +``` + +Leave web traffic on the existing reverse proxy path. + +```text +WAN :80 -> Traefik :80 +WAN :443 -> Traefik :443 +``` + +!!! warning "Do Not Move Mail Client Ports to PMG" + PMG is an SMTP gateway. + +``` +Do not forward IMAP, POP3, SMTPS, Submission, or ManageSieve ports to PMG. +``` + +## Initial PMG Access + +Access the PMG management interface. + +```text +https://192.168.3.15:8006 +``` + +Use the `root` credentials configured during PMG installation. + +!!! note "Certificate Warning" + Browser certificate warnings are expected when accessing PMG by IP address unless a trusted certificate has already been configured for the management interface. + +## Pre-Cutover Connectivity Checks + +Confirm PMG can reach Mailcow on SMTP port `25`. + +Run from the PMG shell: + +```sh +# Confirm PMG can reach Mailcow SMTP +nc -vz 192.168.3.61 25 +``` + +Expected result: + +```text +(UNKNOWN) [192.168.3.61] 25 (smtp) open +``` + +Reverse DNS warnings are not automatically failures. + +```text +inverse host lookup failed: Unknown host +``` + +If port `25` still reports as open, SMTP connectivity is working. + +Confirm Mailcow presents an SMTP banner. + +```sh +# Connect from PMG directly to Mailcow SMTP +nc 192.168.3.61 25 +``` + +Expected banner: + +```text +220-mail.bunny-lab.io ESMTP Postcow +220 mail.bunny-lab.io ESMTP Postcow +``` + +Exit the SMTP session. + +```text +quit +``` + +!!! note "Mailcow SMTP Banner" + Mailcow commonly identifies its SMTP service as `Postcow`. + +``` +That is expected. +``` + +## PMG Mail Proxy Ports + +In PMG, navigate to: + +```text +Configuration > Mail Proxy > Ports +``` + +Confirm: + +```text +External SMTP Port: 25 +``` + +No outbound filtering is configured during this stage. + +!!! note "Internal SMTP Port" + PMG also has an internal SMTP port used for outbound filtering from an internal mail server. + +``` +This deployment does not use outbound PMG filtering yet. +``` + +## PMG Relay Domains + +In PMG, navigate to: + +```text +Configuration > Mail Proxy > Relay Domains +``` + +Add the accepted mail domain. + +```text +bunny-lab.io +``` + +This authorizes PMG to accept mail for the domain. + +!!! warning "Relay Domains Are Required" + If the domain is missing from Relay Domains, PMG may reject inbound mail because it is not configured as responsible for that domain. + +## PMG Default Relay + +In PMG, navigate to: + +```text +Configuration > Mail Proxy > Relaying +``` + +Configure Mailcow as the default relay. + +```text +Default Relay: 192.168.3.61 +Relay Port: 25 +Relay Protocol: smtp +Disable MX Lookup: Yes +Smarthost: none +``` + +Target internal relay path: + +```text +PMG 192.168.3.15 + | + v +Mailcow 192.168.3.61:25 +``` + +!!! note "Disable MX Lookup" + PMG should deliver accepted inbound mail directly to the internal Mailcow server. + +``` +It should not perform public MX lookup for the local mail domain. +``` + +!!! note "No Smarthost" + Leave `Smarthost` unset or set to `none` for inbound-only filtering. + +``` +Smarthost configuration is used for outbound relay behavior. +``` + +## Mailcow Forwarding Host + +Configure Mailcow to trust PMG as a forwarding host. + +In Mailcow, navigate to: + +```text +System > Configuration Dropdown > Options > Forwarding Hosts Dropdown +``` + +Add the PMG IP address. + +```text +192.168.3.15 +``` + +Set the forwarding-host spam filter option to: + +```text +Inactive +``` + +!!! note "Forwarding Host Behavior" + After cutover, Mailcow sees PMG as the immediate SMTP source for inbound mail. + +``` +Trusting PMG allows Mailcow to interpret forwarded mail correctly. +``` + +!!! note "Spam Filtering Placement" + PMG is the primary inbound spam and virus filtering system. + +``` +Leave Mailcow forwarding-host spam filtering inactive to avoid double-filtering messages already inspected by PMG. +``` + +## Outbound Mail + +Leave outbound mail unchanged. + +```text +Mailcow 192.168.3.61 + | + v +Internet +``` + +Do not configure Mailcow to relay outbound mail through PMG during this stage. + +Do not change: + +```text +Relayhost +Outbound firewall rules +DKIM signing +SPF record +DMARC record +``` + +!!! warning "Do Not Move DKIM" + DKIM signing applies to outbound mail. + +``` +This document only moves inbound SMTP filtering. +``` + +## Filtering Policy + +Initial filtering ownership: + +```text +PMG = primary inbound SMTP filtering, tracking, quarantine +Mailcow = mailbox hosting, authentication, webmail, mail client access +``` + +Avoid configuring both PMG and Mailcow to aggressively quarantine the same inbound mail stream. + +!!! note "Keep Filtering Boring" + PMG should own edge filtering first. + +``` +Mailcow should continue owning mailbox and client access behavior. +``` + +## SMTP NAT Cutover + +After PMG relay domains, PMG default relay, and Mailcow forwarding host settings are configured, update the pfSense NAT rule. + +Change: + +```text +WAN :25 -> Mailcow 192.168.3.61:25 +``` + +To: + +```text +WAN :25 -> PMG 192.168.3.15:25 +``` + +Do not change the remaining Mailcow port forwards. ```text 465 -> 192.168.3.61 @@ -440,122 +453,126 @@ These should remain pointed at Mailcow: 4190 -> 192.168.3.61 ``` -Web traffic should remain on the existing Traefik path: +Do not change the Traefik web path. ```text 80 -> Traefik 443 -> Traefik ``` -!!! warning "This Is the Actual Cutover" - Changing the NAT target for `WAN :25` is the point where external mail servers begin hitting PMG instead of Mailcow directly. +!!! warning "Cutover Point" + Changing `WAN :25` is the actual inbound mail cutover. - Make sure PMG relay domains, default relay, and Mailcow forwarding host settings are configured before applying this change. +``` +External SMTP servers will begin connecting to PMG instead of Mailcow directly. +``` -## Testing Inbound SMTP +## Validation -From an external system, test that port `25` is reachable: +### External SMTP Reachability -```bash +From an external system: + +```sh +# Confirm public SMTP is reachable nc -vz mail.bunny-lab.io 25 ``` -Or: +Alternative: -```bash +```sh +# Confirm public SMTP banner using telnet telnet mail.bunny-lab.io 25 ``` -You should see that port `25` is open. - -If using `telnet`, you should receive an SMTP banner from the gateway system. - -!!! note "Testing From Inside the Network" - Internal testing may not accurately represent public mail flow if NAT reflection or split-horizon DNS is involved. - - Test from an external network when possible. - -!!! note "If External Port Testing Is Not Available" - If you do not have a reliable external system to test SMTP connectivity from, send a real test message from an outside mailbox instead. - - Good test sources include: - - ```text - Gmail - Outlook.com - iCloud - Proton Mail - Work email hosted outside Mailcow - ``` - - Then verify that the message appears in: - - ```text - PMG > Tracking Center - ``` - - and that it is delivered into the Mailcow mailbox. - -## Testing Inbound Mail Delivery - -Send a message from an external mailbox to a mailbox hosted on Mailcow. - -Example: +Expected result: ```text -External Gmail / Outlook / work mailbox / other provider - ↓ +Port 25 open +SMTP banner returned by gateway +``` + +!!! note "Internal Testing Limitations" + Internal tests may not represent public mail flow if NAT reflection or split-horizon DNS is involved. + +``` +Prefer external testing. +``` + +If external port testing is unavailable, send real mail from an outside provider. + +Usable external sources: + +```text +Gmail +Outlook.com +iCloud +Proton Mail +Work mailbox hosted outside Mailcow +``` + +### Inbound Delivery + +Send an external message to a Mailcow-hosted mailbox. + +Expected path: + +```text +External mailbox + | + v mail.bunny-lab.io - ↓ + | + v pfSense WAN :25 - ↓ + | + v PMG 192.168.3.15 - ↓ + | + v Mailcow 192.168.3.61 - ↓ + | + v User mailbox ``` -Then review logs in both systems. - -In Proxmox Mail Gateway, check: +Check PMG: ```text -Tracking Center +PMG > Tracking Center ``` -In Mailcow, check: - -```text -System > Logs -``` - -or review the relevant Postfix and Dovecot logs from the Mailcow interface. - -A successful delivery should show something similar in PMG: +Expected PMG status: ```text Status: accepted/delivered Relay: 192.168.3.61[192.168.3.61]:25 ``` -This confirms that PMG accepted the inbound message and relayed it to Mailcow. - -## Testing Mail Client Access - -After the inbound SMTP cutover, confirm that normal mail clients still work. - -Test at least one mobile client and one desktop client if available. - -Confirm that you can still: +Check Mailcow: ```text -Receive mail over IMAP -Send mail using SMTP submission -Access webmail / Roundcube / Mailcow UI +System > Logs ``` -The following service paths should remain unchanged: +or review the relevant Mailcow Postfix and Dovecot logs. + +### Mail Client Access + +Confirm normal mail client behavior remains unchanged. + +Test: + +```text +IMAP receive +SMTP submission send +Mobile mail client access +Desktop mail client access +Webmail / Roundcube access +Mailcow UI access +``` + +Expected service paths: ```text IMAPS: 993 -> Mailcow @@ -564,73 +581,77 @@ SMTPS: 465 -> Mailcow Web: 443 -> Traefik -> Mailcow ``` -!!! note "Outbound Mail Should Still Work" - For this inbound-only deployment, outbound mail should still flow directly from Mailcow using the same behavior that existed before PMG was introduced. +Confirm outbound mail still works by replying from a Mailcow-hosted mailbox to the external sender. - A useful test is to reply from the Mailcow-hosted mailbox back to the original external sender. +### PMG Queues -## Check PMG Queues - -After sending and receiving test messages, confirm that PMG does not have messages stuck in queue. - -In PMG, navigate to: +Check PMG queues after test delivery. ```text -Queues +PMG > Queues ``` -The queue should be empty or near-empty after the test message has delivered. +Expected state: -!!! note "Why Check the Queue?" - Tracking Center confirms what happened to a specific message. +```text +Queue empty or near-empty after delivery +``` - Queue status confirms PMG is not quietly holding or deferring messages because of a relay, DNS, or delivery issue. +Queue status confirms PMG is not silently holding or deferring mail because of relay, DNS, or delivery errors. ## Validation Checklist -Use the following checklist to confirm that PMG is correctly handling inbound mail flow: - -- [ ] Public MX record points to `mail.bunny-lab.io` -- [ ] `mail.bunny-lab.io` resolves to the correct public WAN IP -- [ ] PMG can reach Mailcow on `192.168.3.61:25` -- [ ] Mailcow SMTP banner is visible from PMG -- [ ] Firewall forwards `WAN :25` to `192.168.3.15:25` -- [ ] Firewall still forwards mail client ports directly to Mailcow -- [ ] Traefik still handles web traffic for Mailcow / Roundcube -- [ ] PMG external SMTP port is `25` -- [ ] PMG has `bunny-lab.io` configured as a relay domain -- [ ] PMG default relay points to `192.168.3.61` -- [ ] PMG relay port is set to `25` -- [ ] PMG has MX lookup disabled for internal delivery -- [ ] Mailcow trusts PMG as a forwarding host -- [ ] Mailcow forwarding-host spam filter is set to `Inactive` -- [ ] Inbound test mail appears in PMG Tracking Center -- [ ] PMG Tracking Center shows the test message as `accepted/delivered` -- [ ] Expanded PMG log shows delivery to `192.168.3.61:25` -- [ ] Inbound test mail is delivered to the Mailcow mailbox -- [ ] PMG mail queue is empty after delivery -- [ ] Mobile email client still works -- [ ] Desktop email client still works -- [ ] Replying outbound from Mailcow still works -- [ ] DNS records are unchanged -- [ ] DKIM behavior is unchanged -- [ ] SPF record is unchanged -- [ ] DMARC record is unchanged -- [ ] Outbound mail routing is unchanged +* [ ] Public MX record points to `mail.bunny-lab.io` +* [ ] `mail.bunny-lab.io` resolves to the correct public WAN IP +* [ ] DNS records are unchanged +* [ ] PMG can reach Mailcow on `192.168.3.61:25` +* [ ] Mailcow SMTP banner is visible from PMG +* [ ] PMG external SMTP port is `25` +* [ ] PMG has `bunny-lab.io` configured as a relay domain +* [ ] PMG default relay points to `192.168.3.61` +* [ ] PMG relay port is `25` +* [ ] PMG relay protocol is `smtp` +* [ ] PMG internal delivery has MX lookup disabled +* [ ] PMG smarthost is unset or `none` +* [ ] Mailcow trusts `192.168.3.15` as a forwarding host +* [ ] Mailcow forwarding-host spam filter is `Inactive` +* [ ] Firewall forwards `WAN :25` to `192.168.3.15:25` +* [ ] Firewall still forwards mail client ports directly to Mailcow +* [ ] Traefik still handles Mailcow / Roundcube web traffic +* [ ] Inbound test mail appears in PMG Tracking Center +* [ ] PMG Tracking Center shows `accepted/delivered` +* [ ] PMG log shows delivery to `192.168.3.61:25` +* [ ] Inbound test mail is delivered to the Mailcow mailbox +* [ ] PMG queue is empty after delivery +* [ ] Mobile email client still works +* [ ] Desktop email client still works +* [ ] Webmail still works +* [ ] Replying outbound from Mailcow still works +* [ ] DKIM behavior is unchanged +* [ ] SPF record is unchanged +* [ ] DMARC record is unchanged +* [ ] Outbound mail routing is unchanged ## Troubleshooting ### Inbound Mail Never Reaches PMG -Verify the firewall NAT rule: +Verify NAT. ```text WAN :25 -> 192.168.3.15:25 ``` -Also verify that the ISP is not blocking inbound port `25`. +Verify inbound port `25` is not blocked by the ISP. -If external testing is unavailable, send a real test message from an outside mailbox and check: +From an external system: + +```sh +# Test public SMTP reachability +nc -vz mail.bunny-lab.io 25 +``` + +If external testing is unavailable, send a real external test message and check: ```text PMG > Tracking Center @@ -638,47 +659,67 @@ PMG > Tracking Center ### PMG Receives Mail but Does Not Deliver to Mailcow -Verify the PMG default relay configuration: +Verify PMG relay settings. ```text Default Relay: 192.168.3.61 Relay Port: 25 +Relay Protocol: smtp Disable MX Lookup: Yes ``` -Also verify that Mailcow is listening on port `25` internally: +Verify Mailcow SMTP is reachable from PMG. -```bash +```sh +# Test Mailcow SMTP from PMG nc -vz 192.168.3.61 25 ``` -### PMG Cannot Resolve Reverse DNS for Mailcow +Confirm the Mailcow SMTP banner. -When testing with `nc`, you may see: +```sh +# Inspect Mailcow SMTP banner from PMG +nc 192.168.3.61 25 +``` + +Expected banner: + +```text +220-mail.bunny-lab.io ESMTP Postcow +220 mail.bunny-lab.io ESMTP Postcow +``` + +### PMG Shows Reverse DNS Warning for Mailcow + +A warning like this is not automatically a failure: ```text inverse host lookup failed: Unknown host ``` -This is not automatically a problem. +If the connection still reports port `25` as open, SMTP connectivity is working. -If the connection still shows port `25` as open, SMTP connectivity is working. +### Mailcow Rejects Mail from PMG -### Mailcow Rejects Mail From PMG - -Verify that Mailcow trusts PMG as a forwarding host: +Verify Mailcow trusts PMG as a forwarding host. ```text 192.168.3.15 ``` -Also verify that the recipient domain and mailbox exist in Mailcow. +Verify the recipient domain exists in Mailcow. + +```text +bunny-lab.io +``` + +Verify the recipient mailbox or alias exists in Mailcow. ### Mail Clients Stop Working -Verify that only inbound SMTP port `25` was moved to PMG. +Verify only inbound SMTP port `25` was moved to PMG. -The following ports should still forward directly to Mailcow: +These ports should still forward directly to Mailcow: ```text 465 @@ -690,41 +731,57 @@ The following ports should still forward directly to Mailcow: 4190 ``` +Expected service ownership: + +```text +PMG -> inbound SMTP gateway only +Mailcow -> client access and mailbox services +``` + ### Roundcube or Mailcow Web UI Stops Working -Verify that web traffic was not moved to PMG. +Verify web traffic was not moved to PMG. -The existing web path should remain: +Expected path: ```text WAN :80 -> Traefik :80 WAN :443 -> Traefik :443 ``` -PMG should not replace Traefik for the Mailcow web frontend in this inbound-only deployment. +PMG should not replace Traefik for Mailcow or Roundcube web access. ### Outbound Mail Stops Working -Outbound mail should not be affected by this inbound-only deployment. +Outbound mail should not change during this deployment. -If outbound mail stops working, verify that no routing, relayhost, DKIM, SPF, DMARC, or outbound firewall changes were made. - -### Spam Filtering Seems Confusing - -Decide which system is the primary inbound spam filter. - -Recommended initial behavior: +Verify no changes were made to: ```text -PMG = primary inbound edge spam filter -Mailcow = mailbox hosting and mail client access +Mailcow relayhost +Outbound firewall behavior +DKIM signing +SPF record +DMARC record +Public DNS records ``` -Avoid making both systems aggressively quarantine inbound mail until basic mail flow is confirmed. +### Spam Filtering Behavior Is Confusing + +Use one primary inbound filtering authority. + +Recommended initial state: + +```text +PMG = primary inbound edge spam filter +Mailcow = mailbox hosting and client access +``` + +Avoid dual aggressive quarantine policies until basic mail flow is stable. ## Confirmed Final State -After completing this deployment, the environment should behave as follows: +After Stage 1, the environment should operate as follows: ```text Inbound SMTP: @@ -740,23 +797,41 @@ Webmail / Roundcube: Internet -> Traefik -> Mailcow ``` -The only public NAT behavior changed during this deployment was: +The only public NAT behavior changed is: ```text WAN :25 ``` -All other Mailcow service ports, DNS records, DKIM behavior, SPF, DMARC, outbound mail routing, and Traefik web routing were left unchanged. +Unchanged components: + +```text +DNS records +DKIM behavior +SPF record +DMARC record +Outbound mail routing +SMTP submission +IMAP +POP3 +ManageSieve +Mailcow certificates +Traefik web routing +Mailcow / Roundcube web access +``` ## Deployment Status -This document represents the first stage of a staged PMG deployment: +This document completes Stage 1 of the PMG deployment. ```text Stage 1: Inbound filtering only Stage 2: Optional outbound filtering ``` -At the end of Stage 1, Proxmox Mail Gateway is responsible for inbound SMTP filtering only. +At the end of Stage 1: -Mailcow continues to manage mailboxes, webmail, authenticated submission, certificates, DKIM signing, outbound delivery, and user-facing mail services. \ No newline at end of file +```text +PMG = inbound SMTP filtering only +Mailcow = mailboxes, webmail, authenticated submission, certificates, DKIM, outbound delivery, user-facing mail services +```