Mascota de HectorziN
Blog de HectorziN

Cómo convertir un GL.iNet Flint 3 con OpenWrt en QNetd para un clúster Proxmox

En un clúster Proxmox formado por dos nodos hay un problema bastante conocido: para mantener el quórum necesitamos evitar situaciones en las que cada nodo tenga exactamente la mitad de los votos. Una solución habitual consiste en añadir un QDevice, que utiliza un tercer equipo independiente ejecutando QNetd para actuar como árbitro. En mi caso ya tenía un QDevice funcionando, pero el QNetd estaba alojado en otra máquina. Quería eliminar esa dependencia y aprovechar un dispositivo que está prácticamente siempre encendido y que además es físicamente independiente de los servidores Proxmox: mi router GL.iNet Flint 3 (GL-BE9300). El problema es que el Flint 3 utiliza OpenWrt, no Debian, y los repositorios disponibles en mi firmware no incluyen corosync-qnetd. Importante: esta guía documenta exactamente la solución que utilicé en mi instalación. OpenWrt, GL.iNet, Debian, Corosync y Proxmox evolucionan, por lo que conviene comprobar versiones, rutas y parámetros antes de copiarlos literalmente.

En YouTube comparto más tutoriales, pruebas y domótica real. Suscribirme

Instalar Qnetd, Qdevice, árbito de proxmox en OpenWRT y GL.iNet Flint 3

Vídeo relacionado en YouTube

Video

1. El entorno utilizado

En mi instalación:

Código
Router:
GL.iNet Flint 3 / GL-BE9300
IP: 192.168.1.1
OpenWrt 23.05-SNAPSHOT
Arquitectura ARM64

Clúster:
Nombre: hectormox

Nodo 1:
miniproxmox
192.168.1.6

Nodo 2:
zimaproxmox
192.168.1.7

La Debian mínima quedó instalada en:

/opt/debian-qnetd

QNetd escucha en el puerto estándar:

TCP 5403

2. Entrar por SSH al Flint 3

Desde Windows podemos utilizar directamente el cliente SSH incluido en PowerShell:

ssh root@192.168.1.1

Introducimos la contraseña de administración del router.

Una vez dentro veremos algo similar a:

Código
BusyBox
OpenWrt
root@GL-BE9300:~#

Antes de instalar absolutamente nada merece la pena descubrir qué tenemos realmente.

3. Comprobar sistema, arquitectura, paquetes y espacio disponible

Ejecutamos:

bash
cat /etc/os-release
cat /etc/openwrt_release

uname -a
uname -m

command -v opkg
command -v apk

opkg print-architecture

df -h

En mi Flint obtuve un sistema:

OpenWrt 23.05-SNAPSHOT

aarch64

y opkg como gestor de paquetes.

También comprobé qué herramientas estaban disponibles:

bash
command -v ar
command -v tar
command -v gzip
command -v xz
command -v wget
command -v curl
command -v mount
command -v chroot

Y, especialmente, si OpenWrt ya ofrecía Corosync:

bash
opkg update
opkg list | grep -Ei 'corosync|qnetd|qdevice|libnss|libqb'

En mi firmware no aparecía corosync-qnetd.

Por tanto no podíamos hacer simplemente:

opkg install corosync-qnetd

como haríamos con un paquete nativo de OpenWrt.

4. Por qué utilizar una Debian mínima dentro de OpenWrt

En lugar de intentar compilar Corosync y todas sus dependencias directamente para OpenWrt, opté por una solución bastante más sencilla:

crear una Debian ARM64 mínima dentro de una carpeta y ejecutar QNetd mediante chroot.

OpenWrt continúa siendo el sistema operativo del router. No instalamos otro kernel, no virtualizamos nada y no sustituimos el firmware.

La estructura es simplemente:

Código
OpenWrt
└── /opt/debian-qnetd
    └── Debian 12 ARM64
        └── corosync-qnetd

Es decir, el Flint sigue funcionando como router OpenWrt, pero dispone de un pequeño entorno Debian desde el que podemos ejecutar software que no existe en sus repositorios.

5. Instalar debootstrap en el Flint

Primero actualizamos los índices:

opkg update

Instalamos debootstrap:

opkg install debootstrap

Comprobamos que está disponible:

bash
command -v debootstrap
debootstrap --version

Y revisamos el espacio disponible:

df -h /overlay

En mi caso había varios gigabytes libres, suficiente para una Debian mínima.

6. Problema con GPG y Debian Bookworm

Aquí apareció uno de los primeros problemas específicos de mi versión de OpenWrt.

debootstrap necesita verificar las firmas de los repositorios Debian, pero el gpgv disponible inicialmente en el router era demasiado antiguo para algunas firmas utilizadas por Bookworm.

La solución fue instalar:

opkg install gpgv2

Podemos comprobarla con:

gpgv2 --version

También necesitamos las claves oficiales de Debian.

Preparamos una carpeta temporal:

bash
BASE="/tmp/qnetd-bootstrap"

mkdir -p "$BASE"
mkdir -p "$BASE/bin"

Descargamos el paquete debian-archive-keyring correspondiente a Debian Bookworm.

Aquí conviene comprobar cuál es la versión actual del paquete cuando se siga esta guía, en lugar de copiar permanentemente una URL concreta.

Una vez descargado:

DEB="$BASE/debian-archive-keyring.deb"

Extraemos su contenido:

bash
ar p "$DEB" data.tar.xz |
    xz -dc |
    tar -xf - -C "$BASE"

La clave queda disponible en:

bash
KEY="$BASE/usr/share/keyrings/debian-archive-keyring.gpg"
ls -l "$KEY"

Para asegurarnos de que debootstrap utiliza gpgv2, creamos un pequeño override temporal:

ln -sf /usr/bin/gpgv2 "$BASE/bin/gpgv"

Esto únicamente afectará al PATH que utilizaremos al ejecutar debootstrap.

7. Crear Debian 12 ARM64 minbase

Definimos dónde queremos instalarla:

TARGET="/opt/debian-qnetd"

Ejecutamos:

bash
PATH="$BASE/bin:$PATH" \
debootstrap \
    --arch=arm64 \
    --variant=minbase \
    --keyring="$KEY" \
    bookworm \
    "$TARGET" \
    https://deb.debian.org/debian

Esto descarga e instala una Debian 12 mínima dentro de:

/opt/debian-qnetd

Podemos comprobar su contenido:

ls -la /opt/debian-qnetd

Y entrar manualmente:

chroot /opt/debian-qnetd /bin/bash

Para volver a OpenWrt:

exit

8. Actualizar Debian e instalar QNetd

Desde el propio OpenWrt podemos lanzar directamente comandos dentro del chroot:

chroot "$TARGET" /usr/bin/apt-get update

Antes de instalar comprobamos que el paquete está disponible:

bash
chroot "$TARGET" \
    /usr/bin/apt-cache policy corosync-qnetd

En mi caso Debian ofrecía:

corosync-qnetd 3.0.3-1

La instalación inicial encontró algunas dependencias pendientes del entorno minbase.

Primero reparé la base de paquetes con:

bash
chroot "$TARGET" \
    /usr/bin/apt-get --no-remove -y --fix-broken install

Después instalé:

bash
chroot "$TARGET" \
    /usr/bin/apt-get install -y \
    --no-install-recommends \
    corosync-qnetd \
    libnss3-tools

Entre las dependencias que terminó instalando Debian aparecieron bibliotecas NSS, Perl, netbase y otros paquetes necesarios.

9. /proc y /dev/pts durante la instalación

Durante la instalación aparecieron algunos avisos relacionados con /proc y /dev/pts.

Monté temporalmente:

bash
mount -o bind \
    /proc \
    /opt/debian-qnetd/proc

Y:

bash
mount -o bind \
    /dev/pts \
    /opt/debian-qnetd/dev/pts

Esto nos ayudó durante la preparación de Debian.

Posteriormente comprobamos que QNetd no necesita estos bind mounts para ejecutarse normalmente, por lo que no forman parte del servicio definitivo.

10. Inicializar los certificados de QNetd

QNetd utiliza una base NSS para gestionar sus certificados.

Dentro de nuestra Debian tenemos la utilidad:

corosync-qnetd-certutil

La inicializamos desde OpenWrt:

bash
chroot /opt/debian-qnetd \
    /usr/bin/corosync-qnetd-certutil \
    -i

La base NSS queda, vista desde OpenWrt, en:

/opt/debian-qnetd/etc/corosync/qnetd/nssdb

Podemos comprobarla con:

bash
ls -lah \
    /opt/debian-qnetd/etc/corosync/qnetd/nssdb

Dentro del chroot esa misma ruta sería:

/etc/corosync/qnetd/nssdb

La CA pública queda en:

/opt/debian-qnetd/etc/corosync/qnetd/nssdb/qnetd-cacert.crt

11. Comprobar el usuario coroqnetd

El paquete Debian crea un usuario específico para ejecutar QNetd.

Comprobamos sus identificadores:

chroot /opt/debian-qnetd id coroqnetd

En mi instalación obtuve:

UID 100

GID 101

Esto es importante porque más adelante ejecutaré QNetd con:

--userspec=100:101

Estos números no deben copiarse sin comprobarlos primero.

Cada instalación debe ejecutar:

chroot /opt/debian-qnetd id coroqnetd

y utilizar los valores obtenidos.

También revisamos permisos de la base NSS:

bash
DB="/opt/debian-qnetd/etc/corosync/qnetd/nssdb"
ls -ln "$DB"

En mi caso tuve que ajustar:

bash
chgrp 101 \
    "$DB/pwdfile.txt" \
    "$DB/pkcs11.txt"

chmod 640 \
    "$DB/pwdfile.txt" \
    "$DB/pkcs11.txt"

De nuevo, 101 era el GID concreto de mi instalación.

12. Probar QNetd manualmente

Antes de convertirlo en servicio es importante comprobar que el daemon realmente arranca.

Probé:

bash
timeout -s TERM 10 \
    chroot --userspec=100:101 \
    /opt/debian-qnetd \
    /usr/bin/corosync-qnetd \
    -f \
    -4 \
    -l 192.168.1.1 \
    -p 5403 \
    -s req

Los parámetros utilizados son:

  • -f: ejecutarlo en foreground.
  • -4: utilizar IPv4.
  • -l 192.168.1.1: dirección donde escucha QNetd.
  • -p 5403: puerto.
  • -s req: exigir TLS en la versión que utilizamos.

Antes de copiarlo conviene comprobar la ayuda de la versión instalada:

bash
chroot /opt/debian-qnetd \
    /usr/bin/corosync-qnetd \
    -h

13. El problema de LD_PRELOAD de OpenWrt

Al ejecutar programas Debian desde OpenWrt aparecieron avisos relacionados con una variable LD_PRELOAD del firmware.

Para evitar que el proceso del chroot heredase variables propias de OpenWrt acabé ejecutándolo con un entorno limpio:

bash
/usr/bin/env -i \
    PATH=/usr/sbin:/usr/bin:/sbin:/bin \
    ...

Este detalle acabó formando parte del servicio definitivo.

14. Crear el servicio QNetd en OpenWrt

Aquí tenemos una de las diferencias más importantes respecto a una Debian normal.

En Debian utilizaríamos systemd.

En OpenWrt utilizamos procd y scripts bajo:

/etc/init.d/

Creamos:

bash
cat > /etc/init.d/qnetd-debian <<'EOF'
#!/bin/sh /etc/rc.common

USE_PROCD=1
START=98
STOP=10

start_service() {
    procd_open_instance

    procd_set_param command \
        /usr/bin/env -i \
        PATH=/usr/sbin:/usr/bin:/sbin:/bin \
        /usr/sbin/chroot --userspec=100:101 \
        /opt/debian-qnetd \
        /usr/bin/corosync-qnetd \
        -f -4 -l 192.168.1.1 -p 5403 -s req

    procd_set_param respawn 3600 5 5
    procd_set_param stdout 1
    procd_set_param stderr 1

    procd_close_instance
}
EOF

Le damos permisos:

chmod 755 /etc/init.d/qnetd-debian

Activamos el arranque automático:

/etc/init.d/qnetd-debian enable

Podemos comprobar los enlaces creados:

ls -l /etc/rc.d/*qnetd*

En mi Flint quedaron:

/etc/rc.d/S98qnetd-debian

/etc/rc.d/K10qnetd-debian

Arrancamos el servicio:

/etc/init.d/qnetd-debian start

15. Comprobar que QNetd está funcionando

Primero buscamos el proceso:

pidof corosync-qnetd

Después comprobamos el puerto:

netstat -lntp 2>/dev/null | grep 5403

Deberíamos ver:

192.168.1.1:5403 LISTEN

También podemos comprobar el proceso completo:

ps w | grep '[c]orosync-qnetd'

Y consultar directamente a procd:

bash
ubus call service list \
    '{"name":"qnetd-debian"}'

Un estado correcto contiene:

"running": true

En mi caso también podíamos ver:

Código
/usr/bin/corosync-qnetd
-f
-4
-l 192.168.1.1
-p 5403
-s req

16. Comprobar el respawn

El servicio incluye:

procd_set_param respawn 3600 5 5

Esto permite que procd vuelva a arrancar QNetd si el proceso termina inesperadamente.

Durante las pruebas llegamos a matar el proceso manualmente y comprobamos que reaparecía con otro PID y volvía a escuchar en:

192.168.1.1:5403

17. Preparar Proxmox

Ahora pasamos al primer nodo del clúster:

ssh root@192.168.1.6

Comprobamos el estado actual:

pvecm status

Y:

corosync-qdevice-tool -s

Mi clúster se llama:

hectormox

y anteriormente tenía otro QNetd en:

192.168.1.5:5403

El nuevo será:

192.168.1.1:5403

18. Hacer backup antes de cambiar QDevice

Antes de tocar certificados hice una copia de:

/etc/corosync/qdevice

/etc/pve/corosync.conf

Por ejemplo:

bash
BACKUP="/root/qdevice-backup-$(hostname)-$(date +%Y%m%d-%H%M%S).tar.gz"

tar -czf "$BACKUP" \
    -C / \
    etc/corosync/qdevice \
    etc/pve/corosync.conf

sha256sum "$BACKUP"

ls -lh "$BACKUP"

No recomiendo continuar sin tener este backup.

19. Crear una base NSS nueva en Proxmox

En miniproxmox:

bash
DIR="/root/qnetd-migration"
DB="$DIR/nssdb-new"
PASS="$DIR/pwdfile-new.txt"

mkdir -p "$DIR"
mkdir -m 700 "$DB"

: > "$PASS"
chmod 600 "$PASS"

Inicializamos NSS:

certutil -N \
    -d "sql:$DB" \
    -f "$PASS"

20. Copiar la CA del Flint a Proxmox

Desde miniproxmox:

bash
scp \
    root@192.168.1.1:/opt/debian-qnetd/etc/corosync/qnetd/nssdb/qnetd-cacert.crt \
    /root/qnetd-migration/qnetd-cacert.crt

Importamos la CA:

bash
certutil -A \
    -d "sql:$DB" \
    -n "QNet CA" \
    -t "CT,c,c" \
    -i "$DIR/qnetd-cacert.crt" \
    -f "$PASS"

Comprobamos:

bash
certutil -L \
    -d "sql:$DB" \
    -f "$PASS"

Deberíamos ver:

QNet CA CT,c,c

21. Crear el CSR del clúster

Generamos algo de entropía:

bash
dd if=/dev/urandom \
    of="$DIR/noise-new.txt" \
    bs=1024 \
    count=1 \
    status=none

Creamos el CSR:

bash
CSR="$DIR/qdevice-net-node.crq"
certutil -R \
    -d "sql:$DB" \
    -f "$PASS" \
    -z "$DIR/noise-new.txt" \
    -s "CN=hectormox" \
    -g 3072 \
    -o "$CSR"

Hay que sustituir:

hectormox

por el nombre real del clúster.

Podemos comprobarlo con:

pvecm status

22. Enviar el CSR al Flint

Desde Proxmox:

bash
scp \
    "$CSR" \
    root@192.168.1.1:/opt/debian-qnetd/tmp/hectormox.crq

Entramos de nuevo al Flint:

ssh root@192.168.1.1

Y firmamos:

bash
chroot /opt/debian-qnetd \
    /usr/bin/corosync-qnetd-certutil \
    -s \
    -c /tmp/hectormox.crq \
    -n hectormox

El certificado firmado queda en:

/opt/debian-qnetd/etc/corosync/qnetd/nssdb/cluster-hectormox.crt

23. Recuperar el certificado firmado

Desde miniproxmox:

bash
scp \
    root@192.168.1.1:/opt/debian-qnetd/etc/corosync/qnetd/nssdb/cluster-hectormox.crt \
    /root/qnetd-migration/cluster-hectormox.crt

Podemos convertirlo a PEM:

bash
cd /root/qnetd-migration

openssl x509 \
    -inform DER \
    -in cluster-hectormox.crt \
    -out cluster-hectormox.pem

Y verificarlo:

bash
openssl verify \
    -CAfile qnetd-cacert.crt \
    cluster-hectormox.pem

El resultado correcto es:

OK

24. Importar el certificado del clúster

Añadimos el certificado firmado a NSS:

bash
certutil -A \
    -d "sql:$DB" \
    -n "Cluster Cert" \
    -t "u,u,u" \
    -i "$DIR/cluster-hectormox.crt" \
    -f "$PASS"

Comprobamos:

bash
certutil -L \
    -d "sql:$DB" \
    -f "$PASS"

Ahora deberían aparecer:

QNet CA CT,c,c

Cluster Cert u,u,u

25. Exportar certificado y clave privada a PKCS#12

Generamos:

bash
pk12util \
    -o "$DIR/qdevice-net-node.p12" \
    -d "sql:$DB" \
    -k "$PASS" \
    -W "" \
    -n "Cluster Cert"

Resultado esperado:

PKCS12 EXPORT SUCCESSFUL

Este archivo contiene una clave privada. No debe publicarse ni compartirse.

26. Preparar el segundo nodo Proxmox

Copiamos al segundo nodo:

bash
scp \
    /root/qnetd-migration/qnetd-cacert.crt \
    root@192.168.1.7:/root/qnetd-migration/

Y:

bash
scp \
    /root/qnetd-migration/qdevice-net-node.p12 \
    root@192.168.1.7:/root/qnetd-migration/

En zimaproxmox:

bash
DIR="/root/qnetd-migration"
DB="$DIR/nssdb-new"
PASS="$DIR/pwdfile-new.txt"
CA="$DIR/qnetd-cacert.crt"
P12="$DIR/qdevice-net-node.p12"

mkdir -m 700 "$DB"

: > "$PASS"
chmod 600 "$PASS"

certutil -N \
    -d "sql:$DB" \
    -f "$PASS"

Importamos la CA:

bash
certutil -A \
    -d "sql:$DB" \
    -n "QNet CA" \
    -t "CT,c,c" \
    -i "$CA" \
    -f "$PASS"

Importamos PKCS#12:

bash
pk12util \
    -i "$P12" \
    -d "sql:$DB" \
    -k "$PASS" \
    -W ""

El resultado correcto es:

PKCS12 IMPORT SUCCESSFUL

Y comprobamos:

bash
certutil -L \
    -d "sql:$DB" \
    -f "$PASS"

27. Preparar una base NSS definitiva

Antes de tocar la base utilizada realmente por QDevice preparé otra carpeta:

/root/qnetd-migration/nssdb-ready

En cada nodo:

bash
DIR="/root/qnetd-migration"
READY="$DIR/nssdb-ready"

mkdir -m 700 "$READY"

cp -a \
    "$DIR/nssdb-new/." \
    "$READY/"

install -m 600 \
    "$DIR/pwdfile-new.txt" \
    "$READY/pwdfile.txt"

Comprobamos:

bash
certutil -L \
    -d "sql:$READY" \
    -f "$READY/pwdfile.txt"

Y podemos verificar la identidad:

bash
certutil -L \
    -d "sql:$READY" \
    -n "Cluster Cert" \
    -a |
openssl x509 \
    -noout \
    -subject \
    -issuer

En mi caso:

subject=CN=hectormox

issuer=CN=QNet CA

28. Sustituir las credenciales activas

Este paso lo hicimos nodo por nodo.

Detenemos únicamente QDevice:

systemctl stop corosync-qdevice

No detenemos Corosync.

Guardamos la base antigua:

bash
ACTIVE="/etc/corosync/qdevice/net/nssdb"
BACKUP="${ACTIVE}.pre-glinet-$(date +%Y%m%d-%H%M%S)"
mv "$ACTIVE" "$BACKUP"

Copiamos la nueva:

bash
cp -a \
    /root/qnetd-migration/nssdb-ready \
    "$ACTIVE"

Ajustamos permisos:

bash
chown -R root:root "$ACTIVE"
chmod 700 "$ACTIVE"
chmod 600 "$ACTIVE"/*

Comprobamos:

bash
certutil -L \
    -d "sql:$ACTIVE" \
    -f "$ACTIVE/pwdfile.txt"

Y arrancamos QDevice:

systemctl start corosync-qdevice

Repetimos el mismo procedimiento en el otro nodo.

29. Cambiar la IP del antiguo QNetd

En mi caso QDevice ya estaba configurado contra otro servidor:

192.168.1.5

y debía pasar al Flint:

192.168.1.1

Antes hice otra copia:

bash
cp \
    /etc/pve/corosync.conf \
    "/root/corosync-pre-glinet-$(date +%Y%m%d-%H%M%S).conf"

El cambio fue:

- host: 192.168.1.5

+ host: 192.168.1.1

También aumentamos:

- config_version: 3

+ config_version: 4

El bloque correspondiente quedó similar a:

bash
quorum {
  device {
    model: net
    net {
      algorithm: ffsplit
      host: 192.168.1.1
      tls: on
    }
    votes: 1
  }
}

Hay que tener en cuenta que config_version debe incrementarse respecto al valor que tenga cada instalación.

No hay que copiar literalmente 3 → 4.

30. Reiniciar únicamente QDevice

Después del cambio Corosync adoptó la nueva configuración, pero el proceso QDevice seguía utilizando la dirección antigua hasta reiniciarlo.

Ejecutamos:

systemctl restart corosync-qdevice

Comprobamos:

corosync-qdevice-tool -s

El resultado correcto fue:

Cluster name: hectormox

QNetd host: 192.168.1.1:5403

Algorithm: Fifty-Fifty split

State: Connected

Repetimos el reinicio de QDevice en el segundo nodo.

31. Comprobar el quórum

Ejecutamos:

pvecm status

En nuestro caso el resultado final fue:

Expected votes: 3 Highest expected: 3 Total votes: 3 Quorum: 2 Quorate: Yes

Y en la información de miembros:

0x00000001 1 A,V,NMW 192.168.1.6

0x00000002 1 A,V,NMW 192.168.1.7

0x00000000 1 Qdevice

Es decir:

  • miniproxmox: 1 voto.
  • zimaproxmox: 1 voto.
  • QDevice/QNetd: 1 voto.

Total:

3 votos

y el quórum necesario sigue siendo:

2

32. Hacer una copia completa del QNetd del Flint

Una vez terminado todo hice una copia completa del entorno.

Definimos:

bash
SERVICE="/etc/init.d/qnetd-debian"
BACKUP="/overlay/qnetd-backup-completo-$(date +%Y%m%d-%H%M%S).tar.gz"

Paramos brevemente QNetd:

"$SERVICE" stop

Creamos el backup:

bash
tar -czf "$BACKUP" \
    -C / \
    --exclude=opt/debian-qnetd/proc \
    --exclude=opt/debian-qnetd/dev/pts \
    --exclude=opt/debian-qnetd/run \
    --exclude=opt/debian-qnetd/tmp \
    opt/debian-qnetd \
    etc/init.d/qnetd-debian \
    etc/rc.d/S98qnetd-debian \
    etc/rc.d/K10qnetd-debian

Arrancamos de nuevo:

"$SERVICE" start

Comprobamos la integridad:

bash
tar -tzf "$BACKUP" >/dev/null
sha256sum "$BACKUP"
ls -lh "$BACKUP"

Mi copia final ocupaba aproximadamente:

157 MB

33. Descargar el backup a Windows

Desde PowerShell:

bash
scp -O `
    root@192.168.1.1:/overlay/qnetd-backup-completo-XXXXXXXX.tar.gz `
    "$env:USERPROFILE\Downloads\"

Después calculamos el hash:

bash
Get-FileHash `
    "$env:USERPROFILE\Downloads\qnetd-backup-completo-XXXXXXXX.tar.gz" `
    -Algorithm SHA256

El valor debe coincidir exactamente con el obtenido anteriormente en el Flint.

El backup contiene certificados y claves privadas, por lo que debe almacenarse en un lugar seguro.

34. Probar el sistema después de reiniciar el Flint

No quería considerar terminado el proyecto simplemente porque funcionara después de arrancarlo manualmente.

Reinicié el Flint 3 desde su interfaz web.

Cuando volvió a estar disponible entré otra vez:

ssh root@192.168.1.1

Y comprobé primero que el script seguía ahí:

wc -l /etc/init.d/qnetd-debian

Después:

pidof corosync-qnetd

Comprobé el puerto:

netstat -lntp 2>/dev/null | grep 5403

Y finalmente procd:

bash
ubus call service list \
    '{"name":"qnetd-debian"}'

En la prueba definitiva obtuve:

23 /etc/init.d/qnetd-debian

un PID válido:

28139

el puerto:

192.168.1.1:5403 LISTEN

y:

"running": true

Eso demostraba que QNetd había arrancado automáticamente tras el reboot del router.

35. Verificar que Proxmox se reconecta automáticamente

En miniproxmox:

corosync-qdevice-tool -s

El estado volvió automáticamente a:

QNetd host: 192.168.1.1:5403 State: Connected

Y:

pvecm status

volvió a mostrar:

Expected votes: 3

Total votes: 3

Quorum: 2

Quorate: Yes

Por tanto, si reiniciamos el Flint, los Proxmox pierden temporalmente el voto del QDevice, pero cuando QNetd vuelve a arrancar los QDevice se reconectan automáticamente.

36. Un problema curioso que encontramos

Durante una de las pruebas ocurrió algo extraño.

El servicio indicaba estar habilitado:

/etc/init.d/qnetd-debian enabled

pero QNetd no estaba ejecutándose.

Comprobamos:

pidof corosync-qnetd

y no obteníamos PID.

Tampoco había nada escuchando:

bash
netstat -lntp 2>/dev/null |
    grep 5403

Revisamos entonces el script:

wc -l /etc/init.d/qnetd-debian

Y descubrimos:

0 /etc/init.d/qnetd-debian

El fichero se había quedado vacío.

Sin embargo, seguían existiendo:

/etc/rc.d/S98qnetd-debian

/etc/rc.d/K10qnetd-debian

Por eso OpenWrt podía indicar que el servicio estaba habilitado aunque realmente no hubiese nada que ejecutar.

Reconstruimos el script y repetimos completamente la prueba de reboot.

Desde entonces arrancó correctamente.

La conclusión es importante:

no basta con comprobar que un servicio está habilitado.

Conviene verificar además:

bash
pidof corosync-qnetd
netstat -lntp 2>/dev/null | grep 5403
ubus call service list \ '{"name":"qnetd-debian"}'

37. Diagnóstico rápido si QNetd no arranca

Primero comprobamos que el script existe y tiene contenido:

bash
wc -l /etc/init.d/qnetd-debian
cat /etc/init.d/qnetd-debian

Después:

/etc/init.d/qnetd-debian enabled

Buscamos el proceso:

pidof corosync-qnetd

Puerto:

bash
netstat -lntp 2>/dev/null |
    grep 5403

Estado en procd:

bash
ubus call service list \
    '{"name":"qnetd-debian"}'

Y si queremos probar QNetd fuera de procd:

bash
timeout 5 /usr/bin/env -i \
    PATH=/usr/sbin:/usr/bin:/sbin:/bin \
    /usr/sbin/chroot --userspec=100:101 \
    /opt/debian-qnetd \
    /usr/bin/corosync-qnetd \
    -f -4 \
    -l 192.168.1.1 \
    -p 5403 \
    -s req

echo "EXIT=$?"

Si devuelve:

124

significa que el daemon seguía vivo cuando timeout lo terminó.

En ese caso probablemente tenemos un problema con el servicio procd, no con QNetd.

38. Diagnóstico rápido desde Proxmox

Comprobamos primero los servicios:

bash
systemctl is-active corosync
systemctl is-active corosync-qdevice

Después:

corosync-qdevice-tool -s

Lo correcto es:

State: Connected

Y:

pvecm status

debe mostrar:

Total votes: 3

Quorate: Yes

Si aparece:

Cannot initialize CMAP service

no significa necesariamente que QNetd esté fallando.

Conviene comprobar primero:

systemctl is-active corosync

Durante mis pruebas tuvimos precisamente una incidencia de este tipo y acabó resultando ser un problema independiente de QNetd relacionado con unos montajes NFS del host Proxmox.

39. Valores que debes adaptar a tu instalación

No hay que copiar literalmente todos los valores de esta guía.

Dirección del Flint

En mi caso:

192.168.1.1

Nodos Proxmox

192.168.1.6

192.168.1.7

Nombre del clúster

hectormox

Compruébalo con:

pvecm status

Arquitectura

Mi Flint es:

ARM64

pero debemos comprobar:

uname -m

UID y GID de coroqnetd

En mi instalación:

100:101

Pero hay que consultar:

bash
chroot /opt/debian-qnetd \
    id coroqnetd

Ruta de Debian

Yo elegí:

/opt/debian-qnetd

No es obligatoria.

Versión de Debian

En esta guía:

Debian 12 Bookworm

TLS

Mi versión utilizaba:

-s req

Hay que comprobarlo con:

bash
chroot /opt/debian-qnetd \
    /usr/bin/corosync-qnetd \
    -h

config_version

No copies:

3 → 4

Hay que incrementar en uno el valor que tenga actualmente nuestro corosync.conf.

40. Resultado final

Después de completar todo el proceso el Flint 3 queda funcionando así:

Código
OpenWrt
└── Debian 12 ARM64 en chroot
    └── corosync-qnetd

QNetd:

192.168.1.1:5403

TLS

procd

respawn

arranque automático

Y el clúster:

Código
miniproxmox  → QDevice ─┐
                         ├──→ Flint 3 / QNetd
zimaproxmox  → QDevice ─┘

El resultado final que podemos comprobar con:

corosync-qdevice-tool -s

es:

QNetd host: 192.168.1.1:5403

State: Connected

Y con:

pvecm status

obtenemos:

Expected votes: 3

Total votes: 3

Quorum: 2

Quorate: Yes

Lo interesante de esta solución es que no hemos convertido el Flint 3 en un servidor Debian ni hemos sustituido OpenWrt.

El Flint continúa siendo nuestro router OpenWrt.

Simplemente aprovechamos que tenemos un dispositivo ARM64 siempre encendido, con almacenamiento suficiente y soporte para chroot, para crear una Debian mínima dedicada a ejecutar QNetd.

De esta forma podemos disponer de un tercer voto físicamente independiente para un clúster Proxmox de dos nodos sin mantener encendido otro servidor únicamente para ejecutar el árbitro.

¿Dónde comprarlo?

Si te interesa el GL.iNet GL-BE9300 Flint 3, aquí tienes las opciones de compra disponibles:

Video relacionado

CUPONES ALIEXPRESS