Back to tutorials
Tutorial

DKIM Setup Tutorial (2026): Configure OpenDKIM + Postfix on Ubuntu VPS for Reliable Email Delivery

DKIM setup tutorial for 2026: configure OpenDKIM with Postfix on Ubuntu VPS, publish DNS keys, and verify signed outbound mail.

By Anurag Singh
Updated on Jun 21, 2026
Category: Tutorial
Share article
DKIM Setup Tutorial (2026): Configure OpenDKIM + Postfix on Ubuntu VPS for Reliable Email Delivery

Email deliverability issues rarely look tidy. One message lands, the next bounces, and then you start hearing “your mail isn’t trusted.” On a VPS, a common cause is simple and fixable: your outbound mail isn’t cryptographically signed.

This DKIM setup tutorial shows how to enable DKIM signing for Postfix on Ubuntu with OpenDKIM. You’ll publish the required DNS TXT record, then confirm that outbound mail leaves your server with a valid signature.

The steps below assume you’re running Postfix on Ubuntu 24.04/24.10 (or newer) and you control DNS for your domain.

This works on any VPS. It’s easier with a stable IP and clean reverse DNS.

If you’re building a mail-capable server for apps or WordPress, a HostMyCode VPS gives you the isolation and control you need. You also avoid inheriting someone else’s mail reputation.

What you’ll build (and what DKIM actually changes)

DKIM (DomainKeys Identified Mail) adds a signature header to outbound messages. Receiving servers validate that signature using a public key you publish in DNS.

If the signature matches, the content wasn’t altered in transit. The sending domain is also authenticated at the message level.

  • Before DKIM: you mostly depend on IP reputation and SPF; forwarding and mailing lists can muddy authentication signals.
  • After DKIM: each message can be validated against your DNS key, and most large providers expect it by default in 2026.

DKIM doesn’t replace SPF and DMARC. It supports them.

If your reverse DNS is wrong, fix that first. DKIM won’t compensate for a bad PTR record.

Pair this guide with rDNS setup tutorial and PTR record troubleshooting.

Prerequisites checklist (don’t skip this)

  • Ubuntu server with root or sudo access
  • Postfix installed and sending outbound mail
  • A hostname (FQDN) that resolves to your server IP (A/AAAA record)
  • Working reverse DNS (PTR) that matches your hostname
  • Ability to add DNS TXT records for your sending domain

Quick diagnostics:

hostname -f
postconf -n | egrep 'myhostname|mydomain|myorigin|inet_interfaces'

# Confirm outbound connectivity to recipient MX (basic)
ss -lntp | egrep ':25|:587'

Step 1: Install OpenDKIM and tools on Ubuntu

OpenDKIM is the standard choice for DKIM signing with Postfix on Ubuntu. Install the packages, then confirm the service starts cleanly.

sudo apt update
sudo apt install -y opendkim opendkim-tools

systemctl status opendkim --no-pager

If you’re running a firewall, you don’t need to open anything new for DKIM. Signing happens locally, between Postfix and OpenDKIM.

If you administer a server through locked-down panels, keep them private. Use a tunnel instead—see SSH tunnel setup guide.

Step 2: Create DKIM keys (selector-based, per domain)

DKIM keys are scoped by domain and selector. The selector makes rotation painless.

You publish a new selector, switch signing to it, then keep the old selector briefly for delayed mail.

A simple convention is date-based, like s2026 or mta2026.

Create a directory for your domain keys:

sudo mkdir -p /etc/opendkim/keys/example.com
sudo chown -R opendkim:opendkim /etc/opendkim
sudo chmod 0750 /etc/opendkim/keys/example.com

Generate a 2048-bit keypair (typical for DKIM in 2026):

cd /etc/opendkim/keys/example.com
sudo -u opendkim opendkim-genkey -b 2048 -s s2026 -d example.com
sudo -u opendkim chmod 0600 s2026.private
ls -la

You should now have:

  • s2026.private (private key used by OpenDKIM)
  • s2026.txt (DNS TXT record content you’ll publish)

Step 3: Configure OpenDKIM (SigningTable, KeyTable, TrustedHosts)

Use the standard mapping approach. It stays readable and scales cleanly when you add more domains.

  • /etc/opendkim/TrustedHosts
  • /etc/opendkim/KeyTable
  • /etc/opendkim/SigningTable

3.1 Trusted hosts (who is allowed to ask OpenDKIM to sign):

sudo tee /etc/opendkim/TrustedHosts >/dev/null <<'EOF'
127.0.0.1
localhost

# Add your server IPs if needed (optional)
# 203.0.113.10
EOF

3.2 KeyTable (selector/domain to private key path):

sudo tee /etc/opendkim/KeyTable >/dev/null <<'EOF'
s2026._domainkey.example.com example.com:s2026:/etc/opendkim/keys/example.com/s2026.private
EOF

3.3 SigningTable (which From: domains get which selector):

sudo tee /etc/opendkim/SigningTable >/dev/null <<'EOF'
*@example.com s2026._domainkey.example.com
EOF

Next, update /etc/opendkim.conf so OpenDKIM uses those mapping files. You also need a socket that Postfix can reach.

On Ubuntu, you can use an inet socket on localhost or a unix socket. For a first setup, inet on localhost is usually the least confusing.

sudo cp -a /etc/opendkim.conf /etc/opendkim.conf.bak
sudo nano /etc/opendkim.conf

Set (or ensure) these key lines exist:

Syslog                  yes
SyslogSuccess           yes
LogWhy                  yes

UMask                   002

Canonicalization        relaxed/simple
Mode                    sv
SubDomains              no
AutoRestart             yes
AutoRestartRate         10/1h
Background              yes

# Where Postfix will connect
Socket                  inet:8891@localhost

# Mapping files
ExternalIgnoreList      refile:/etc/opendkim/TrustedHosts
InternalHosts           refile:/etc/opendkim/TrustedHosts
KeyTable                refile:/etc/opendkim/KeyTable
SigningTable            refile:/etc/opendkim/SigningTable

Pitfall: if you previously configured a unix socket, don’t leave both options in place. OpenDKIM may start, but Postfix can point at the wrong socket.

When that happens, mail leaves without a DKIM signature.

Step 4: Connect Postfix to OpenDKIM (milter settings)

Postfix signs mail by handing messages to a milter. Configure Postfix to send outbound mail through OpenDKIM before it leaves the server.

sudo postconf -e 'milter_default_action=accept'
sudo postconf -e 'milter_protocol=6'
sudo postconf -e 'smtpd_milters=inet:localhost:8891'
sudo postconf -e 'non_smtpd_milters=inet:localhost:8891'

Restart services:

sudo systemctl restart opendkim
sudo systemctl restart postfix

Then confirm Postfix can reach the milter:

sudo journalctl -u opendkim -n 50 --no-pager
sudo journalctl -u postfix -n 80 --no-pager

You want clean startup logs and milter connections.

If you get “connection refused,” OpenDKIM isn’t listening where Postfix expects.

Step 5: Publish the DKIM DNS TXT record (the part that usually goes wrong)

Open the generated TXT file and copy the record value:

sudo cat /etc/opendkim/keys/example.com/s2026.txt

DNS panels often show this in a BIND-style format. In most providers, add a TXT record with:

  • Name/Host: s2026._domainkey
  • Type: TXT
  • Value: starts with v=DKIM1; k=rsa; p= and then a long key

Common pitfalls and fixes:

  • Wrong name: some DNS UIs want the full s2026._domainkey.example.com. Others want only s2026._domainkey. The difference is whether the UI auto-appends your zone name.
  • Line breaks/quotes: paste it as one line unless the provider explicitly supports multi-string TXT values.
  • Multiple DKIM records: don’t publish two TXT records with the same selector. Rotate by changing the selector, not by stacking TXT values.

If you manage DNS with HostMyCode, keep the zone organized and set TTLs intentionally before mail changes.

The workflow is the same one you’d use for web cutovers—see DNS propagation tutorial.

After publishing the TXT record, verify it from your VPS:

sudo apt install -y dnsutils

dig +short TXT s2026._domainkey.example.com

You should see the DKIM value returned.

If you get nothing back, the record name is wrong or it hasn’t propagated yet.

Step 6: Test signing with a real message (and inspect headers)

Send a message to an external mailbox you control (Gmail, Outlook, Fastmail). You can use mail or sendmail.

If mailx isn’t installed:

sudo apt install -y bsd-mailx

echo "DKIM test $(date -Is)" | mail -s "DKIM test" you@yourmailbox.com

Open the message and view the full headers. You should see something like:

DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=example.com; s=s2026; ...

If the header is missing, watch the OpenDKIM logs while sending again:

sudo journalctl -u opendkim -f

Useful clue: “no signing table match” means the From: domain didn’t match your SigningTable rule.

That’s usually a typo, or you’re sending from a different domain than you intended.

Step 7: Add SPF and DMARC alignment (minimal, practical)

DKIM gets you most of the way. Receivers still evaluate SPF + DKIM + DMARC together.

For a single VPS sending mail for one domain, this baseline is a good start.

SPF TXT record (at the root of the domain):

v=spf1 a mx ip4:203.0.113.10 -all

DMARC TXT record (start in monitoring mode):

Host/Name: _dmarc
Value: v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com; adkim=s; aspf=s

After you confirm legitimate senders are aligned, move from p=none to p=quarantine. Then move to p=reject if it fits your risk tolerance.

If you run WordPress forms or app mail, make sure every sending path uses the same authenticated server.

For a clean pattern, follow Email relay setup tutorial.

Step 8: Key rotation plan (so you’re not stuck with one key forever)

DKIM rotation is normal maintenance. Plan to rotate at least yearly.

Rotate immediately if you suspect key exposure.

  1. Generate a new selector (example: s2026b) and publish its TXT record.
  2. Update SigningTable (or KeyTable reference) to use the new selector.
  3. Restart OpenDKIM and Postfix.
  4. Leave the old TXT record published for 7–14 days so delayed mail can still validate.
  5. Remove the old selector from DNS and delete the old private key.

Key hygiene: private keys should be readable only by the OpenDKIM user.

If you back up /etc/opendkim/keys, treat it like credentials.

Troubleshooting: the 6 failures you’ll actually see

  • No DKIM-Signature header at all: Postfix isn’t using milters, or the OpenDKIM socket doesn’t match. Re-check postconf -n | grep milter and Socket in /etc/opendkim.conf.
  • “no signing table match” in opendkim logs: the From domain doesn’t match your SigningTable pattern. Confirm the visible From header.
  • DKIM fails with “bad signature” at receiver: the DNS record is wrong (truncated key, extra quotes, wrong selector). Re-dig the TXT and compare to s2026.txt.
  • Mail bounces despite DKIM passing: this is usually PTR mismatch or IP reputation. Start with reverse DNS checks: PTR record troubleshooting tutorial.
  • Mail stuck in queue: DKIM won’t clear a backlog. Inspect Postfix queues and logs. This guide helps: Email queue troubleshooting tutorial.
  • Multiple domains on one Postfix: you need a SigningTable entry per domain and a key directory per domain.

Hardening checklist for a mail-capable VPS

DKIM is one piece of a working mail server. If you host client mail or send application traffic, these checks prevent the usual headaches:

  • Lock down SSH access (keys, allowlists, audit logging).
  • Enable automatic security updates and scheduled reboots when required.
  • Monitor disk usage—mail queues and logs can fill disks quietly.
  • Set up basic monitoring and alerts for Postfix and OpenDKIM processes.
  • Keep DNS tidy: A/AAAA, MX, SPF, DKIM, DMARC, and PTR must agree.

If you’d rather not own the daily maintenance (updates, baseline hardening, and ongoing monitoring), managed VPS hosting is often a better fit for production mail and WordPress stacks.

Summary: what “done” looks like

  • OpenDKIM installed and running on localhost:8891
  • Postfix configured with smtpd_milters and non_smtpd_milters
  • DKIM TXT record published and verifiable via dig
  • Outbound test emails contain a valid DKIM-Signature header
  • SPF and DMARC exist and are aligned with your sending domain

After this DKIM setup tutorial is working, your next wins come from consistency. Keep one or two known sending paths, stable DNS, and routine key rotation.

If you’re migrating mail workloads or rebuilding a server, start with infrastructure you can control.

Deploy on a HostMyCode VPS so your MTA settings, IP identity, and DNS changes stay in your hands.

If you’re setting up outbound mail for WordPress or client sites, run it on infrastructure you can actually tune and troubleshoot. A HostMyCode VPS gives you full control over Postfix, OpenDKIM, and DNS alignment, while managed VPS hosting is a good fit if you want day-to-day operations handled for you.

FAQ

Should I use one DKIM key for every subdomain and service?

You can, but separating by purpose is usually cleaner. Use different selectors (or a dedicated sending subdomain like mail.example.com) so you can rotate or revoke without disrupting everything.

What selector name should I choose in 2026?

Choose a name that makes rotation obvious, like s2026 or mta2026. Avoid a generic default if you plan to operate the server long-term.

Can DKIM break anything?

Not typically. Most “breaks” are failed validation from a bad DNS record, or messages modified by a mailing list.

Your DMARC policy and alignment settings determine how strict receivers will be.

How do I confirm DKIM passes without guessing?

Check the recipient’s authentication results header (often Authentication-Results). Confirm it shows dkim=pass for your domain and selector.

Do I still need PTR/rDNS if DKIM is configured?

Yes. Many providers still penalize mail from IPs without correct PTR, even if DKIM passes. If you’re seeing rejections, fix rDNS first.

DKIM Setup Tutorial (2026): Configure OpenDKIM + Postfix on Ubuntu VPS for Reliable Email Delivery | HostMyCode