# Inbound management SSH over the WireGuard tunnel

How the busfleet hub reaches a GL-XE3000 router for management, and how to fix it when
inbound SSH over the tunnel is broken.

## How it works

The router runs a WireGuard **client** (`wgclient1`, `proto=wgclient`) that dials the hub
at `167.172.237.162:51820`. Once the tunnel is up the router holds `10.88.0.2/32` and the
hub is `10.88.0.1`. The hub SSHes *inbound* to `10.88.0.2:22` over that tunnel using the
`busfleet-hub-jump` key.

The key detail: on OpenWrt the WG client interface is in its **own firewall zone**
(`wgclient1`), which defaults to `input='DROP'`. Traffic arriving over the tunnel is
evaluated by the `zone_wgclient1_input` iptables chain — **not** `zone_wan_input`. So the
mgmt-SSH accept rule must have its source zone set to `wgclient1`, or it lands in the wrong
chain and never matches (tunnel SSH silently hits the zone DROP).

## Provisioning a router

1. **Confirm the WG client zone name** (may differ per unit):

   ```sh
   uci show network | grep -i wgclient          # interface, e.g. network.wgclient1
   uci show firewall | grep -iE 'name=|\.network=|input='   # find its zone + input policy
   ```

2. **Allow inbound mgmt SSH over the tunnel.** Bind the rule's `src` to the WG client zone
   (not `wan`), restricted to the hub subnet:

   ```sh
   uci add firewall rule
   uci set firewall.@rule[-1].name='Allow-WG-mgmt-SSH'
   uci set firewall.@rule[-1].src='wgclient1'        # the ACTUAL WG zone from step 1
   uci set firewall.@rule[-1].proto='tcp'
   uci set firewall.@rule[-1].dest_port='22'
   uci set firewall.@rule[-1].family='ipv4'
   uci set firewall.@rule[-1].src_ip='10.88.0.0/24'
   uci set firewall.@rule[-1].target='ACCEPT'
   uci commit firewall && /etc/init.d/firewall restart
   ```

3. **Install the hub jump key:**

   ```sh
   echo 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMS842ZbXPXHbVd9IjyVGubq7M/yQA/cn/vHgB5R0/ZE busfleet-hub-jump' >> /etc/dropbear/authorized_keys
   chmod 600 /etc/dropbear/authorized_keys
   ```

## Verifying

Use `wg show` as the source of truth for tunnel health — a recent `latest handshake` plus
non-zero transfer counters means the data path is live:

```sh
wg show                                         # endpoint, latest handshake, transfer
iptables -S zone_wgclient1_input | grep 'dport 22'   # exactly one ACCEPT from 10.88.0.0/24
```

Gotchas:

- **BusyBox `nc` has no `-v`/`-z` flags** (`nc [IPADDR PORT]` only), and `51820` is UDP —
  don't rely on `nc -vz` to test the tunnel. Use `wg show`.
- **The hub does not answer ICMP over the tunnel**, so `ping 10.88.0.1` shows 100% loss even
  when the tunnel is healthy. The definitive end-to-end test is the hub SSHing in.

## Troubleshooting: hub can't SSH in

1. `wg show` — is there a recent handshake? If not, the tunnel is down (check WAN/5G, the
   hub endpoint, and keys) before looking at the firewall.
2. `uci show firewall | grep Allow-WG-mgmt-SSH` up through the rule — confirm `src` is the
   WG client zone (`wgclient1`), **not** `wan`. This is the most common misconfiguration:

   ```sh
   uci set firewall.<section>.src='wgclient1'
   uci commit firewall && /etc/init.d/firewall restart
   ```

3. `grep busfleet-hub-jump /etc/dropbear/authorized_keys` — key present, file perms `600`.

## History

- **2026-07-01** — Fixed inbound mgmt SSH on a unit whose `Allow-WG-mgmt-SSH` rule was bound
  to `src='wan'` instead of `src='wgclient1'`, so tunnel SSH hit the `wgclient1` zone DROP.
  Repointed the rule to `wgclient1` and installed the `busfleet-hub-jump` key.
