LibrePortal
Sponsor
Install

LibrePost on any server

Use LibrePost as an ordinary Debian or Ubuntu package, without LibrePortal. It keeps your mail server private and changes nothing else on the machine.

On this page
  1. How it works
  2. What you need
  3. Install it
  4. Describe your setup
  5. Connect your mail server
  6. Publish the DNS records
  7. Check that it works
  8. When your mail server is away
  9. DKIM
  10. Logs and privacy
  11. Stopping and removing
  12. If it does not work

LibrePost is free and open source, and its code is at git.libreportal.org/LibrePortal/LibrePost. It is the post office that sits in front of a private mail server. Hide your mail server with LibrePost describes the LibrePortal app. This page is about the same idea as a plain Linux package, for a public machine that does not run LibrePortal.

You want this when the public machine already has a job. It might serve a website, host a game, or run its own firewall and reverse proxy. LibrePortal brings its own proxy, its own intrusion prevention and its own firewall manager, and a second set of those would fight the first. The package brings none of them. It never touches your firewall, your web server, CrowdSec or fail2ban. It tells you which ports it needs, and opening them is up to you.

How it works#

Other mail servers deliver to the public machine. LibrePost accepts mail for your domains, refuses what should not get in, and passes the rest over a private link to your mail server. Your mail server sends its own mail out the same way, so it is never named in DNS, in headers or in logs.

The private link is something you already have: WireGuard, another VPN, or a LAN. LibrePost uses it and never builds one.

Three things keep it from being a nuisance to other people or a risk to you:

  • It is never an open relay. Outgoing mail is accepted only from your mail server's address, only after it signs in over TLS, and only from your own domains. librepost check tries to break this on every run and must be refused each time.
  • Unknown addresses are refused at the door. Before it accepts a recipient, LibrePost asks your mail server whether that mailbox exists. A message for a name that does not exist is refused while the sender is still connected, so nobody gets a bounce for mail they never sent.
  • Both ends prove who they are. Being on the same private network is not proof. Each direction has its own long password and runs inside TLS, and outgoing mail must also come from an address on your list.

What you need#

  • A Debian 12 or newer, or Ubuntu 22.04 or newer, machine with a public address.
  • Port 25 open both ways at your hosting provider. Many providers close it until you ask.
  • A host name for the machine, such as post.example.org, whose reverse DNS says the same. Your hosting provider sets reverse DNS.
  • A private link to your mail server, and a mail server that can accept mail on a private port and send through a relay. Stalwart 0.16 is the one LibrePost is tested with.

Install it#

Download the package and check it. Releases are signed with LibrePortal's release key, so you can be sure the file is the one we published.

cd "$(mktemp -d)"
base=https://get.libreportal.org/librepost
curl -fsSLO $base/latest.json
v=$(jq -r .version latest.json)
arch=$(dpkg --print-architecture)
curl -fsSLO $base/v$v/librepost_${v}_$arch.deb
curl -fsSLO $base/v$v/SHA256SUMS
curl -fsSLO $base/v$v/SHA256SUMS.minisig
minisign -Vm SHA256SUMS -P RWRBf8o+a1KSvF08fA3oKrVz/71D60YeF4GO66ntVeJvzAkI57sjgM1S
sha256sum --ignore-missing -c SHA256SUMS
sudo apt install ./librepost_${v}_$arch.deb

The package adds a program, a copy of the Stalwart mail engine, a systemd service and a system user called librepost. It starts nothing and changes no other setting. The service runs as that user with a single privilege, the right to open ports below 1024.

Describe your setup#

One command makes the folders and secrets and a starting config file. It asks no questions, so a script can run it.

sudo librepost init --hostname post.example.org --domain example.org --upstream-address 10.99.0.2

Then open /etc/librepost/librepost.toml. These are the settings that matter first. Every other setting has a safe default.

[server]
hostname    = "post.example.org"
public_ipv4 = ["203.0.113.10"]

[upstream]
address = "10.99.0.2"       # your mail server on the private link
port    = 2526              # where it accepts the relay's mail

[outbound]
listen     = ["10.99.0.1"]  # this machine's address on the private link
allow_from = ["10.99.0.2"]  # the only address outgoing mail may come from

Why the outgoing port has its own address

The port your mail server sends through listens only on the private address you give it. A port that is not on the public address cannot be probed from the internet, and the allow_from list means a correct password still does nothing from anywhere else.

Check it, apply it and start it:

sudo librepost validate
sudo librepost apply
sudo systemctl enable --now librepost

apply is safe to repeat. When nothing has changed it says so and does nothing. The first time, it starts the mail engine for a few seconds in a throwaway network of its own, so the engine's factory settings cannot touch any port on your machine while it is being configured.

Connect your mail server#

Your mail server needs a port that accepts the relay's mail, and a route that sends its own outgoing mail through the relay. LibrePost prints the exact settings for Stalwart:

sudo librepost upstream stalwart-plan --bind 10.99.0.2 > plan.jsonl

Copy that file to your mail server, run stalwart-cli apply --stdin < plan.jsonl there, and delete it afterwards, because it holds the two passwords. LibrePortal's own LibrePost app and this package are two forms of the same thing; you cannot run both on one machine, because both need port 25. How to move between them. For a WireGuard example and a sketch for Postfix, see the existing link guide.

Publish the DNS records#

sudo librepost dns-records

lists what to publish at your DNS provider and checks each record against live DNS: the MX for each domain, the relay's address, SPF, DMARC, and DKIM when the relay signs. It also says what the reverse DNS of the machine's address must be. Run it again after you change DNS. A script can ask for --json, or use --strict to get exit code 6 while a required record is missing or wrong.

Check that it works#

sudo librepost status
sudo librepost check

status shows whether the link to your mail server is up, how many messages are waiting, what the last 24 hours looked like, when the certificate runs out and the last few problems. check runs the self-tests: the config, the service, the ports, the certificate, the open-relay test, the link to your mail server, the unknown-recipient check, the reverse DNS, the DNS records and the secrets.

When your mail server is away#

Mail for it waits in a queue on the relay and is tried again after a minute, then two, five, ten and fifteen, and after that every half hour. It is kept for five days by default (queue_expire). After that the sender is told it failed.

While your server is away, LibrePost still accepts mail for addresses it has recently seen, and tells the sender to try again later for any address it has not. It does not guess. You can look at the queue and push it:

sudo librepost queue list
sudo librepost queue flush --all

DKIM#

By default your mail server signs outgoing mail and LibrePost passes the signature through untouched. To sign at the relay instead, set mode = "sign" under [dkim] and run apply. LibrePost makes a key for each domain and dns-records shows the record to publish. Turn off signing on your mail server too, or each message carries two signatures.

Logs and privacy#

The service logs to the journal: journalctl -u librepost. Logs hold envelope addresses and IP addresses, which you need to see what happened, but never message bodies. LibrePost keeps its own counters and problem notes for seven days. A log file for tools such as CrowdSec is optional (log.file). The relay keeps no copy of a message once it is delivered.

Secrets are mode 600 and belong to the librepost user. No password is ever accepted without TLS.

Stopping and removing#

sudo apt remove librepost removes the program and keeps your config, keys and queue. sudo apt purge librepost removes those and the librepost user as well. Nothing else on the machine was changed, so there is nothing else to put back.

If it does not work#

What you see What it usually is
check says the upstream is not reachable The link is down, the port is wrong, or your mail server's firewall blocks the relay's address.
Sign-in is refused The password at your mail server is not the relay's. sudo librepost upstream secrets prints it.
Mail from your server is refused with a 5xx Its address is not in allow_from, the sender's domain is not one of yours, or the password is wrong.
apply cannot bind the private address The private link is not up yet. Start it before the service.
Mail goes to spam at the other end Check SPF, DKIM, DMARC and the reverse DNS with dns-records and check.

Next steps