diff --git a/deployments/services/email/Proxmox Mail Gateway.md b/deployments/services/email/Proxmox Mail Gateway.md new file mode 100644 index 0000000..5fd257c --- /dev/null +++ b/deployments/services/email/Proxmox Mail Gateway.md @@ -0,0 +1,762 @@ +--- + +tags: +- Proxmox Mail Gateway +- PMG +- Mailcow +- Email +- SMTP +- Gateway +- Spam Filtering + +--- + +## 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. + +!!! 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. + + This document uses the following example IP addresses: + + ```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 + ``` + + The intent is for Proxmox Mail Gateway to filter inbound SMTP traffic before delivering accepted mail to Mailcow. + +## Target Mail Flow + +Before deploying Proxmox Mail Gateway, inbound SMTP traffic is sent directly to Mailcow: + +```text +Internet + ↓ +pfSense WAN :25 + ↓ +Mailcow 192.168.3.61:25 +``` + +After deploying Proxmox Mail Gateway, inbound SMTP traffic should be sent to PMG first: + +```text +Internet + ↓ +pfSense WAN :25 + ↓ +Proxmox Mail Gateway 192.168.3.15:25 + ↓ +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: + +```text +Inbound SMTP on port 25 +Spam filtering +Virus filtering +Mail gateway tracking +Quarantine handling +Delivery of accepted inbound mail to Mailcow +``` + +Mailcow will continue to handle: + +```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: + +```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: + +```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. + + 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 +``` + +Use the root credentials configured during installation. + +!!! 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. + +Change this: + +```text +WAN :25 -> Mailcow 192.168.3.61:25 +``` + +To this: + +```text +WAN :25 -> PMG 192.168.3.15:25 +``` + +Do not change the other Mailcow port forwards. + +These should remain pointed at Mailcow: + +```text +465 -> 192.168.3.61 +587 -> 192.168.3.61 +993 -> 192.168.3.61 +995 -> 192.168.3.61 +143 -> 192.168.3.61 +110 -> 192.168.3.61 +4190 -> 192.168.3.61 +``` + +Web traffic should remain on the existing Traefik 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. + + Make sure PMG relay domains, default relay, and Mailcow forwarding host settings are configured before applying this change. + +## Testing Inbound SMTP + +From an external system, test that port `25` is reachable: + +```bash +nc -vz mail.bunny-lab.io 25 +``` + +Or: + +```bash +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: + +```text +External Gmail / Outlook / work mailbox / other provider + ↓ +mail.bunny-lab.io + ↓ +pfSense WAN :25 + ↓ +PMG 192.168.3.15 + ↓ +Mailcow 192.168.3.61 + ↓ +User mailbox +``` + +Then review logs in both systems. + +In Proxmox Mail Gateway, check: + +```text +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: + +```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: + +```text +Receive mail over IMAP +Send mail using SMTP submission +Access webmail / Roundcube / Mailcow UI +``` + +The following service paths should remain unchanged: + +```text +IMAPS: 993 -> Mailcow +Submission: 587 -> Mailcow +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. + + A useful test is to reply from the Mailcow-hosted mailbox back to the original external sender. + +## Check PMG Queues + +After sending and receiving test messages, confirm that PMG does not have messages stuck in queue. + +In PMG, navigate to: + +```text +Queues +``` + +The queue should be empty or near-empty after the test message has delivered. + +!!! note "Why Check the Queue?" + Tracking Center confirms what happened to a specific message. + + Queue status confirms PMG is not quietly holding or deferring messages because of a relay, DNS, or delivery issue. + +## 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 + +## Troubleshooting + +### Inbound Mail Never Reaches PMG + +Verify the firewall NAT rule: + +```text +WAN :25 -> 192.168.3.15:25 +``` + +Also verify that the ISP is not blocking inbound port `25`. + +If external testing is unavailable, send a real test message from an outside mailbox and check: + +```text +PMG > Tracking Center +``` + +### PMG Receives Mail but Does Not Deliver to Mailcow + +Verify the PMG default relay configuration: + +```text +Default Relay: 192.168.3.61 +Relay Port: 25 +Disable MX Lookup: Yes +``` + +Also verify that Mailcow is listening on port `25` internally: + +```bash +nc -vz 192.168.3.61 25 +``` + +### PMG Cannot Resolve Reverse DNS for Mailcow + +When testing with `nc`, you may see: + +```text +inverse host lookup failed: Unknown host +``` + +This is not automatically a problem. + +If the connection still shows port `25` as open, SMTP connectivity is working. + +### Mailcow Rejects Mail From PMG + +Verify that Mailcow trusts PMG as a forwarding host: + +```text +192.168.3.15 +``` + +Also verify that the recipient domain and mailbox exist in Mailcow. + +### Mail Clients Stop Working + +Verify that only inbound SMTP port `25` was moved to PMG. + +The following ports should still forward directly to Mailcow: + +```text +465 +587 +993 +995 +110 +143 +4190 +``` + +### Roundcube or Mailcow Web UI Stops Working + +Verify that web traffic was not moved to PMG. + +The existing web path should remain: + +```text +WAN :80 -> Traefik :80 +WAN :443 -> Traefik :443 +``` + +PMG should not replace Traefik for the Mailcow web frontend in this inbound-only deployment. + +### Outbound Mail Stops Working + +Outbound mail should not be affected by this inbound-only 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: + +```text +PMG = primary inbound edge spam filter +Mailcow = mailbox hosting and mail client access +``` + +Avoid making both systems aggressively quarantine inbound mail until basic mail flow is confirmed. + +## Confirmed Final State + +After completing this deployment, the environment should behave as follows: + +```text +Inbound SMTP: +Internet -> pfSense WAN :25 -> PMG 192.168.3.15:25 -> Mailcow 192.168.3.61:25 + +Outbound SMTP: +Mailcow -> Internet + +Mail Client Access: +Clients -> Mailcow + +Webmail / Roundcube: +Internet -> Traefik -> Mailcow +``` + +The only public NAT behavior changed during this deployment was: + +```text +WAN :25 +``` + +All other Mailcow service ports, DNS records, DKIM behavior, SPF, DMARC, outbound mail routing, and Traefik web routing were left unchanged. + +## Deployment Status + +This document represents the first stage of a staged 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. + +Mailcow continues to manage mailboxes, webmail, authenticated submission, certificates, DKIM signing, outbound delivery, and user-facing mail services. \ No newline at end of file