|
1 | | -# Reverse SSH tunnel: fin1 -> fin4, exposing fin1's loopback-bound |
2 | | -# services on fin4's loopback. The Seneschal data-api on fin4 depends |
3 | | -# on these three forwards: |
| 1 | +# Persistent reverse tunnel fin1 → fin4 exposing local chain RPCs to the |
| 2 | +# data-api host: monerod (18081), zebra (8232) and NFPT (3555) appear on |
| 3 | +# fin4's 127.0.0.1. The data-api, its pollers and the ops-monitor probes |
| 4 | +# all depend on these forwards. |
4 | 5 | # |
5 | | -# fin4 127.0.0.1:18081 -> fin1 monerod RPC |
6 | | -# fin4 127.0.0.1:8232 -> fin1 zebra (Zcash) RPC |
7 | | -# fin4 127.0.0.1:3555 -> fin1 NFPT scanner API |
| 6 | +# Installed on fin1 as /etc/systemd/system/fin1-seneschal-tunnel.service: |
| 7 | +# sudo systemctl daemon-reload |
| 8 | +# sudo systemctl enable --now fin1-seneschal-tunnel.service |
8 | 9 | # |
9 | | -# INSTALL (on fin1, which we cannot reach from the dev box — fin1 only |
10 | | -# connects outward to fin4): |
| 10 | +# Replaces the per-user unit (~/.config/systemd/user/seneschal-chain-tunnel |
| 11 | +# .service, retired 2026-06-12): with Linger=no a user unit only runs while |
| 12 | +# rotwang has a session, so an unattended reboot left the tunnel down. |
| 13 | +# A system unit starts at boot unconditionally. |
11 | 14 | # |
12 | | -# 1. Copy this file to /etc/systemd/system/seneschal-tunnel.service |
13 | | -# 2. Confirm root@fin1 already has a key authorised on fin4 (it does — |
14 | | -# the tunnel runs today as root with an ED25519 key). |
15 | | -# 3. If the current hand-started tunnel is running, kill it first so |
16 | | -# the listen ports are free (`pgrep -af "ssh.*18081"` on fin1). |
17 | | -# 4. systemctl daemon-reload && systemctl enable --now seneschal-tunnel |
| 15 | +# Runs as rotwang with the dedicated tunnel key — restricted on fin4 with |
| 16 | +# `restrict,port-forwarding,command="echo seneschal-tunnel-only"`, so a |
| 17 | +# leaked key can only open this same tunnel: no shell, no exec. |
18 | 18 | # |
19 | | -# Why plain ssh + systemd Restart instead of autossh: systemd already |
20 | | -# does supervised restart with backoff, and ServerAliveInterval makes |
21 | | -# ssh itself exit when the link goes quiet — autossh would only add a |
22 | | -# second supervisor doing the same job. |
23 | | -# |
24 | | -# ExitOnForwardFailure=yes makes ssh fail fast if fin4 still has a |
25 | | -# stale listener on any port (e.g. an old tunnel session that hasn't |
26 | | -# timed out) instead of starting half-connected; systemd then retries |
27 | | -# until the stale socket clears. |
| 19 | +# ExitOnForwardFailure + Restart=always: a half-up tunnel (binds taken / |
| 20 | +# connection dropped) dies and retries rather than lingering. fin4's sshd |
| 21 | +# runs ClientAliveInterval 30 / CountMax 3 (sshd_config.d/99-clientalive |
| 22 | +# .conf) so a dead client's stale listeners are reaped within ~90s — |
| 23 | +# without it a SIGKILL'd client wedges the rebind forever. |
| 24 | +# StartLimitIntervalSec=0: never stop retrying — after a long fin4 outage |
| 25 | +# the tunnel must come back on its own. |
28 | 26 |
|
29 | 27 | [Unit] |
30 | 28 | Description=Seneschal reverse tunnel to fin4 (monerod/zebra/NFPT forwards) |
31 | 29 | After=network-online.target |
32 | 30 | Wants=network-online.target |
| 31 | +StartLimitIntervalSec=0 |
33 | 32 |
|
34 | 33 | [Service] |
35 | 34 | Type=exec |
| 35 | +User=rotwang |
36 | 36 | ExecStart=/usr/bin/ssh -NT \ |
| 37 | + -i /home/rotwang/.ssh/seneschal_tunnel_ed25519 \ |
| 38 | + -o IdentitiesOnly=yes \ |
| 39 | + -o BatchMode=yes \ |
37 | 40 | -o ExitOnForwardFailure=yes \ |
38 | 41 | -o ServerAliveInterval=30 \ |
39 | 42 | -o ServerAliveCountMax=3 \ |
40 | 43 | -o ConnectTimeout=15 \ |
41 | | - -o BatchMode=yes \ |
42 | 44 | -o StrictHostKeyChecking=accept-new \ |
| 45 | + -o StreamLocalBindUnlink=yes \ |
43 | 46 | -R 127.0.0.1:18081:127.0.0.1:18081 \ |
44 | 47 | -R 127.0.0.1:8232:127.0.0.1:8232 \ |
45 | 48 | -R 127.0.0.1:3555:127.0.0.1:3555 \ |
46 | | - root@65.108.233.209 |
| 49 | + root@fin4 |
47 | 50 | Restart=always |
48 | | -RestartSec=10 |
| 51 | +RestartSec=15 |
49 | 52 |
|
50 | 53 | [Install] |
51 | 54 | WantedBy=multi-user.target |
0 commit comments