Deployment guide

Debian 13 VM with Proxmox Mail Gateway 9

Videos

Overview: Proxmox Mail Gateway 9 on Debian 13 on Azure: overview (watch on YouTube)

Launch and log in: Proxmox Mail Gateway 9 on Debian 13 on Azure: launch and log in (watch on YouTube)

Deep Dive: Proxmox Mail Gateway 9 on Debian 13 on Azure: deep dive (watch on YouTube)

Overview

This image runs Proxmox Mail Gateway 9 on Debian 13 (trixie). Proxmox Mail Gateway is an open source email security gateway. It sits between the internet and your own mail servers as a full mail proxy, and it checks every message for spam, viruses and policy violations before it relays the message on.

The gateway combines SpamAssassin scoring, Bayesian filtering, DNS blocklists, SPF and DKIM checks and greylisting with the ClamAV antivirus engine. It adds an object-based rule system, a per-user spam quarantine with daily reports, a tracking center that follows each message, and a web interface and REST API for all of it.

The software is installed unmodified from Proxmox's own package repository with the proxmox-mailgateway-container package. This is the complete Proxmox Mail Gateway without a Proxmox kernel, so the VM keeps the Debian cloud kernel built for Azure.

Secure by default. No login is baked into the image. On the first boot of every VM:

  • A web administrator, admin@pmg, is created with a random 24 character password. The password is written to a file that only root can read.
  • The web interface certificate, the API ticket signing key, the CSRF key, the SMTP TLS certificate and the local database TLS key are generated for that VM alone, so no two deployments share a secret.
  • Current antivirus signatures are downloaded from the ClamAV project. No signature database ships in the image.

The gateway also starts closed. It relays mail for no domains until you add yours, and the internal relay port accepts mail only from the VM's own subnet.

What you get:

  • Proxmox Mail Gateway 9.1 (pmg-api, pmg-gui, rule system, quarantine, tracking center, REST API).
  • Postfix, SpamAssassin 4, ClamAV 1.4 and PostgreSQL 17, as packaged by Proxmox and Debian.
  • Opportunistic STARTTLS for SMTP with a per-VM certificate.
  • The free pmg-no-subscription update repository configured, and the subscription-only repository present but disabled.
  • A boot-time helper that keeps the gateway's host name and mail domain resolvable on Azure.
  • 24/7 SecureAnyCloud support.

Proxmox is a registered trademark of Proxmox Server Solutions GmbH in the EU, the U.S. and other countries. SecureAnyCloud builds and supports this image. It is not affiliated with, sponsored by or endorsed by Proxmox Server Solutions GmbH. Proxmox Mail Gateway is free software licensed under the GNU Affero General Public License v3.

Prerequisites

  • An Azure subscription with permission to create virtual machines, network security groups and public IP addresses.
  • A mail domain you control, and access to its DNS so you can publish MX and SPF records.
  • The host name or IP address of the mail server that should receive filtered mail. This is your own server, and it must be reachable from the VM.
  • An SSH key pair.

VM size. Proxmox Mail Gateway keeps the ClamAV signature set in memory, about 1 GiB, which briefly doubles while a signature update loads. It also runs several SpamAssassin filter processes.

We measured a Standard_B2s (4 GiB) VM under a burst of 40 concurrent messages during a signature reload. Memory in use peaked at 3.8 of 3.8 GiB with only 22 MiB available. We therefore recommend Standard_B2ms (2 vCPU, 8 GiB) or larger for production, and Standard_B2s for evaluation only.

Azure and outbound port 25: read this first

Receiving mail works on every subscription, because inbound TCP port 25 is not restricted. Sending mail directly to other domains' mail servers on TCP port 25 depends on your subscription type. Microsoft's current policy (Troubleshoot outbound SMTP connectivity problems in Azure) is:

  • Enterprise Agreement and Microsoft Customer Agreement for enterprise (MCA-E): outbound port 25 is not blocked. Microsoft notes there is no guarantee that other domains will accept mail from Azure IP addresses.
  • Enterprise Dev/Test: outbound port 25 is blocked by default. To remove the block, run the Cannot send email (SMTP-Port 25) diagnostic under Diagnose and solve problems on your virtual network in the Azure portal. Then stop, deallocate and start the VM.
  • All other subscription types (for example Pay-As-You-Go, Visual Studio, CSP and free trial): the Azure platform blocks outbound port 25, and Microsoft recommends an authenticated SMTP relay instead.

What this means for a mail gateway:

  • Inbound filtering to a mail server you reach privately works on every subscription. This covers a server in the same virtual network, a peered network, or reached over VPN or ExpressRoute. The block applies only to traffic routed directly to the internet.
  • Relaying to a mail server over the internet on port 25, or sending outbound mail straight to recipients' MX hosts, works only on subscriptions where port 25 is open. Otherwise, send outbound mail through a smart host that accepts mail on port 587, such as Azure Communication Services or another SMTP relay (see Step 10). Connections to relays on port 587 are not restricted on any subscription type.

You can check your own subscription from the VM in Step 7.

1

Deploy from the Azure Marketplace

  • Open the Debian 13 VM with Proxmox Mail Gateway 9 listing by SecureAnyCloud in Azure Marketplace and select Create.
  • Choose a resource group, a region and a VM size (see Prerequisites).
  • Set the administrator username, for example azureuser, and paste your SSH public key.
  • On Networking, allow inbound ports 22, 25, 26 and 8006. Step 3 explains what each port is for and how to restrict it.
  • Select Review + create, then Create.
2

Deploy with the Azure CLI (alternative)

# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:proxmox-mail-gateway:default:latest
az vm create \
  --resource-group my-mail-rg \
  --name pmg01 \
  --image sac1647283583153:proxmox-mail-gateway:default:latest \
  --size Standard_B2ms \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_rsa.pub \
  --public-ip-sku Standard
3

Network security group rules

The gateway listens on exactly four ports off the VM. Open each one only to the recommended source.

  • 22/TCP: SSH administration. Allow your admin IP range only.
  • 25/TCP: the SMTP external port, for mail from the internet to your domains. Allow the internet.
  • 26/TCP: the SMTP internal port, for outgoing mail from your own mail servers. Allow your internal mail servers only.
  • 8006/TCP: the HTTPS web interface and API. Allow your admin IP range only.

Everything else listens on the loopback interface only. That covers PostgreSQL, the filter daemons, the policy service and the API daemon. Restrict the administrative ports, for example:

az network nsg rule create --resource-group my-mail-rg --nsg-name pmg01NSG \
  --name allow-pmg-admin --priority 1010 --direction Inbound --access Allow --protocol Tcp \
  --source-address-prefixes <your-mgmt-cidr> --destination-port-ranges 22 8006
4

Connect over SSH

ssh azureuser@<public-ip>
5

Confirm the gateway is running

systemctl is-active pmgproxy pmgdaemon pmg-smtp-filter pmgpolicy postfix postgresql@17-main clamav-daemon clamav-freshclam pmgversion
sudo ss -tln | grep -E ':(22|25|26|8006)\s'

Every service reports active. pmgversion shows the running Proxmox Mail Gateway API version and the Debian cloud kernel. The listeners are SSH, the two SMTP ports and the web interface.

On the very first boot, allow about a minute for the antivirus signatures to download before clamav-daemon reports active.

6

Retrieve your administrator login

sudo ls -l /root/proxmox-mail-gateway-credentials.txt
sudo cat /root/proxmox-mail-gateway-credentials.txt

Only root can read the file. It contains the per-VM administrator login and the web address.

PMG_ADMIN_USER=admin@pmg PMG_ADMIN_PASSWORD=<generated on first boot> PMG_URL=https://<public-ip>:8006/ PMG_PRIVATE_URL=https://<private-ip>:8006/ PMG_FQDN=<vm-name>.<azure-dns-suffix>

You can check that the login works from the shell without typing the password. The command reads the password from the file and passes it to curl on standard input.

PMG_USER=$(sudo awk -F= '$1=="PMG_ADMIN_USER"{print $2}' /root/proxmox-mail-gateway-credentials.txt)
sudo awk -F= '$1=="PMG_ADMIN_PASSWORD"{printf "%s", $2}' /root/proxmox-mail-gateway-credentials.txt \
  | curl -sk -d "username=${PMG_USER}" --data-urlencode 'password@-' https://127.0.0.1:8006/api2/json/access/ticket \
  | python3 -c 'import sys, json; d = json.load(sys.stdin)["data"]; print("signed in as", d["username"], "with role", d["role"])'

Expected output:

signed in as admin@pmg with role admin

root@pam is Proxmox Mail Gateway's built-in superuser. Azure images keep the Linux root password locked, so root@pam cannot sign in. Use admin@pmg instead.

The admin role manages the whole mail filtering configuration. You do system tasks such as package upgrades over SSH with sudo.

7

Check whether your subscription allows outbound port 25

if timeout 8 bash -c 'exec 3<>/dev/tcp/gmail-smtp-in.l.google.com/25' 2>/dev/null; then echo "outbound TCP 25: open on this subscription" else echo "outbound TCP 25: blocked (use a port 587 smart host, see Step 10)" fi
8

Sign in to the web interface

  • Browse to the PMG_URL from the credentials file, for example https://<public-ip>:8006/. The certificate is self-signed and unique to this VM, so your browser shows a warning the first time. Step 12 explains how to install a trusted certificate.
  • Enter User name admin and the password from the credentials file.
  • Set Realm to Proxmox Mail Gateway authentication server. The default, Linux PAM, is for root@pam and does not accept this login.
  • Select OK on the No valid subscription notice. Proxmox Mail Gateway shows it on installations without a Proxmox subscription key. It is informational: this image uses the free no-subscription repository, and every feature works.

The dashboard shows mail volume, spam, processing time and resource usage.

Change the password now. Go to Configuration > User Management > Local, select admin@pmg and choose Password. Then add two factor authentication under Configuration > User Management > Two Factor.

9

Prove spam and antivirus filtering work

Send the standard GTUBE spam test message through the gateway's external port and follow it in the log tracker. A result line ending in :Q: means the gateway quarantined the message.

FQDN=$(hostname -f)
START=$(date '+%F %T')
python3 - "$FQDN" <<'PY' import smtplib, sys fqdn = sys.argv[1] gtube = "XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X" msg = f"From: test@{fqdn}\r\nTo: postmaster@{fqdn}\r\nSubject: GTUBE spam test\r\n\r\n{gtube}\r\n" with smtplib.SMTP("127.0.0.1", 25) as s: s.sendmail(f"test@{fqdn}", [f"postmaster@{fqdn}"], msg) print("test message submitted") PY sleep 15
sudo pmg-log-tracker -s "$START"

In the web interface, Administration > Tracking Center lists the message with the status quarantine.

Select the postmaster address under E-Mail in Administration > Spam Quarantine. The message appears there with a spam score of 1000, ready to deliver or delete.

Now confirm that the antivirus engine is loaded and detecting. The standard antivirus test string streams to ClamAV from memory, so nothing is written to disk.

clamdscan --version printf '%s%s' 'X5O!P%@AP[4\PZX54(P^)7CC)7}$' 'EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*' | clamdscan --no-summary - echo "clamdscan exit code: $? (1 means a threat was found)"

Expected output. The database number and date change daily.

ClamAV 1.4.4/28125/Wed Sep 16 06:24:23 2026 stream: Eicar-Test-Signature FOUND clamdscan exit code: 1 (1 means a threat was found)

The rule system that made these decisions is under Mail Filter. The default rules block viruses and dangerous attachments, add spam headers and quarantine mail with a spam score of 3 or more.

10

Route mail for your domain

A new gateway relays for no domains, so it rejects mail addressed to anything but itself. Check the starting point.

postconf -h mynetworks relay_domains
sudo pmgsh get /config/domains

1. Add your domain and the server that receives its mail. In the web interface, use Configuration > Mail Proxy > Relay Domains and Transports. From SSH, run the following and replace the example values with your own.

sudo pmgsh create /config/domains --domain <your-domain> --comment "filtered by this gateway"
sudo pmgsh create /config/transport --domain <your-domain> --host <your-mail-server> --port 25 --use_mx 0

2. Trust your internal mail servers so they can send outgoing mail through port 26. The VM's own subnet is trusted automatically.

sudo pmgsh create /config/mynetworks --cidr <your-internal-cidr> --comment "internal mail servers for <your-domain>"

3. If your subscription blocks port 25, send outbound mail through a smart host (see the port 25 section). Set the smart host and port under Configuration > Mail Proxy > Relaying, or run:

sudo pmgsh set /config/mail --smarthost smtp.<your-domain> --smarthostport 587

Proxmox Mail Gateway's smart host setting has no field for a username and password. For a relay that requires authentication, such as Azure Communication Services, use one of these options:

  • Allow the gateway's public IP address on the relay provider's side.
  • Add Postfix SASL settings through Proxmox Mail Gateway's custom configuration templates, as described under "Configuration files" in the Proxmox Mail Gateway administration guide.

4. Set the administrator e-mail address that receives reports and notifications. Select Configuration itself, then the Options tab, or run:

sudo pmgsh set /config/admin --email postmaster@<your-domain>

Once the trusted network is in place, point your mail server's outgoing relay at the gateway's port 26. Only then change your MX record (Step 11).

11

Host name and DNS

Mail servers judge a gateway by its name. The image names itself <vm-name>.<azure-dns-suffix> automatically. For production, give it a public name in your domain.

sudo hostnamectl set-hostname mail echo <your-domain> | sudo tee /etc/sac/pmg-domain
sudo systemctl restart proxmox-mail-gateway-hostname.service
sudo pmgconfig sync --restart 1 hostname -f

Then publish these records in DNS:

  • An A record for mail.<your-domain> that points at the VM's public IP address.
  • An MX record for <your-domain> that points at mail.<your-domain>.
  • An SPF record that includes the address your mail is sent from.
  • A reverse DNS (PTR) name for the public IP. Give the public IP a DNS name label and a reverse FQDN, for example az network public-ip update --resource-group my-mail-rg --name pmg01PublicIP --dns-name pmg01 --reverse-fqdn mail.<your-domain>.

Use a static public IP address so the MX and PTR records stay valid.

12

TLS certificate, updates and subscription

Certificate. Under Configuration > Certificates, upload certificates or request them with ACME (Let's Encrypt). You set them separately for the web interface (API) and for SMTP. The HTTP challenge needs port 80 reachable while it runs. The DNS challenge needs no extra port.

Updates. The free pmg-no-subscription repository is configured, and unattended-upgrades applies Debian security updates. To apply all Proxmox and Debian updates, run:

sudo apt-get update && sudo apt-get dist-upgrade

Subscription. The subscription-only pmg-enterprise repository is present in /etc/apt/sources.list.d/pmg-enterprise.sources with Enabled: no. If you buy a subscription from Proxmox, enter the key under Configuration > Subscription. Then remove the Enabled: no line to switch to the enterprise repository.

Security recommendations

  • Restrict ports 22, 26 and 8006 to the networks that need them (Step 3). Only port 25 needs to be open to the internet.
  • Change the admin@pmg password after the first sign-in and enable two factor authentication under Configuration > User Management.
  • Create separate accounts with the Quarantine Manager, Help Desk or Auditor role instead of sharing the administrator account. Use Configuration > User Management.
  • Leave the default antivirus and spam rules enabled, and review Statistics and the Tracking Center regularly.
  • Keep the gateway patched (Step 12) and take configuration backups under Configuration > Backup/Restore.

Troubleshooting

systemctl is-active proxmox-mail-gateway-firstboot proxmox-mail-gateway-hostname
sudo mailq
sudo journalctl -u pmg-smtp-filter -n 20 --no-pager
  • Login refused in the web interface: check that the realm is Proxmox Mail Gateway authentication server and that the user name is admin.
  • clamav-daemon is not active in the first minute: the signature download is still running. The service starts automatically once the signatures arrive. To follow progress, run sudo journalctl -u clamav-freshclam -n 20 --no-pager.
  • Mail to your server stays in the queue: check the transport host and port, and the NSG and routing between the gateway and your server. Also check whether the connection is an outbound port 25 connection that Azure blocks on your subscription (Step 7).
  • Gateway services fail after a host name change: run sudo systemctl restart proxmox-mail-gateway-hostname.service and sudo pmgconfig sync --restart 1.

Support

SecureAnyCloud provides 24/7 support for this image by email at sales@secureanycloud.com. Proxmox Server Solutions GmbH offers commercial support and enterprise repository access for Proxmox Mail Gateway itself separately.

Licensing

Proxmox Mail Gateway is free and open source software licensed under the GNU Affero General Public License, version 3 or later. Proxmox publishes the source code at git.proxmox.com. Debian, Postfix, SpamAssassin, ClamAV and PostgreSQL are distributed under their own open source licenses. Your VM downloads the ClamAV signature databases directly from the ClamAV project.

Proxmox is a registered trademark of Proxmox Server Solutions GmbH. All other product and company names are trademarks or registered trademarks of their respective holders. Their use here does not imply any affiliation with or endorsement by them.

Deploy on Azure

Launch Debian 13 VM with Proxmox Mail Gateway 9 on Azure with 24/7 support from SecureAnyCloud.

View this image

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure