PMG behind Proxmox DNAT - real sender IP not visible, SPF checks failing

Al Bakk

New Member
Jul 10, 2026
2
0
1
Hello community,


I have PMG running as a VM inside Proxmox VE. All incoming mail on port 25 is forwarded via DNAT to the PMG VM.


Current setup:



Internet → Proxmox Host (public IP)
→ DNAT port 25 → PMG VM (10.0.0.4)
→ PMG always sees: connect from unknown[internal gateway 10.0.0.1]

Problem:


PMG always sees the internal gateway IP instead of the real external sender IP. This causes SPF checks to fail for senders with -all in their SPF record, because the internal gateway IP is not authorized to send for their domain.


What I already tried:


  • XFORWARD: configured on PMG (smtpd_authorized_xforward_hosts = internal gateway IP) but Proxmox DNAT cannot pass XFORWARD
  • XCLIENT: same problem, Proxmox DNAT is in between

Question:


Is there a way to make PMG see the real sender IP without changing the network architecture? For example using a bridge network, or any other solution that works with Proxmox DNAT?


Thank you!
 
Hello,

The reason you are seeing the internal gateway IP (10.0.0.1) instead of the real public IP is usually due to Source NAT (SNAT) or Masquerading being applied on the Proxmox Host alongside the DNAT rule.

When masquerading is active for the whole subnet, the host replaces the original sender's IP with its own internal bridge IP so the VM knows how to route the traffic back. Standard DNAT alone sometimes struggles to preserve the original source IP depending on how the host routing and firewall rules are set up.

While I cannot guarantee this will perfectly fit your specific environment, here are a few ideas that might be worth exploring:

Idea 1: Reviewing Masquerading vs Pure DNAT
If your PMG VM already uses the Proxmox Host (10.0.0.1) as its default gateway for all outbound internet traffic, you might not need SNAT for incoming mail traffic. You could try checking if your host masquerade rule is too broad.

For example, if the host has a broad rule like:

iptables -t nat -A POSTROUTING -s '10.0.0.0/24' -o eth0 -j MASQUERADE

You could try ensuring that masquerading is only applied to traffic actually leaving the host for the internet, rather than traffic directed inbound to the VM. In theory, if the PMG VM uses the host as its default gateway, a pure DNAT rule without SNAT should allow the original source IP to pass through:

iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 25 -j DNAT --to-destination 10.0.0.4:25

Idea 2: Looking into the PROXY Protocol
If you are open to using a lightweight TCP proxy (like HAProxy or Nginx stream) on the host instead of a raw iptables DNAT rule, you might be able to use the PROXY protocol to pass the real client IP in the TCP header.

PMG supports this via Postfix. It usually involves adding configuration lines to the Postfix templates on PMG, such as:
smtpd_upstream_proxy_protocol = haproxy
smtpd_upstream_proxy_timeout = 5s

Then, the proxy on the host would need to be configured to send the proxy protocol header when forwarding port 25 to the VM.

Idea 3: Considering a Direct Bridge (Bypassing NAT)

If the NAT configurations continue to cause issues with SPF, another alternative could be exposing the PMG VM directly to the internet if you have an extra public IP available.
By attaching the VM directly to the physical bridge (vmbr0) and assigning it a public IP, you could bypass the host NAT entirely, which generally resolves SPF and RBL detection issues.

Hopefully, one of these approaches gives you a good starting point to experiment with.