Frequently Asked Questions
ulaknode
- 🔗 What is ulaknode and how does it differ from hosted email services?
ulaknode is a free, self-hosted email server for Linux distributed as a single Docker container. It bundles four production-grade components into one cohesive package:
- Postfix — SMTP mail transfer
- Dovecot — IMAP mailbox access
- Rspamd — spam filtering, DKIM signing, and DMARC enforcement
- ClamAV — antivirus scanning of attachments
Unlike hosted services such as Google Workspace or Microsoft 365, ulaknode gives you complete control over your data. There are no per-user or per-mailbox fees, and you are not subject to a third-party provider's terms of service, storage limits, or data-residency policies. The trade-off is that you are responsible for operating the Linux host it runs on.
- 🔗 What are the system requirements for running ulaknode?
ulaknode requires a Linux server (physical, VM, or VPS) with Docker installed. Minimum recommended specifications for a small organisation:
- CPU: 2 vCPUs
- RAM: 2 GB (4 GB recommended — ClamAV alone loads ~1 GB of virus definitions into memory)
- Disk: 20 GB for the OS and container image, plus mailbox storage as needed
- Network: A static public IP address and a fully-qualified domain name (FQDN) with a matching reverse DNS (PTR) record
Port 25 (SMTP) must be open outbound. Many cloud providers block port 25 by default — check with your hosting provider before deploying.
- 🔗 How do I start ulaknode?
ulaknode ships with a
docker-compose.yml. Set theMAIL_HOSTNAMEenvironment variable to your mail server's FQDN, then start the container:MAIL_HOSTNAME=mail.yourdomain.com docker compose up -dOn first boot the container seeds all configuration volumes from the image defaults and applies your hostname automatically. Services start in dependency order: ClamAV → Redis → Rspamd → Postfix → Dovecot.
ClamAV loads its full signature database (~1 GB) during startup. Wait about a minute before testing mail flow after a fresh start or restart.
To check the version of all bundled components:
docker exec ulaknode ulaknode-version - 🔗 What DNS records do I need to set up before going live?
Correct DNS configuration is essential for mail deliverability. You need at minimum:
- MX record — points your domain to your mail server hostname, e.g.
mail.yourdomain.com - A record — resolves
mail.yourdomain.comto your server's public IP - PTR record (reverse DNS) — resolves your public IP back to
mail.yourdomain.com; configured with your hosting or ISP provider - SPF TXT record — use
ulaknode-spf generateto produce the correct value (see the SPF FAQ below) - DKIM TXT record — use
ulaknode-dkim showto retrieve the value to publish (see the DKIM FAQ below) - DMARC TXT record — use
ulaknode-dmarc generateto produce the correct value (see the DMARC FAQ below)
Missing or incorrect PTR and SPF records are the most common reason legitimate mail is rejected by major providers. Verify all records with a tool such as MXToolbox after deployment.
- MX record — points your domain to your mail server hostname, e.g.
- 🔗 How do I configure DKIM signing?
ulaknode includes the
ulaknode-dkimtool that manages DKIM keys and updates Rspamd's signing configuration automatically.1. Generate a 2048-bit RSA key pair for your domain:
docker exec ulaknode ulaknode-dkim generate yourdomain.comThe default selector is
mail. You can pass a custom selector as a second argument.2. Retrieve the DNS TXT record to publish:
docker exec ulaknode ulaknode-dkim show yourdomain.comThe output shows the exact TXT record to add to your DNS zone, in the form:
mail._domainkey.yourdomain.com IN TXT "v=DKIM1; k=rsa; p=<public-key>"3. Restart Rspamd to apply the new key:
docker exec ulaknode ulaknode-service restart rspamdOther useful commands:
# List all DKIM keys docker exec ulaknode ulaknode-dkim list # Remove a key docker exec ulaknode ulaknode-dkim remove yourdomain.com mailAfter DNS propagation, verify signing with mail-tester.com — look for
DKIM=passin the received headers. - 🔗 How do I generate an SPF record?
The
ulaknode-spftool generates a ready-to-publish SPF TXT record and can also look up what is currently published in DNS.Basic SPF using the domain's own MX hosts (recommended starting point):
docker exec ulaknode ulaknode-spf generate yourdomain.com --mxAdd a specific IP address and use a strict fail policy:
docker exec ulaknode ulaknode-spf generate yourdomain.com --mx --ip4 203.0.113.10 --all failAuthorize an external sending service:
docker exec ulaknode ulaknode-spf generate yourdomain.com --mx --include sendgrid.net --all softfailAvailable
--allpolicies:softfail(~all) — unauthorized senders are flagged but not rejected; recommended when starting outfail(-all) — unauthorized senders are rejected outrightneutral(?all) — no assertion about unauthorized senders
Look up the currently published SPF record:
docker exec ulaknode ulaknode-spf show yourdomain.comCopy the output into a DNS TXT record for
yourdomain.com. - 🔗 How do I set up a DMARC policy?
The
ulaknode-dmarctool generates a ready-to-publish DMARC TXT record.Start in monitoring mode (no action on failures, collect aggregate reports):
docker exec ulaknode ulaknode-dmarc generate yourdomain.com \ --policy none \ --rua mailto:dmarc@yourdomain.comMove to quarantine once you are confident in DKIM and SPF:
docker exec ulaknode ulaknode-dmarc generate yourdomain.com \ --policy quarantine \ --rua mailto:dmarc@yourdomain.comStrict reject mode:
docker exec ulaknode ulaknode-dmarc generate yourdomain.com \ --policy reject \ --rua mailto:dmarc@yourdomain.com \ --pct 100The output is the exact TXT record value to publish under
_dmarc.yourdomain.com.Look up the currently published DMARC record:
docker exec ulaknode ulaknode-dmarc show yourdomain.comThe recommended rollout sequence is:
none→quarantine→reject, advancing only after reviewing aggregate reports to ensure no legitimate mail is failing. - 🔗 How do I add or remove email domains?
Use the
ulaknode-domaintool to manage virtual domains hosted on your server.# Add a domain docker exec ulaknode ulaknode-domain add yourdomain.com # List all hosted domains docker exec ulaknode ulaknode-domain list # Show all mailboxes and aliases for a domain docker exec ulaknode ulaknode-domain show yourdomain.com # Remove a domain and all its associated mailboxes and aliases docker exec ulaknode ulaknode-domain remove yourdomain.comAfter adding a domain, set up the DNS records described in the DNS FAQ above, then create mailboxes and DKIM keys for the domain.
- 🔗 How do I add, remove, or manage email accounts?
Use the
ulaknode-mailboxtool for all mailbox operations.Create a new mailbox:
docker exec ulaknode ulaknode-mailbox add alice@yourdomain.com secretpasswordList all mailboxes for a domain:
docker exec ulaknode ulaknode-mailbox list yourdomain.comChange a mailbox password:
docker exec ulaknode ulaknode-mailbox passwd alice@yourdomain.com newpasswordSet a storage quota:
docker exec ulaknode ulaknode-mailbox quota-set alice@yourdomain.com 5GAccepted suffixes:
K,M,G. Use0for unlimited (the default).Check current quota usage:
docker exec ulaknode ulaknode-mailbox quota alice@yourdomain.comShow mailbox details:
docker exec ulaknode ulaknode-mailbox show alice@yourdomain.comRemove a mailbox:
docker exec ulaknode ulaknode-mailbox remove alice@yourdomain.com - 🔗 How do I manage email aliases?
Use the
ulaknode-aliastool to create and manage address aliases. An alias forwards mail from a source address to one or more destination addresses.# Add an alias docker exec ulaknode ulaknode-alias add info@yourdomain.com alice@yourdomain.com # List all aliases for a domain docker exec ulaknode ulaknode-alias list yourdomain.com # Show the destination(s) for a specific alias docker exec ulaknode ulaknode-alias show info@yourdomain.com # Remove an alias docker exec ulaknode ulaknode-alias remove info@yourdomain.comBoth the source and destination must be full email addresses. You can point the same source alias at multiple destinations by running
ulaknode-alias addmultiple times with different destinations. - 🔗 How do I install or renew a TLS certificate?
Use the
ulaknode-certtool to install a certificate (e.g. from Let's Encrypt) and verify it is correctly configured.Install a certificate:
docker exec ulaknode ulaknode-cert install /tmp/fullchain.pem /tmp/privkey.pemShow the currently installed certificate:
docker exec ulaknode ulaknode-cert showVerify the certificate and key match and check expiry:
docker exec ulaknode ulaknode-cert checkThis command warns if the certificate expires within 14 days.
Restart services after installing a new certificate:
docker exec ulaknode ulaknode-service restart postfix docker exec ulaknode ulaknode-service restart dovecot - 🔗 How does spam filtering work, and how can I tune it?
ulaknode uses Rspamd for spam filtering. Rspamd scores each incoming message across hundreds of rules — DNS blocklists, content analysis, header checks, Bayes statistics, and more. Messages above the configured threshold are rejected or tagged.
Train the Bayes classifier with known spam and ham:
docker exec ulaknode rspamc learn_spam /path/to/spam.eml docker exec ulaknode rspamc learn_ham /path/to/ham.emlCommon tuning via Rspamd configuration (edit files in
/etc/rspamd/local.d/):- Whitelist a sender: add the address or domain to the
whitelist_frommap - Blacklist a sender: add to the
blacklist_frommap - Adjust score thresholds: edit
actionsinrspamd.confto raise or lower the reject/greylist/add-header thresholds
After editing configuration files, restart Rspamd:
docker exec ulaknode ulaknode-service restart rspamdThe Rspamd web UI (port 11334) provides live statistics and per-message score breakdowns useful for diagnosing false positives or negatives.
- Whitelist a sender: add the address or domain to the
- 🔗 How do I troubleshoot a message that was not delivered?
Start with the error log tool, then inspect the mail queue.
View recent Postfix errors:
docker exec ulaknode ulaknode-errlog postfix docker exec ulaknode ulaknode-errlog postfix 100The optional second argument sets how many lines to show (default: 50). The same command works for
dovecot,rspamd,clamav, andfail2ban.View the mail queue:
docker exec ulaknode mailqInspect a specific queued message by its queue ID:
docker exec ulaknode postcat -q QUEUEIDCommon causes of non-delivery:
- Deferred (4xx): temporary issue on the remote side — Postfix will retry automatically
- Bounced (5xx): permanent rejection — read the DSN for the reason (often a missing PTR record, SPF failure, or blocklist listing)
- Spam-filtered locally: check the Rspamd log to see if the message was rejected before reaching the queue
If you need further assistance, open a ticket at the support portal with the relevant log excerpts.
- 🔗 How do I back up and restore ulaknode data?
ulaknode stores all persistent data in named Docker volumes: mailboxes, logs, TLS certificates, and configuration for Postfix, Dovecot, Rspamd, and ClamAV. A reliable backup strategy must cover all of these volumes.
We recommend docker-volume-backup-borg, a purpose-built tool that automates encrypted, compressed backups of Docker volumes using BorgBackup. It discovers volumes automatically from running containers and supports both local and remote (SSH) repositories.
Basic backup run targeting the ulaknode container:
docker run --rm \ --env-file .env \ -e BACKUP_CONTAINERS=ulaknode \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /var/lib/docker/volumes:/var/lib/docker/volumes:ro \ -v ~/.ssh:/root/.ssh:ro \ itefixnet/docker-volume-backup-borgConfigure at minimum these variables in your
.envfile:BORG_REPO— destination repository (local path oruser@host:pathfor remote)BORG_PASSPHRASE— encryption passphrase; store this securely, without it restores are impossibleKEEP_DAILY/KEEP_WEEKLY/KEEP_MONTHLY— retention policy (defaults: 7 / 4 / 6)
Stop the container during backup for a fully consistent snapshot:
docker run --rm \ --env-file .env \ -e BACKUP_CONTAINERS=ulaknode \ -e STOP_CONTAINERS=ulaknode \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /var/lib/docker/volumes:/var/lib/docker/volumes:ro \ itefixnet/docker-volume-backup-borgList available backups:
docker run --rm --env-file .env \ itefixnet/docker-volume-backup-borg listRestore a specific archive:
docker run --rm --env-file .env \ -v $(pwd):/restore \ itefixnet/docker-volume-backup-borg extract ARCHIVE_NAMEKeep the
.envfile and your passphrase in a safe, separate location from the backup repository itself. - 🔗 Is ulaknode really free? Are there hidden per-user fees?
Yes, ulaknode is genuinely free. It is released under a permissive BSD-style license with no per-user, per-mailbox, or per-domain charges. You can run it for any number of users on your own hardware at no cost.
Optional commercial support plans are available starting at $549/year for organisations that want professional assistance with deployment, DNS configuration, migration, maintenance, and spam-filtering optimisation. Multi-year and volume discounts are available.
To learn more about support options or to request a quote, reach us via our contact form.