Radagast remote SSH and VNC through kelp

Parent: pomelo–kelp SOCKS5 BIND design; Radagast client identity and TLS configuration; Radagast host overview

Deployed and verified 2026-10-17. Radagast creates two independent, outbound SOCKS5 BIND control connections through its mutually authenticated stunnel connection to kelp. Dante on kelp supplies the remote listeners; no SSH tunnel is involved. Public SSH uses kelp:2225; public VNC uses kelp:15905 and requires a trusted TLS client certificate.

Port map

ServicePublic kelp endpointDante listener on kelpLocal Radagast target
SSH0.0.0.0:2225 (socat)127.0.0.1:22225127.0.0.1:22
VNC0.0.0.0:15905 (stunnel, mTLS)127.0.0.1:5905127.0.0.1:5902 (Xvnc display :2)
Radagast BIND clients -> localhost:12081 -> stunnel mTLS -> kelp:12080 -> Dante localhost:2080
SSH client -> kelp:2225 -> socat -> Dante BIND :22225 -> existing TLS/control connection -> Radagast sshd :22
VNC viewer -> client stunnel mTLS -> kelp:15905 -> Dante BIND :5905 -> existing TLS/control connection -> Radagast Xvnc :5902

Ports were checked before use. Kelp's 15901/5901 currently serve kelp's own Xtigervnc desktop; 15907/5907 are another existing tunnel. Those endpoints and pomelo's 2222/15900 paths were preserved. The requested nearby free ports were moved higher to 2225 and 15905 at John's direction.

Radagast services

Installed /usr/local/libexec/socks5_bind_client.py by copying pomelo's /home/john/bin/socks5_bind_client.py, with only an added --help documentation pointer. Python standard library only; services explicitly use /usr/local/bin/python3.12. Each invocation accepts one incoming connection, relays it, and exits. FreeBSD daemon(8) supervises and restarts it after five seconds. No overlapping second BIND is created.

rc.d files: /usr/local/etc/rc.d/socks5_bind_ssh and socks5_bind_vnc. Both require NETWORKING and stunnel, run clients as john, and use daemon -f -r -R 5 -P /var/run/<service>.pid -u john -S -T <service>. The pidfile contains the supervisor PID, so stopping the rc service stops its child rather than accidentally causing an immediate restart. Both services are enabled in /etc/rc.conf. Logs: /var/log/messages under socks5_bind_ssh and socks5_bind_vnc.

sysrc socks5_bind_ssh_enable=YES socks5_bind_vnc_enable=YES
service socks5_bind_ssh start
service socks5_bind_vnc start
service socks5_bind_ssh status
service socks5_bind_vnc status
# SSH client arguments:
# --proxy-host 127.0.0.1 --proxy-port 12081 --bind-port 22225 --target-port 22 --timeout 86400
# VNC client arguments:
# --proxy-host 127.0.0.1 --proxy-port 12081 --bind-port 5905 --target-port 5902 --timeout 86400

Radagast's stunnel configuration additionally sets remote SO_KEEPALIVE=1, TCP_KEEPIDLE=60, TCP_KEEPINTVL=20, TCP_KEEPCNT=3, matching pomelo. Verified from Radagast's tcp(4) manual that these socket-level timers are seconds (the similarly named sysctls use milliseconds).

Kelp services and firewall

Existing Dante /etc/sockd.conf already permits SOCKS5 BIND and binds listeners to 127.0.0.1. No Dante change/restart was needed. Added and enabled socat-radagast-ssh-relay.service: /usr/bin/socat TCP-LISTEN:2225,bind=0.0.0.0,reuseaddr,fork TCP:127.0.0.1:22225.

Added and enabled stunnel-radagast-vnc.service using /etc/stunnel/radagast/vnc-server.conf. It uses kelp's existing /etc/stunnel/server.pem, server.key and shared CA trust, verify=2, foreground=yes, accept=0.0.0.0:15905 and connect=127.0.0.1:5905. Separate service/config avoids restarting the existing VNC stunnel instance or activating unrelated pending edits. Source files are in /home/john/tmp/radagast-reverse/ on kelp; task artifacts also exist under pomelo /home/john/py/rainbow/output/stunnel-radagast/.

Verified AWS account 095171621201, kelp instance i-00fbb7584cd890340 in eu-central-1, public IP 3.79.21.179 at deployment, security group sg-09b115cb2f93edb4f. Added only TCP/2225 ingress from 0.0.0.0/0, matching existing SSH exposure (rule sgr-08ed50c6c469c65a1). VNC 15905 was already covered by the existing 15900–15909 rule; no additional VNC rule or plaintext VNC ingress was added. Used pomelo /home/john/.local/bin/aws --profile frankfurt. Kelp's system aws CLI has an OpenSSL Python dependency mismatch and no configured credentials with user-site packages disabled; no packages or credentials there were changed.

Verification and client use

Authenticated SSH from pomelo through public kelp:2225 with /home/john/.ssh/id_rsa_radagast, verifying Radagast's pre-existing host key via HostKeyAlias=[localhost]:2222. Returned radagast.critchley.biz and root.

ssh -o BatchMode=yes -o ProxyCommand=none -o HostKeyAlias='[localhost]:2222' -o StrictHostKeyChecking=yes -o IdentitiesOnly=yes -i /home/john/.ssh/id_rsa_radagast -p 2225 root@kelp.critchley.biz

For another client, use kelp.critchley.biz port 2225 with a username/key authorized on Radagast. The host key is Radagast's, not kelp's. A VNC viewer needs a local stunnel client using its existing trusted client cert/key/CA, checkHost=John Critchley, and connect=kelp.critchley.biz:15905. Example section, choosing an unused local viewer port:

[radagast-vnc]
client = yes
accept = 127.0.0.1:15905
connect = kelp.critchley.biz:15905
checkHost = John Critchley
# Inherit the client's cert, key, CAfile and verify=2 settings.

Public VNC test from pomelo verified the TLS certificate, received RFB 003.008, exchanged the RFB version, and received security types [19,2] (VeNCrypt and VNC authentication). Test helper: sudo python3 /home/john/py/rainbow/output/stunnel-radagast/verify_vnc.py. An openssl s_client TLS 1.2 attempt without a client certificate was rejected with handshake failure.

After both verification connections closed, daemon supervisors recreated both fixed BIND listeners after five seconds, confirmed by Radagast BIND_LISTEN logs and kelp socket ownership. As with pomelo, only one active SSH relay and one active VNC relay are available at a time. TIME_WAIT can occasionally delay rebinding; the copied client detects a wrong randomly assigned port and retries every five seconds rather than accepting it.

version 2  ·  created 2026-10-17  ·  updated 2026-10-17  ·  tags radagast, kelp, stunnel, dante, socks5, ssh, vnc