# WireGuard Tunnel for Remote MikroTik Access

When the user wants the agent to have direct SSH access to a MikroTik router for monitoring/onboarding, set up a WireGuard tunnel from the router to the management server. This is the same pattern used for the home CCR.

## Server side (management box)

```bash
apt-get install -y wireguard
wg genkey | tee /root/wg-server.key | wg pubkey > /root/wg-server.pub
```

**UFW: WireGuard port must be opened or handshakes never happen.** The symptom is `wg show wg0` shows 0 bytes transferred and no handshake timestamp, even though both sides are configured correctly and the router can reach the server.

```bash
ufw allow 51820/udp comment "WireGuard VPN"
ufw reload
```

Write `/etc/wireguard/wg0.conf`:

```ini
[Interface]
Address = 10.77.0.1/24
ListenPort = 51820
PrivateKey = <contents of /root/wg-server.key>

[Peer]
PublicKey = <client-public-key>
AllowedIPs = 10.77.0.2/32, <router-lan-subnet>
```

Start the service:

```bash
systemctl enable wg-quick@wg0
systemctl start wg-quick@wg0
```

## Client side (MikroTik CCR)

GENERATE FRESH CLIENT KEYS on the server for each new router:

```bash
CCR_PRIV=$(wg genkey)
CCR_PUB=$(echo "$CCR_PRIV" | wg pubkey)
```

Update the server config with `CCR_PUB`, then present the MikroTik script with `CCR_PRIV` embedded:

```routeros
/interface wireguard add name=wg-itpp listen-port=13231 \
  private-key="<CCR_PRIV>" comment="IT Pro Partner Tunnel"

/interface wireguard peers add interface=wg-itpp \
  public-key="<server-public-key>" \
  endpoint-address=<server-public-ip> endpoint-port=51820 \
  allowed-address=10.77.0.0/24 persistent-keepalive=25

/ip address add address=10.77.0.2/24 interface=wg-itpp

/ip firewall filter add chain=input protocol=udp dst-port=13231 \
  place-before=1 comment="allow WG tunnel (ITPP)"
```

Verify with `/ping 10.77.0.1` on the router.

## Key principle: generate-then-present-not-store

- Generate fresh client keys on the server
- Update the server's peer config with the client's public key
- Present the generated private key in the MikroTik script
- Do this in the same terminal session
- The private key is delivered in the script output — the user pastes it onto the router immediately

## Verification

After the tunnel is up on both sides:

```bash
# From the management server
ping -c 2 10.77.0.2
# Then SSH to the router through the tunnel
ssh -i ~/.ssh/wisp_rsa admin@10.77.0.2 "/system identity print"
```

The MikroTik's LAN subnet (e.g. 10.10.10.0/24) is also reachable through the tunnel via the AllowedIPs directive.

## Pitfall: Router public key in export vs live mismatch

The `/export show-sensitive` output shows the router's public key from when the config was last saved. If the private key was regenerated on the router (e.g. someone ran `/interface wireguard reset`), the export becomes stale. **Always verify the live public key**:

```routeros
/interface wireguard print detail where name=wg-itpp
```

Compare the `public-key=` field against what the server's `wg0.conf` peer entry has. If they differ, update the server peer config with the live router public key. The router's live public key is authoritative — the export file is not.

## Pitfall: Router-side peer key mismatches after migration

When migrating Hermes from one server to another, the router's WireGuard peer points at the old server's public key. On the router, update the peer:

```routeros
/interface wireguard peers set [find comment="Core (netcup)"] public-key="<new-server-public-key>"
```

Also verify the `endpoint-port` matches the new server's ListenPort. If the port changed (e.g. 51820→51821), the router side endpoint-port must match.

## Pitfall: Multiple tunnels to the same router

Each server needs its own WG IP (10.77.0.1 for primary, 10.77.0.3 for standby) and its own peer entry on the router. Add the second peer via:

```routeros
/interface wireguard peers add interface=wg-itpp public-key="<second-server-pubkey>" allowed-address=10.77.0.3/32 endpoint-address=<second-server-ip> endpoint-port=51821 persistent-keepalive=25s comment="app1-bu (Hetzner standby)"
```
