Sipeed NanoKVM

The Sipeed NanoKVM is a great little IP KVM with HDMI pass-through (although I have not tested the limits of the HDMI bandwidth to see if 5K or 4K 240Hz and/or VRR modes are supported)…

Wireguard

Although Tailscale is natively supported out of the box with a UI to go, Wireguard is purely a shell-based set-up… To boot, the iptables_raw module is not available in the application version 1.2.14 (current as of publication), so wg-quick will fail, and no combination of update-alternatives will save you.

  • /usr/local/sbin/wg0.sh
    • adapting an init.d start up script for the systemd-based NanoKVM, taking into consideration this unit’s limitations:
#!/bin/sh

wait_for_wireguard() {
    echo "Waiting for WireGuard module to load..."
    MAX_ATTEMPTS=30
    DELAY_SECONDS=2
    ATTEMPTS=0

    while [ $ATTEMPTS -lt $MAX_ATTEMPTS ]; do
        # Check if module is already loaded
        if lsmod | grep -q wireguard; then
            echo "WireGuard module detected!"
            return 0
        fi

        # Attempt manual loading if the file exists
        if [ -f /kvmcomm/ko/wireguard.ko ]; then
            insmod /kvmcomm/ko/wireguard.ko 2>/dev/null
        else
            modprobe wireguard 2>/dev/null
        fi

        ATTEMPTS=$((ATTEMPTS + 1))
        sleep $DELAY_SECONDS
    done

    echo "Error: WireGuard module failed to load after $((MAX_ATTEMPTS * DELAY_SECONDS)) seconds."
    return 1
}

wait_for_internet() {
    echo "Waiting for network connectivity..."

    PEER_IP="<PEER IP>"
    MAX_RETRIES=60
    WAIT_SEC=2
    COUNT=0
    # Loop until we can ping the public internet (8.8.8.8) or our peer
    # -c 1 (one packet), -W 1 (1 second timeout)
    while ! ping -q -c 1 -W 1 "$PEER_IP" >/dev/null 2>&1; do
        if [ $COUNT -ge $MAX_RETRIES ]; then
            echo "Network timeout reached. WireGuard will not start."
            return 1
        fi
        echo "Network not ready yet... (Attempt $COUNT/$MAX_RETRIES)"
        sleep $WAIT_SEC
        COUNT=$((COUNT + 1))
    done

    return 0
}

ENDPOINT_IP=$(ping -c 1 <PEER IP> | head -n 1 | awk -F'(' '{print $2}' | awk -F')' '{print $1}')

case "$1" in
    start)
        # Loop until WireGuard module is loaded & ping to WireGuard peer is successful
        if wait_for_wireguard && wait_for_internet; then
            # Start WireGuard
            #wg-quick up wg0 # DOESN'T WORK ON SIPEED NANOKVM - USE FOLLOWING COMMANDS IN REPLACEMENT
            ip link add dev wg0 type wireguard >>/var/log/wireguard.log 2>&1
            ip link set dev wg0 mtu 1360 >>/var/log/wireguard.log 2>&1
            ip address add <LOCAL WIREGUARD IP>/32 dev wg0 >>/var/log/wireguard.log 2>&1
            wg setconf wg0 /etc/wireguard/wg0.conf >>/var/log/wireguard.log 2>&1
            ip link set up dev wg0 >>/var/log/wireguard.log 2>&1
            # Prevents the encrypted tunnel traffic from looping back into the tunnel
            ip route add $ENDPOINT_IP via $(ip route show default | awk '/default/ {print $3}') dev eth0
            # Alternative to usurping default route and breaking Internet
            ip route add 0.0.0.0/1 dev wg0
            ip route add 128.0.0.0/1 dev wg0
        fi
        ;;
    stop)
        echo "Stopping WireGuard..."
        #wg-quick down wg0 # DOESN'T WORK ON SIPEED NANOKVM - USE FOLLOWING COMMANDS IN REPLACEMENT
        ip link set down dev wg0
        ip address delete <LOCAL WIREGUARD IP>/32 dev wg0
        ip link delete dev wg0
        ip route delete $ENDPOINT_IP
        ip route delete 0.0.0.0/1
        ip route delete 128.0.0.0/1
        ;;
    restart|reload)
        "$0" stop
        "$0" start
        ;;
    *)
        echo "Usage: $0 {start|stop|restart}"
        exit 1
esac
exit 0

 

  •  /etc/systemd/system/wireguard.service
    • create systemd service
[Unit]
Description=Auto-retry WireGuard Tunnel for NanoKVM
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
RemainAfterExit=yes

# This loops every 2 seconds (up to 30 times) waiting for the kernel module
ExecStartPre=/bin/sh -c 'for i in $(seq 1 30); do if lsmod | grep -q wireguard; then exit 0; fi; insmod /kvmcomm/ko/wireguard.ko 2>/dev/null || modprobe wireguard 2>/dev/null; sleep 2; done; exit 1'

# Starts WireGuard once the module is confirmed active
ExecStart=/usr/local/sbin/wg0.sh start
ExecStop=/usr/local/sbin/wg0.sh stop

[Install]
WantedBy=multi-user.target
    • update then enable this new service
      • systemctl daemon-reload
      • systemctl enable wireguard.service

 

  •  /etc/wireguard/wg0.conf
    • since we are not using wg-quick but just wg setconf,  we have to strip any commands recognised only by wg-quick.
[Interface]
PrivateKey = <PRIVATE KEY>

[Peer]
PublicKey = <PEER PUBLIC KEY>
PresharedKey = <PRESHARED KEY>
Endpoint = <PEER IP OR FQDN>:<PORT>
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 5