YUX/floo
High-throughput, token-authenticated tunneling built in Zig.
_____.__
_/ ____\ | ____ ____
\ __\| | / _ \ / _ \
| | | |_( <_> | <_> )
|__| |____/\____/ \____/
Floo is a lightweight, secure tunneling toolkit that lets you:
Written in Zig with modern cryptography (Noise XX protocol), Floo provides both forward tunneling (reach into private networks) and reverse tunneling (expose local services) with strong authentication.
Run floos on a public VPS and flooc on your home server. Connect to localhost:5432 on your laptop to reach your home PostgreSQL instance.
# On VPS (floos.toml):
[services]
postgres = "10.0.0.5:5432"
# On laptop (flooc.toml):
[services]
postgres = "127.0.0.1:5432"
Share your home media server (Jellyfin/Plex)
Expose your local Jellyfin server to friends without opening router ports or using dynamic DNS.
# On VPS (floos.toml):
[reverse_services]
media = "0.0.0.0:8096"
# On home server (flooc.toml):
[reverse_services]
media = "127.0.0.1:8096"
Friends access http://your-vps:8096 β your home Jellyfin.
Your company blocks everything except HTTP/HTTPS proxies. Floo can tunnel through SOCKS5 or HTTP CONNECT proxies.
# flooc.toml:
[advanced]
proxy_url = "socks5://corporate-proxy:1080"
Download prebuilt binaries:
Or build from source:
git clone https://github.com/YUX/floo.git
cd floo
zig build -Doptimize=ReleaseFast
# Binaries in: zig-out/bin/
β οΈ Security First: Never use default or weak credentials!
# Generate a strong PSK (Pre-Shared Key)
openssl rand -base64 32
# Generate a strong token
openssl rand -base64 24
Save these somewhere secure - you'll need them for both server and client.
Copy the example config:
cp configs/floos.example.toml floos.toml
Edit floos.toml and set your real credentials:
bind = "0.0.0.0"
port = 8443
cipher = "aes256gcm"
psk = "YOUR_GENERATED_PSK_HERE" # β Paste your openssl output
token = "YOUR_GENERATED_TOKEN_HERE" # β Paste your openssl output
[services]
# Example: allow clients to reach an internal database
database = "10.0.0.5:5432"
[reverse_services]
# Example: accept connections from clients and expose on port 8096
media = "0.0.0.0:8096"
Copy the example config:
cp configs/flooc.example.toml flooc.toml
Edit flooc.toml with the same credentials:
server = "your-vps-ip:8443" # β Your VPS address
cipher = "aes256gcm"
psk = "YOUR_GENERATED_PSK_HERE" # β Must match server!
token = "YOUR_GENERATED_TOKEN_HERE" # β Must match server!
[services]
# Listen locally and connect through tunnel to server's "database" service
database = "127.0.0.1:5432"
[reverse_services]
# Expose your local media server through the tunnel
media = "127.0.0.1:8096"
On the server (VPS):
./floos floos.toml
# [SERVER] Port: 8443
# [SERVER] Mode: Blocking I/O + Threads
On the client (home machine):
./flooc flooc.toml
# [CLIENT] Connected to tunnel server
# [CLIENT] All services started
If you configured the database example:
# On your laptop (where flooc is running):
psql -h 127.0.0.1 -p 5432
# You're now connected to your home database through the encrypted tunnel!
If you configured reverse media sharing:
# From anywhere on the internet:
curl http://your-vps-ip:8096
# You're accessing your home media server!
Scenario: You have a database at home, want to access it from your laptop.
βββββββββββ encrypted βββββββββββ ββββββββββββ
β Laptop ββββββββtunnelβββββ VPS ββββββββββββββββ Home DB β
β (you) β β (floos) β local β 10.0.0.5 β
βββββββββββ βββββββββββ ββββββββββββ
flooc
connects to defines [services]
127.0.0.1:5432 database = "10.0.0.5:5432"
Client config (flooc.toml): Local listener
[services]
database = "127.0.0.1:5432"
Server config (floos.toml): Target location
[services]
database = "10.0.0.5:5432"
Scenario: Share your home media server with friends.
βββββββββββ βββββββββββ encrypted ββββββββββββ
β Friend ββββββββββββββββ VPS ββββββββtunnelβββββ Home β
β Browser β internet β (floos) β β Jellyfin β
βββββββββββ βββββββββββ ββββββββββββ
binds on flooc
connects to 0.0.0.0:8096 exposes
your-vps:8096 [reverse_services] 127.0.0.1:8096
Server config (floos.toml): Public listener
[reverse_services]
media = "0.0.0.0:8096"
Client config (flooc.toml): Local service
[reverse_services]
media = "127.0.0.1:8096"
The simplest possible setup:
floos.toml (server):
port = 8443
psk = "your-strong-psk-here"
token = "your-strong-token-here"
[services]
web = "10.0.0.10:80"
flooc.toml (client):
server = "vps.example.com:8443"
psk = "your-strong-psk-here"
token = "your-strong-token-here"
[services]
web = "127.0.0.1:8080"
Choose based on your hardware:
| Cipher | Single Stream | Multi-Stream (4x) | Hardware Acceleration | Use When |
|---|---|---|---|---|
aegis128l |
22.1 Gbps | 7.7 Gbps | ARMv8, x86 AES-NI | Modern CPU, max speed |
aegis256 |
19.2 Gbps | 7.4 Gbps | ARMv8, x86 AES-NI | Modern CPU, max security |
aes128gcm |
14.5 Gbps | 5.9 Gbps | ARMv8, x86 AES-NI | Modern CPU, compatibility |
aes256gcm |
13.4 Gbps | 5.6 Gbps | ARMv8, x86 AES-NI | Modern CPU, standard choice |
chacha20poly1305 |
3.4 Gbps | 2.3 Gbps | Software-only | Older CPU, mobile devices |
none (plaintext) |
30.9 Gbps | 9.6 Gbps | N/A | Debug/testing only |
Performance tested on Apple M1 (4 vCPU). Single stream = optimal throughput, Multi-stream = realistic concurrent usage.
Add extra security by requiring different tokens per service:
token = "default-token"
[services]
web = "10.0.0.10:80"
web.token = "public-web-token"
database = "10.0.0.20:5432"
database.token = "sensitive-db-token"
Clients must use the matching token to access each service.
Tunnel UDP traffic (DNS, VoIP, games):
[services]
dns = "8.8.8.8:53/udp"
voip = "10.0.0.30:5060/udp"
[advanced]
socket_buffer_size = 4194304 # 4MB buffers for high throughput
num_tunnels = 0 # 0 = auto based on CPU cores
pin_threads = true # Pin tunnel handlers to CPU cores
io_batch_bytes = 131072 # Per-stream I/O buffer size
tcp_nodelay = true # Disable Nagle for lower latency
heartbeat_interval_seconds = 30 # Keepalive frequency
βΉοΈ num_tunnels: leave at
0to match your CPU core count automatically. Set an explicit number only when you need to cap or boost tunnel fan-out.βΉοΈ pin_threads: keeps each tunnel on a dedicated core (Linux/Unix). Disable only if your scheduler forbids manual affinity.
βΉοΈ io_batch_bytes: per-stream read/write buffer size. Increase for jumbo frames or high-latency satellite links; decrease for memory-constrained devices.
Validate your configuration before running:
# Test server config
./floos --doctor floos.toml
# β Configuration valid
# β Can bind on 0.0.0.0:8443
# β All forward targets reachable
# Test client config
./flooc --doctor flooc.toml
# β Configuration valid
# β Server reachable at vps.example.com:8443
# β Warning: proxy_url not set
Measure tunnel latency:
./flooc --ping flooc.toml
# Noise handshake latency: 8.2ms
Test target connectivity:
./floos --ping floos.toml
# [PING] database (10.0.0.5:5432): 1.2ms β
# [PING] api (10.0.0.10:443): 3.5ms β
Every release publishes optimized binaries for:
| Platform | File | Best For |
|---|---|---|
| Linux x86_64 | floo-x86_64-linux-gnu.tar.gz |
Ubuntu, Debian, RHEL, Fedora |
| Linux x86_64 (Haswell+) | floo-x86_64-linux-gnu-haswell.tar.gz |
Modern servers (2013+), 3-5Γ crypto speed |
| Linux x86_64 (static) | floo-x86_64-linux-musl.tar.gz |
Alpine, containers, no glibc |
| Linux ARM64 | floo-aarch64-linux-gnu.tar.gz |
Raspberry Pi, AWS Graviton, cloud ARM |
| Linux ARM64 (optimized) | floo-aarch64-linux-gnu-neoverse-n1.tar.gz |
AWS Graviton, Ampere Altra |
| macOS Apple Silicon | floo-aarch64-macos-m1.tar.gz |
M1/M2/M3/M4 Macs |
| macOS Intel | floo-x86_64-macos.tar.gz |
Intel Macs |
Download from releases page.
Requires Zig 0.15.1+
# Debug build (fast compilation)
zig build
# Optimized release build
zig build -Doptimize=ReleaseFast
# Cross-compile for Raspberry Pi
zig build -Doptimize=ReleaseFast -Dtarget=aarch64-linux-gnu -Dcpu=cortex_a72
# Build all release artifacts
zig build release-all
Run tests:
zig build test
β οΈ Important Security Notes:
cipher = "none" only for debugging on trusted networksThe examples/ directory contains complete working setups:
Each example includes ready-to-use config files and setup instructions.
Compression for high-latency links
io_uring backend (Linux performance boost)
QUIC/DTLS transport for UDP
Prometheus metrics endpoint
Web dashboard for monitoring
Pull requests welcome! Please:
zig fmt src/*.zig before committing--doctor mode to validate config changesMIT License - see LICENSE file.
Benchmarked on Apple M1 (4 vCPU), 1 second duration:
| Cipher | Forward | Reverse | vs FRP | vs Rathole |
|---|---|---|---|---|
| Plaintext | 30.9 Gbps | 30.5 Gbps | 3.4x faster | 1.9x faster |
| AEGIS-128L | 22.1 Gbps | 23.3 Gbps | 2.4x faster | 1.3x faster |
| AEGIS-256 | 19.2 Gbps | 21.2 Gbps | 2.1x faster | 1.2x faster |
| AES-128-GCM | 14.5 Gbps | 16.2 Gbps | 1.6x faster | Similar |
| AES-256-GCM | 13.4 Gbps | 14.1 Gbps | 1.5x faster | Similar |
| ChaCha20 | 3.4 Gbps | 3.4 Gbps | Similar | 0.5x |
FRP: 9.2 Gbps, Rathole: 16.6 Gbps (single stream baseline)
| Cipher | Forward | Reverse | Notes |
|---|---|---|---|
| Plaintext | 9.6 Gbps | 9.6 Gbps | Still 3x faster than FRP |
| AEGIS-128L | 7.7 Gbps | 7.9 Gbps | Best encrypted option |
| AES-256-GCM | 5.6 Gbps | 5.5 Gbps | Widely compatible |
| ChaCha20 | 2.3 Gbps | 2.3 Gbps | Software fallback |
Key Takeaway: For maximum throughput, use single streams with AEGIS-128L. For multiple concurrent connections, performance scales linearly with CPU cores.
Questions? Check the examples/ directory or open an issue.
Every floos/flooc process keeps live counters for:
Dump a snapshot at any time with SIGUSR1, or just stop the process cleanly:
kill -USR1 $(pgrep floos) # server side
kill -USR1 $(pgrep flooc) # client side
Sample output:
[PROFILE] server encryption total=12000 ns calls=14 avg=857 ns
[PROFILE] server throughput tx=865 bytes (0.00 MB) rx=9649744503 bytes (9202.71 MB)
Because the counters are always on in the data path, thereβs no extra agent to runβjust signal the process and parse the two log lines.