Skip to content
BILLETKnowledge Base

Install a relay

Install the relay on a Linux server, give it a certificate for browser sessions, enroll it with the portal and run it as a service.

For
Administrators
Applies to
Billet 1.0
Updated

The relay carries a session between a person and a desktop when they cannot reach each other directly. Both ends dial out to it, so it needs a public address that people's computers and your hosts can both reach.

A relay is two services: billet-relay itself, and the Billet stats agent in relay mode beside it, which enrolls the relay with the portal and reports its health.

These steps are for Ubuntu 24.04 LTS, with the relay on a server of its own.

Before you start

  • The certificate authority exists. The portal issues the relay's certificate from it when the relay enrolls.
  • A public DNS name for the relay, for example relay.example.com, pointing at this server.
  • These ports open to everyone who will connect, and to your hosts:
Port For
UDP 4444 Sessions from the Billet app and hosts
TCP 443 Sessions in a browser tab (a secure WebSocket)
TCP 80 Only while Let's Encrypt issues or renews the certificate

1. Make a relay enrollment token

In the console, open Deployment, Enrollment, Create an enrollment token. Choose It enrolls: A relay, and the tenant it serves. Copy the token: it is shown once, works once, and expires after a short time.

2. Install the programs

From the server release (see Install the portal for checking and unpacking it):

sudo useradd --system --no-create-home --shell /usr/sbin/nologin billet
sudo install -d -o root -g root   -m 0755 /opt/billet
sudo install -d -o root -g billet -m 0770 /etc/billet
sudo install -o root -g root -m 0755 Billet-Server-1.0.0-linux-x64/relay/billet-relay /opt/billet/
sudo install -o root -g root -m 0755 Billet-Server-1.0.0-linux-x64/agent/billet-stats-agent /opt/billet/

3. Get a certificate for browser sessions

Browsers only accept a certificate from a public authority, so the relay needs one for its name:

sudo apt-get install -y certbot
sudo certbot certonly --standalone -d relay.example.com \
  --deploy-hook 'install -o root -g billet -m 0644 "$RENEWED_LINEAGE/fullchain.pem" /etc/billet/relay-ws.crt &&
                 install -o root -g billet -m 0640 "$RENEWED_LINEAGE/privkey.pem"   /etc/billet/relay-ws.key'

The deploy hook copies the certificate where the relay's account can read it, now and at every renewal. The relay picks up a renewed certificate at its next connection, with no restart.

4. Enroll the relay

sudo -u billet BILLET_CREDENTIAL_FILE=/etc/billet/agent-credential.json \
  /opt/billet/billet-stats-agent \
  --register-relay https://portal.example.com \
  --register-token <the relay token> \
  --host-id relay1 \
  --relay-endpoint relay.example.com:4444 \
  --enroll-only
Option Meaning
--register-relay Your portal's address.
--register-token The token from step 1.
--host-id What this relay is called in the console, for example relay1.
--relay-endpoint The public name and UDP port hosts and the Billet app dial.

This writes /etc/billet/agent-credential.json, the relay's identity and the secret the relay needs to start. Keep it: removing it makes the relay a new one that needs a new token.

5. Configure the relay

Create /etc/billet/relay.env, replacing the two names:

BILLET_RELAY_ADDR=0.0.0.0:4444
BILLET_CREDENTIAL_FILE=/etc/billet/agent-credential.json
BILLET_RELAY_WS_ADDR=0.0.0.0:443
BILLET_RELAY_WS_CERT=/etc/billet/relay-ws.crt
BILLET_RELAY_WS_KEY=/etc/billet/relay-ws.key
BILLET_RELAY_WS_PUBLIC=wss://relay.example.com
BILLET_RELAY_WS_ORIGINS=https://portal.example.com

BILLET_RELAY_WS_ORIGINS is the portal's own address. A browser page from any other site is refused. If tenants have addresses of their own, add them as one more entry, for example https://portal.example.com,https://*.tenants.example.com.

sudo chown root:billet /etc/billet/relay.env
sudo chmod 0640 /etc/billet/relay.env

6. Run both as services

/etc/systemd/system/billet-relay.service:

[Unit]
Description=Billet relay
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/opt/billet/billet-relay
User=billet
Group=billet
EnvironmentFile=/etc/billet/relay.env
# Lets the relay's account listen on 443.
AmbientCapabilities=CAP_NET_BIND_SERVICE
Restart=always
RestartSec=10s

[Install]
WantedBy=multi-user.target

/etc/systemd/system/billet-relay-agent.service, replacing the portal's name:

[Unit]
Description=Billet stats agent, relay mode
After=network-online.target billet-relay.service
Wants=network-online.target
Requires=billet-relay.service

[Service]
Type=simple
ExecStart=/opt/billet/billet-stats-agent
User=billet
Group=billet
Environment=BILLET_CREDENTIAL_FILE=/etc/billet/agent-credential.json
Environment=BILLET_URL=https://portal.example.com
Environment=BILLET_RELAY_LOCAL_ADDR=127.0.0.1:4444
Restart=always
RestartSec=10s

[Install]
WantedBy=multi-user.target

Start them:

sudo systemctl daemon-reload
sudo systemctl enable --now billet-relay billet-relay-agent

7. Check it

  • In the console, Relays lists the relay, and it reports in.
  • From outside, check the browser port answers with the right certificate:
openssl s_client -connect relay.example.com:443 -servername relay.example.com </dev/null 2>/dev/null \
  | openssl x509 -noout -subject -issuer

A relay on the portal's server

If the relay shares a server with the portal, nginx already has TCP 443. Give the relay's WebSocket another port, for example BILLET_RELAY_WS_ADDR=0.0.0.0:8443 and BILLET_RELAY_WS_PUBLIC=wss://relay.example.com:8443, and open that port instead. Some networks only allow 443, so people on them cannot open browser sessions; a relay on a server of its own avoids that.

Cloudflare and other proxies

Keep the relay's DNS record DNS only in Cloudflare. UDP 4444 cannot pass through Cloudflare's proxy at all. The WebSocket can, but only with extra relay settings, because the relay binds each session to the address that asked for it; ask Billet support before proxying it.