*Cube-Host– full cloud services!!

How to set up your own Postfix mail server on VPS UBUNTU: step by step

How to set up your own Postfix mail server on VPS UBUNTU: step by step

Deliverable email on an Ubuntu VPS: what to prepare first

Running your own mail server is possible, but “it works” and “it delivers to Inbox” are two different things. Deliverability depends on your IP reputation, correct DNS (SPF/DKIM/DMARC), and reverse DNS (PTR). This guide shows a practical baseline setup: Postfix + TLS + authenticated submission + (optional) Dovecot for IMAP.

For stable performance and full control over networking (PTR/rDNS, firewall rules, ports), start with a clean Linux VPS or choose scalable VPS hosting if you expect growth and need more resources later.

Before you start: 7 things that decide if mail will work

  • Static public IP (mail servers don’t mix well with frequently changing IPs).
  • Domain name you control (example.com) and a dedicated hostname (mail.example.com).
  • Reverse DNS (PTR) must point to mail.example.com (set in provider panel/support).
  • Port 25 availability: many VPS providers restrict outbound 25 to fight spam. If blocked, you’ll need a relay provider (smarthost) or request unblocking.
  • Correct system time (TLS and DKIM are sensitive to time drift).
  • Firewall policy: open only required ports (25/587, and 993 if you use IMAP).
  • Realistic expectations: a brand‑new IP may take time to build reputation; always warm up sending volumes.

Step 1 — Prepare Ubuntu and set a proper hostname

Use Ubuntu 22.04/24.04 LTS (recommended). Replace example.com with your domain and mail.example.com with your server hostname.

sudo -i
apt update && apt -y upgrade
apt -y install ca-certificates curl ufw nano unzip dnsutils

# Set hostname
hostnamectl set-hostname mail.example.com

# Make sure /etc/hosts has a local mapping (adjust IP if needed)
nano /etc/hosts

# Set timezone (pick yours)
timedatectl set-timezone Europe/Kyiv
timedatectl status

Step 2 — Open only the required ports (UFW)

Minimal safe baseline: SSH, SMTP (25) for inbound mail, and Submission (587) for authenticated sending. If you add Dovecot IMAP, open 993 too.

ufw default deny incoming
ufw default allow outgoing

ufw allow OpenSSH
ufw allow 25/tcp
ufw allow 587/tcp

# Optional (IMAPS)
ufw allow 993/tcp

ufw enable
ufw status verbose

Step 3 — Install Postfix and verify it runs

Install Postfix and a minimal mail utility. During setup select Internet Site and set system mail name to example.com.

apt -y install postfix mailutils

systemctl enable --now postfix
systemctl status postfix --no-pager

# See active Postfix settings
postconf -n

Step 4 — Set a safe baseline Postfix configuration (no open relay)

These settings are a practical baseline to avoid becoming an open relay and to support authenticated sending later.

postconf -e "myhostname = mail.example.com"
postconf -e "mydomain = example.com"
postconf -e "myorigin = $mydomain"
postconf -e "inet_interfaces = all"
postconf -e "inet_protocols = all"
postconf -e "mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain"

# Only local networks are trusted
postconf -e "mynetworks = 127.0.0.0/8 [::1]/128"

# IMPORTANT: relay restrictions (prevents open relay)
postconf -e "smtpd_relay_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination"
postconf -e "smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination"

systemctl restart postfix
postconf -n | sed -n '1,120p'

Step 5 — TLS certificates (Let’s Encrypt) for secure submission

For Let’s Encrypt, your DNS A-record must already point to this server. If you cannot open port 80, use DNS challenge instead; below is the simplest “standalone” flow.

# Temporarily allow port 80 for cert issuing
ufw allow 80/tcp

apt -y install certbot
certbot certonly --standalone -d mail.example.com

# Tighten firewall after issuance if you don’t host a website
ufw delete allow 80/tcp

# Configure Postfix TLS
postconf -e "smtpd_tls_cert_file = /etc/letsencrypt/live/mail.example.com/fullchain.pem"
postconf -e "smtpd_tls_key_file = /etc/letsencrypt/live/mail.example.com/privkey.pem"
postconf -e "smtpd_tls_security_level = may"
postconf -e "smtp_tls_security_level = may"
postconf -e "smtpd_tls_loglevel = 1"
postconf -e "smtpd_tls_protocols = !SSLv2, !SSLv3"
postconf -e "smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3"

systemctl restart postfix

Step 6 — Enable authenticated submission on port 587 (recommended)

Port 25 is for server-to-server mail exchange. For users/apps, use 587 with authentication + TLS. This reduces abuse and improves deliverability.

Edit /etc/postfix/master.cf and enable the submission service (and optionally smtps 465). Keep it simple: allow only authenticated users.

nano /etc/postfix/master.cf

Add or uncomment this block (adjust if it already exists):

submission inet n       -       y       -       -       smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
  -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
  -o milter_macro_daemon_name=ORIGINATING

Step 7 — Add IMAP (optional): Dovecot for mailbox access

If you only need sending for apps, you can skip IMAP. If you want real mailboxes (Thunderbird/Outlook/webmail), install Dovecot and use IMAPS (993).

apt -y install dovecot-imapd dovecot-pop3d

systemctl enable --now dovecot
systemctl status dovecot --no-pager

Set Maildir format and enable secure authentication:

# Mail location
nano /etc/dovecot/conf.d/10-mail.conf
# Set:
# mail_location = maildir:~/Maildir

# Authentication (recommended)
nano /etc/dovecot/conf.d/10-auth.conf
# Ensure:
# disable_plaintext_auth = yes
# auth_mechanisms = plain login

Expose Dovecot auth socket for Postfix SASL:

nano /etc/dovecot/conf.d/10-master.conf

# In the service auth section, ensure you have:
# unix_listener /var/spool/postfix/private/auth {
#   mode = 0660
#   user = postfix
#   group = postfix
# }

Enable SASL in Postfix and restart both services:

postconf -e "smtpd_sasl_type = dovecot"
postconf -e "smtpd_sasl_path = private/auth"
postconf -e "smtpd_sasl_auth_enable = yes"
postconf -e "smtpd_tls_auth_only = yes"

systemctl restart dovecot
systemctl restart postfix

Step 8 — DNS records for deliverability (A, MX, SPF, DKIM, DMARC, PTR)

Without correct DNS, your mail will often land in spam (or be rejected). Use the following baseline records (examples shown).

RecordNameValue (example)Notes
Amail203.0.113.10mail.example.com → server IP
MX@mail.example.comPriority 10
PTR203.0.113.10mail.example.comSet in VPS/provider panel
TXT (SPF)@v=spf1 mx a ip4:203.0.113.10 -allAdjust IP(s) as needed
TXT (DMARC)_dmarcv=DMARC1; p=none; rua=mailto:dmarc@example.com; fo=1Start with p=none, then tighten

Step 9 — DKIM signing with OpenDKIM (recommended)

DKIM adds a cryptographic signature to outgoing mail. Receivers use it to confirm messages are not forged and were not modified in transit.

apt -y install opendkim opendkim-tools

mkdir -p /etc/opendkim/keys/example.com
opendkim-genkey -D /etc/opendkim/keys/example.com/ -d example.com -s mail

chown -R opendkim:opendkim /etc/opendkim/keys/example.com
chmod 750 /etc/opendkim/keys/example.com
chmod 640 /etc/opendkim/keys/example.com/mail.private

Create tables for keys and signing:

nano /etc/opendkim/KeyTable
# Add:
# mail._domainkey.example.com example.com:mail:/etc/opendkim/keys/example.com/mail.private

nano /etc/opendkim/SigningTable
# Add:
# *@example.com mail._domainkey.example.com

nano /etc/opendkim/TrustedHosts
# Add:
# 127.0.0.1
# localhost
# *.example.com

Make OpenDKIM socket accessible for Postfix (Ubuntu smtpd is commonly chrooted). Use a socket inside Postfix spool:

mkdir -p /var/spool/postfix/opendkim
chown opendkim:postfix /var/spool/postfix/opendkim
chmod 750 /var/spool/postfix/opendkim

nano /etc/opendkim.conf
# Ensure these lines exist / match:
# Socket local:/var/spool/postfix/opendkim/opendkim.sock
# KeyTable /etc/opendkim/KeyTable
# SigningTable refile:/etc/opendkim/SigningTable
# ExternalIgnoreList /etc/opendkim/TrustedHosts
# InternalHosts /etc/opendkim/TrustedHosts

Connect the DKIM milter in Postfix:

postconf -e "milter_default_action = accept"
postconf -e "milter_protocol = 6"
postconf -e "smtpd_milters = unix:opendkim/opendkim.sock"
postconf -e "non_smtpd_milters = $smtpd_milters"

systemctl restart opendkim
systemctl restart postfix

Add DKIM DNS record: open /etc/opendkim/keys/example.com/mail.txt and publish its TXT value as mail._domainkey for your domain.

Step 10 — Testing and troubleshooting

Check logs first — they tell you exactly what’s wrong.

tail -n 200 /var/log/mail.log
postqueue -p
mailq

Install swaks for clean SMTP testing (great for debugging submission 587):

apt -y install swaks

# Example (replace values). Use 587 with TLS:
swaks --to you@example.net --from test@example.com 
  --server mail.example.com --port 587 --tls 
  --auth LOGIN --auth-user testuser --auth-password 'StrongPassword'

Security hardening checklist (high impact)

  • Never allow open relay (keep reject_unauth_destination in restrictions).
  • Use 587 + auth + TLS for users/apps. Avoid sending mail from port 25 using app credentials.
  • Enable Fail2Ban for sshd/postfix/dovecot and monitor brute-force attempts.
  • Keep ports minimal: 25, 587, (993 if IMAP). Avoid exposing POP3/IMAP plaintext.
  • Back up configs: /etc/postfix, /etc/dovecot, /etc/opendkim, and your Let’s Encrypt certs.
  • Warm up sending volume and monitor bounces/spam complaints (reputation matters).

Need a server ready for Postfix?

If you’re building mail infrastructure for a project, start on a stable Linux VPS (full root access and predictable resources). For scaling and upgrades without migration stress, consider VPS hosting.

Prev
Menu