A Herdr plugin. Forward a listener from a remote Herdr workspace onto this laptop as:
http://herdr.{workspace}.localhost:{port}
Plugin id: herdr.ports_forwarding
Binary: herdr-ports (Rust)
It uses native saved machines (herdr machine add). It does not wrap
herdr --remote.
The recording is a real session: a loopback service on workmbp (Tailscale
chenyangzhaos-macbook-pro) fails on this laptop until herdr-ports add
opens SSH -L. MP4 · asciicast ·
re-record with docs/record-session.sh.
Version 0.4.0 adds optional Cloudflare Quick Tunnels for temporary public HTTPS sharing. The popup keeps cached lists, separate forwarding and browser actions, three-state status indicators, and discovery of detached workspace servers.
Tunnels are SSH -L forwards on a ControlMaster that:
- lives under
/tmp/hp-<hash>(short enough for macOS Unix sockets) - starts in a new session with SIGHUP ignored, so closing the manager pane does not kill the mux
- uses
ControlPersist=yes - is recorded in plugin state
- is restored by
./herdr-ports restoreon Herdr startup
Closing the popup leaves its forwards running. A forward stops when you toggle
it off, run stop, reboot, or lose its SSH connection. Saved forwards can be
resumed with Space or restore.
The manager opens in a popup without changing your pane layout.
- Select Local in the sidebar (the bind happens on this laptop).
- Run the pick action.
- Choose a machine, then a workspace.
- A row shows
○(closed),◐(closed but saved), or●(saved and alive). Click a row to select it. Press Space to start, resume, or stop its forward. Enter oroopens its URL, including for local listeners. - To share a service publicly, press
t, thenyto confirm. Escape stops public sharing without stopping the SSH forward.
Use arrow keys (or j/k) and the mouse wheel to select rows. Press Enter or o to open
the selected URL, r to refresh, and Escape or q to go back. Escape or q
at the machine list closes the popup. Port conflicts open a local-port prompt.
Alive means the SSH master is running and owns the local forwarding listener.
It does not confirm that the remote application responds. Saved forwards remain
visible after their tunnel stops. stop <local-port> also removes an inactive
saved forward. JSON scans include saved, forwarded (alive), and status.
The popup keeps errors visible and leaves active forwards running when closed.
Machine, workspace, and port lists are cached while the popup is open. Going
back, selecting a row, or opening a URL does not rescan. Space updates only the
selected port's status. Press r to refresh external changes; a failed refresh
keeps the previous port list visible. Refreshing the workspace list returns to
the machine list; select the machine again to load its workspaces. Displayed URLs use
http://herdr.{workspace}.localhost:{local-port}, including remapped ports.
The hostname is a browser address for a loopback-only SSH forward. It does not provide HTTPS or separate port namespaces: two workspaces cannot use the same local port at once. If a port is occupied, choose another in the popup. The remote service must accept the workspace hostname in its HTTP Host header.
Select a port and press t to open the sharing view. Press y to confirm
public access and start a Cloudflare Quick Tunnel. For a remote port, first
press Space in the port list to enable its SSH forward. Local ports work directly.
The view shows a temporary https://….trycloudflare.com URL. Enter or o
opens that public URL. Escape or q stops the public tunnel and returns to
the cached port list. The SSH forward stays active. Public tunnels are not
saved or restored; keep the sharing view open while using the link.
Anyone with the URL can access the service. The plugin adds no authentication. Share only services and data that you intend to make public.
Install cloudflared on the host running the popup (on macOS:
brew install cloudflared). No Cloudflare account is needed for Quick Tunnels.
The plugin connects to http://127.0.0.1:{local-port} and sets the origin Host
header to herdr.{workspace}.localhost:{local-port}. Your application must accept
that header. The existing local workspace URL does not change.
Quick Tunnels are for testing, not production: their URLs are temporary,
they have a 200 concurrent-request limit, and they do not support SSE.
A .cloudflared/config.yaml can prevent Quick Tunnels from working; the plugin
does not change your Cloudflare configuration. Named tunnels, custom public
domains, and Cloudflare Access configuration are not included.
See Cloudflare's Quick Tunnel documentation.
The plugin scans TCP listeners and first matches their process ancestry to
Herdr panes. For detached services, it checks the process working directory
against pane directories. It also recognizes an absolute --directory or -d
argument from python -m http.server, which can serve a project while running
from another directory. The most specific matching directory wins; ambiguous
matches are omitted.
Listeners without enough ownership evidence are not assigned to a workspace.
Use add <machine> <port> --workspace NAME to forward a known service manually.
Forwarding currently targets IPv4 loopback on the remote host; IPv6-only or
interface-only services need a compatible remote listener.
Needs cargo on the machine that installs the plugin.
herdr plugin install randomradio/herdr-ports --yes
herdr server reload-configRun the same commands to update a GitHub installation. For a local development checkout, build and link it instead:
cargo build --release
cp target/release/herdr-ports herdr-ports
herdr plugin link "$PWD" --enabled
herdr server reload-configClose and reopen an existing popup after an update. To switch a local link back
to a GitHub installation, first run herdr plugin unlink herdr.ports_forwarding.
[[keys.command]]
key = "prefix+shift+p"
type = "plugin_action"
command = "herdr.ports_forwarding.pick"
description = "pick remote port"Reload config after install (global menu → reload config).
After install, herdr-ports is in the plugin root.
./herdr-ports scan workbox
./herdr-ports scan workbox --json
./herdr-ports pick workbox
./herdr-ports add workbox 8765 --open
./herdr-ports add workbox 8765 --local-port 18765 --workspace mo
./herdr-ports list
./herdr-ports stop 8765
./herdr-ports restore- Herdr 0.9.0 or newer
- macOS or Linux
- Rust/
cargoto build - OpenSSH with key auth:
ssh -o BatchMode=yes <target> true lsoforsson each scanned hostlsoforsson the local host to verify forwarding status- Optional:
cloudflaredon the popup host for public sharing
Public GitHub repository with topic herdr-plugin. Herdr indexes that topic
about every 30 minutes: https://herdr.dev/plugins/
Install from GitHub:
herdr plugin install randomradio/herdr-ports --yes