Set up your relay
The relay carries a transfer when two devices cannot reach each other directly. Running it yourself keeps that traffic on your own infrastructure. It is free for personal use; a business license adds multiple relays, unlimited simultaneous transfers and usage metrics. You need a server with a public IP and Docker installed.
Installation
- 1
Open UDP 49737
Allow it in your firewall and in your provider's security group.
sudo ufw allow 49737/udp - 2
Create docker-compose.yml
services: relay: image: ghcr.io/altersend/relay:latest network_mode: host restart: unless-stopped environment: RELAY_HOST: ${RELAY_HOST:?set RELAY_HOST to this server's public IP} ALTERSEND_LICENSE: ${ALTERSEND_LICENSE:-} volumes: - relay-data:/etc/altersend-relay volumes: relay-data: - 3
Set your server address
Compose reads .env on every command, so keep it in the file rather than passing it inline.
echo 'RELAY_HOST=203.0.113.7' > .env - 4
Start the relay
On first boot it generates a permanent identity and stores it in the volume.
docker compose up -d - 5
Copy your relay code
The logs print your code and a QR code for phones, followed by a stats line every 30 seconds once it is running.
docker compose logs relayAlterSend relay listening relay public key: 6fad022df811a2bfbc734260df47c55499973409bc34b89f66ad791c24be2197 add this relay in AlterSend — Settings → Connection: relay:6fad022df811a2bfbc734260df47c55499973409bc34b89f66ad791c24be2197@203.0.113.7 [stats] egress 0GB | sessions=0 pairings=0 matched=0 - 6
Add it in AlterSend
Settings → Connection → Self-hosted relay. Paste the code and press send: it saves and tests the connection in one step.
Only your own devices need the code. When you send to someone else, your app passes the relay details along with the connection.
Business licenses
Add your license to .env and restart. The relay now prints an org code instead of a relay code. Hand that one code to every device in your team; the servers behind it are managed centrally and can change without anyone re-pasting.
ALTERSEND_LICENSE=<your license>
# optional: POST bytes and timestamp per transfer, nothing else
REPORT_URL=https://example.com/hook
REPORT_TOKEN=<bearer token>[selfhost] licensed to Acme GmbH until 2027-08-27
[selfhost] published org relay record (seq 1)
add this relay in AlterSend — Settings → Connection:
org:7f6f2d059d8a549e30314fa436a98fbe1f62d314a5ec2a2b2be980075ef75226The org code is the public key of a signed record on the network holding your relay list, addresses included. Devices read the list from it, which is why changing servers never changes the code.
Running several relays
Install the same way on each server, using the same license so none of them are capped. Get the new relay's public key, then publish the full list from the server that printed your org code. Other servers print org codes of their own on first boot; ignore those and only ever hand out the first one.
# on the new server
docker compose exec relay node key.js
# on the server that printed your org code
docker compose exec relay node conf/publish.js \
<key1>@203.0.113.7@-5 \
<key2>@198.51.100.4@8Updates and backups
Updating pulls the new image and restarts; your identity and settings live in the volume, so codes stay valid.
docker compose pull
docker compose up -dTroubleshooting
The logs say the variable RELAY_HOST is missing
Compose reads .env for every command, not just up. Make sure the file sits next to docker-compose.yml and contains RELAY_HOST.
The app says it cannot reach the relay
UDP 49737 is almost always the cause. Check both your firewall and your provider's security group, then confirm the container is running with docker compose ps.
Transfers still show as direct
Usually normal: a relay only carries a transfer when the two devices cannot reach each other directly, and the direct path is faster when available. If it never says relayed, check that RELAY_HOST is an IP rather than a domain, since the app matches the connection address to label the transfer.
Who can use my relay?
Anyone holding your relay code. It is not a shared secret you can rotate, so treat it like an invite: hand it to your own devices and people you work with. Transfers stay end-to-end encrypted either way.
