satmux
TCP multiplexer and 1-RTT HTTP/TLS relay for geostationary (GEO) inflight Wi-Fi (Inmarsat GX, Viasat, Panasonic, SITA). Pure Python 3 stdlib, zero external dependencies.
Measured inflight over Inmarsat GX Ka-band (~620 ms RTT, SITA AS206433 Amsterdam ground station):
ORIGIN (6× PARALLEL) RAW CABIN WI-FI (:443) 1-RTT BBR + ZLIB MUX SPEEDUP
──────────────────── ──────────────────────── ────────────────────── ─────────
GitHub Repo ████████████ TIMEOUT ███░░░░░░░░░ 4.66s FIXED ✓
GitHub API ████████████ TCP RESET ██░░░░░░░░░░ 2.66s FIXED ✓
Hacker News ████████████ TIMEOUT ██░░░░░░░░░░ 2.28s FIXED ✓
MDN Docs ████████░░░░ 12.01s ██░░░░░░░░░░ 2.30s 5.2×
Cloudflare ██░░░░░░░░░░ 2.97s █░░░░░░░░░░░ 1.40s 2.1×
PyPI JSON API █████░░░░░░░ 7.09s ██░░░░░░░░░░ 2.64s 2.7×
──────────────────────────────────────────────────────────────────────────────────
6-Origin Burst: 19.13s (3/6 failed) → 5.35s (0/6 failed) [3.6× faster · -76% TTFB]Problem
Non-Starlink inflight Wi-Fi usually breaks on three things unrelated to raw bandwidth:
- Onboard
:443middleboxes and DNS interception. Cabin gateways intercept:53DNS and run a transparent:443split-TCP proxy (PEP) whose state table drops connections under load (Connection reset by peer/ TLS timeouts ongithub.com,api.github.com, package registries). Non-443 TCP ports pass through untouched. - Handshake round-trips (
~620 msper GEO hop). Every new origin normally pays multiple satellite round-trips (DNS + TCP + TLS) before transferring payload bytes. - Cubic congestion collapse. Cabin Wi-Fi packet loss causes standard TCP to halve
cwndrepeatedly, leaving most of your per-seat token-bucket cap unused.
How it works
Direct (:443):
laptop ──▶ cabin DNS + :443 PEP ══(3–4 GEO RTTs)══▶ ground ──▶ origin (frequent TCP resets)
satmux (:8444):
laptop ══(12 persistent TCP :8444 BBR + zlib pipes)══▶ ground VM ──(2 ms)──▶ origin- Persistent non-443 carrier pool (
:8444): Keeps 12 pre-warmed TCP connections open to a Linux VM near the satellite ground station, bypassing the cabin:443proxy and onboard DNS. Streams are scheduled onto the carrier with the lowest recent byte load so idle browser keepalives do not cause head-of-line queueing. - 0-RTT stream open (
127.0.0.1:1080SOCKS5 /127.0.0.1:8080HTTP CONNECT): ReturnsOKlocally in<1 msand sendsFT_OPEN+ TLSClientHelloin the same TCP burst, saving one full satellite RTT while preserving end-to-end TLS from the laptop. - 1-RTT ground fetch (
127.0.0.1:8081): Sends an encrypted (BLAKE2b-512stream +HMAC-SHA256) request frame over a warm carrier. The ground VM performs DNS, verified TLS 1.3, and HTTP redirects on fiber (~2–5 ms) and compresses plaintext responses withzlibbefore crossing the satellite link. gitandghCLI routing: Go binaries such asghignore macOSscutilproxies.satmuxexposes a0600local Unix socket (/tmp/satmux-gh-tls.sock) wired togh'shttp_unix_socketthat wraps requests in verified end-to-end TLS on the laptop and tunnels them over SOCKS5, fixing already-running coding agents without restarting them.- BBR +
MSS 1280: Ground-to-cabin sockets enableTCP_CONGESTION=bbrandTCP_MAXSEG=1280.
Limits
- Latency floor (
~580–650 ms): Speed-of-light propagation to geostationary orbit (35,786 km) does not change;satmuxremoves extra round-trips, not the physical RTT of one hop. - Per-seat shaper (
~4–5 Mbpstypical): Cabin routers police total bandwidth per client lease. Compressible traffic (HTML, JSON, code, APIs) exceeds that rate in effective throughput viazlib; already-compressed binaries (.mp4,.zip) stay bounded by the seat cap (though BBR + parallelsatmux-getkeep throughput near the ceiling). - Single paid session: Uses your authenticated cabin Wi-Fi lease; it does not bypass captive portals.
Setup
1. Ground VM
Rent a small Linux VM ($0.01–$0.03/h, Python 3.9+, open TCP port 8444) close to where the satellite downlinks to fiber. Check curl ipinfo.io on raw cabin Wi-Fi first to see the egress country/ASN:
- Emirates / Middle East & European flights (Inmarsat GX / SITA
AS206433): Amsterdam, Frankfurt, or Hetzner EU (downlink lands in the Netherlands). - North America:
us-eastorus-west. - Asia-Pacific: Singapore or Tokyo.
Pause UDP VPNs (Tailscale/WireGuard) inflight—blocked UDP retry traffic competes for cabin airtime.
2. Run
With a coding agent:
Spin up a temporary Ubuntu VM near my current satellite egress IP, start
https://github.com/Th0rgal/satmuxon port8444, connect the local 12-carrier client, enablebin/satmux-macos on, and runbin/satmux-bench.
Or manually:
# 1. Laptop: generate PSK
git clone https://github.com/Th0rgal/satmux.git && cd satmux
openssl rand -hex 32 > mux.psk && chmod 600 mux.psk
# 2. Ground VM: start server
scp satmux.py mux.psk root@<SERVER_IP>:/root/
ssh root@<SERVER_IP> 'nohup env SATMUX_PSK=$(cat /root/mux.psk) python3 /root/satmux.py server --port 8444 >/var/log/satmux.log 2>&1 &'
# 3. Laptop: start client + enable macOS / git / gh routing
SATMUX_PSK=$(cat mux.psk) python3 satmux.py client --host <SERVER_IP> --port 8444 --carriers 12 &
./bin/satmux-macos on <SERVER_IP>Benchmark or run parallel range downloads:
./bin/satmux-bench
./bin/satmux-get https://example.com/archive.tar.gz3. Teardown after landing
./bin/satmux-macos offRestores macOS Wi-Fi proxy settings, ~/.gitconfig, gh http_unix_socket, and launchctl env vars, then destroy the temporary VM.
License
MIT