Skip to content

KatIsCoding/yatun

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

62 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

yatun — Yet Another Tunnel

yatun is an open-source TCP reverse tunneling tool (think ngrok / cloudflared) written in Go. It exposes local services to the internet through a public relay server.

┌──────────┐    TCP     ┌────────────────┐   yamux   ┌──────────┐   TCP   ┌─────────┐
│ Internet │───────────▶│  yatund        │◀═════════▶│  yatun   │────────▶│ local   │
│ Client   │ random port│  (relay server)│  session  │  (agent) │ :port   │ service │
└──────────┘            └────────────────┘           └──────────┘         └─────────┘

Why

I wanted to understand how tools like ngrok and cloudflared work under the hood, so I built one.

Architecture

Component Role
yatund Public relay server. Agents connect on port 5678. For each agent, it opens an ephemeral TCP port and forwards all incoming traffic through a yamux multiplexed session back to the agent.
yatun Agent that runs alongside your local service. Connects to yatund, authenticates, and starts forwarding. Comes with a real-time Bubble Tea TUI showing tunnel status, active connections, and ping latency.

Data flow

  1. Agent opens a TCP connection to yatund:5678, upgrades to a yamux session.
  2. Agent sends connection details (subdomain) over the first yamux stream.
  3. Server opens an ephemeral TCP port, sends the public address back to the agent, starts a heartbeat ping loop.
  4. When an internet client connects to the open port, the server opens a new yamux stream toward the agent.
  5. Agent dials localhost:<port> and bidirectionally copies data between the yamux stream and the local service.

Concurrency model

Each agent gets its own TCP port on the server. All connections to that port are multiplexed over a single yamux session to the agent, which forwards them to the local service.


Installation

Via Go install

# For the client
go install github.com/KatIsCoding/yatun/cmd/yatun@latest
# For the server
go install github.com/KatIsCoding/yatun/cmd/yatund@latest

Download binary

Pre-built binaries are available on the Releases page.


Quick start

Client (agent)

Expose a local service through the public relay at yatun.snowdev.one — no server setup needed.

# Expose local port 8080
yatun --port 8080

The agent opens a TUI showing connection status, the public address, active connections, and ping latency.

  • Press q or Ctrl+C to quit.
  • Press c to copy the public address to your clipboard.

Use --server to point at a different relay:

yatun --port 8080 --server your-server.com

Server (relay)

Run your own relay on a machine with a public IP.

# Optional: set your public domain so addresses are reported as domain.com:port
export DOMAIN=https://tunnel.example.com

yatund

The server listens on port 5678 for agent connections.


Configuration

Server environment variables

Variable Required Default Description
DOMAIN No "" Public-facing domain. When set, the server reports addresses as yourdomain.com:<port> instead of raw IP:port.
TLS No 0 (off) Enable TLS for incoming external connections. Set to any non‑0 value. Requires certificate files.
CERT_PATH No certs/cert.cer Path to the TLS certificate (fullchain). Only used when TLS is enabled.
KEY_PATH No certs/cert_key.key Path to the TLS private key. Only used when TLS is enabled.

Agent flags

Flag Required Default Description
--port Yes Local TCP port to expose through the tunnel.
--server No yatun.snowdev.one Address of the yatund server (hostname or IP).

Docker deployment

A Dockerfile and compose file are provided for a simple example of how the relay could be deployed with docker.

cd deploy
docker compose up --build

The compose file requires an .env file in deploy/. Example:

# Domain for address reporting (optional)
DOMAIN=https://tunnel.example.com

# TLS (set to 1 to enable)
TLS=1

# Paths to your certificate files on the host (For the purposes of the example in the deploy/ folder)
HOST_CER_FILE=/root/.acme.sh/example.com_ecc/fullchain.cer
HOST_KEY_FILE=/root/.acme.sh/example.com_ecc/example.com.key

The server looks for certificates at certs/cert.cer (fullchain) and certs/cert_key.key (private key) inside the container by default (can be changed over env vars). The compose file maps host paths to those locations.


Wire protocol

Messages between agent and server use a simple binary format:

[1 byte: type][2 bytes: payload length (big-endian uint16)][N bytes: JSON payload]
Byte Message Direction Description
A TCPConnection Agent → Server Signal: agent requests a TCP tunnel
B ConnectionDetails Agent → Server Handshake: subdomain info (JSON)
C ResponseMessage Server → Agent Server response with public address (JSON)
D PingMessage Server → Agent Heartbeat from server (JSON)

Development

yatun/
├── cmd/
│   ├── yatun/              # Agent binary
│   │   └── main.go
│   └── yatund/             # Server binary
│       └── main.go
├── deploy/
│   ├── Dockerfile
│   └── docker-compose.yml
├── internal/
│   ├── config/             # Server configuration from env vars
│   ├── message/            # Wire protocol encoding / decoding
│   ├── server/             # Server-side tunneling logic
│   ├── tls/                # TLS certificate loading and connection wrapping
│   └── tui/                # Bubble Tea TUI for the agent
├── ssl/
    └── install.sh          # Helper to install acme.sh

License

MIT

About

self hostable tcp reverse tunnel with a free to use relay server

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages