Run it · 6 of 19
inbuxa Relay
A small relay on a public machine that takes mail in for your server and sends its mail on, so your server never opens a mail port to the internet. Your server dials out to it; you manage it from the console.
On this page
inbuxa Relay is a small program for a machine the internet can reach, such as a cloud server. It answers port 25 for your domains and passes the mail to your inbuxa server, and it can send your server's outgoing mail on. It suits a server at home, on a private network, or anywhere that can't open mail ports.
It isn't a second mail server. It has no accounts, no settings of its own and nothing to sign in to: everything is set from your server's console, and the relay takes mail only for addresses that really exist on your server. If you'd rather run a full inbuxa in front instead, see An edge server in front.
How it works
- Your server dials the relay, never the other way round. Each node of your server keeps one encrypted link open to it, on port 443 by default. Your server needs no open port at all, only a way out to the relay.
- While the link is up, the relay is live: when someone sends mail, your server answers during their session. Your spam filter, your directory and your rules decide, and a message your server refuses is refused to the sender at the door. Accepted mail is in your server before the sender hears that it was.
- While the link is down, the relay holds mail for the addresses your server last sent it, and passes it on once the link is back. Held mail is encrypted to your server's key as it arrives: the relay can't read it back, and neither can anyone who takes the disk.
- Outgoing, your server signs each message with DKIM and hands it over the link. The relay delivers it, with DANE and MTA-STS where the other side publishes them, and reports back to your server's queue.
- Port 25 does nothing else. There is no sign-in on it, it takes mail only for your domains and only for real addresses, and it sends nothing that didn't come over the link.
A relay takes mail for every domain on your server. Addresses that a directory (LDAP, SQL or OIDC) answers for reach it once the person has signed in to your server at least once; until then, mail to them is refused.
Before you start
- A machine for the relay, Linux on x86-64 or ARM64, reachable from the internet on port 25 and from your server on the link port. It needs little: the relay is one 8 MB program.
- A public name for it, such as
mx1.example.com, with an A or AAAA record for its address, and a reverse DNS name that matches. - Your server can reach the relay on port 443, or the port you choose. Keep that port closed to everyone else with a firewall, list who may link, or put the link on WireGuard (below).
- Your server and the relay run the same release. The relay comes with every server release, under the same version.
1. Add it in the console
Under Settings › Mail flow › Sending › Relays, choose Add a relay…:
| Name | anything, such as edge-west |
| Link address | the relay machine's address, as your server reaches it |
| Link port | 443 |
| Public name | mx1.example.com |
Choose Add. The console shows a command with a join token, once, with a button to copy it. The token is good for 24 hours. If it runs out, or you lose it, choose New join… on the relay for another.
2. Install it
With the installer
On the relay's machine, download the installer released with your server's version, and run as root:
inbuxa relay install --token -
Paste the token when it waits for it. It shows what it will do and stops:
run it again with --yes to carry it out. It fetches the relay of that
release, checks it against the checksum in the installer and the inbuxa
release key's signature, sets it up as the steps below do by hand, joins
and starts it. Add --link-listen [fd42:1::2]:443 to put the link on one
address (below). Run it again at any time: it changes only what
isn't right, and leaves a relay the console has upgraded alone.
inbuxa relay status shows how it is, and inbuxa relay uninstall takes it
away.
On the machine, by hand
Download the relay from the same release as your server, and check it:
V=v27.1-rc.5 # your server's release, from git.coffeylabs.org/inbuxa/inbuxa-server/releases
curl -fLO https://git.coffeylabs.org/inbuxa/inbuxa-server/releases/download/$V/inbuxa-relay-x86_64-linux-musl
curl -fLO https://git.coffeylabs.org/inbuxa/inbuxa-server/releases/download/$V/SHA256SUMS
sha256sum --check --ignore-missing SHA256SUMS
Use inbuxa-relay-aarch64-linux-musl on an ARM machine. It is a static
program: it runs on any Linux of that kind. Then give it a user and a
home, as root:
useradd --system --no-create-home --shell /usr/sbin/nologin inbuxa-relay
install -d -o inbuxa-relay -g inbuxa-relay /opt/inbuxa-relay/bin
install -o inbuxa-relay -g inbuxa-relay -m 755 inbuxa-relay-x86_64-linux-musl /opt/inbuxa-relay/bin/inbuxa-relay
install -d -o inbuxa-relay -g inbuxa-relay -m 700 /var/lib/inbuxa-relay
curl -fLo /etc/systemd/system/inbuxa-relay.service \
https://git.coffeylabs.org/inbuxa/inbuxa-server/raw/tag/$V/resources/systemd/inbuxa-relay.service
The binary belongs to the relay's own user so that an upgrade from the console can replace it. The service unit lets it open ports 25 and 443 and nothing more, and keeps the rest of the machine read-only to it.
Join, with the command the console showed, as the relay's user, and start it:
sudo -u inbuxa-relay /opt/inbuxa-relay/bin/inbuxa-relay join <token> --state /var/lib/inbuxa-relay
systemctl enable --now inbuxa-relay
In a container
docker run -d --name inbuxa-relay --restart unless-stopped \
-p 25:25 -p 443:443 \
-v inbuxa-relay:/var/lib/inbuxa-relay \
-e INBUXA_RELAY_JOIN_TOKEN='<token>' \
registry.coffeylabs.org/inbuxa/inbuxa-relay:27.1-rc.5
Use your server's version as the tag. The image holds the relay and nothing else, and runs it as an ordinary user. It joins with the token on its first run and ignores it after that, so you can leave it in place.
3. Check it joined
Within a few seconds the relay's card in the console says Linked on 1 of 1 nodes, with its version, and the relay opens port 25. On the machine:
sudo -u inbuxa-relay /opt/inbuxa-relay/bin/inbuxa-relay status --state /var/lib/inbuxa-relay
or docker exec inbuxa-relay /usr/local/bin/inbuxa-relay status shows the link, the mail
it holds and its version.
Port 25 stays closed until your server has sent the relay its settings and its list of addresses, which happens as soon as it links. The card says nothing more while all is well. When something needs you, such as a node without a link, a filling spool or a certificate about to run out, it says so in a line under the relay.
Send a message from an outside address to someone at your domain: it
arrives as usual. An address nobody has is refused with 550 5.1.1, and a
domain that isn't yours with 550 5.7.1.
DNS and the certificate
Where a domain's DNS is managed here (Automatic, see DNS), your server publishes the MX records itself: one for each relay that is turned on, has joined and has a public name, at its MX preference (10 unless you change it in the relay's settings). It never replaces two or more MX hosts with one. The SPF record names every relay that sends, and your own server too unless all mail goes through relays. Without managed DNS, set the MX records to the relays' public names yourself.
The relay needs a certificate for its public name for STARTTLS. Where the public name is under a domain whose DNS and certificates are both managed here, your server orders one by DNS-01, puts it on the relay, and renews it 30 days before it runs out; the relay never opens port 80. Otherwise upload one under the relay's Settings… › Certificate. Until it has one, the relay offers STARTTLS with a certificate it made itself, which senders accept as they accept any.
Sending through it
In the relay's Settings…, turn on Send all outgoing mail through relays. Mail for the outside world then goes through the linked relays in turn. With no relay linked, it waits in your server's queue. To send only some mail that way, add a route of the inbuxa Relay kind under Settings › Mail flow › Sending › Routes instead, and use it in your delivery rules.
Turn on Takes mail in only for a relay that shouldn't send, for example while its address is new to other providers or not yet in your SPF record.
Its settings
Everything is in the relay's Settings…, and a linked relay has a change within seconds:
- Taking mail in: the addresses it listens on, the largest message, recipients per message, limits per sending address, how long to Wait for an answer from your server (30 seconds), how many days to Hold mail while your server is unreachable (30, at most 90), and Blocklists to check only while it holds mail.
- Sending mail on: the waits between attempts, when to give up, and Encryption where the other side publishes neither DANE nor MTA-STS: When offered (the default) or Always, which never sends without STARTTLS.
Queue… shows what the relay holds, both ways, and lets you discard held mail or cancel outgoing mail.
Over WireGuard
The link works over a WireGuard network you already have, with nothing changed in the relay or your server. The link port is then not on the internet at all.
-
Make the relay and every node of your server peers on it.
-
Have the relay listen for the link on its WireGuard address only:
systemctl edit inbuxa-relay[Service] ExecStart= ExecStart=/opt/inbuxa-relay/bin/inbuxa-relay run --state /var/lib/inbuxa-relay --link-listen [fd42:1::2]:443In a container, add
run --state /var/lib/inbuxa-relay --link-listen [fd42:1::2]:443after the image name, with the container on the host's network. -
In the console, set the relay's Link address to that WireGuard address,
fd42:1::2here.
Port 25 stays on the public address. The link checks the relay's key and your server's as it always does: WireGuard adds a wall, not a replacement for them.
Who may link
In the relay's Settings…, Who may link limits the link port to the
addresses and ranges you list, such as 192.0.2.7 or 198.51.100.0/24, up
to 64 of them. The relay drops a connection from anywhere else before it
answers. Empty, the default, takes the link from anyone, which suits a link
behind a firewall or on WireGuard. A new relay takes the link from anyone
until it has joined.
List every address your server's nodes reach the relay from. The console knows the ones the relay has seen, and warns before you save a list that leaves any of them out. Links already open stay open when the list changes.
A list that leaves out all of your nodes locks your server out. To undo it,
add --link-allow-any to the relay's run command, as the
WireGuard steps add --link-listen, and restart it. It then
takes the link from anywhere until your server sends it a new list, so fix
the list in the console, and take the option away again.
Replacing the link CA
Your server's nodes prove who they are to a relay with certificates from a link CA your server keeps, which every relay trusts. If a node's certificate, or a copy of your server's data, may have got out, replace the CA: choose Replace link CA… at the top of the Relays page.
Every relay then trusts the new CA beside the old one, and a line on the page names any relay it waits for. Once all of them do, which takes seconds while they're linked, your server's nodes move to the new CA, each relay drops the old one, and any link on a certificate from it is cut. No relay needs a new join.
A relay that is off or can't be reached holds the change up. Finish now… goes ahead without it, and its card then asks for a new join. Cancel it… drops the new CA instead. A join started before the change finished can't complete either: start a new one.
Wrapping the relay keys
Your server keeps the relays' keys in its data store: the link CA's, the key held mail is encrypted to, and each relay's recipient key. Anyone with a copy of the store, such as a backup, has them too. To keep them out of it, wrap them under a key file kept elsewhere. Make one, readable by the server's user and no one else:
sudo install -m 640 -o root -g inbuxa /dev/null /etc/inbuxa-relay.key
openssl rand -base64 32 | sudo tee /etc/inbuxa-relay.key >/dev/null
Then name it in the server's environment
as INBUXA_RELAY_KEY_FILE=/etc/inbuxa-relay.key, and restart the server. In
a container, mount the file read-only and name it where it lands, for
instance -v /etc/inbuxa-relay.key:/run/secrets/relay.key:ro -e INBUXA_RELAY_KEY_FILE=/run/secrets/relay.key; the container's user, 2000,
must be able to read it. On a cluster, every node needs the same file.
Within seconds the server wraps the keys, and the Relays page says they're wrapped. From then on:
- Back the file up on its own, away from the server's backups. Without it, mail a relay holds can't be opened, and every relay needs a new join.
- A node started without the file, or with another one, makes no link to any relay, and says why under each relay.
- Taking the setting away doesn't unwrap the keys: the links just stop.
Upgrades
When your server is upgraded, each relay on an older release says so on its card.
- On a machine, choose Upgrade…, and pick the relay binary for its
machine and its
.sigfile from your server's release. The relay checks that the inbuxa release key signed it, refuses an older release, tries the new one, keeps the old asinbuxa-relay.previous, and restarts on it. - In a container, pull the image with your server's version and start the container again with it.
Turning it off, or removing it
Turning off Linked in its settings stops your server dialling it. The relay keeps the mail it holds and goes on taking mail in, held, until you turn it back on.
Removing it (the bin on its card) stops your server linking to it for good. The relay itself still keeps its mail and goes on taking mail in until you stop it on its machine and reset it:
systemctl disable --now inbuxa-relay
sudo -u inbuxa-relay /opt/inbuxa-relay/bin/inbuxa-relay reset --state /var/lib/inbuxa-relay
reset refuses while the relay holds mail, unless you add
--discard-held. To move a relay to a fresh install, reset it, then
choose New join… on its card and join again.