Skip to content

Latest commit

 

History

History
199 lines (146 loc) · 5.86 KB

File metadata and controls

199 lines (146 loc) · 5.86 KB

Running the Recon2x rendezvous server on a Raspberry Pi

The rendezvous server is how two Recon2x peers find each other. It is a small HTTP service: peers publish opaque encrypted blobs to a room (keyed by a shared word) and fetch the blobs others left there. It stores only ciphertext it cannot read — no IPs, no identities in the clear.

This guide puts that server on a Raspberry Pi and makes it reachable on the public internet at your own domain, even though the Pi is behind CGNAT.

Why this setup (and why CGNAT matters)

Most home/mobile ISPs put you behind carrier-grade NAT (CGNAT) — your "public" IP is shared, and you cannot port-forward to your Pi. Inbound connections simply never arrive.

The fix is a reverse tunnel: the Pi makes an outbound connection to Cloudflare and holds it open. Inbound web requests hit Cloudflare and travel down that tunnel to the Pi. Outbound connections pass through any NAT, so CGNAT is bypassed entirely. The Pi never needs to be directly reachable.

Internet ─▶ yourdomain.com ─▶ Cloudflare ─▶ [tunnel] ─▶ Raspberry Pi
                                                          ├─ recon2x --server
                                                          └─ cloudflared

Cloudflare Tunnel proxies HTTP/HTTPS/WebSocket. The rendezvous server is plain HTTP, so this is sufficient. (It is not enough for a UDP relay — that is a separate, later concern.)

Prerequisites

  • A Raspberry Pi on your network, powered on most of the time.
  • A domain you control, with its DNS managed by Cloudflare (free plan is fine). If your domain is registered elsewhere, you can still move just its DNS to Cloudflare.
  • SSH access to the Pi.

Step 1 — Build the Recon2x binary for the Pi

The Pi is ARM. Build on the Pi itself (simplest), or cross-compile.

On the Pi:

# Install Rust if needed
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"

# From a copy of this repo on the Pi (only the backend/ crate is needed):
cd recon2x/backend
cargo build --release --no-default-features
# Binary: backend/target/release/recon2x-backend

--no-default-features disables the frontend feature. The rendezvous server does not serve a UI, and the frontend build/ directory will not exist on the Pi (you only copied backend/) — so embedding it must be switched off, or the build fails with a RustEmbed folder ... does not exist error.

Step 2 — Run the rendezvous server

RECON2X_PORT=8788 ./recon2x-backend --server

It listens on http://[::]:8788. Verify locally on the Pi:

curl http://localhost:8788/r/health
# {"role":"rendezvous","status":"ok","version":"..."}

--server selects the rendezvous role. Without it the binary runs the desktop peer app instead — keep the flag.

Step 3 — Install cloudflared on the Pi

# Debian/Raspberry Pi OS (arm64):
curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm64 \
  -o /usr/local/bin/cloudflared
chmod +x /usr/local/bin/cloudflared
cloudflared --version

(For a 32-bit OS use cloudflared-linux-arm instead.)

Step 4 — Create the tunnel

# Authenticate cloudflared with your Cloudflare account (opens a browser link)
cloudflared tunnel login

# Create a named tunnel
cloudflared tunnel create recon2x

# Route your domain (or a subdomain) to the tunnel
cloudflared tunnel route dns recon2x rendezvous.yourdomain.com

cloudflared tunnel create prints a tunnel UUID and writes a credentials JSON file (path shown in the output) — note both.

Step 5 — Configure the tunnel

Create ~/.cloudflared/config.yml on the Pi:

tunnel: <TUNNEL-UUID>
credentials-file: /home/pi/.cloudflared/<TUNNEL-UUID>.json

ingress:
  # Forward all traffic for the hostname to the local rendezvous server.
  - hostname: rendezvous.yourdomain.com
    service: http://localhost:8788
  # Required catch-all.
  - service: http_status:404

Test it:

cloudflared tunnel run recon2x

From any other machine:

curl https://rendezvous.yourdomain.com/r/health
# {"role":"rendezvous","status":"ok","version":"..."}

If that responds, the Pi is publicly reachable through the tunnel.

Step 6 — Keep both services running (systemd)

So they survive reboots and crashes.

Rendezvous server/etc/systemd/system/recon2x.service:

[Unit]
Description=Recon2x rendezvous server
After=network-online.target
Wants=network-online.target

[Service]
ExecStart=/home/pi/recon2x-backend --server
Environment=RECON2X_PORT=8788
Restart=always
RestartSec=5
User=pi

[Install]
WantedBy=multi-user.target

Cloudflare tunnel — install it as a service:

sudo cloudflared service install

Enable and start both:

sudo systemctl daemon-reload
sudo systemctl enable --now recon2x
sudo systemctl enable --now cloudflared

Check status / logs:

systemctl status recon2x cloudflared
journalctl -u recon2x -f

Step 7 — Point Recon2x peers at your node

Each peer's desktop app needs to know the rendezvous URL — https://rendezvous.yourdomain.com. (Wiring this into the peer app and UI is the next development step; this guide only stands the server up.)

Maintenance notes

  • Updating the server: rebuild the binary, replace it, sudo systemctl restart recon2x.
  • Memory: the registry is in-memory and self-expiring (entries live ~10 minutes). Restarting the service clears all rooms — harmless, since peers re-publish.
  • Multiple nodes later: the registry is intentionally a single-node design for now. If you add a second node, peers will not need to change — the peer-facing API hides node topology.
  • It is zero-knowledge: the Pi cannot read any blob. A compromised Pi leaks room activity and timing, but not peer IPs or identities (those are inside the encrypted blobs).