How to Turn a GL.iNet Flint 3 with OpenWrt into QNetd for a Proxmox Cluster
A two-node Proxmox cluster has a well-known problem: to maintain quorum, we need to avoid situations where each node has exactly half the votes. A common solution is to add a QDevice, which uses a separate third machine running QNetd to act as an arbitrator. In my case, I already had a working QDevice, but QNetd was hosted on another machine. I wanted to remove that dependency and make use of a device that is almost always on and physically independent of the Proxmox servers: my GL.iNet Flint 3 router (GL-BE9300). The problem is that the Flint 3 uses OpenWrt, not Debian, and the repositories available in my firmware do not include corosync-qnetd. Important: this guide documents the exact solution I used in my installation. OpenWrt, GL.iNet, Debian, Corosync, and Proxmox evolve, so check versions, paths, and parameters before copying them verbatim.
On YouTube I share more tutorials, hands-on tests and real smart home setups. Subscribe on YouTube

Related video on YouTube
Video1. The environment used
In my installation:
Router:
GL.iNet Flint 3 / GL-BE9300
IP: 192.168.1.1
OpenWrt 23.05-SNAPSHOT
ARM64 architecture
Cluster:
Name: hectormox
Node 1:
miniproxmox
192.168.1.6
Node 2:
zimaproxmox
192.168.1.7The minimal Debian system was installed at:
/opt/debian-qnetd
QNetd listens on the standard port:
TCP 5403
2. Connect to the Flint 3 over SSH
From Windows, we can use the SSH client included with PowerShell:
ssh root@192.168.1.1
Enter the router’s administrator password.
Once connected, we should see something similar to:
BusyBox
OpenWrt
root@GL-BE9300:~#Before installing anything, it is worth finding out exactly what we have.
3. Check the system, architecture, packages, and available space
Run:
cat /etc/os-release
cat /etc/openwrt_release
uname -a
uname -m
command -v opkg
command -v apk
opkg print-architecture
df -hOn my Flint, I found a system with:
OpenWrt 23.05-SNAPSHOT
aarch64
and opkg as the package manager.
I also checked which tools were available:
command -v ar
command -v tar
command -v gzip
command -v xz
command -v wget
command -v curl
command -v mount
command -v chrootAnd, especially, whether OpenWrt already provided Corosync:
opkg update
opkg list | grep -Ei 'corosync|qnetd|qdevice|libnss|libqb'My firmware did not include corosync-qnetd.
So we could not simply run:
opkg install corosync-qnetd
as we would with a native OpenWrt package.
4. Why use a minimal Debian system inside OpenWrt
Instead of trying to compile Corosync and all its dependencies directly for OpenWrt, I chose a much simpler solution:
create a minimal ARM64 Debian system in a directory and run QNetd through chroot.
OpenWrt remains the router’s operating system. We do not install another kernel, virtualize anything, or replace the firmware.
The layout is simply:
OpenWrt
└── /opt/debian-qnetd
└── Debian 12 ARM64
└── corosync-qnetdIn other words, the Flint continues to work as an OpenWrt router, but it has a small Debian environment from which we can run software that is not available in its repositories.
5. Install debootstrap on the Flint
First, update the package indexes:
opkg update
Install debootstrap:
opkg install debootstrap
Check that it is available:
command -v debootstrap
debootstrap --versionThen check the available space:
df -h /overlay
In my case, several gigabytes were free, which was enough for a minimal Debian system.
6. GPG issue with Debian Bookworm
This is where one of the first issues specific to my OpenWrt version appeared.
debootstrap needs to verify the signatures of the Debian repositories, but the gpgv initially available on the router was too old for some signatures used by Bookworm.
The solution was to install:
opkg install gpgv2
We can check it with:
gpgv2 --version
We also need the official Debian keys.
Create a temporary directory:
BASE="/tmp/qnetd-bootstrap"
mkdir -p "$BASE"
mkdir -p "$BASE/bin"Download the debian-archive-keyring package for Debian Bookworm.
It is a good idea to check which package version is current when following this guide, rather than relying on a specific URL indefinitely. instead of permanently copying a specific URL.
Once it has been downloaded:
DEB="$BASE/debian-archive-keyring.deb"
Extract its contents:
ar p "$DEB" data.tar.xz |
xz -dc |
tar -xf - -C "$BASE"The key is available at:
KEY="$BASE/usr/share/keyrings/debian-archive-keyring.gpg"
ls -l "$KEY"To make sure debootstrap uses gpgv2, create a small temporary override:
ln -sf /usr/bin/gpgv2 "$BASE/bin/gpgv"
This only affects the PATH used when running debootstrap.
7. Create a Debian 12 ARM64 minbase system
Set the installation path:
TARGET="/opt/debian-qnetd"
Run:
PATH="$BASE/bin:$PATH" \
debootstrap \
--arch=arm64 \
--variant=minbase \
--keyring="$KEY" \
bookworm \
"$TARGET" \
https://deb.debian.org/debianThis downloads and installs a minimal Debian 12 system in:
/opt/debian-qnetd
Check its contents:
ls -la /opt/debian-qnetd
Then enter it manually:
chroot /opt/debian-qnetd /bin/bash
To return to OpenWrt:
exit
8. Update Debian and install QNetd
From OpenWrt itself, we can run commands directly inside the chroot:
chroot "$TARGET" /usr/bin/apt-get update
Before installing it, check that the package is available:
chroot "$TARGET" \
/usr/bin/apt-cache policy corosync-qnetdIn my case, Debian offered:
corosync-qnetd 3.0.3-1
The initial installation found some pending dependencies in the minbase environment.
First, I repaired the package database with:
chroot "$TARGET" \
/usr/bin/apt-get --no-remove -y --fix-broken installThen I installed:
chroot "$TARGET" \
/usr/bin/apt-get install -y \
--no-install-recommends \
corosync-qnetd \
libnss3-toolsAmong the dependencies Debian installed were NSS libraries, Perl, netbase and other required packages.
9. /proc and /dev/pts during installation
During installation, some warnings appeared concerning /proc and /dev/pts.
I mounted these temporarily:
mount -o bind \
/proc \
/opt/debian-qnetd/procAnd:
mount -o bind \
/dev/pts \
/opt/debian-qnetd/dev/ptsThis helped us while preparing Debian.
We later confirmed that QNetd does not need these bind mounts to run normally, so they are not part of the final service.
10. Initialize the QNetd certificates
QNetd uses an NSS database to manage its certificates.
Our Debian system includes this utility:
corosync-qnetd-certutil
Initialize it from OpenWrt:
chroot /opt/debian-qnetd \
/usr/bin/corosync-qnetd-certutil \
-iFrom OpenWrt, the NSS database is located at:
/opt/debian-qnetd/etc/corosync/qnetd/nssdb
Check it with:
ls -lah \
/opt/debian-qnetd/etc/corosync/qnetd/nssdbInside the chroot, the same path is:
/etc/corosync/qnetd/nssdb
The public CA is located at:
/opt/debian-qnetd/etc/corosync/qnetd/nssdb/qnetd-cacert.crt
11. Check the user coroqnetd
The Debian package creates a dedicated user to run QNetd.
Check its IDs:
chroot /opt/debian-qnetd id coroqnetd
In my installation, I got:
UID 100
GID 101
This matters because later I will run QNetd with:
--userspec=100:101
Do not copy these numbers without checking them first.
Run this on each installation:
chroot /opt/debian-qnetd id coroqnetd
and use the values it returns.
We also check the NSS database permissions:
DB="/opt/debian-qnetd/etc/corosync/qnetd/nssdb"
ls -ln "$DB"In my case, I had to adjust:
chgrp 101 \
"$DB/pwdfile.txt" \
"$DB/pkcs11.txt"
chmod 640 \
"$DB/pwdfile.txt" \
"$DB/pkcs11.txt"Again, 101 was the specific GID in my installation.
12. Test QNetd manually
Before turning it into a service, it is important to check that the daemon actually starts.
I tested:
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 reqThe parameters used are:
-f: run in the foreground.-4: use IPv4.-l 192.168.1.1: address where QNetd listens.-p 5403: port.-s req: require TLS in the version we are using.
Before copying this, check the help for the installed version:
chroot /opt/debian-qnetd \
/usr/bin/corosync-qnetd \
-h13. OpenWrt’s LD_PRELOAD issue
When running Debian programs from OpenWrt, warnings appeared about an OpenWrt firmware LD_PRELOAD variable.
To prevent the chroot process from inheriting OpenWrt-specific variables, I ended up running it with a clean environment:
/usr/bin/env -i \
PATH=/usr/sbin:/usr/bin:/sbin:/bin \
...This detail became part of the final service.
14. Create the QNetd service in OpenWrt
This is one of the most important differences from a standard Debian system.
On Debian, we would use systemd.
On OpenWrt, we use procd and scripts under:
/etc/init.d/
Create:
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
}
EOFSet the permissions:
chmod 755 /etc/init.d/qnetd-debian
Enable automatic startup:
/etc/init.d/qnetd-debian enable
Check the links that were created:
ls -l /etc/rc.d/*qnetd*
On my Flint, these were:
/etc/rc.d/S98qnetd-debian
/etc/rc.d/K10qnetd-debian
Start the service:
/etc/init.d/qnetd-debian start
15. Check that QNetd is running
First, find the process:
pidof corosync-qnetd
Then check the port:
netstat -lntp 2>/dev/null | grep 5403
We should see:
192.168.1.1:5403 LISTEN
We can also check the full process:
ps w | grep '[c]orosync-qnetd'
And query procd directly:
ubus call service list \
'{"name":"qnetd-debian"}'A healthy status contains:
"running": true
In my case, we could also see:
/usr/bin/corosync-qnetd
-f
-4
-l 192.168.1.1
-p 5403
-s req16. Check respawning
The service includes:
procd_set_param respawn 3600 5 5
This allows procd to restart QNetd if the process exits unexpectedly.
During testing, we killed the process manually and confirmed that it reappeared with a new PID and started listening again at:
192.168.1.1:5403
17. Prepare Proxmox
Now move to the first cluster node:
ssh root@192.168.1.6
Check the current status:
pvecm status
And:
corosync-qdevice-tool -s
My cluster is called:
hectormox
Previously, it had another QNetd at:
192.168.1.5:5403
The new one will be:
192.168.1.1:5403
18. Back up before changing QDevice
Before touching the certificates, I made a backup of:
/etc/corosync/qdevice
/etc/pve/corosync.conf
For example:
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"I do not recommend continuing without this backup.
19. Create a new NSS database on Proxmox
On miniproxmox:
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. Copy the Flint CA to Proxmox
From miniproxmox:
scp \
root@192.168.1.1:/opt/debian-qnetd/etc/corosync/qnetd/nssdb/qnetd-cacert.crt \
/root/qnetd-migration/qnetd-cacert.crtImport the CA:
certutil -A \
-d "sql:$DB" \
-n "QNet CA" \
-t "CT,c,c" \
-i "$DIR/qnetd-cacert.crt" \
-f "$PASS"Check:
certutil -L \
-d "sql:$DB" \
-f "$PASS"We should see:
QNet CA CT,c,c
21. Create the cluster CSR
Generate some entropy:
dd if=/dev/urandom \
of="$DIR/noise-new.txt" \
bs=1024 \
count=1 \
status=noneCreate the CSR:
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"Replace:
hectormox
with the actual cluster name.
Check it with:
pvecm status
22. Send the CSR to the Flint
From Proxmox:
scp \
"$CSR" \
root@192.168.1.1:/opt/debian-qnetd/tmp/hectormox.crqConnect to the Flint again:
ssh root@192.168.1.1
Then sign it:
chroot /opt/debian-qnetd \
/usr/bin/corosync-qnetd-certutil \
-s \
-c /tmp/hectormox.crq \
-n hectormoxThe signed certificate is located at:
/opt/debian-qnetd/etc/corosync/qnetd/nssdb/cluster-hectormox.crt
23. Retrieve the signed certificate
From miniproxmox:
scp \
root@192.168.1.1:/opt/debian-qnetd/etc/corosync/qnetd/nssdb/cluster-hectormox.crt \
/root/qnetd-migration/cluster-hectormox.crtWe can convert it to PEM:
cd /root/qnetd-migration
openssl x509 \
-inform DER \
-in cluster-hectormox.crt \
-out cluster-hectormox.pemThen verify it:
openssl verify \
-CAfile qnetd-cacert.crt \
cluster-hectormox.pemThe expected result is:
OK
24. Import the cluster certificate
Add the signed certificate to NSS:
certutil -A \
-d "sql:$DB" \
-n "Cluster Cert" \
-t "u,u,u" \
-i "$DIR/cluster-hectormox.crt" \
-f "$PASS"Check:
certutil -L \
-d "sql:$DB" \
-f "$PASS"The following entries should now appear:
QNet CA CT,c,c
Cluster Cert u,u,u
25. Export the certificate and private key to PKCS#12
Generate:
pk12util \
-o "$DIR/qdevice-net-node.p12" \
-d "sql:$DB" \
-k "$PASS" \
-W "" \
-n "Cluster Cert"Expected result:
PKCS12 EXPORT SUCCESSFUL
This file contains a private key. Do not publish or share it.
26. Prepare the second Proxmox node
Copy to the second node:
scp \
/root/qnetd-migration/qnetd-cacert.crt \
root@192.168.1.7:/root/qnetd-migration/And:
scp \
/root/qnetd-migration/qdevice-net-node.p12 \
root@192.168.1.7:/root/qnetd-migration/On zimaproxmox:
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"Import the CA:
certutil -A \
-d "sql:$DB" \
-n "QNet CA" \
-t "CT,c,c" \
-i "$CA" \
-f "$PASS"Import the PKCS#12 file:
pk12util \
-i "$P12" \
-d "sql:$DB" \
-k "$PASS" \
-W ""The expected result is:
PKCS12 IMPORT SUCCESSFUL
Then check:
certutil -L \
-d "sql:$DB" \
-f "$PASS"27. Prepare a permanent NSS database
Before touching the database actually used by QDevice, I prepared another directory:
/root/qnetd-migration/nssdb-ready
On each node:
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"Check:
certutil -L \
-d "sql:$READY" \
-f "$READY/pwdfile.txt"We can also verify the identity:
certutil -L \
-d "sql:$READY" \
-n "Cluster Cert" \
-a |
openssl x509 \
-noout \
-subject \
-issuerIn my case:
subject=CN=hectormox
issuer=CN=QNet CA
28. Replace the active credentials
We performed this step one node at a time.
Stop only QDevice:
systemctl stop corosync-qdevice
Do not stop Corosync.
Save the old database:
ACTIVE="/etc/corosync/qdevice/net/nssdb"
BACKUP="${ACTIVE}.pre-glinet-$(date +%Y%m%d-%H%M%S)"
mv "$ACTIVE" "$BACKUP"Copy the new one:
cp -a \
/root/qnetd-migration/nssdb-ready \
"$ACTIVE"Adjust the permissions:
chown -R root:root "$ACTIVE"
chmod 700 "$ACTIVE"
chmod 600 "$ACTIVE"/*Check:
certutil -L \
-d "sql:$ACTIVE" \
-f "$ACTIVE/pwdfile.txt"Then start QDevice:
systemctl start corosync-qdevice
Repeat the same procedure on the other node.
29. Change the IP address of the old QNetd
In my case, QDevice was already configured to use another server:
192.168.1.5
and I needed to switch it to the Flint:
192.168.1.1
I made another backup first:
cp \
/etc/pve/corosync.conf \
"/root/corosync-pre-glinet-$(date +%Y%m%d-%H%M%S).conf"The change was:
- host: 192.168.1.5
+ host: 192.168.1.1
We also increased:
- config_version: 3
+ config_version: 4
The relevant section looked like this:
quorum {
device {
model: net
net {
algorithm: ffsplit
host: 192.168.1.1
tls: on
}
votes: 1
}
}Keep in mind that config_version must be incremented from the value used by each installation.
Do not copy 3 → 4 literally.
30. Restart QDevice only
After the change, Corosync adopted the new configuration, but the QDevice process kept using the old address until it was restarted.
Run:
systemctl restart corosync-qdevice
Check:
corosync-qdevice-tool -s
The expected result was:
Cluster name: hectormox
QNetd host: 192.168.1.1:5403
Algorithm: Fifty-Fifty split
State: Connected
Repeat the QDevice restart on the second node.
31. Check quorum
Run:
pvecm status
In our case, the final result was:
Expected votes: 3 Highest expected: 3 Total votes: 3 Quorum: 2 Quorate: Yes
And in the member information:
0x00000001 1 A,V,NMW 192.168.1.6
0x00000002 1 A,V,NMW 192.168.1.7
0x00000000 1 Qdevice
That is:
miniproxmox: 1 vote.zimaproxmox: 1 vote.- QDevice/QNetd: 1 vote.
Total:
3 votes
and the required quorum is still:
2
32. Make a full backup of the Flint QNetd
Once everything was done, I made a full backup of the environment.
Set:
SERVICE="/etc/init.d/qnetd-debian"
BACKUP="/overlay/qnetd-backup-completo-$(date +%Y%m%d-%H%M%S).tar.gz"Stop QNetd briefly:
"$SERVICE" stop
Create the backup:
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-debianStart it again:
"$SERVICE" start
Check the integrity:
tar -tzf "$BACKUP" >/dev/null
sha256sum "$BACKUP"
ls -lh "$BACKUP"My final backup was approximately:
157 MB
33. Download the backup to Windows
From PowerShell:
scp -O `
root@192.168.1.1:/overlay/qnetd-backup-completo-XXXXXXXX.tar.gz `
"$env:USERPROFILE\Downloads\"Then calculate the hash:
Get-FileHash `
"$env:USERPROFILE\Downloads\qnetd-backup-completo-XXXXXXXX.tar.gz" `
-Algorithm SHA256The value must exactly match the one obtained earlier on the Flint.
The backup contains certificates and private keys, so it must be stored securely., so it must be stored securely.
34. Test the system after restarting the Flint
I did not want to consider the project finished just because it worked after starting it manually.
I restarted the Flint 3 from its web interface.
When it was available again, I connected once more:
ssh root@192.168.1.1
First, I checked that the script was still there:
wc -l /etc/init.d/qnetd-debian
Then:
pidof corosync-qnetd
I checked the port:
netstat -lntp 2>/dev/null | grep 5403
And finally, procd:
ubus call service list \
'{"name":"qnetd-debian"}'In the final test, I got:
23 /etc/init.d/qnetd-debian
a valid PID:
28139
the port:
192.168.1.1:5403 LISTEN
and:
"running": true
This showed that QNetd had started automatically after the router rebooted.
35. Verify that Proxmox reconnects automatically
On miniproxmox:
corosync-qdevice-tool -s
The status automatically returned to:
QNetd host: 192.168.1.1:5403 State: Connected
And:
pvecm status
showed again:
Expected votes: 3
Total votes: 3
Quorum: 2
Quorate: Yes
Therefore, when we restart the Flint, the Proxmox nodes temporarily lose the QDevice vote, but once QNetd starts again, the QDevices reconnect automatically.
36. A curious issue we found
Something strange happened during one of the tests.
The service was shown as enabled:
/etc/init.d/qnetd-debian enabled
but QNetd was not running.
We checked:
pidof corosync-qnetd
but got no PID.
Nothing was listening either:
netstat -lntp 2>/dev/null |
grep 5403So we checked the script:
wc -l /etc/init.d/qnetd-debian
And found:
0 /etc/init.d/qnetd-debian
The file had become empty.
However, these still existed:
/etc/rc.d/S98qnetd-debian
/etc/rc.d/K10qnetd-debian
That is why OpenWrt could report that the service was enabled even though there was actually nothing to run.
We rebuilt the script and repeated the full reboot test.
After that, it started correctly.
The takeaway is important:
checking that a service is enabled is not enough.
It is also a good idea to check:
pidof corosync-qnetd
netstat -lntp 2>/dev/null | grep 5403
ubus call service list \ '{"name":"qnetd-debian"}'37. Quick troubleshooting if QNetd will not start
First, check that the script exists and is not empty:
wc -l /etc/init.d/qnetd-debian
cat /etc/init.d/qnetd-debianThen:
/etc/init.d/qnetd-debian enabled
Find the process:
pidof corosync-qnetd
Port:
netstat -lntp 2>/dev/null |
grep 5403Status in procd:
ubus call service list \
'{"name":"qnetd-debian"}'To test QNetd outside procd:
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=$?"If it returns:
124
it means the daemon was still running when timeout stopped it.
In that case, the problem is probably with the procd service, not QNetd.
38. Quick troubleshooting from Proxmox
First, check the services:
systemctl is-active corosync
systemctl is-active corosync-qdeviceThen:
corosync-qdevice-tool -s
The correct result is:
State: Connected
And:
pvecm status
should show:
Total votes: 3
Quorate: Yes
If you see:
Cannot initialize CMAP service
that does not necessarily mean QNetd is failing.
It is a good idea to check this first:
systemctl is-active corosync
During my tests, we encountered exactly this kind of issue. It turned out to be unrelated to QNetd and was caused by NFS mounts on the Proxmox host.
39. Values to adapt to your installation
Do not copy all the values in this guide literally.
Flint address
In my case:
192.168.1.1
Proxmox nodes
192.168.1.6
192.168.1.7
Cluster name
hectormox
Check it with:
pvecm status
Architecture
My Flint is:
ARM64
but we should check with:
uname -m
UID and GID for coroqnetd
In my installation:
100:101
But check with:
chroot /opt/debian-qnetd \
id coroqnetdDebian path
I chose:
/opt/debian-qnetd
It is not required.
Debian version
In this guide:
Debian 12 Bookworm
TLS
My version used:
-s req
Check it with:
chroot /opt/debian-qnetd \
/usr/bin/corosync-qnetd \
-hconfig_version
Do not copy:
3 → 4
Increment the current value in our corosync.conf.
40. Final result
After completing the whole process, the Flint 3 works like this:
OpenWrt
└── Debian 12 ARM64 in chroot
└── corosync-qnetdQNetd:
192.168.1.1:5403
TLS
procd
respawn
automatic startup
And the cluster:
miniproxmox → QDevice ─┐
├──→ Flint 3 / QNetd
zimaproxmox → QDevice ─┘The final result, which we can check with:
corosync-qdevice-tool -s
is:
QNetd host: 192.168.1.1:5403
State: Connected
And with:
pvecm status
we get:
Expected votes: 3
Total votes: 3
Quorum: 2
Quorate: Yes
The useful thing about this solution is that we have not turned the Flint 3 into a Debian server or replaced OpenWrt.
The Flint remains our OpenWrt router.
We simply make use of an always-on ARM64 device with enough storage and support for chroot, to create a minimal Debian system dedicated to running QNetd.
This gives us a physically independent third vote for a two-node Proxmox cluster without keeping another server running solely to act as the arbitrator.
Recommended gear
Device used in this project: GL.iNet GL-BE9300 Flint 3. If you need it, here is where to find it:
- GL.iNet GL-BE9300 Flint 3 — Reviewed in the video: AliExpress España · AliExpress desde Europa · AliExpress Oficial GL.iNet · Amazon


