Auto-update blog content from Obsidian: 2026-05-24 20:12:49
All checks were successful
Blog Deployment / Merge (push) Successful in 6s
Blog Deployment / Deploy-Production (push) Successful in 1m3s
Blog Deployment / Test-Production (push) Successful in 3s
Blog Deployment / Clean (push) Has been skipped
Blog Deployment / Notify (push) Successful in 2s
Blog Deployment / Check-Rebuild (push) Successful in 6s
Blog Deployment / Build (push) Has been skipped
Blog Deployment / Deploy-Staging (push) Successful in 1m3s
Blog Deployment / Test-Staging (push) Successful in 2s
All checks were successful
Blog Deployment / Merge (push) Successful in 6s
Blog Deployment / Deploy-Production (push) Successful in 1m3s
Blog Deployment / Test-Production (push) Successful in 3s
Blog Deployment / Clean (push) Has been skipped
Blog Deployment / Notify (push) Successful in 2s
Blog Deployment / Check-Rebuild (push) Successful in 6s
Blog Deployment / Build (push) Has been skipped
Blog Deployment / Deploy-Staging (push) Successful in 1m3s
Blog Deployment / Test-Staging (push) Successful in 2s
This commit is contained in:
@@ -0,0 +1,283 @@
|
||||
---
|
||||
slug: migrate-passive-opnsense-node-to-truenas
|
||||
title: Migrate my Passive OPNsense HA Node to TrueNAS
|
||||
description: I migrated my passive OPNsense HA VM from Proxmox to TrueNAS to keep routing and firewalling available even when my Proxmox cluster is down.
|
||||
date: 2026-05-24
|
||||
draft: true
|
||||
tags:
|
||||
- opnsense
|
||||
- truenas
|
||||
- proxmox
|
||||
- high-availability
|
||||
categories:
|
||||
- homelab
|
||||
---
|
||||
## Intro
|
||||
|
||||
Mon réseau homelab est géré par un cluster OPNsense composé de deux nœuds VM. Ces deux VM fonctionnent dans mon cluster Proxmox VE. Vous pouvez trouver les détails dans cet [article]({{< ref "post/15-migration-opnsense-proxmox-highly-available" >}}).
|
||||
|
||||
Cette configuration fonctionne bien la plupart du temps. Le problème concerne plutôt les rares cas où le cluster Proxmox lui-même est arrêté. Quand cela arrive, les deux nœuds OPNsense sont indisponibles en même temps, ce qui signifie qu’il ne me reste aucun routeur, donc aucun réseau du tout.
|
||||
|
||||
Récemment, j’ai installé un serveur TrueNAS dans le lab, que j'ai documenté dans ce [post]({{< ref "post/18-create-nas-server-with-truenas" >}}). Il est principalement là pour agir comme NAS, mais il pourrait aussi héberger des machines virtuelles. Cela me donne une bonne opportunité d’améliorer la résilience de mon réseau sans changer toute la conception.
|
||||
|
||||
💡 L’idée est simple : garder le nœud OPNsense actif sur Proxmox, mais déplacer le nœud passif vers TrueNAS.
|
||||
|
||||
De cette façon, si le cluster Proxmox tombe, le nœud OPNsense passif peut toujours prendre le relais et garder le réseau fonctionnel.
|
||||
|
||||
---
|
||||
## Préparer les nœuds OPNsense
|
||||
|
||||
Avant de déplacer quoi que ce soit, je veux m’assurer que les VM OPNsense peuvent fonctionner avec moins de mémoire.
|
||||
|
||||
Le serveur TrueNAS n’a pas autant de RAM disponible que le cluster Proxmox, donc la première étape est de réduire l’allocation mémoire des nœuds OPNsense au minimum.
|
||||
|
||||
Je commence avec le nœud passif, `cerbere-head2` :
|
||||
|
||||
- Éteindre le nœud passif
|
||||
- Réduire son allocation mémoire de 4 à 2GB
|
||||
- Le redémarrer
|
||||
- Vérifier la santé du cluster
|
||||
- Basculer le service vers le nœud passif
|
||||
- Exécuter des vérifications réseau
|
||||
|
||||
Ensuite, je répète la même opération sur le nœud actif, `cerbere-head1`.
|
||||
|
||||
Le faire un nœud à la fois me permet de garder le cluster HA en bonne santé tout en validant que l’allocation mémoire réduite est toujours suffisante pour ma configuration.
|
||||
|
||||
---
|
||||
## Préparer le réseau TrueNAS
|
||||
|
||||
La partie la plus importante de cette migration n’est pas l’export du disque ni la création de la VM. C’est le réseau.
|
||||
|
||||
Une VM OPNsense n’est pas un simple serveur avec une seule interface de management. Elle a besoin d’accéder à plusieurs réseaux, incluant le management, le WAN, les réseaux utilisateurs, l’IoT, pfSync, la DMZ et les réseaux lab.
|
||||
|
||||
Du côté TrueNAS, je commence depuis `System` > `Network` et j’ajoute des interfaces VLAN.
|
||||
|
||||
La première est le VLAN utilisateur :
|
||||
|
||||
- Type : `VLAN`
|
||||
- Nom : `vlan13`
|
||||
- Description : `User`
|
||||
- Interface parente : `enp1s0`
|
||||
- Tag VLAN : `13`
|
||||
|
||||

|
||||
|
||||
J’ajoute ensuite les autres VLANs de la même manière.
|
||||
|
||||
TrueNAS n’applique pas les changements réseau directement. Il donne l’option de tester les changements d’abord, avec une courte fenêtre de validation. Si la configuration n’est pas confirmée à temps, il revient automatiquement en arrière.
|
||||
|
||||
C’est vraiment pratique lorsqu’on change la configuration réseau de la machine à laquelle on est actuellement connecté.
|
||||
|
||||

|
||||
|
||||
Pour le réseau de management, j’ai créé un bridge appelé `br1`.
|
||||
|
||||
Ce bridge porte la configuration IP de management de TrueNAS à la place de l’interface physique `enp1s0`, parce qu’elle doit aussi être partagée avec la VM OPNsense.
|
||||
|
||||

|
||||
|
||||
Après cela, je retire la configuration IP de l’interface physique et je la garde sur le bridge.
|
||||
|
||||

|
||||
|
||||
J’ai initialement essayé d’utiliser DHCP pour le bridge de management après avoir mis à jour l’adresse MAC dans Dnsmasq, mais j’ai finalement décidé de garder une adresse IP statique pour TrueNAS. Après certains changements réseau, DHCP a donné une autre adresse du pool, donc l’adressage statique était l’option la plus sûre et la plus simple pour ce serveur.
|
||||
|
||||
Pour la VM OPNsense, je crée un bridge pour chaque VLAN. Par exemple, `br13` utilise `vlan13`, je déplace aussi la description, comme `User`, de l’interface VLAN vers le bridge pour plus de clarté.
|
||||
|
||||
La configuration réseau finale de TrueNAS :
|
||||
|
||||

|
||||
|
||||
---
|
||||
## Create a Temporary Export Dataset
|
||||
|
||||
To move the passive OPNsense VM disk from Proxmox to TrueNAS, I first need a place to export the disk image.
|
||||
|
||||
In TrueNAS, I create a dataset named `storage/vm/disk`, then create a NFS share from it.
|
||||
|
||||
In the advanced options of the NFS share, I configured:
|
||||
|
||||
- Maproot user: `root`
|
||||
- Authorized hosts:
|
||||
- `192.168.88.21`
|
||||
- `192.168.88.22`
|
||||
- `192.168.88.23`
|
||||
|
||||
These are the Proxmox VE nodes allowed to mount the share.
|
||||
|
||||
I don't manually create a zvol at that point. The VM creation process in TrueNAS handle the disk import and conversion.
|
||||
|
||||
---
|
||||
## Export the VM Disk from Proxmox
|
||||
|
||||
From the Proxmox VE web interface, I locate the node hosting the passive OPNsense VM `cerbere-head2`, it is running on `Zenith`.
|
||||
|
||||
I log into that Proxmox node over SSH and mount the NFS share from TrueNAS:
|
||||
|
||||
```bash
|
||||
mount granite.mgmt.vezpi.com:/mnt/storage/vm/disk /mnt
|
||||
```
|
||||
|
||||
Then I shut down the VM from the Proxmox VE interface. I don't shut it down from inside OPNsense because the VM has HA enabled.
|
||||
|
||||
Once the VM is stopped, I export the main disk to qcow2. I don't export the EFI disk.
|
||||
|
||||
```bash
|
||||
qemu-img convert -f raw -O qcow2 -p \
|
||||
rbd:ceph-workload/vm-123-disk-1 \
|
||||
/mnt/cerbere-head2.qcow2
|
||||
```
|
||||
|
||||
The conversion took about one minute for a 20 GB disk.
|
||||
|
||||
At this point, the passive OPNsense disk is available on TrueNAS and ready to be imported into a new VM.
|
||||
|
||||
---
|
||||
## Recreate the OPNsense VM in TrueNAS
|
||||
|
||||
The next step is to recreate the passive OPNsense VM in TrueNAS with parameters matching the original VM as closely as possible.
|
||||
|
||||
From the TrueNAS web interface, I go to the `Virtual Machines` section.
|
||||
|
||||

|
||||
|
||||
I create a new VM with these settings.
|
||||
|
||||
For the operating system:
|
||||
|
||||
- Guest Operating System: `FreeBSD`
|
||||
- Name: `cerberehead2`
|
||||
- System Clock: `Local`
|
||||
- Boot Method: `UEFI`
|
||||
- Enable Secure Boot: disabled
|
||||
- Enable Trusted Platform Module: disabled
|
||||
- Shutdown Timeout: `90`
|
||||
- Start on Boot: enabled
|
||||
- Enable Display VNC: disabled
|
||||
|
||||
The VM name does not use dashes because TrueNAS do not allow them there.
|
||||
|
||||
For CPU and memory:
|
||||
|
||||
- Virtual CPUs: `1`
|
||||
- Cores: `2`
|
||||
- Threads: `1`
|
||||
- CPU Mode: `Custom`
|
||||
- CPU Model: `qemu64`
|
||||
- Memory Size: `2 GiB`
|
||||
|
||||
For the disk:
|
||||
|
||||
- Create new disk image
|
||||
- Import Image: enabled
|
||||
- Image source: `/mnt/storage/vm/files/cerbere-head2.qcow2`
|
||||
- Disk Type: `VirtIO`
|
||||
- Storage Location: `storage/vm`
|
||||
- Size: `20 GiB`
|
||||
|
||||
For the first network interface:
|
||||
|
||||
- Adapter Type: `VirtIO`
|
||||
- MAC Address: keep the proposed one
|
||||
- Attach NIC: `br1: Mgmt`
|
||||
|
||||
I skip installation media and GPU configuration, then confirm the summary.
|
||||
|
||||

|
||||
|
||||
After confirmation, TrueNAS convert the imported qcow2 image into a zvol.
|
||||
|
||||

|
||||
|
||||
Once the VM is created, I open the VM details and add the remaining NICs.
|
||||
|
||||

|
||||
|
||||
For each additional NIC, I used VirtIO as the adapter type and attach it to the corresponding bridge.
|
||||
|
||||
For the WAN NIC, I copy the old MAC address because I use a single WAN IP address trick. I also increment the digit in the Device Order to keep the same as in Proxmox.
|
||||
|
||||

|
||||
|
||||
🎉 Finally I can start the OPNsense VM in TrueNAS.
|
||||
|
||||

|
||||
|
||||
---
|
||||
## Validate the HA cluster
|
||||
|
||||
Once the passive node is running on TrueNAS, I need to validate that the OPNsense HA cluster is still behaving correctly.
|
||||
|
||||
I start with basic checks on the passive node:
|
||||
|
||||
- Management interface ping from the bastion: `192.168.88.3`
|
||||
- User interface ping from a laptop: `192.168.13.3`
|
||||
- IoT interface ping: `192.168.37.3`
|
||||
- pfSync ping from the other node: `192.168.44.2`
|
||||
- DMZ interface ping: `192.168.55.3`
|
||||
- Lab interface ping from DockerVM: `192.168.66.3`
|
||||
|
||||
I also check that the node was accessible over SSH from my laptop using `192.168.13.3`, and that the web interface was reachable at:
|
||||
|
||||
```text
|
||||
https://192.168.13.3:4443
|
||||
```
|
||||
|
||||
Then I validate the OPNsense HA state:
|
||||
|
||||
- CARP VIP status must be `BACKUP` on all VIPs
|
||||
- HA status page must show that the active node can log in to the passive node
|
||||
- Services must be running as expected
|
||||
- HA service synchronization must work
|
||||
- Firmware update checks must be accessible
|
||||
|
||||
From the active node, I use the HA status page and force a full synchronization with `Synchronize and reconfigure all`.
|
||||
|
||||
---
|
||||
## Switchover Tests
|
||||
|
||||
Before testing failover, I start a SSH session to `dockerVM` to confirm that firewall states are preserved across nodes. I also start a ping from a laptop to `192.168.37.120`.
|
||||
|
||||
For the switchover test, I gracefully enable maintenance mode on the master node.
|
||||
|
||||
The new passive node become `MASTER`, and I validate the important services:
|
||||
|
||||
- Extra VLAN routing with ping to `192.168.37.120`
|
||||
- WAN access with ping to `8.8.8.8`
|
||||
- Firewall states by keeping the SSH session alive
|
||||
- External DNS resolution with `host redhat.com`
|
||||
- Internal DNS resolution with `host SLZB-06M.mgmt.vezpi.com`
|
||||
- Access to a random internet page
|
||||
- Caddy reverse proxy
|
||||
- Caddy layer4 proxy
|
||||
- Wireguard access from outside
|
||||
- mDNS by checking if the printer showed up
|
||||
|
||||
✅ The switchover is successful.
|
||||
|
||||
---
|
||||
## Failover Tests
|
||||
|
||||
After the graceful switchover test, I test a more direct failover scenario by forcing a poweroff of the active node.
|
||||
|
||||
I repeated the same validation checklist.
|
||||
|
||||
✅ The failover is successful.
|
||||
|
||||
Finally, I restart the active OPNsense VM.
|
||||
|
||||
🎯 At that point, the OPNsense HA cluster is operational again, with the passive node now running on TrueNAS instead of Proxmox.
|
||||
|
||||
---
|
||||
## Conclusion
|
||||
|
||||
This migration is a small but important improvement for my homelab.
|
||||
|
||||
Before, both OPNsense nodes depended on the Proxmox VE cluster. If the cluster was down, my whole network routing layer was down with it.
|
||||
|
||||
Now, the active node still runs on Proxmox, but the passive node runs on TrueNAS. This gives me a better separation between the virtualization cluster and the network failover layer.
|
||||
|
||||
Little disclaimer, while TrueNAS offers virtualization features, it is not comparable to Proxmox VE in terms of clustering and infrastructure management capabilities.
|
||||
|
||||
A note about QEMU Guest Agent, the OPNsense VM already had the QEMU Guest Agent installed before expert. In this setup, it does not seem useful because TrueNAS does not have it implemented as a hypervisor feature. I kept it installed anyway, because it is harmless.
|
||||
Reference in New Issue
Block a user