com.harryaskham.vpno · Swift · menu bar · ssh

vpno

A partial VPN from the menu bar. For each configured host, vpno keeps one SSH tunnel up with a SOCKS5 proxy and any number of local port forwards, and lets you switch each host on and off. Apps that use the proxy reach the world through that host; everything else stays on your own network.

What Connect does

One host, one ssh process What Connect does for one configured host. vpno runs a single ssh -N child process with a SOCKS5 proxy on a local port (-D) and any number of local port forwards (-L), all bound to 127.0.0.1. Apps that use the proxy egress through the host; a forward reaches one service as seen from the host. ExitOnForwardFailure makes ssh exit if a forward cannot be bound, and ServerAliveInterval detects a dead link. apps with a proxysocks5h://127.0.0.1:11080 a local client127.0.0.1:17350 ssh -N-D 127.0.0.1:11080-L 127.0.0.1:17350:…:7350 the hostyour ssh target its network :7350a service encrypted
ssh -N \
  -o ExitOnForwardFailure=yes -o ServerAliveInterval=30 -o ServerAliveCountMax=3 \
  -L 127.0.0.1:<localPort>:<remoteHost>:<remotePort> \
  -D 127.0.0.1:<socksPort> \
  <host>

Everything binds to the loopback address. Point a program at a host's proxy with, for example, HTTPS_PROXY=socks5h://127.0.0.1:11080.

Staying up

  1. Disconnected
  2. Connecting
  3. Connected · the ports answer, checked every 3 s
  4. Reconnecting · after 2, 4, 8 … up to 60 s
  5. Exited · ssh ended unexpectedly; its log is in the host's menu

A host set to start automatically connects when vpno launches. If its tunnel drops or ssh exits, vpno schedules a reconnect with exponential backoff and resets the delay once the link is steady. The menu-bar icon sums up every host; each host's submenu shows its own state and forwards.

Configuration

Hosts live in ~/.config/vpno/config.yaml, which starts empty; the Settings window edits the same file. vpno --print-config loads it and prints it back, a quick way to check a hand edit.

hosts:
  - name: "build box"
    ssh: "builder"          # an ssh target from your ~/.ssh/config
    socksPort: 11080
    autoStart: true
    forwards:
      - name: "Dashboard"
        localPort: 17350
        remotePort: 7350