Settings of the Proxmox Mail Gateway as SMTP server with SMTP authenication

testOA

New Member
Aug 25, 2025
1
0
1
Hi everyone, I am trying to build a Proxmox Mail Gateway as SMTP server to send notification for external person.
By default, it delivers by 25 and 26 ports. And sometimes reponsed that the emails become spam mail that without SMTP auth.
So I trying to enable the SMTP authenication.

I had read some instruction to do the configuration in the main.cf file of Postfix , creating SASL for SMTP authenication.
Mostly the instruction describe to use the gmail SMTP as the relayhost.
However, I don't want to use the external SMTP server and the gmail accounts.

For example, I created the VM , installed Proxmox Mail Gateway 7.0.6 , running as Debian OS in default.
I assigned the DNS name "pmg.mydomain.com" to it.
And I also allowed all ports for SMTP required.
Is it possible to set the server itself as the SMTP server with the SMTP authenication?


In main.cf:
Code:
relayhost = [pmg.mydomain.com]:587
smtp_use_tls = yes
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt

In sasl_passwd
Code:
[pmg.mydomain.com]:587    SMTP_username:SMTP_password
 
So i also had a strong use case to have the gateway support auth email.

I wanted it so not run on the config of Proxmox Mail Gateway to minimize problems interference ect. so i run the auth option on port 587

This is the changed you need to do for PMG 9.0-1 Install:
/var/lib/pmg/templates/master.cf.in
#----------------------------------------------------------
# Custom Code: Submission Port 587 for SMTP AUTH
#----------------------------------------------------------
587 inet n - - - - smtpd
-o smtpd_tls_cert_file=/etc/pmg/pmg-tls.pem
-o smtpd_tls_key_file=/etc/pmg/pmg-tls.pem
-o smtpd_tls_security_level=encrypt
-o smtpd_tls_auth_only=yes
-o smtpd_sasl_auth_enable=yes
-o smtpd_sasl_type=cyrus
-o smtpd_sasl_path=smtpd
-o smtpd_sasl_security_options=noanonymous
-o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
#----------------------------------------------------------
cat > /etc/sasl2/smtpd.conf <<'EOF'
pwcheck_method: auxprop
auxprop_plugin: sasldb
mech_list: PLAIN LOGIN
sasldb_path: /etc/sasldb2
EOF
#----------------------------------------------------------

#----------------------------------------------------------
apt install sasl2-bin libsasl2-modules
#----------------------------------------------------------
pmgconfig sync --restart 1
systemctl restart postfix
#----------------------------------------------------------

#----------------------------------------------------------
Create Users for Auth.
#----------------------------------------------------------
saslpasswd2 -c -u DOMAIN USERNAME -> this will create a user USERNAME@DOMAIN
Password need to be input here
#----------------------------------------------------------

#----------------------------------------------------------
List Users for Auth.
#----------------------------------------------------------
sasldblistusers2
#----------------------------------------------------------

#----------------------------------------------------------
Remove Users for Auth.
#----------------------------------------------------------
saslpasswd2 -d -u DOMAIN USERNAME
#----------------------------------------------------------
Hope this help anyone took me hours to figure this one out and get it to work.

Pros with this is you can keep config for ports 25 and 26 as is and have a seperate smarthost firewall rule for port 587.

Working nicely for me.
 
Last edited:
  • Like
Reactions: AlexHK
We also implemented Nginx and Fail2ban now for extra security and able to use the portal for when 8006 in not allowed: these are our notes of it:

We run the let encypt option in pmg and use those in the config.

#----------------------------------------------------------
Nginx Website Port 443: (8006):
#----------------------------------------------------------
apt update
apt install nginx
#----------------------------------------------------------
/etc/nginx/sites-available/pmg

#########################
# Rate-limit zone for login
#########################
limit_req_zone $binary_remote_addr zone=pmg_login:10m rate=6r/m;

#########################
# HTTP ? HTTPS redirect
# Exclude PMG ACME HTTP validation
#########################
server {
listen 80;
server_name FQDN;

# ACME HTTP validation for Let's Encrypt
location /.well-known/acme-challenge/ {
proxy_pass http://127.0.0.1:80
proxy_set_header Host $host;
}

# Redirect all other HTTP traffic to HTTPS
location / {
return 301 https://$host$request_uri;
}
}

################################
# HTTPS Reverse Proxy for PMG
################################
server {
listen 443 ssl;
server_name FQDN;

# Enable HTTP/2
http2 on;

# Dedicated access log
access_log /var/log/nginx/pmg-access.log;

# PMG certificate (combined cert + key)
ssl_certificate /etc/pmg/pmg-api.pem;
ssl_certificate_key /etc/pmg/pmg-api.pem;

#######################################
# TLS
#######################################
ssl_protocols TLSv1.2 TLSv1.3;

# TLS 1.2 explicit ciphers (the 4 you requested)
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
ssl_prefer_server_ciphers on;

# Recommended ECDH curves
ssl_ecdh_curve X25519:secp521r1:secp384r1:secp256r1;

# TLS 1.3 ciphers (OpenSSL 3.5.4 handles automatically)
# TLS_AES_256_GCM_SHA384
# TLS_CHACHA20_POLY1305_SHA256
# TLS_AES_128_GCM_SHA256

# OCSP stapling disabled (PMG cert has no responder)
# ssl_stapling on;
# ssl_stapling_verify on;

resolver 1.1.1.1 1.0.0.1 valid=300s;
resolver_timeout 5s;

# Session cache
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1h;
ssl_session_tickets off;

# HSTS
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

# Security headers
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options DENY always;
add_header Referrer-Policy no-referrer always;

#######################################
# REVERSE PROXY TO PMG
#######################################
location / {
proxy_pass https://127.0.0.1:8006

proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;

# WebSocket support for PMG UI
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

# Buffers for PMG UI
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;

proxy_max_temp_file_size 0;
}

#######################################
# BRUTE-FORCE PROTECTION: LOGIN ENDPOINTS
#######################################
location = /api2/json/access/ticket {
limit_req zone=pmg_login burst=3 nodelay;
proxy_pass https://127.0.0.1:8006
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}

location = /api2/extjs/access/ticket {
limit_req zone=pmg_login burst=3 nodelay;
proxy_pass https://127.0.0.1:8006
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
}


#----------------------------------------------------------
rm /etc/nginx/sites-enabled/default
ln -s /etc/nginx/sites-available/pmg /etc/nginx/sites-enabled/

nginx -t
systemctl restart nginx
systemctl reload nginx



#----------------------------------------------------------
Fail2Ban:
#----------------------------------------------------------
apt install fail2ban

systemctl enable fail2ban
systemctl start fail2ban
systemctl status fail2ban

#----------------------------------------------------------
/etc/fail2ban/filter.d/pmg-login.conf
[Definition]
# Match failed login requests to PMG webgui (ticket API)
failregex = ^<HOST> - - \[.*\] "(POST|GET) /api2/(json|extjs)/access/ticket HTTP/[\d.]+" 200 ([5-9][0-9]|100) .*
ignoreregex =

/etc/fail2ban/jail.d/pmg-login.local
[pmg-login]
enabled = true
filter = pmg-login
action = nftables-multiport[name=PMGLogin, port=443, protocol=tcp]
logpath = /var/log/nginx/pmg-access.log
maxretry = 5
findtime = 600
bantime = 3600

/etc/fail2ban/jail.d/postfix-submission.local
[postfix-submission-auth]
enabled = true
filter = postfix[mode=auth]
action = nftables-multiport[name=PostfixSubmissionAuth, port="587", protocol=tcp]
logpath = /var/log/mail.log
maxretry = 5
findtime = 600 ; 10 minutes
bantime = 3600 ; 1 hour

/etc/fail2ban/jail.d/recidive.local
[DEFAULT]
ignoreip = 127.0.0.1/8 10.0.0.0/8
bantime = 3600
findtime = 600
maxretry = 5
backend = auto