Je n’ai jamais eu d’OOB sur mon routeur à la maison, bien que j’ai un
backup 4G en cas de défaillance de ma FTTH (principalement dû à des
écrasements/rebranchements). Ce qui fait que je suis peu ou prou protégé
contre la bêtise de l’infra FTTH, mais pas contre ma propre bêtise si
jamais je me coupe la main sur mon routeur sans être chez moi.
Mon setup est fait de telle façon que le routeur 4G n’est pas là pour
prendre complètement la main du routeur de la FTTH, mais pour servir de
support à des tunnels wireguard qui ont un cost OSPF plus élevé que le PPP
sur la FTTH. De cette façon, j’ai fallback transparent (modulo le MTU)
entre les connexions.
Histoire de pouvoir prendre la main sur mon NanoKVM même en cas de coupure
de fibre je veux avoir la main dessus par la 4G, mais aussi directement
via mon LAN pour éviter de bouffer mon forfait 4G pour rien lorsque je
l’utilise depuis chez moi (par exemple quand j’installe une nouvelle
machine et que j’ai la flemme de brancher un écran dessus).
La configuration de base de mon routeur 4G est de nater tout ce qui vient
du routeur FTTH vers n’importe quoi. L’idée est que ça m’évite de faire du
routage dynamique sur le routeur 4G pour que la réponse des tunnels
wireguard revienne à mon routeur. Après avoir installé snmpd et tcpdump
dessus, il ne reste que 1.2M libres sur la flash ; bird n’est pas packagé
et frr n’est pas particulièrement léger.
La configuration de mon routeur wireguard est très similaire puisque
l’utilité première est de prendre la main sur des machines nomades à
distance pour lesquelles je dois assurer la maintenance (celles de la
famille quoi).
Ici ça m’arrange parce que du coup j’ai pas besoin de gérer des tables de
routage différentes sur le NanoKVM entre le LAN et le wireguard. L’IP
source vue par le KVM sera forcément celle sur la route directement
connectée, donc la réponse ira au bon endroit.
Le setup sur le Teltonika qui gère la 4G est très simple : j’ai une route
par défaut sur la 4G (qmimux0), mes IPs en more-spec sur
l’interco avec mon routeur FTTH (br-lan), et un /30 dédié au
NanoKVM (br-ifLan1). J’ai gardé la configuration en DHCP côté
NanoKVM comme ça je peux facilement le brancher ailleurs si besoin. Et
avec ça, je peux accéder au NanoKVM depuis chez moi.
root@Teltonika-RUT950:~# ip r
default dev qmimux0 proto static scope link src 10.222.240.167 metric 1
10.0.0.0/8 via 10.0.4.1 dev br-lan proto static metric 3
10.0.4.0/31 dev br-lan proto static scope link metric 3
10.0.4.64/30 dev br-ifLan1 proto kernel scope link src 10.0.4.65
10.222.240.167 dev qmimux0 proto static scope link metric 1
45.91.126.0/24 via 10.0.4.1 dev br-lan proto static metric 3
172.16.0.0/12 via 10.0.4.1 dev br-lan proto static metric 3
192.168.0.0/16 via 10.0.4.1 dev br-lan proto static metric 3
root@Teltonika-RUT950:~# grep -C2 nanokvm /etc/config/dhcp
config host
option mac '48:da:35:6f:a0:73'
option name 'nanokvm'
option ip '10.0.4.66'
alarig@x280 ~ % ping nanokvm.int.no.swordarmor.fr
PING nanokvm.int.no.swordarmor.fr (10.0.4.66) 56(84) bytes of data.
64 bytes from nanokvm.int.no.swordarmor.fr (10.0.4.66): icmp_seq=1 ttl=62 time=1.71 ms
64 bytes from nanokvm.int.no.swordarmor.fr (10.0.4.66): icmp_seq=2 ttl=62 time=1.59 ms
^C
--- nanokvm.int.no.swordarmor.fr ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 1.591/1.649/1.707/0.058 ms
Arrivé ici je vais naturellement sur l’interface web (le port ssh n’était
pas dispo) pour voir si je peux activer le SSH, et on peut !
Une fois loggué en root, je commence à regarder ce que j’ai sous la main,
parce que sinon c’est pas drôle. Nous avons donc affaire à un Linux (pas
surprenant) qui tourne sur un RISC-V 64-bit (malin pour avoir une faible
conso) dont je connais pas le modèle exact parce que lscpu
n’est pas dispo. Il s’agît d’une disto custom,
/etc/os-release parle de Buildroot 2023.11.2, mais on a tout
le userland habituel et même htop ainsi que 6.4G encore
disponibles sur la partition principale.
Tout cela est très sympathique mais ce que j’aimerais quand même, c’est
avoir un wireguard dessus pour prendre la main via la 4G (c’est à dire
sans être routé par la FTTH, puisque c’est sur ce routeur que je risque de
reprendre la main). Malheureusement l’interface web ne parle que de
tailscale mais pas d’un simple wireguard comme je l’aimerais. Qu’à cela ne
tienne je suis root, je vais trouver un arrangement.
Le classique /etc/rc.local n’est pas vide mais parle de
fichiers qui n’existent pas. Dans le doute je me dis que ça risque d’être
écrasé lors d’une mise à jour. Je ne peux pas non plus lancer un cron
@reboot, le daemon est installé mais n’est pas lancé.
J’ai également envie d’envoyer les logs vers la machine chez moi qui les
reçoit tous, histoire d’être carré. Bien que l’interface web ne propose
pas de pouvoir le faire, le service d’init parle de la variable
SYSLOGD_ARGS dans le fichier
/etc/default/syslogd (il faut lire le man de busybox pour
savoir quelles options on peut utiliser).
Pour les curieux, voici le
dmesg.
# cat /etc/rc.local
#!/bin/sh
echo "HELLO WORLD"
if [ -e /boot/maixcam ]
then
/maixapp/apps/launcher/launcher &
fi
# file /boot/maixcam
/boot/maixcam: cannot open `/boot/maixcam' (No such file or directory)
# file /maixapp/apps/launcher/launcher
/maixapp/apps/launcher/launcher: cannot open `/maixapp/apps/launcher/launcher' (No such file or directory)
# which crond
/usr/sbin/crond
# ps aux | grep cron
1384 root grep cron
# ps aux | grep log
224 root /sbin/syslogd -n
237 root /sbin/klogd -n
1671 root grep log
# cat /etc/default/syslogd
SYSLOGD_ARGS="-R msi.no.swordarmor.fr -L"
# /etc/init.d/S01syslogd restart
Stopping syslogd: OK
Starting syslogd: OK
# ps aux | grep log
237 root /sbin/klogd -n
1935 root /sbin/syslogd -n -R msi.no.swordarmor.fr -L
1941 root grep log
Donc il ne me reste plus qu’à faire les choses proprement : écrire un
script d’init.
La commande systemctl n’existe pas et
/etc/init.d/ contient tous les services qui sont lancés. Je
me dis que c’est une bonne idée de se mettre au même niveau de priorité
que sshd, puisqu’il a également besoin que le réseau soit up avant de
démarrer. Je ne m’embête pas avec la gestion du PID vu que c’est un module
kernel que je lance, ni avec les commandes pour faire tomber le VPN vu que
j’ai pas prévu de le faire, mais ça serait assez trivial à ajouter.
Le mtr montre bien que je fais le tour de mon réseau pour revenir chez
moi. Je ne distribue pas d’IP publique dans le VPN parce que je ne vois
pas spécialement de cas d’usage où je ne pourrais pas monter mon propre
VPN pour y accéder.
À noter aussi qu’à l’époque où j’avais monté les tunnels wireguard pour
sécuriser ma FTTH, je n’avais de MTU à 1500 sur la 4G, mais ça semble
désormais être le cas.
# ls -lh /etc/init.d/
total 120K
-rwxr-xr-x 1 root root 646 Mar 7 10:50 S00kmod
-rwxr-xr-x 1 1000 1000 735 May 9 2025 S00pmu
-rwxr-xr-x 1 root root 1.2K Mar 7 10:50 S01fs
-rwxr-xr-x 1 1000 1000 1.2K May 9 2025 S01seedrng
-rwxr-xr-x 1 1000 1000 1012 May 9 2025 S01syslogd
-rwxr-xr-x 1 1000 1000 1.7K May 9 2025 S02config
-rwxr-xr-x 1 1000 1000 1004 May 9 2025 S02klogd
-rwxr-xr-x 1 1000 1000 2.7K May 9 2025 S02sysctl
-rwxr-xr-x 1 root root 5.1K Mar 7 10:50 S03usbdev
-rwxr-xr-x 1 1000 1000 324 May 9 2025 S04fb
-rwxr-xr-x 1 1000 1000 1.6K May 9 2025 S10udev
-rwxr-xr-x 1 1000 1000 1.3K May 9 2025 S10uuid
-rwxr-xr-x 1 root root 6.7K Mar 7 10:50 S15kvmhwd
-rwxr-xr-x 1 1000 1000 404 May 9 2025 S21haveged
-rwxr-xr-x 1 1000 1000 229 May 9 2025 S25wifimod
-rwxr-xr-x 1 1000 1000 1.6K May 9 2025 S30dbus
-rwxr-xr-x 1 root root 1.7K Mar 7 10:50 S30eth
-rwxr-xr-x 1 1000 1000 1.3K May 9 2025 S30rndis
-rwxr-xr-x 1 1000 1000 820 May 9 2025 S35iptables
-rwxr-xr-x 1 1000 1000 438 May 9 2025 S40network
-rwxr-xr-x 1 1000 1000 918 May 9 2025 S49ntp
-rwxr-xr-x 1 1000 1000 690 May 9 2025 S50ser2net
-rwxr-xr-x 1 root root 1.2K Mar 7 10:50 S50sshd
-rwxr-xr-x 1 1000 1000 538 May 9 2025 S80dnsmasq
-rwxr-xr-x 1 root root 2.2K Mar 7 10:50 S95nanokvm
-rwxr-xr-x 1 1000 1000 423 May 9 2025 rcK
-rwxr-xr-x 1 1000 1000 408 May 9 2025 rcS
# vim /etc/wireguard/wg0.conf
# vim /etc/init.d/S50wireguard
# cat /etc/init.d/S50wireguard
#!/bin/sh
case "$1" in
start)
echo "Start ovpn.fr connection"
ip link add dev wg0 type wireguard
wg setconf wg0 /etc/wireguard/wg0.conf
ip addr add 10.0.1.9/31 dev wg0
ip link set up dev wg0
ping -c1 10.0.1.8
#ip route add 0.0.0.0/0 dev wg0
;;
stop)
;;
restart|reload)
"$0" stop
"$0" start
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
esac
exit $?
# chmod +x /etc/init.d/S50wireguard
# /etc/init.d/S50wireguard start
# ip a
1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 48:da:35:6f:a0:73 brd ff:ff:ff:ff:ff:ff permaddr c2:e8:e7:a3:16:80
inet 10.0.4.66/30 brd 10.0.4.67 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::4ada:35ff:fe6f:a073/64 scope link
valid_lft forever preferred_lft forever
3: ip6tnl0@NONE: mtu 1452 qdisc noop state DOWN group default qlen 1000
link/tunnel6 :: brd :: permaddr 8aa8:c467:33d4::
4: usb0: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 48:da:35:6e:a0:73 brd ff:ff:ff:ff:ff:ff
inet 10.160.115.1/24 scope global usb0
valid_lft forever preferred_lft forever
inet6 fe80::4ada:35ff:fe6e:a073/64 scope link
valid_lft forever preferred_lft forever
5: wg0: mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000
link/none
inet 10.0.1.9/31 scope global wg0
valid_lft forever preferred_lft forever
root@kvm-a073 ~ # tracepath ovpn.fr.swordarmor.fr
1?: [LOCALHOST] pmtu 1500
1: Teltonika-RUT950.com 2.881ms
1: eth0.105.rut950.int.no.swordarmor.fr 2.950ms
2: no reply
3: 192.168.8.62 59.745ms asymm 2
4: 192.168.255.22 47.473ms asymm 7
5: no reply
6: no reply
7: no reply
8: no reply
9: no reply
10: no reply
11: no reply
12: no reply
13: no reply
14: no reply
15: no reply
16: ovpn.fr.as208627.net 87.731ms reached
Resume: pmtu 1500 hops 16 back 13
alarig@x280 ~ % mtr -bzwe nanokvm-wg.int.no.swordarmor.fr
Start: 2026-03-07T15:44:08+0100
HOST: x280.int.no.swordarmor.fr Loss% Snt Last Avg Best Wrst StDev
1. AS??? enp3s0.101.core02-rennes.fr.as208627.net (192.168.5.254) 0.0% 10 1.1 1.1 0.8 1.2 0.1
2. AS??? ppp0.edge01-th2lf.swordarmor.fr (10.0.4.16) 0.0% 10 6.9 7.0 6.3 8.4 0.7
3. AS??? eno1.104.regis.swordarmor.fr (10.0.4.24) 0.0% 10 13.6 13.9 13.1 15.7 0.8
4. AS204092 ovpn.fr.as208627.net (89.234.186.219) 0.0% 10 14.1 13.9 13.1 15.2 0.6
5. AS??? nanokvm-wg.int.no.swordarmor.fr (10.0.1.9) 0.0% 10 57.4 79.0 53.0 119.6 19.3
Et maintenant qu’on a tout ça, on peut enfin regarder si la fonction de
KVM est bien remplie. Donc déjà premier test : est-ce qu’il reste bien
allumé si je redémarre le routeur ? (si jamais il prenait l’alimentation
électrique depuis l’USB qui sert à envoyer les I/O clavier.
Et c’est bien le cas, l’uptime du KVM est supérieur à celui du routeur.
alarig@x280 ~ % ssh root@nanokvm.int.no.swordarmor.fr
root@nanokvm.int.no.swordarmor.fr's password:
# uptime
11:57:12 up 23 min, load average: 5.30, 5.57, 4.10
#
alarig@x280 ~ % ssh root@core01-rennes.fr.swordarmor.fr
Linux core01-rennes.fr.swordarmor.fr 6.18.12-gentoo-core01-arm #1 SMP PREEMPT_DYNAMIC Fri Feb 20 00:23:04 CET 2026 aarch64 GNU/Linux
Last login: Sat Mar 7 11:28:15 CET 2026 from 192.168.5.1 on pts/1
core01-rennes ~ # uptime
12:57:32 up 8 min, 1 user, load average: 0.17, 0.12, 0.07
core01-rennes ~ #
J’ai bien les logs dmesg qui me disent que l’émulation de
clavier/souris est présente. J’ai même le /data du NanoKVM
qui est exposé.
core01-rennes ~ # dmesg | grep -i NanoKVM
[ 3.190596] usb 16-1: Product: NanoKVM
[ 3.274675] input: sipeed NanoKVM as /devices/platform/PNP0D10:09/usb16/16-1/16-1:1.2/0003:3346:1009.0001/input/input1
[ 3.426555] hid-generic 0003:3346:1009.0001: input,hidraw0: USB HID v1.01 Keyboard [sipeed NanoKVM] on usb-PNP0D10:09-1/input2
[ 3.427383] input: sipeed NanoKVM as /devices/platform/PNP0D10:09/usb16/16-1/16-1:1.3/0003:3346:1009.0002/input/input2
[ 3.427588] hid-generic 0003:3346:1009.0002: input,hidraw1: USB HID v1.01 Mouse [sipeed NanoKVM] on usb-PNP0D10:09-1/input3
[ 3.428332] input: sipeed NanoKVM as /devices/platform/PNP0D10:09/usb16/16-1/16-1:1.4/0003:3346:1009.0003/input/input3
[ 3.428452] hid-generic 0003:3346:1009.0003: input,hidraw2: USB HID v1.01 Mouse [sipeed NanoKVM] on usb-PNP0D10:09-1/input4
[ 4.537290] scsi 0:0:0:0: Direct-Access NanoKVM USB Mass Storage 0520 PQ: 0 ANSI: 2
core01-rennes ~ # fdisk -l /dev/sda
Disk /dev/sda: 21.49 GiB, 23076012032 bytes, 45070336 sectors
Disk model: USB Mass Storage
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x00000000
Et quand je vais sur l’interface web, j’ai bien la sortie tty et je peux
taper des trucs dedans sans avoir des caractères bizarres comme sur les
IPMI supermicro quand il y a un mix qwerty/azery.

Donc à voir sur la durée si mes bricoles résistent aux upgrades, mais ça
me semble être un produit de qualité tout à fait respectable et largement
hackable.
La puissance du CPU ne semble pas être très élevée, puisque quand j’ai téléchargé l’ISO d’arch (qui fait 1.4Go) ça a pris un peu plus de vingt minutes, soit un débit de ~10Mbps. Pendant ce temps le CPU était à 100% tout du long.