paseo-relay

April 12, 2026 · View on GitHub

中文 | English

A lightweight self-hosted relay server for Paseo.

The relay bridges your Paseo daemon and the mobile app when they can't connect directly. It forwards encrypted bytes without being able to read them — the relay is completely untrusted by design.

How it works

Mobile App  ──────────────────────────────────────┐

                                           [ paseo-relay ]

Paseo Daemon ─────────────────────────────────────┘

All traffic between daemon and app is E2E encrypted with XSalsa20-Poly1305 (NaCl box). The relay sees only IP addresses, timing, message sizes, and session IDs — never the content.

Protocol (v2)

Three WebSocket endpoints under GET /ws:

RoleQuery paramsDescription
Daemon controlrole=server&v=2One per daemon session, receives connect/disconnect events
Daemon datarole=server&connectionId=<c>&v=2One per client connection, forwards encrypted frames
Clientrole=client[&connectionId=<c>]&v=2App socket, multiple allowed per connectionId

GET /health returns {"status":"ok","version":"<version>"}.

Quick start

Docker

docker run -p 8411:8411 ghcr.io/zenghongtu/paseo-relay:latest

Binary (pre-built)

Download the binary for your platform from Releases:

PlatformFile
Linux x86_64paseo-relay-<version>-linux-amd64.tar.gz
Linux ARM64paseo-relay-<version>-linux-arm64.tar.gz
macOS x86_64paseo-relay-<version>-darwin-amd64.tar.gz
macOS Apple Siliconpaseo-relay-<version>-darwin-arm64.tar.gz
Windows x86_64paseo-relay-<version>-windows-amd64.zip
# Linux/macOS
curl -L https://github.com/zenghongtu/paseo-relay/releases/latest/download/paseo-relay-v0.3.0-linux-amd64.tar.gz | tar xz
./paseo-relay

# Windows: extract the .zip and run paseo-relay.exe

Build from source

git clone https://github.com/zenghongtu/paseo-relay
cd paseo-relay
go build -o paseo-relay .
./paseo-relay

Configuration

FlagEnv varDefaultDescription
--addrRELAY_ADDR:8411Listen address
--max-buffer-frames200Max frames buffered per connection while daemon is connecting
--log-formatLOG_FORMATtextLog format: text or json
--versionPrint version and exit

Deployment

systemd

[Unit]
Description=Paseo relay
After=network.target

[Service]
ExecStart=/usr/local/bin/paseo-relay --addr :8411 --log-format json
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

Docker Compose

services:
  relay:
    image: ghcr.io/zenghongtu/paseo-relay:latest
    restart: unless-stopped
    ports:
      - "8411:8411"
    environment:
      LOG_FORMAT: json

TLS should be terminated upstream (nginx, Caddy, Cloudflare, etc.).

Configure Paseo daemon

In ~/.paseo/config.json:

With domain:

{
  "daemon": {
    "relay": {
      "enabled": true,
      "endpoint": "relay.yourdomain.com:443",
      "publicEndpoint": "relay.yourdomain.com:443"
    }
  }
}

With IP address:

{
  "daemon": {
    "relay": {
      "enabled": true,
      "endpoint": "1.2.3.4:8411",
      "publicEndpoint": "1.2.3.4:8411"
    }
  }
}

Then restart the daemon: paseo daemon stop && paseo daemon start.

Security

  • The relay is zero-knowledge — it cannot read or forge messages.
  • No authentication on the relay itself; security is enforced end-to-end by Paseo's ECDH + NaCl box encryption.
  • Always terminate TLS upstream; do not expose the relay over plain HTTP.
  • See Paseo SECURITY.md for the full threat model.

License

AGPLv3 — see LICENSE.