Install Tealhand Relay
Tealhand Relay passes encrypted traffic between your phone and your computers when they can’t reach each other directly, for example when you are away from home. You need one only for that. On your own network, no relay is needed. This page is the install. For what a relay sees and keeps, read Relays; for every config key and the upload answers, read Run your own relay.
What you need
Section titled “What you need”- A Linux server (a VPS) with a public IP address. The examples use
203.0.113.10andrelay.example.com. - Either a DNS name that points at the server (for a certificate from Let’s Encrypt), or nothing but the IP address (for a self-signed certificate that your devices pin).
- Your phone, with Tealhand installed, to copy its owner key from.
- Git, Rust through
rustup, and a C compiler on the server, or build elsewhere and copy the binary over.
1. Build and install the program
Section titled “1. Build and install the program”git clone https://github.com/tealvpn/tealhandcd tealhandrustup toolchain installcargo build --release -p tealhand-relaysudo install -m 755 target/release/tealhand-relay /usr/local/bin/tealhand-relayRun the relay as its own normal user, never as root:
sudo useradd --system --home-dir /var/lib/tealhand-relay --create-home --shell /usr/sbin/nologin tealhand-relaysudo mkdir -p /etc/tealhand-relaysudo chown tealhand-relay:tealhand-relay /etc/tealhand-relay2. Get the owner key from your phone
Section titled “2. Get the owner key from your phone”In Tealhand, open Settings, then Network, and find Owner key. Copy it. It is your phone’s device
public key in text form: thhw: and 66 hex digits. The relay admits only devices listed in a signed device list
from an owner you name, so this key is how the relay knows your phone.
3. Write the config
Section titled “3. Write the config”Save this as /etc/tealhand-relay/config.toml, with your own addresses and your owner key:
relay_bind = "203.0.113.10:443"roster_bind = "203.0.113.10:8443"allowed_owners = ["thhw:REPLACE_WITH_THE_OWNER_KEY_66_HEX_DIGITS"]data_dir = "/var/lib/tealhand-relay"
[tls]cert = "/etc/tealhand-relay/fullchain.pem"key = "/etc/tealhand-relay/privkey.pem"relay_bindis the relay itself (HTTPS).roster_bindis a second HTTPS listener where your phone uploads its device list. Both are required, and each needs its own address and port.- Both addresses must belong to the machine.
0.0.0.0and[::]are refused, so the relay never listens on every interface by accident. On a server with its own public address, write that address. On a cloud server where the provider forwards the public address to the machine, write the machine’s private IP (ip addrshows it) and keep the public address in your DNS name or your phone’s settings. allowed_ownerstakes one key per phone you own. An empty list allows nobody.- The key file must be readable by its owner only (
chmod 600). The relay refuses a key that group or others can read.
Optional keys (http_bind, quic_bind, connection and rate limits) are in
Relay config.
4. A TLS certificate
Section titled “4. A TLS certificate”Pick one of the two ways.
Option A: a DNS name and certbot
Section titled “Option A: a DNS name and certbot”Point a DNS name (here relay.example.com) at the server, then get a certificate with certbot’s standalone mode.
Standalone mode needs TCP port 80 open and free while certbot runs; the relay does not use port 80.
sudo certbot certonly --standalone -d relay.example.comCertbot keeps its files in /etc/letsencrypt/live/relay.example.com/, readable by root only. The relay runs as
its own user, so a deploy hook copies the certificate and key to where the relay can read them, every time
certbot renews. Save this as /etc/letsencrypt/renewal-hooks/deploy/tealhand-relay.sh:
#!/bin/shset -einstall -o tealhand-relay -g tealhand-relay -m 644 "$RENEWED_LINEAGE/fullchain.pem" /etc/tealhand-relay/fullchain.peminstall -o tealhand-relay -g tealhand-relay -m 600 "$RENEWED_LINEAGE/privkey.pem" /etc/tealhand-relay/privkey.pemMake it executable and run it once now:
sudo chmod 755 /etc/letsencrypt/renewal-hooks/deploy/tealhand-relay.shsudo RENEWED_LINEAGE=/etc/letsencrypt/live/relay.example.com /etc/letsencrypt/renewal-hooks/deploy/tealhand-relay.shThe relay re-reads the certificate and key once a day, so a renewal needs no restart. The phone and the computers check this certificate against the public roots, so you enter no fingerprint anywhere.
Option B: a self-signed certificate and a pinned fingerprint
Section titled “Option B: a self-signed certificate and a pinned fingerprint”For a server with no DNS name, make a certificate that names the IP address, and let your devices pin it: they then accept only this one certificate, recognised by its SHA-256 fingerprint, and refuse every other. The name is not checked; the certificate’s dates still are.
sudo -u tealhand-relay openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -nodes -days 825 \ -subj "/CN=tealhand-relay" -addext "subjectAltName=IP:203.0.113.10" \ -keyout /etc/tealhand-relay/privkey.pem -out /etc/tealhand-relay/fullchain.pemsudo chmod 600 /etc/tealhand-relay/privkey.pemThen print the fingerprint (the relay also logs it at every start):
tealhand-relay fingerprint --config /etc/tealhand-relay/config.tomlsha256:<64 hex digits>Pin it on both sides:
- Phone: Settings, then Network, then My own relay. Fill in the relay address
https://203.0.113.10, the device list upload addresshttps://203.0.113.10:8443/tealhand/v1/roster, and paste the fingerprint into Certificate fingerprint. - Each computer:
tealhand-host connect --relay https://203.0.113.10 --relay-pin sha256:<64 hex digits>.connectsaves both.runtakes the same two options to use another relay for one start.
A new certificate has a new fingerprint: pin the new one on the phone and on every computer. Don’t pin a certificate that renews by itself (Let’s Encrypt); leave the field empty and the public roots check it. There is no switch that turns certificate checking off.
5. Open the ports
Section titled “5. Open the ports”| Port | Why | Needed |
|---|---|---|
TCP 443 (relay_bind) |
The relay itself | Always |
TCP 8443 (roster_bind) |
Your phone’s device list upload | Always |
| TCP 80 | certbot’s standalone challenge | Only while certbot runs, option A |
UDP 7842 (quic_bind) |
Address discovery | Only if you turn on quic_bind |
With ufw:
sudo ufw allow 443/tcpsudo ufw allow 8443/tcpIf your provider has its own firewall or security group, open the same ports there. A normal user can’t listen on a port below 1024 on its own. The unit below gives the relay that one right.
6. Start it
Section titled “6. Start it”Save this as /etc/systemd/system/tealhand-relay.service. It is an example, not a file the repository ships:
[Unit]Description=Tealhand RelayAfter=network-online.targetWants=network-online.target
[Service]User=tealhand-relayExecStart=/usr/local/bin/tealhand-relay --config /etc/tealhand-relay/config.tomlAmbientCapabilities=CAP_NET_BIND_SERVICERestart=on-failureRestartSec=5
[Install]WantedBy=multi-user.targetsudo systemctl daemon-reloadsudo systemctl enable --now tealhand-relaysudo journalctl -u tealhand-relayAt start it logs where the source code of this version lives, the addresses it listens on and, with a certificate it can read, the certificate fingerprint. A config problem exits with code 2 and names the setting. Every error is two lines: what happened, then what to do.
7. Point your devices at it
Section titled “7. Point your devices at it”- Phone: Settings, then Network, then My own relay: the relay address and the upload address, both
starting with
https://. With option A they arehttps://relay.example.comandhttps://relay.example.com:8443/tealhand/v1/roster. The phone has no default for the upload address. Changing it reconnects your devices and loses nothing. - Each computer:
tealhand-host connect --relay https://relay.example.com, thentealhand-host run. The choice is saved atconnect.
Settings, then Network, shows under Right now whether the phone reaches each computer directly or via the relay. Away from home it should say via relay.
Next: Connect your phone.