p.enthalabs

GitHub - cosmind-rusu/smuf: Self-hosted HTTP tunnel tool — like ngrok, but yours. No quotas, no limits, on your own server.

![Image 1: smuf — self-hosted HTTP tunnel](https://github.com/cosmind-rusu/smuf/blob/main/banner.svg)

SELF-HOSTED · OPEN SOURCE · WRITTEN IN GO

![Image 2: Go](https://go.dev/)![Image 3: License: Apache 2.0](https://github.com/cosmind-rusu/smuf/blob/main/LICENSE)![Image 4: Self-hosted](https://github.com/cosmind-rusu/smuf/blob/main)![Image 5: yamux](https://github.com/hashicorp/yamux)

- * *

smuf exposes a local port on a public URL — like ngrok, but **yours**: no quotas, no limits, on your own server.

``` localhost:3000 ◄─────► https://a3f1c9.yourdomain.com ```

![Image 6: smuf demo](https://github.com/cosmind-rusu/smuf/blob/main/assets/demo.svg)

- * *

Deploy on Railway

[](https://github.com/cosmind-rusu/smuf#deploy-on-railway) One-click deploy `smuf-server` to Railway:

![Image 7: Deploy on Railway](https://railway.com/deploy/high-warm?utm_medium=integration&utm_source=template&utm_campaign=generic)

Once deployed, the server URL and auth token are set via Railway's environment variables (see Configuration below). Then connect with the client from any machine.

- * *

Installation

[](https://github.com/cosmind-rusu/smuf#installation)

Option A: Download a binary (recommended)

[](https://github.com/cosmind-rusu/smuf#option-a-download-a-binary-recommended) Go to Releases and download the binary for your OS.

| Binary | Where it goes | | --- | --- | | `smuf-server` | Your VPS / server | | `smuf` | Your local machine |

Option B: Docker

[](https://github.com/cosmind-rusu/smuf#option-b-docker)

docker compose up -d

Option C: Build from source

[](https://github.com/cosmind-rusu/smuf#option-c-build-from-source) You'll need Go 1.21+.

git clone https://github.com/cdrusu/smuf.git && cd smuf go build -o smuf-server ./cmd/smuf-server go build -o smuf ./cmd/smuf

- * *

Usage

[](https://github.com/cosmind-rusu/smuf#usage) **First time:** run without arguments and the wizard will set everything up:

./smuf-server # on the server ./smuf --setup # on your machine

**After that:**

./smuf 3000 # exposes localhost:3000 ./smuf 3000 4000 5000 # multiple ports at once ./smuf --sub myapp 3000 # fixed URL: myapp.yourdomain.com ./smuf --tcp 22 # pure TCP tunnel (SSH, DB, etc.)

Output:

``` Tunnel ready!

Local → http://localhost:3000 Public → https://a3f1c9.yourdomain.com

Press Ctrl+C to stop ```

- * *

Dashboard

[](https://github.com/cosmind-rusu/smuf#dashboard) While the server is running, open in your browser:

``` http://yourdomain.com:8080/ ```

It is designed in HashiCorp style: dark `#0d0e12` background, system-ui font, cards with micro-shadows and blue accent (`#1060ff`).

Shows all active tunnels with:

- Tunnel type (HTTP / TCP)

- Public URL

- Local port and client IP

- Uptime

Updates every 5 s. The JSON endpoint is at `/_smuf/tunnels`.

- * *

Configuration

[](https://github.com/cosmind-rusu/smuf#configuration) Everything goes through environment variables (or a `.env` file next to the binary).

Server (`smuf-server`)

[](https://github.com/cosmind-rusu/smuf#server-smuf-server) | Variable | Default | Description | | --- | --- | --- | | `SMUF_DOMAIN` | `localhost` | Your base domain | | `SMUF_AUTH_TOKEN` | — | Secret token (**recommended in production**) | | `SMUF_CONTROL_PORT` | `7000` | Port for clients to connect | | `SMUF_HTTP_PORT` | `8080` | Public HTTP port | | `SMUF_HTTPS` | `false` | Automatic HTTPS with Let's Encrypt | | `SMUF_HTTPS_PORT` | `443` | HTTPS port | | `SMUF_ACME_EMAIL` | — | Email for certificate notices | | `SMUF_MAX_CONNS_PER_IP` | `5` | Max tunnels per IP | | `SMUF_HANDSHAKE_TIMEOUT` | `10s` | Handshake timeout | | `SMUF_TCP_PORT_RANGE` | — | Public TCP port range (e.g. `20000-30000`) |

Client (`smuf`)

[](https://github.com/cosmind-rusu/smuf#client-smuf) | Variable | Default | Description | | --- | --- | --- | | `SMUF_SERVER` | `localhost:7000` | Server address | | `SMUF_AUTH_TOKEN` | — | Token (must match the server) | | `SMUF_SUBDOMAIN` | — | Fixed subdomain (equivalent to `--sub`) |

**Server `.env` example:**

SMUF_DOMAIN=yourdomain.com SMUF_AUTH_TOKEN=a-long-secret-token

SMUF_HTTPS=true

SMUF_ACME_EMAIL=you@email.com

**Client `.env` example:**

SMUF_SERVER=yourdomain.com:7000 SMUF_AUTH_TOKEN=a-long-secret-token

SMUF_SUBDOMAIN=myapp

> Generate a secure token with `openssl rand -hex 32`

- * *

How it works

[](https://github.com/cosmind-rusu/smuf#how-it-works)

``` smuf 3000 ──TCP──► smuf-server :7000 │ "PORT 3000 SUB myapp" → "OK myapp https://myapp.yourdomain.com" │ yamux (multiplexing) │ request → myapp.yourdomain.com → yamux stream → localhost:3000 ```

Uses `hashicorp/yamux` to multiplex multiple HTTP requests over a single TCP connection.

- * *

Roadmap

[](https://github.com/cosmind-rusu/smuf#roadmap)

- Automatic HTTPS with Let's Encrypt

- Token authentication

- Per-IP rate limiting

- Real-time web dashboard (HashiCorp style)

- Multiple tunnels per process

- Custom subdomain

- WebSockets

- TCP tunnels (not only HTTP)

- Official Docker image

- Pre-compiled binaries

- Server-Sent Events (SSE)

- * *

Project structure

[](https://github.com/cosmind-rusu/smuf#project-structure)

``` smuf/ ├── cmd/ │ ├── smuf/ # Client (your machine) │ └── smuf-server/ # Server (your VPS) └── internal/ ├── tunnel/ # Registry + BufConn ├── wizard/ # Interactive setup └── logger/ # Timestamped logging ```

- * *

Contributing

[](https://github.com/cosmind-rusu/smuf#contributing) Found a bug or have an idea? Open an issue or submit a pull request.

- * *