How to Build a Censorship-Resistant Tunnel with Aether and MASQUE
Aether is a Rust userspace implementation of Cloudflare’s WARP protocol, built specifically for highly filtered networks. It runs entirely in userspace — no kernel modules, no TUN drivers that require root — and it speaks MASQUE over HTTP/3 and HTTP/2 under the hood. That last part matters: MASQUE is IETF-standardized proxying over QUIC, which means the traffic profile looks like a QUIC connection to a CDN edge. Firewalls that do deep packet inspection on OpenVPN or WireGuard headers see nothing unusual here.
This guide walks through getting Aether running on a Linux box, verifying it actually routes traffic, and understanding enough of the internals to debug it when something breaks. All commands are tested against Ubuntu 24.04.
Step 1 – Prerequisites and Build
Aether compiles from source. You need Rust 1.78 or later. If you’re on a fresh machine, install via rustup rather than your distro’s package manager — distro Rust packages lag by months and the project uses recent async APIs.
curl -fsSL https://sh.rustup.rs | sh -s -- -y
source ~/.cargo/env
rustup update stable
git clone https://github.com/CluvexStudio/Aether.git
cd Aether
cargo build --release 2>&1 | tail -5
The build pulls in Quinn (the Rust QUIC implementation), Tokio for async I/O, and a few platform-specific TLS backends. Expect three to five minutes on a VPS with two cores. The output binary lands at target/release/aether. Copy it somewhere on your PATH, for example /usr/local/bin/. No other runtime dependencies — the binary is statically linked against the crypto backend.
Step 2 – Configuration File
Aether reads a TOML config. The two required fields are your WARP registration token and the proxy mode. MASQUE is default and the right choice for censored networks; HTTP/2 fallback exists for environments where QUIC is dropped entirely (some ISPs in Iran and China block UDP above a certain packet rate).
# ~/.config/aether/config.toml
[warp]
token = "YOUR_WARP_REGISTRATION_TOKEN"
mode = "masque" # or "http2" if QUIC is blocked
[proxy]
listen = "127.0.0.1:10808" # local SOCKS5 endpoint
dns = "1.1.1.1"
Getting the WARP token: Cloudflare issues these through the WARP app registration flow. The Aether README links to a helper script that calls the registration API and prints the token. You register once; the token persists across restarts. Keep it out of git — treat it like a private key.
If your ISP drops QUIC completely, set
mode = "http2". Performance drops because QUIC’s 0-RTT reconnect is gone, but the connection still terminates at a Cloudflare edge and the traffic still passes through MASQUE tunneling semantics.
Step 3 – Run and Verify
Start Aether and point a curl request through the SOCKS5 listener to confirm you’re exiting through Cloudflare’s network. The --proxy flag in curl accepts SOCKS5 directly.
aether --config ~/.config/aether/config.toml &
# give it two seconds to handshake
sleep 2
# check exit IP
curl -s --proxy socks5h://127.0.0.1:10808 https://ifconfig.me
# verify it's a Cloudflare AS (ASN 13335)
curl -s --proxy socks5h://127.0.0.1:10808 https://ipinfo.io | python3 -m json.tool | grep org
You want to see "org": "AS13335 Cloudflare, Inc." in the output. If you see your own ISP’s ASN, the tunnel didn’t connect. Check the logs — Aether spits structured JSON logs by default. The most common failure at this step is a firewall blocking outbound UDP to port 2408 (WARP’s default QUIC port). Either open it on your host firewall or fall back to HTTP/2 mode, which uses port 443.
Step 4 – Route Specific Traffic Through the Tunnel
Running everything through Aether is usually wrong. DNS lookups, local services, and traffic to your own VPS should not go through Cloudflare. The right setup is selective routing: send only blocked or sensitive destinations through SOCKS5, let everything else go direct.
For terminal tools, set the proxy per-command or export it for a session:
# one command
https_proxy=socks5h://127.0.0.1:10808 curl https://t.me
# or for an interactive session
export ALL_PROXY=socks5h://127.0.0.1:10808
# unset when done
unset ALL_PROXY
For browser traffic, Aether’s SOCKS5 listener works directly as a manual proxy setting in Firefox. Chrome/Chromium accepts it with the --proxy-server flag. For system-wide routing on Linux, proxychains-ng wraps arbitrary binaries; set its config to your SOCKS5 address and prepend proxychains4 before any command. On systems where you want kernel-level routing without a TUN interface, redsocks can redirect iptables-marked traffic to the SOCKS5 endpoint.
Step 5 – Run as a Systemd Service
Running Aether in the background with & is fine for testing. For a machine you want reliably tunneled, run it as a user systemd service so it restarts on crash and starts on boot without root.
# ~/.config/systemd/user/aether.service
[Unit]
Description=Aether WARP tunnel
After=network-online.target
[Service]
ExecStart=/usr/local/bin/aether --config %h/.config/aether/config.toml
Restart=on-failure
RestartSec=5
[Install]
WantedBy=default.target
systemctl --user daemon-reload
systemctl --user enable --now aether
systemctl --user status aether
One thing worth knowing: WARP tokens expire periodically. When they do, Aether fails to handshake and exits with a 403 from the registration endpoint. Set up a systemd timer or a cron job that re-registers and writes a fresh token to the config every 30 days. The Aether repo includes a scripts/renew-token.sh that does exactly this — pipe its output into the config file and send SIGHUP to the running process to reload without restarting the SOCKS5 listener.
Next steps
Aether solves one narrow problem well: it gets WARP-tunneled traffic out of a filtered network without a kernel TUN interface or root privileges. It doesn’t replace a full VPN for all traffic, and it doesn’t solve DNS leaks on its own — pair it with a local DNS resolver that sends queries through the same SOCKS5 endpoint. If you’re on a network where UDP is throttled hard enough to make QUIC unusable, test the HTTP/2 mode before assuming Aether won’t work. The MASQUE-over-HTTP/2 path is slower but surprisingly functional even on heavily filtered connections.
For mobile, the MatinSenPai/Aether-GUI project wraps the same Rust core in a Tauri v2 + React 19 desktop app with a one-click interface. The underlying tunnel logic is identical — same binary, same config format.