v0.2.0 — single binary · MIT

mole digs
one SSH tunnel.

Then it forwards every port it finds on the other side. No port lists to maintain, no ssh -L gymnastics — point it at a remote and localhost mirrors whatever starts listening there.

$ curl -fsSL https://raw.githubusercontent.com/Luqueee/mole/main/scripts/install.sh | sh

Linux · macOS · Windows · *BSD

this machine
one SSH connection
localhost:3000 workstation:3000
localhost:5173 workstation:5173
localhost:8080 workstation:8080
re-scans every 15 s ssh-agent · ~/.ssh/id_*
remote host — sshd only, no agent
Features

What the tunnel carries

From auto-discovered dev servers to periodic health checks — mole removes the busywork of port forwarding.

One connection

A single SSH client multiplexes every forwarded port.

Smart auto-discover

Enumerates the remote's real TCP listeners (ss/netstat) and forwards them — any port, not a fixed list. Re-scans every 15 s, so servers you start after launch get picked up.

SSH config aliases

A remote like dev is resolved through ~/.ssh/config (ssh -G): HostName, User, Port, IdentityFile, Include, Match — all honoured.

Exclude list

System/reserved ports (22, 25, 53, 111, 631) are skipped by default; fully configurable.

Auto-reconnect

Transparent reconnect on tunnel drop, with periodic health checks.

Native auth

ssh-agent first (Unix socket / Windows named pipe), then ~/.ssh/id_* keys.

Background daemon

mole up -d detaches; mole down stops it; mole status and mole logs introspect it.

Beautiful logs

mole logs renders the daemon log with colour level badges, a green FORWARD badge, and (×N) collapsing of repeats.

How it works

Under the hood

Four goroutines, one SSH client, no port list to maintain.

  1. 01

    Connect

    Open one SSH client connection to the remote. ssh-agent or ~/.ssh/id_* keys; aliases resolved via ssh -G.

  2. 02

    Discover

    Enumerate the remote's TCP listeners (ss/netstat) every 15 s, or fall back to probing discover_ports. Skip exclude_ports.

  3. 03

    Forward

    For each port, bind 127.0.0.1:<port> locally; on a local connection, dial 127.0.0.1:<port> through the tunnel and bridge bytes both ways.

  4. 04

    Heal

    A watchdog reconnects the SSH session if it dies; re-discovery picks up new servers; UNFWD prunes dead ones.

Logs

Colourised, structured, skimmable

Every line gets a level badge, a timestamp, and repeated events collapse to a single line with a (×N) counter.

mole logs
INFO 14:32:01 starting mole, version 0.2.0
INFO 14:32:01 connected to dev (workstation:22) via ssh-agent
INFO 14:32:02 auto-discover: 3 remote ports found
FORWARD localhost:3000 → workstation:3000
FORWARD localhost:5173 → workstation:5173
FORWARD localhost:8080 → workstation:8080
INFO 14:32:08 re-discover: 4 remote ports found
FORWARD localhost:9090 → workstation:9090
UNFWD localhost:8080 pruned (remote closed)
INFO 14:32:14 ssh tunnel healthy
INFO 14:32:20 forwarded connection on :3000 (×12)

FORWARD when a port starts forwarding · UNFWD when a dead remote port is pruned · INFO for the rest

Install

From curl to forwarded ports

Three commands. Under a minute from download to a live tunnel.

  1. 01 Install the binary
    $ curl -fsSL https://raw.githubusercontent.com/Luqueee/mole/main/scripts/install.sh | sh
  2. 02 Configure + start — interactive, accepts an ssh config alias
    $ mole init
  3. 03 Later
    $ mole status      # what's forwarded right now
    mole logs -f     # pretty, colourised, live
    mole down        # stop the background daemon

mole init writes the config, then offers to start mole in the background for you. From there it keeps the tunnel up and forwards new servers as they appear.

Commands

The full CLI surface

Twelve commands cover the full lifecycle. Run mole help for the built-in reference.

Command What it does
mole up Start the forwarder in the foreground (add -d to background it).
mole down Stop a backgrounded mole (started with up -d).
mole restart Stop and re-launch a backgrounded mole using the same config.
mole status Query the local admin API for live stats + forwarded ports.
mole logs Show the daemon log, colourised; -f to follow, clean to truncate.
mole ports Manage the auto-discover port list: add, remove, list.
mole config Open the active mole.yaml in $VISUAL / $EDITOR.
mole init Generate a mole.yaml interactively (or scripted).
mole clip Share clipboard images over the tunnel: clip serve, clip pull.
mole update Update mole in place to the latest release (re-runs the installer).
mole version · mole help The obvious.
Platforms

Runs on your machine

Same source, same commands, every desktop OS.

Linux glibc & musl
curl -fsSL https://raw.githubusercontent.com/Luqueee/mole/main/scripts/install.sh | sh
macOS Intel & Apple Silicon
curl -fsSL https://raw.githubusercontent.com/Luqueee/mole/main/scripts/install.sh | sh
Windows PowerShell 5+
irm https://raw.githubusercontent.com/Luqueee/mole/main/scripts/install.ps1 | iex
FreeBSD Unix-like
curl -fsSL https://raw.githubusercontent.com/Luqueee/mole/main/scripts/install.sh | sh
FAQ

Common questions

If yours isn't here, the README and the GitHub Issues have the rest.

How is mole different from `ssh -L`?

A single SSH client multiplexes every forwarded port. mole auto-discovers what's listening on the remote, so you don't keep a port list. It transparently reconnects when the tunnel drops, and `mole logs` gives you colourised, structured output.

Does it work with my existing `~/.ssh/config`?

Yes. Pass an alias as the remote (e.g. `mole up --remote dev`) and mole resolves it via `ssh -G` — HostName, User, Port, IdentityFile, Include and Match are all honoured.

Where does the binary run — on my laptop or the remote?

On your laptop. The remote only needs sshd. The mole daemon opens the SSH connection, enumerates listeners over the encrypted channel, and binds the forwarded ports on 127.0.0.1 locally.

What if the SSH connection drops?

A watchdog goroutine reconnects the tunnel. Re-discovery picks up any new servers that came up while the connection was down, and a UNFWD badge prunes ports that closed on the remote.