Skip to content

aeroxy/tunnix

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

tunnix

An encrypted SOCKS5/HTTP proxy tunnel over HTTP/SSE.

tunnix routes your SOCKS5 and HTTP(S) proxy traffic through a plain HTTP connection, end-to-end encrypted with ChaCha20-Poly1305. It is designed for environments that serve HTTP but block direct TCP — Cloud Shell, Codespaces, Gitpod, or any host behind a reverse proxy.

Features

  • End-to-end encryption — ChaCha20-Poly1305, Argon2id key derivation
  • HTTP/SSE transport — no WebSocket required; works wherever plain HTTP works
  • Dual-protocol listener — SOCKS5 and HTTP proxy on the same port, auto-detected
  • Connection multiplexing — many connections share one SSE stream
  • Custom header injection — for cookie-authenticated reverse proxies
  • Path prefix support — serve under a sub-path (/foo/bar/stream/...) to coexist with other apps on the same host
  • Single binarytunnix server / tunnix client

Installation

Homebrew (macOS / Linux):

brew tap aeroxy/tunnix https://github.com/aeroxy/tunnix
brew install tunnix

Cargo:

cargo install tunnix

Or download a pre-built binary from the releases page.

Quick Start

# Server
tunnix server --listen 0.0.0.0:8080 --password "your-secret"

# Client
tunnix client \
  --server https://your-host.example.com \
  --password "your-secret" \
  --local-addr 127.0.0.1:7890

# Test
curl -x http://127.0.0.1:7890 https://ifconfig.me
curl --socks5 127.0.0.1:7890 https://ifconfig.me

Deployment Scenarios

Google Cloud Shell

Cloud Shell's Web Preview issues a temporary HTTPS URL for your HTTP server. tunnix runs inside Cloud Shell and the client connects using the preview URL with Cloud Shell's authorization cookies.

Server (inside Cloud Shell terminal):

tunnix server --listen 0.0.0.0:8080 --password "your-secret"

Open Web Preview on port 8080 to get the preview URL.

Get cookies: Browser DevTools → Network tab → any request to *.cloudshell.dev → copy the Cookie header.

Client (local machine):

tunnix client \
  --server "https://8080-cs-XXXX.cs-region.cloudshell.dev" \
  --password "your-secret" \
  --cookie "CloudShellAuthorization=Bearer ...; CloudShellPartitionedAuthorization=Bearer ..."

GitHub Codespaces

Codespaces exposes forwarded ports via a GitHub-authenticated HTTPS URL.

Server (inside Codespace terminal):

tunnix server --listen 0.0.0.0:8080 --password "your-secret"

In the Ports panel, set port 8080 visibility to Public (or pass a GitHub token).

Client:

tunnix client \
  --server "https://your-codespace-name-8080.app.github.dev" \
  --password "your-secret"

Gitpod

Same pattern as Codespaces. Make the port public in the Gitpod ports UI.

Client:

tunnix client \
  --server "https://8080-your-workspace.ws-eu.gitpod.io" \
  --password "your-secret"

Behind nginx (path prefix)

When tunnix shares a host with other services, use path_prefix to scope all its routes under a sub-path. nginx handles TLS; tunnix binds to a local port.

config.toml (server):

[server]
listen = "127.0.0.1:9000"
password = "your-secret"
path_prefix = "/tunnix"

nginx snippet:

location /tunnix/ {
    proxy_pass http://127.0.0.1:9000;
    proxy_http_version 1.1;
    proxy_buffering off;
    proxy_cache off;
    proxy_set_header Connection "";
    proxy_set_header X-Accel-Buffering "no";
    proxy_read_timeout 3600s;
}

Client:

tunnix client --server "https://your-domain.com/tunnix" --password "your-secret"

The bare /health endpoint always responds regardless of prefix, so load-balancer probes continue to work.

Railway / Render / Fly.io

These platforms run long-lived processes and assign a public HTTPS URL. They set a $PORT environment variable.

Dockerfile (minimal):

FROM debian:bookworm-slim
COPY tunnix /usr/local/bin/tunnix
CMD tunnix server --listen "0.0.0.0:$PORT" --password "$TUNNIX_PASSWORD"

Set TUNNIX_PASSWORD as an environment secret in the platform dashboard.

Client:

tunnix client \
  --server "https://your-app.railway.app" \
  --password "your-secret"

Vercel is not recommended. Serverless functions have short execution timeouts (10–60 s depending on plan) that are incompatible with long-lived SSE streams. Use a container-based platform instead.

Configuration

Copy config.example.toml to config.toml and customize:

[server]
listen = "0.0.0.0:8080"
password = "your-secret"
# path_prefix = "/tunnix"   # optional; leave empty for root

[client]
server_url = "https://your-host.example.com"
password = "your-secret"
local_addr = "127.0.0.1:7890"

[client.headers]
# Cookie = "..."   # only needed for cookie-authenticated hosts

[logging]
level = "info"
# file = "./tunnix.log"

Run with a config file:

tunnix server --config config.toml
tunnix client --config config.toml

CLI flags always override config file values. The password can also be supplied via the TUNNIX_PASSWORD environment variable.

Changes to config.toml are picked up automatically every few seconds — no restart needed. Hot-reloadable fields: password, headers, path_prefix, root_redirect, root_html, health_response. Fields that require a restart: listen, local_addr, server_url, logging.level. CLI overrides are never clobbered by file changes.

Building

cargo build --release
# Binary: target/release/tunnix

Cross-compile for Linux (requires cargo-zigbuild):

cargo zigbuild --release --target x86_64-unknown-linux-gnu

Or use make:

make release          # native
make release-linux    # Linux x86_64
make release-all      # both

Architecture

Local SOCKS5/HTTP client
        │
        ▼
  tunnix client
  ├── proxy.rs       — TCP listener; detects protocol (0x05=SOCKS5, letter=HTTP)
  ├── socks5.rs      — SOCKS5 handshake (RFC 1928, CONNECT only)
  ├── http_proxy.rs  — HTTP CONNECT + plain HTTP forwarding
  ├── relay.rs       — bidirectional relay; connection ID counter
  └── tunnel.rs      — HTTP/SSE tunnel to server
          │
          │  POST /[prefix]/send/{session}    encrypted binary body
          │  GET  /[prefix]/stream/{session}  SSE text/event-stream
          ▼
  tunnix server
  └── server.rs      — hyper HTTP/1.1 server; session routing; prefix stripping
          │
          │  raw TCP
          ▼
  Target (e.g. api.example.com:443)

The client auto-detects the incoming protocol by peeking the first byte:

  • 0x05 → SOCKS5
  • ASCII letter → HTTP proxy (CONNECT for HTTPS, method for plain HTTP)

Security

  • Argon2id key derivation from the shared password
  • ChaCha20-Poly1305 AEAD, per-message random nonce
  • No plaintext payload logging
  • Use a strong, randomly generated password — it is the only credential

Use with Clash / ClashX

proxies:
  - name: tunnix
    type: socks5      # or type: http
    server: 127.0.0.1
    port: 7890

License

MIT

About

An encrypted SOCKS5/HTTP proxy tunnel over HTTP/SSE — built for environments where only plain HTTP works.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors