Reach the open internet.
OpenRung is a relay network that helps people living behind internet censorship reach blocked websites and apps through Foundation-operated and volunteer-run relays in unrestricted regions.
Website · Architecture · WSS fallback · Broker API · Report an issue
OpenRung connects censored users with relays in unrestricted regions, similar in spirit to Tor's Snowflake:
- Clients (mobile VPN apps, the desktop proxy app, and a terminal client with proxy and full-device TUN modes) route user traffic through a relay.
- Relay operators — the OpenRung Foundation and community volunteers — run a small command-line app that relays that traffic to the open internet.
- The broker is a control plane only: it matches clients with healthy relays and never proxies user traffic.
flowchart LR
client["📱 Client app<br/>(VPN mode)"]
relay["🔁 Relay"]
broker["🧭 Broker<br/>(control plane)"]
web["🌐 Open internet"]
client -. "relay discovery" .-> broker
relay -. "register + heartbeats" .-> broker
client == "VLESS + REALITY + Vision" ==> relay
relay ==> web
Relay transport uses Xray-core's VLESS + REALITY + Vision, designed to be hard to distinguish from ordinary TLS traffic. The broker ranks relay candidates using recent shared metrics — connection success, active sessions, observed latency, and speed tests — so clients are steered toward relays that actually work.
End-user broker-facing clients share the independently versioned
brokerapi Go module. It is the single source for relay
directory requests and raw-response signature verification, identity and
cache-control headers, telemetry and WSS-ticket requests, the loopback-only
cleartext exception, and the broker TLS transport. For the Cloudflare front
that transport opportunistically uses a compiled-in ECH configuration,
refreshes it from authenticated retry configurations, and quickly retries with
ordinary TLS when ECH is blocked. It never bootstraps ECH through DNS and never
applies ECH to the CloudFront front. That front omits the TLS server name
instead, letting the encrypted HTTP Host header select the distribution while
the same certificate verification runs against its exact hostname. On a direct
connection the CloudFront front therefore never puts its hostname in a
cleartext ClientHello, while the Cloudflare front conceals its own only as long
as ECH survives — the ordinary-TLS fallback sends it. A configured proxy
tunnels both fronts outside this transport and keeps sending the name.
The desktop app and both mobile clients still try direct Reality first. When a
genuine network failure blocks a direct-mode Foundation relay, that relay may
advertise its own signed WSS fronts. Each CDN front terminates at the same
relay's local sidecar, which carries opaque Reality bytes only to that relay's
loopback Reality listener. The broker issues relay- and front-bound
authorization tickets but remains outside the user data path. Those clients
and the relay-local sidecar share the transport mechanics from the
independently versioned wsscore module; ticket authority,
origin authentication, deployment policy, telemetry orchestration, and user
interfaces remain in their owning applications.
- 🙌 Simple volunteering — one line on any Linux VPS, or one CLI plus an Xray binary; IPv6-first with IPv4 and dual-stack options.
- 🕳️ Works behind CGNAT — volunteer-run relays with no inbound port can join through a reverse-tunnel relay hub.
- ⚡ Direct paths when possible — compatible clients and tunneled relays attempt NAT hole punching first, with the relay hub as the fallback.
- 📱 Full-device mobile client — the OpenRung app routes all device traffic in VPN mode (developed in a separate React Native repository).
- 🛡️ Direct-first censorship fallback — the desktop app and both mobile clients can carry the existing end-to-end Reality connection through a relay-owned WSS/CDN front when the direct route is blocked.
- 🧭 Privacy-aware control plane — the broker matchmakes but never carries user traffic.
- 🗄️ Production-friendly broker — optional shared PostgreSQL state for safe restarts and load-balanced deployments.
- 📊 Operational visibility — colored per-connection logs for relay operators and an opt-in, token-protected telemetry dashboard.
The fastest way to help people reach the open internet is to turn a Linux VPS with a public IPv4 address into a volunteer relay. One command sets everything up (on Debian/Ubuntu it installs Docker for you):
curl -fsSL https://raw.githubusercontent.com/openrung/openrung/main/deploy/relay/volunteer-up.sh | sudo shThe script pulls the official relay image, runs it with the same hardened container setup the Foundation fleet uses, auto-detects your server's public IP, mints a stable relay identity and a public adjective-noun relay name, registers with the public OpenRung broker, and confirms the relay is actually serving before it declares success. No account or token is needed.
To choose the public relay name on the first run (letters, digits, ., _,
and -; at most 63 characters), pass OPENRUNG_LABEL through sudo:
curl -fsSL https://raw.githubusercontent.com/openrung/openrung/main/deploy/relay/volunteer-up.sh | sudo env OPENRUNG_LABEL=my-relay shOnce /etc/openrung/relay.env exists, it is authoritative. Edit that file and
re-run the installer to change an existing relay's name or other settings.
Afterwards:
- Allow inbound TCP 443 in your provider's firewall (and
sudo ufw allow 443/tcpif you use ufw) so clients can reach the relay. - Update by re-running the same command — your relay keeps its identity, and a failed update rolls back to the running version automatically.
- Watch it:
docker logs -f openrung-relay - Stop volunteering:
docker rm -f openrung-relay(also delete/etc/openrung/relay.envto forget the relay's identity).
Important
Before you volunteer: relays currently act as direct exits, so the websites a user visits can see your server's IP address — much like a Tor exit node. Please read the security and abuse notes and make sure you are comfortable with that before relaying. Letting volunteers act as entry relays in front of dedicated exit servers is on the roadmap.
Prefer a home computer over a VPS? The one-click
desktop volunteer app works behind home NAT. For
configuration options and other setups, see
deploy/relay/README.md.
Everything below runs the broker, relays, and clients from source for development and self-hosting. Volunteers don't need any of it — volunteer relays register with the public OpenRung broker automatically.
You need Go 1.25+. Running a relay also requires an
Xray-core binary that supports
xray x25519 and xray run -config. The terminal client and the desktop app
bundle their own sing-box engine — no separate install; build them with
-tags with_utls,with_external_windivert (as the Makefile, the desktop
packaging scripts, and the release workflows do: uTLS to dial Reality relays,
and no embedded WinDivert driver), and pass the client's -sing-box <path>
only to substitute an external binary.
The broker fails closed: it refuses to start unless you either set a shared
registration token (OPENRUNG_VOLUNTEER_TOKEN, matched by hubs and
volunteer-run relays) or
explicitly opt into an open, unauthenticated broker. Running open lets anyone
register a relay into the directory, so only do it on a trusted/private network.
It also requires OPENRUNG_RELAY_SIGNING_KEY — standard base64 of the 32-byte
Ed25519 seed that signs every relay-list response (generate one with
openssl rand -base64 32):
OPENRUNG_ALLOW_ANONYMOUS_REGISTRATION=true \
OPENRUNG_RELAY_SIGNING_KEY="$(openssl rand -base64 32)" \
go run ./cmd/broker -addr :8080For safer restarts or multiple brokers behind a load balancer, run the broker with shared PostgreSQL relay state (keep the token / anonymous flag):
OPENRUNG_ALLOW_ANONYMOUS_REGISTRATION=true \
OPENRUNG_RELAY_SIGNING_KEY="$(openssl rand -base64 32)" \
OPENRUNG_RELAY_STORE=postgres \
OPENRUNG_RELAY_DATABASE_URL='postgres://openrung:change-me@localhost:5432/openrung?sslmode=disable' \
go run ./cmd/broker -addr :8080Relay ranking uses recent connection telemetry, capacity, and operator-set weights, with heartbeat recency and IPv6 used as tie-breakers.
To enable the protected telemetry dashboard, set a separate administrator token
before starting the broker, then open /admin/telemetry:
OPENRUNG_ALLOW_ANONYMOUS_REGISTRATION=true \
OPENRUNG_RELAY_SIGNING_KEY="$(openssl rand -base64 32)" \
OPENRUNG_DASHBOARD_TOKEN='replace-with-a-long-random-token' \
go run ./cmd/broker -addr :8080When the variable is unset, the dashboard and its data API return 404. In production, serve the broker over HTTPS so the administrator session cookie is protected in transit.
go run ./cmd/relay \
-broker http://localhost:8080 \
-public-host 127.0.0.1 \
-public-port 8443 \
-listen-host 127.0.0.1 \
-listen-port 8443 \
-xray /path/to/xrayUseful to know:
- With connection logging enabled (the default),
-listen-host ::opens both the IPv6 and IPv4 wildcard listeners. When-public-hostis omitted, the relay advertises the first global IPv6 address it finds. Set-public-hostto advertise a DNS name, IPv4 address, or specific IPv6 address, and set-listen-hostwhen the local bind address should differ. - A global IPv6 address still needs inbound firewall/router rules that allow clients to reach the relay port.
- Client connection events print in color by default — green on open, red on
close, with client IP, duration, and byte counts. Pass
-connection-log=falseto let Xray bind the public port directly. - The broker currently advertises one
public_hostper relay. For both IPv4 and IPv6 discovery, advertise a DNS name with A and AAAA records, or run separate registrations.
Volunteer-run relays with no inbound port (carrier-grade NAT) can join through a relay hub. For local development, start an anonymous hub bound to loopback:
OPENRUNG_ALLOW_ANONYMOUS_VOLUNTEERS=true \
go run ./cmd/relayhub \
-broker http://localhost:8080 \
-control-addr 127.0.0.1:9443 \
-public-host 127.0.0.1 \
-public-bind-host 127.0.0.1 \
-port-range 20000-20100Then run the relay in tunnel mode — it binds Xray to loopback and dials the hub
instead of exposing a port (no -public-host needed):
go run ./cmd/relay \
-tunnel \
-hub 127.0.0.1:9443 \
-hub-tls=false \
-xray /path/to/xrayThese loopback commands deliberately use an anonymous, plaintext hub for local
development only. A public hub should require the shared registration token
and TLS described in deploy/relayhub/README.md.
When NAT punching is unavailable or fails, all traffic for a CGNAT relay
transits the hub. Keep the relay path opt-in (public-IP relays should stay in
direct mode) and run public hubs away from metered cloud egress. See
deploy/relayhub/README.md for cost details and
TLS setup.
Inspect the raw relay directory response and confirm that the terminal client can select a usable relay:
curl http://localhost:8080/api/v1/relays
go run -tags with_utls,with_external_windivert ./cmd/client check -broker http://localhost:8080Then connect with the interactive client (enter connects from the Relays list, q quits):
go run -tags with_utls,with_external_windivert ./cmd/client connect -broker http://localhost:8080For the zero-privilege desktop proxy app, and for the terminal client's views,
keys, and full-device TUN mode, see
docs/desktop-client.md.
The separately maintained Android and iOS clients implement the same
direct-first WSS/CDN fallback through pinned brokerapi and wsscore modules.
cmd/broker/ Broker HTTP API (control plane).
cmd/relay/ Relay CLI for Xray-backed registration.
cmd/relayhub/ Relay hub for CGNAT volunteer-run relays
(reverse-tunnel data plane).
cmd/wsssidecar/ Relay-local WSS/CDN origin with a fixed loopback target.
cmd/client/ Terminal client (TUI; proxy and TUN capture modes).
internal/broker/ Broker store and HTTP handlers.
internal/punch/ NAT hole-punch QUIC layer (session, transport, bridges) over punchcore.
internal/relay/ Server-side relay registration and identity models.
internal/relayhub/ Relay hub configuration.
internal/tunnel/ Reverse-tunnel transport (hub + relay client, yamux).
internal/relayruntime/ Relay runtime, Xray config, and broker client helpers.
internal/wssbridge/ Relay-side tickets, replay/origin authentication,
admission limits, and sidecar orchestration over wsscore.
brokerapi/ Shared broker control-plane Go client and exported relay
schema (nested module github.com/openrung/openrung/brokerapi)
for desktop, Android, and iOS bindings.
connectcore/ Client policy engine — connect ladder, ranking, WSS
fallback and punch policy, telemetry classifier/outbox,
sing-box config builder, discovery, and the cross-repo
contract vectors (nested Go module
github.com/openrung/openrung/connectcore) consumed by the
terminal client, desktop app, and mobile bindings.
punchcore/ Shared NAT hole-punch protocol core (nested Go module
github.com/openrung/openrung/punchcore) consumed by the
servers and the desktop, Android, and iOS clients.
wsscore/ Shared opaque Reality-over-WSS transport core (nested Go
module github.com/openrung/openrung/wsscore) consumed by
the desktop, Android, and iOS clients and relay sidecar.
desktop/ Desktop GUI client (Wails v2 + React; own Go module).
desktop-volunteer/ One-click volunteer relay GUI (Wails v2 + React; own
Go module).
deploy/ Broker proxy, relay hub, and relay deployment assets.
docs/ Architecture, API, client, and operations docs.
| Document | What it covers |
|---|---|
| Architecture | Goals, components, and trust boundaries |
| Broker API | HTTP API reference (/api/v1) |
| Component versioning | Independent release identities and compatibility contracts |
| Desktop clients | GUI proxy mode, Linux shell setup, and the terminal client's proxy and TUN modes |
| WSS fallback | Per-relay protocol, trust boundaries, failure policy, and rollout |
| Per-relay CloudFront deployment | CloudFront and relay-local sidecar configuration |
| Security and abuse | Threat model, volunteer risk, and abuse handling |
| Relay hub deployment | Running a hub: TLS, ports, and cost |
- Dedicated exit servers — let volunteer operators choose to act as entry relays instead of direct exits.
- Abuse and rate controls — exit policies, rate limits, and abuse reporting ahead of a broad public rollout.
- NAT hole-punch coverage — direct client↔relay paths for volunteer-run
relays behind CGNAT are implemented in the desktop, Android, and iOS clients
using
github.com/openrung/openrung/punchcore; broader production rollout and harder NAT mappings remain planned. - Dual-stack relay discovery — multiple public endpoints per relay.
Have an opinion on what should come first? Open an issue — roadmap feedback is welcome.
Run make test for the root module, all shared Go modules, and both desktop
apps' service packages; run make fmt to format Go code across those modules.
The test target also checks the volunteer app's version metadata. Relay
integration tests use the Xray version pinned in deploy/relay/Dockerfile.
Run npm ci, npm test, and npm run build separately in each app's
frontend/ directory. Full Wails builds additionally require the platform's
native dependencies.
make broker starts a loopback development broker with a temporary signing
seed unless OPENRUNG_RELAY_SIGNING_KEY is already set. Set that variable to
reuse a signing identity across restarts.
OpenRung is under active development, and reports from real networks are the most valuable contribution:
- 🐛 Found a bug or a rough edge? Open an issue — relay IDs, connection logs, and network conditions help a lot.
- 💡 Feature ideas and questions are welcome as issues too.
- 🙋 Want to run a relay or help test the mobile app? Email admin@openrung.org.
Contributions are accepted under GPL-3.0-or-later with a Developer Certificate
of Origin sign-off. See CONTRIBUTING.md for the details,
and thank you for helping people reach the open internet.
OpenRung is licensed under the GNU General Public License v3.0 or later
(GPL-3.0-or-later). See LICENSE.
The mobile app (maintained in its own repository), the terminal client
(cmd/client), and the desktop app statically link
sing-box (GPL-3.0-or-later), so the
combined apps — and the project as a whole — are GPL-3.0-or-later. The relay
transport's VLESS + REALITY + Vision support comes
from Xray-core (MPL-2.0), which the
relay runs as a separate process.
Third-party components bundled or linked into distributed artifacts (Docker
images, server binaries), and the attribution and source-offer
obligations they carry, are documented in
THIRD_PARTY_NOTICES.md. Complete corresponding
source for any released binary is available from this repository.
OpenRung builds on excellent open source work:
- Xray-core — VLESS + REALITY + Vision relay transport
- sing-box — client tunnel and proxy engine
- MapLibre — maps in the mobile app
- Tor's Snowflake — inspiration for volunteer-powered circumvention
OpenRung is not affiliated with or endorsed by the sing-box, Xray, or MapLibre projects; their names are used descriptively.