Reverse proxy
The relay speaks plain HTTP. A reverse proxy in front of it must:
- terminate TLS for your domain,
- forward to the relay’s port (
127.0.0.1:8080with the defaults), - pass the WebSocket upgrade through for
/ws, and not time out an idle WebSocket quickly, - set
X-Forwarded-For— the admin login rate limiter uses it to tell clients apart.
Caddy gets a certificate, handles WebSockets and sets X-Forwarded-For on its own:
tpp.example.com { reverse_proxy 127.0.0.1:8080}map $http_upgrade $connection_upgrade { default upgrade; '' close;}
server { listen 443 ssl http2; server_name tpp.example.com;
ssl_certificate /etc/letsencrypt/live/tpp.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/tpp.example.com/privkey.pem;
# One WebSocket frame carries at most 10 MiB; larger entries are chunked. client_max_body_size 12m;
location / { proxy_pass http://127.0.0.1:8080; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; # required for /ws proxy_set_header Connection $connection_upgrade; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme;
# A WebSocket is idle between clipboard events; do not cut it off. proxy_read_timeout 1h; proxy_send_timeout 1h; }}Labels for the server service in your docker-compose.yml, assuming Traefik runs in Docker on
the same network with a certificate resolver named le. Traefik handles WebSockets and
X-Forwarded-For on its own.
server: # ...as in the Docker guide, but without the `ports:` section... labels: - traefik.enable=true - traefik.http.routers.tpp.rule=Host(`tpp.example.com`) - traefik.http.routers.tpp.entrypoints=websecure - traefik.http.routers.tpp.tls.certresolver=le - traefik.http.services.tpp.loadbalancer.server.port=8080Check it
Section titled “Check it”curl -fsS https://tpp.example.com/healthz # → okThen sign in at https://tpp.example.com/admin/.
Endpoints
Section titled “Endpoints”| Path | Purpose |
|---|---|
/healthz |
Health check. Returns ok. |
/ws |
The devices’ WebSocket. |
/admin/ |
The admin page: dashboard and creation tokens. Its own API is under /admin/api/. |
/pair |
The page a pairing link opens on a device without the app. |
/source |
Redirects to the relay’s source code (TPP_SOURCE_URL). |
/<token> |
Group creation. A browser GET returns 404 on purpose; only the app’s POST uses the token. |