diff --git a/content/page/homelab/images/homelab-enclore-open-closed.png b/content/page/homelab/images/homelab-enclore-open-closed.png new file mode 100644 index 0000000..d5803df Binary files /dev/null and b/content/page/homelab/images/homelab-enclore-open-closed.png differ diff --git a/content/page/homelab/images/homelab-network-schema.png b/content/page/homelab/images/homelab-network-schema.png new file mode 100644 index 0000000..f3b50cc Binary files /dev/null and b/content/page/homelab/images/homelab-network-schema.png differ diff --git a/content/page/homelab/images/homelab-rack-legend.png b/content/page/homelab/images/homelab-rack-legend.png new file mode 100644 index 0000000..1abb659 Binary files /dev/null and b/content/page/homelab/images/homelab-rack-legend.png differ diff --git a/content/page/homelab/index.fr.md b/content/page/homelab/index.fr.md index a86ebf2..0bd7694 100644 --- a/content/page/homelab/index.fr.md +++ b/content/page/homelab/index.fr.md @@ -122,9 +122,9 @@ La meilleure solution que j'ai trouvée a été de percer deux trous de 40 mm a Voici à quoi ça ressemble : -![Front view of my homelab with legend](img/homelab-rack-legend.png) +![Vue de face de mon homelab avec légende](images/homelab-rack-legend.png) -![Different views of my homelab with open and closed enclosure](img/homelab-enclore-open-closed.png) +![Différentes vues de mon homelab avec armoire ouverte et fermée](images/homelab-enclore-open-closed.png) --- ## Stack Logicielle @@ -183,7 +183,7 @@ Cette configuration de proxy à deux couches centralise la gestion des certifica Pour un accès distant sécurisé, j'ai configuré **WireGuard** sur OPNsense. Ce VPN léger fournit une connectivité chiffrée à mon lab où que je sois, permettant ainsi de gérer tous mes services sans les exposer directement à Internet. #### Schéma Réseau -![Diagram of my home network ](img/homelab-network-schema.png) +![Schéma de mon réseau domestique](images/homelab-network-schema.png) ### Application diff --git a/content/page/homelab/index.md b/content/page/homelab/index.md index c51ca76..9da9b0f 100644 --- a/content/page/homelab/index.md +++ b/content/page/homelab/index.md @@ -121,9 +121,9 @@ Inside the rack, I also added two 80mm fans to help with airflow. To keep everyt Here what is look like: -![Front view of my homelab with legend](img/homelab-rack-legend.png) +![Front view of my homelab with legend](images/homelab-rack-legend.png) -![Different views of my homelab with open and closed enclosure](img/homelab-enclore-open-closed.png) +![Different views of my homelab with open and closed enclosure](images/homelab-enclore-open-closed.png) --- @@ -184,7 +184,7 @@ This two-layer proxy setup centralizes SSL certificate management in **Caddy** w For secure remote access, I configured **WireGuard** on OPNsense. This lightweight VPN provides encrypted connectivity to my lab from anywhere, allowing management of all my services without exposing them all directly to the internet. #### Network Diagram -![Diagram of my home network ](img/homelab-network-schema.png) +![Diagram of my home network ](images/homelab-network-schema.png) ### Application Let's dive into the fun part! What started as a modest setup meant to serve a few personal needs quickly turned into a full ecosystem of open source services, each solving a specific need or just satisfying curiosity. diff --git a/content/post/1-proxmox-cloud-init-vm-template/images/proxmox-download-iso-img.png b/content/post/1-proxmox-cloud-init-vm-template/images/proxmox-download-iso-img.png new file mode 100644 index 0000000..d15fda8 Binary files /dev/null and b/content/post/1-proxmox-cloud-init-vm-template/images/proxmox-download-iso-img.png differ diff --git a/content/post/1-proxmox-cloud-init-vm-template/index.fr.md b/content/post/1-proxmox-cloud-init-vm-template/index.fr.md index 5662155..daeb690 100644 --- a/content/post/1-proxmox-cloud-init-vm-template/index.fr.md +++ b/content/post/1-proxmox-cloud-init-vm-template/index.fr.md @@ -32,7 +32,7 @@ Tout d'abord, nous devons télécharger une image compatible cloud-init. Bien qu Trouvez des images compatibles cloud dans le [Guide des images OpenStack](https://docs.openstack.org/image-guide/obtain-images.html). Dans Proxmox, accédez à **Storage > ISO Images > Upload** pour uploader l'image téléchargée. -![Download window for ISO images in Proxmox](img/proxmox-download-iso-img.png) +![Fenêtre de téléchargement pour images ISO dans Proxmox](images/proxmox-download-iso-img.png) ## Créer la VM Ensuite, on crée une VM en utilisant la ligne de commande (CLI) depuis le nœud Proxmox avec la commande suivantes : diff --git a/content/post/1-proxmox-cloud-init-vm-template/index.md b/content/post/1-proxmox-cloud-init-vm-template/index.md index 1c39ffe..6bb629a 100644 --- a/content/post/1-proxmox-cloud-init-vm-template/index.md +++ b/content/post/1-proxmox-cloud-init-vm-template/index.md @@ -32,7 +32,7 @@ First, we need to download an image with cloud-init support. Although Rocky Linu Find cloud-ready images from the [OpenStack Image Guide](https://docs.openstack.org/image-guide/obtain-images.html). In Proxmox, navigate to **Storage > ISO Images > Upload** to upload the downloaded image. -![Download window for ISO images in Proxmox](img/proxmox-download-iso-img.png) +![Download window for ISO images in Proxmox](images/proxmox-download-iso-img.png) ## Create the VM diff --git a/content/post/10-opnsense-crash-disk-panic/images/homelab-network-schema.png b/content/post/10-opnsense-crash-disk-panic/images/homelab-network-schema.png new file mode 100644 index 0000000..f3b50cc Binary files /dev/null and b/content/post/10-opnsense-crash-disk-panic/images/homelab-network-schema.png differ diff --git a/content/post/10-opnsense-crash-disk-panic/images/opnsense-download-backup.png b/content/post/10-opnsense-crash-disk-panic/images/opnsense-download-backup.png new file mode 100644 index 0000000..bfd37d1 Binary files /dev/null and b/content/post/10-opnsense-crash-disk-panic/images/opnsense-download-backup.png differ diff --git a/content/post/10-opnsense-crash-disk-panic/index.fr.md b/content/post/10-opnsense-crash-disk-panic/index.fr.md index 486c2fd..eeedabf 100644 --- a/content/post/10-opnsense-crash-disk-panic/index.fr.md +++ b/content/post/10-opnsense-crash-disk-panic/index.fr.md @@ -21,7 +21,7 @@ Ce genre d’exercice est la pire chose que vous souhaitez voir arriver, parce q Ma box OPNsense tournait parfaitement depuis des mois. Routeur, pare-feu, DNS, DHCP, VLANs, VPN, reverse proxy et même contrôleur UniFi : toutes les pièces de mon homelab passe par elle. Mais pas seulement, elle fournit aussi Internet à la maison. -![Diagram of my home network ](img/homelab-network-schema.png) +![Le schéma réseau de mon Homelab](images/homelab-network-schema.png) Cette box est le cœur de mon réseau, sans elle, je ne peux quasiment rien faire. J’ai détaillé son fonctionnement dans ma section [Homelab]({{< ref "page/homelab" >}}). Tout “fonctionnait juste”, et je ne m’en inquiétait pas. J’étais confiant, sa sauvegarde vivait uniquement à l’intérieur de la machine… @@ -61,7 +61,7 @@ pkg: sqlite error while executing iterator in file pkgdb_iterator.c:1110: databa ``` 🚨 Mon alarme interne s'est déclenchée. J’ai pensé aux sauvegardes et j’ai immédiatement téléchargé la dernière : -![Backup configuration in OPNsense](img/opnsense-download-backup.png) +![Sauvegarde de configuration dans OPNsense](images/opnsense-download-backup.png) En cliquant sur le bouton `Download configuration`, j’ai récupéré le `config.xml` en cours d’utilisation. Je pensais que ça suffirait. diff --git a/content/post/10-opnsense-crash-disk-panic/index.md b/content/post/10-opnsense-crash-disk-panic/index.md index bdda277..39b89ec 100644 --- a/content/post/10-opnsense-crash-disk-panic/index.md +++ b/content/post/10-opnsense-crash-disk-panic/index.md @@ -21,7 +21,7 @@ This kind of exercise is the worst thing you want to happen because it's never f My OPNsense box had been running smoothly for months. Router, firewall, DNS, DHCP, VLANs, VPN, reverse proxy and even UniFi controller: all the pieces of my homelab run through it. but not only, it is also serving internet at home. -![Diagram of my home network ](img/homelab-network-schema.png) +![My Homelab network diagram](images/homelab-network-schema.png) This box is the heart of my network, without it, I can hardly do anything. I have detailed how this is working in my [Homelab]({{< ref "page/homelab" >}}) section. It was “just working,” and I wasn’t worried about it. I felt confident, its backup was living only inside the machine... @@ -62,7 +62,7 @@ pkg: sqlite error while executing iterator in file pkgdb_iterator.c:1110: databa ``` 🚨 My internal alarm sensor triggered, I wondered about backups, I immediately decided to download the latest backup: -![Backup configuration in OPNsense](img/opnsense-download-backup.png) +![Backup configuration in OPNsense](images/opnsense-download-backup.png) Clicking the `Download configuration` button, I downloaded the current `config.xml` in use my the instance, I though it was enough. diff --git a/content/post/11-proxmox-cluster-networking-sdn/images/proxmox-apply-sdn-homelan-configuration.png b/content/post/11-proxmox-cluster-networking-sdn/images/proxmox-apply-sdn-homelan-configuration.png new file mode 100644 index 0000000..e9b91c4 Binary files /dev/null and b/content/post/11-proxmox-cluster-networking-sdn/images/proxmox-apply-sdn-homelan-configuration.png differ diff --git a/content/post/11-proxmox-cluster-networking-sdn/images/proxmox-change-vm-nic-vlan-vnet.png b/content/post/11-proxmox-cluster-networking-sdn/images/proxmox-change-vm-nic-vlan-vnet.png new file mode 100644 index 0000000..bf285e0 Binary files /dev/null and b/content/post/11-proxmox-cluster-networking-sdn/images/proxmox-change-vm-nic-vlan-vnet.png differ diff --git a/content/post/11-proxmox-cluster-networking-sdn/images/proxmox-console-ping-vm-vlan-66.png b/content/post/11-proxmox-cluster-networking-sdn/images/proxmox-console-ping-vm-vlan-66.png new file mode 100644 index 0000000..c2f80a5 Binary files /dev/null and b/content/post/11-proxmox-cluster-networking-sdn/images/proxmox-console-ping-vm-vlan-66.png differ diff --git a/content/post/11-proxmox-cluster-networking-sdn/images/proxmox-create-vlan-vnet-homelan.png b/content/post/11-proxmox-cluster-networking-sdn/images/proxmox-create-vlan-vnet-homelan.png new file mode 100644 index 0000000..c18e584 Binary files /dev/null and b/content/post/11-proxmox-cluster-networking-sdn/images/proxmox-create-vlan-vnet-homelan.png differ diff --git a/content/post/11-proxmox-cluster-networking-sdn/images/proxmox-create-vlan-zone-homelan.png b/content/post/11-proxmox-cluster-networking-sdn/images/proxmox-create-vlan-zone-homelan.png new file mode 100644 index 0000000..b81f021 Binary files /dev/null and b/content/post/11-proxmox-cluster-networking-sdn/images/proxmox-create-vlan-zone-homelan.png differ diff --git a/content/post/11-proxmox-cluster-networking-sdn/images/proxmox-default-localnetwork-zone.png b/content/post/11-proxmox-cluster-networking-sdn/images/proxmox-default-localnetwork-zone.png new file mode 100644 index 0000000..b4d216e Binary files /dev/null and b/content/post/11-proxmox-cluster-networking-sdn/images/proxmox-default-localnetwork-zone.png differ diff --git a/content/post/11-proxmox-cluster-networking-sdn/images/proxmox-node-network-configuration.png b/content/post/11-proxmox-cluster-networking-sdn/images/proxmox-node-network-configuration.png new file mode 100644 index 0000000..803181f Binary files /dev/null and b/content/post/11-proxmox-cluster-networking-sdn/images/proxmox-node-network-configuration.png differ diff --git a/content/post/11-proxmox-cluster-networking-sdn/images/proxmox-sdn-all-vlan-homelan.png b/content/post/11-proxmox-cluster-networking-sdn/images/proxmox-sdn-all-vlan-homelan.png new file mode 100644 index 0000000..84c812e Binary files /dev/null and b/content/post/11-proxmox-cluster-networking-sdn/images/proxmox-sdn-all-vlan-homelan.png differ diff --git a/content/post/11-proxmox-cluster-networking-sdn/images/proxmox-terraform-test-deploy-vlan66.png b/content/post/11-proxmox-cluster-networking-sdn/images/proxmox-terraform-test-deploy-vlan66.png new file mode 100644 index 0000000..71d9a87 Binary files /dev/null and b/content/post/11-proxmox-cluster-networking-sdn/images/proxmox-terraform-test-deploy-vlan66.png differ diff --git a/content/post/11-proxmox-cluster-networking-sdn/images/terraform-code-update-vlan66.png b/content/post/11-proxmox-cluster-networking-sdn/images/terraform-code-update-vlan66.png new file mode 100644 index 0000000..dc04570 Binary files /dev/null and b/content/post/11-proxmox-cluster-networking-sdn/images/terraform-code-update-vlan66.png differ diff --git a/content/post/11-proxmox-cluster-networking-sdn/index.fr.md b/content/post/11-proxmox-cluster-networking-sdn/index.fr.md index 6af30e9..ff0590d 100644 --- a/content/post/11-proxmox-cluster-networking-sdn/index.fr.md +++ b/content/post/11-proxmox-cluster-networking-sdn/index.fr.md @@ -13,7 +13,7 @@ categories: ## Intro Quand j’ai construit mon cluster **Proxmox VE 8** pour la première fois, le réseau n’était pas ma priorité. Je voulais simplement remplacer rapidement un vieux serveur physique, alors j’ai donné la même configuration de base à chacun de mes trois nœuds, créé le cluster et commencé à créer des VM : -![Configuration réseau d’un nœud Proxmox](img/proxmox-node-network-configuration.png) +![Configuration réseau d’un nœud Proxmox](images/proxmox-node-network-configuration.png) Cela a bien fonctionné pendant un moment. Mais comme je prévois de virtualiser mon routeur **OPNsense**, j’ai besoin de quelque chose de plus structuré et cohérent. C’est là que la fonctionnalité **S**oftware-**D**efined **N**etworking (SDN) de Proxmox entre en jeu. @@ -21,7 +21,7 @@ Cela a bien fonctionné pendant un moment. Mais comme je prévois de virtualiser ## Mon Réseau Homelab Par défaut, chaque nœud Proxmox dispose de sa propre zone locale, appelée `localnetwork`, qui contient le pont Linux par défaut (`vmbr0`) comme VNet : -![Proxmox default `localnetwork` zones](img/proxmox-default-localnetwork-zone.png) +![Zones `localnetwork` par défaut dans Proxmox](images/proxmox-default-localnetwork-zone.png) C’est suffisant pour des configurations isolées, mais rien n’est coordonné au niveau du cluster. @@ -61,29 +61,29 @@ Proxmox prend en charge plusieurs types de zones : - **EVPN** : VXLAN avec BGP pour du routage L3 dynamique Comme mon réseau domestique utilise déjà des VLAN, j’ai créé une **zone VLAN** appelée `homelan`, en utilisant `vmbr0` comme pont et en l’appliquant à tout le cluster : -![Create a VLAN zone in the Proxmox SDN](img/proxmox-create-vlan-zone-homelan.png) +![Création d’une zone VLAN dans Proxmox SDN](images/proxmox-create-vlan-zone-homelan.png) ### VNets Un **VNet** est un réseau virtuel à l’intérieur d’une zone. Dans une zone VLAN, chaque VNet correspond à un ID VLAN spécifique. J’ai commencé par créer `vlan55` dans la zone `homelan` pour mon réseau DMZ : -![Create a VNet for VLAN 55 in the homelan zone](img/proxmox-create-vlan-vnet-homelan.png) +![Création d’un VNet pour le VLAN 55 dans la zone homelan](images/proxmox-create-vlan-vnet-homelan.png) Puis j’ai ajouté les VNets correspondant à la plupart de mes VLAN, puisque je prévois de les rattacher à une VM OPNsense : -![All my VLANs created in the Proxmox SDN](img/proxmox-sdn-all-vlan-homelan.png) +![Tous mes VLANs créés dans le Proxmox SDN](images/proxmox-sdn-all-vlan-homelan.png) Enfin, j’ai appliqué la configuration dans **Datacenter → SDN** : -![Application de la configuration SDN dans Proxmox](img/proxmox-apply-sdn-homelan-configuration.png) +![Application de la configuration SDN dans Proxmox](images/proxmox-apply-sdn-homelan-configuration.png) --- ## Test de la Configuration Réseau Dans une vieille VM que je n'utilise plus, je remplace l'actuel `vmbr0` avec le VLAN tag 66 par mon nouveau VNet `vlan66`: -![Change the network bridge in a VM](img/proxmox-change-vm-nic-vlan-vnet.png) +![Changement du pont réseau dans une VM](images/proxmox-change-vm-nic-vlan-vnet.png) Après l'avoir démarrée, la VM obtient une IP du DHCP d'OPNsense sur ce VLAN, ce qui est super. J'essaye également de ping une autre machine et ça fonctionne : -![Ping another machine in the same VLAN](img/proxmox-console-ping-vm-vlan-66.png) +![Ping d’une autre machine dans le même VLAN](images/proxmox-console-ping-vm-vlan-66.png) --- ## Mise à jour de Cloud-Init et Terraform @@ -92,7 +92,7 @@ Pour aller plus loin, j’ai mis à jour le pont réseau utilisé dans mon **tem Comme avec la VM précédente, j’ai remplacé `vmbr0` et le tag VLAN 66 par le nouveau VNet `vlan66`. J’ai aussi adapté mon code **Terraform** pour refléter ce changement : -![Mise à jour du code Terraform pour vlan66](img/terraform-code-update-vlan66.png) +![Mise à jour du code Terraform pour vlan66](images/terraform-code-update-vlan66.png) Ensuite, j’ai validé qu’aucune régression n’était introduite en déployant une VM de test : ```bash @@ -129,7 +129,7 @@ vm_ip = "192.168.66.181" ``` La création s’est déroulée sans problème, tout est bon : -![VM déployée par Terraform sur vlan66](img/proxmox-terraform-test-deploy-vlan66.png) +![VM déployée par Terraform sur vlan66](images/proxmox-terraform-test-deploy-vlan66.png) --- ## Conclusion diff --git a/content/post/11-proxmox-cluster-networking-sdn/index.md b/content/post/11-proxmox-cluster-networking-sdn/index.md index 46b62d0..eac00ef 100644 --- a/content/post/11-proxmox-cluster-networking-sdn/index.md +++ b/content/post/11-proxmox-cluster-networking-sdn/index.md @@ -13,7 +13,7 @@ categories: ## Intro When I first built my **Proxmox VE 8** cluster, networking wasn’t my main concern. I just wanted to replace an old physical server quickly, so I gave each of my three nodes the same basic config, created the cluster, and started running VMs: -![Configuration réseau d’un nœud Proxmox](img/proxmox-node-network-configuration.png) +![Proxmox node network configuration](images/proxmox-node-network-configuration.png) That worked fine for a while. But as I plan to virtualize my **OPNsense** router, I need something more structured and consistent. This is where Proxmox **S**oftware-**D**efined **N**etworking (SDN) feature comes in. @@ -21,7 +21,7 @@ That worked fine for a while. But as I plan to virtualize my **OPNsense** router ## My Homelab Network By default, every Proxmox node comes with its own local zone, called `localnetwork`, which contains the default Linux bridge (`vmbr0`) as a VNet: -![Proxmox default `localnetwork` zones](img/proxmox-default-localnetwork-zone.png) +![Proxmox default `localnetwork` zones](images/proxmox-default-localnetwork-zone.png) That’s fine for isolated setups, but at the cluster level nothing is coordinated. @@ -61,29 +61,29 @@ Proxmox supports several zone types: - **EVPN**: VXLAN with BGP to establish Layer 3 routing Since my home network already relies on VLANs, I created a **VLAN Zone** named `homelan`, using `vmbr0` as the bridge and applying it cluster-wide: -![Create a VLAN zone in the Proxmox SDN](img/proxmox-create-vlan-zone-homelan.png) +![Create a VLAN zone in the Proxmox SDN](images/proxmox-create-vlan-zone-homelan.png) ### VNets A **VNet** is a virtual network inside a zone. In a VLAN zone, each VNet corresponds to a specific VLAN ID. I started by creating `vlan55` in the `homelan` zone for my DMZ network: -![Create a VNet for VLAN 55 in the homelan zone](img/proxmox-create-vlan-vnet-homelan.png) +![Create a VNet for VLAN 55 in the homelan zone](images/proxmox-create-vlan-vnet-homelan.png) Then I added VNets for most of my VLANs, since I plan to attach them to an OPNsense VM: -![All my VLANs created in the Proxmox SDN](img/proxmox-sdn-all-vlan-homelan.png) +![All my VLANs created in the Proxmox SDN](images/proxmox-sdn-all-vlan-homelan.png) Finally, I applied the configuration in **Datacenter → SDN**: -![Application de la configuration SDN dans Proxmox](img/proxmox-apply-sdn-homelan-configuration.png) +![Apply SDN configuration in Proxmox](images/proxmox-apply-sdn-homelan-configuration.png) --- ## Test the Network Configuration In a old VM which I don't use anymore, I replace the current `vmbr0` with VLAN tag 66 to my new VNet `vlan66`: -![Change the network bridge in a VM](img/proxmox-change-vm-nic-vlan-vnet.png) +![Change the network bridge in a VM](images/proxmox-change-vm-nic-vlan-vnet.png) After starting it, the VM gets an IP from the DHCP on OPNsense on that VLAN, which sounds good. I also try to ping another machine and it works: -![Ping another machine in the same VLAN](img/proxmox-console-ping-vm-vlan-66.png) +![Ping another machine in the same VLAN](images/proxmox-console-ping-vm-vlan-66.png) --- ## Update Cloud-Init Template and Terraform @@ -91,7 +91,7 @@ After starting it, the VM gets an IP from the DHCP on OPNsense on that VLAN, whi To go further, I update the bridge used in my **cloud-init** template, which I detailed the creation in that [post]({{< ref "post/1-proxmox-cloud-init-vm-template" >}}). Pretty much the same thing I've done with the VM, I replace the current `vmbr0` with VLAN tag 66 with my new VNet `vlan66`. I also update the **Terrafom** code to take this change into account: -![Mise à jour du code Terraform pour vlan66](img/terraform-code-update-vlan66.png) +![Terraform code change for the vlan66](images/terraform-code-update-vlan66.png) I quicky check if I don't have regression and can still deploy a VM with Terraform: ```bash @@ -128,7 +128,7 @@ vm_ip = "192.168.66.181" ``` The VM is deploying without any issue, everything is OK: -![VM déployée par Terraform sur vlan66](img/proxmox-terraform-test-deploy-vlan66.png) +![VM hardware in Proxmox deployed by Terraform](images/proxmox-terraform-test-deploy-vlan66.png) --- ## Conclusion diff --git a/content/post/12-opnsense-virtualization-highly-available/images/homelan-current-physical-layout.png b/content/post/12-opnsense-virtualization-highly-available/images/homelan-current-physical-layout.png new file mode 100644 index 0000000..a4757ed Binary files /dev/null and b/content/post/12-opnsense-virtualization-highly-available/images/homelan-current-physical-layout.png differ diff --git a/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-assign-pfsync-interface.png b/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-assign-pfsync-interface.png new file mode 100644 index 0000000..bdca1b4 Binary files /dev/null and b/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-assign-pfsync-interface.png differ diff --git a/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-carp-status.png b/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-carp-status.png new file mode 100644 index 0000000..ba0dbf6 Binary files /dev/null and b/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-carp-status.png differ diff --git a/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-create-vip-carp.png b/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-create-vip-carp.png new file mode 100644 index 0000000..d416994 Binary files /dev/null and b/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-create-vip-carp.png differ diff --git a/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-dnsmasq-add-option.png b/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-dnsmasq-add-option.png new file mode 100644 index 0000000..93d8f55 Binary files /dev/null and b/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-dnsmasq-add-option.png differ diff --git a/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-firewall-allow-pfsync.png b/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-firewall-allow-pfsync.png new file mode 100644 index 0000000..47eb298 Binary files /dev/null and b/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-firewall-allow-pfsync.png differ diff --git a/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-high-availability-settings.png b/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-high-availability-settings.png new file mode 100644 index 0000000..ea6f438 Binary files /dev/null and b/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-high-availability-settings.png differ diff --git a/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-high-availability-status.png b/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-high-availability-status.png new file mode 100644 index 0000000..0e1c033 Binary files /dev/null and b/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-high-availability-status.png differ diff --git a/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-installation-assign-interfaces.png b/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-installation-assign-interfaces.png new file mode 100644 index 0000000..2285455 Binary files /dev/null and b/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-installation-assign-interfaces.png differ diff --git a/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-installation-cli-menu.png b/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-installation-cli-menu.png new file mode 100644 index 0000000..d914b78 Binary files /dev/null and b/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-installation-cli-menu.png differ diff --git a/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-installation-interfaces-configured.png b/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-installation-interfaces-configured.png new file mode 100644 index 0000000..7eb8b5b Binary files /dev/null and b/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-installation-interfaces-configured.png differ diff --git a/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-installation-progress-bar.png b/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-installation-progress-bar.png new file mode 100644 index 0000000..756f996 Binary files /dev/null and b/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-installation-progress-bar.png differ diff --git a/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-installation-welcome.png b/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-installation-welcome.png new file mode 100644 index 0000000..503d4de Binary files /dev/null and b/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-installation-welcome.png differ diff --git a/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-webgui-from-poc-lan.png b/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-webgui-from-poc-lan.png new file mode 100644 index 0000000..b4cdbed Binary files /dev/null and b/content/post/12-opnsense-virtualization-highly-available/images/opnsense-vm-webgui-from-poc-lan.png differ diff --git a/content/post/12-opnsense-virtualization-highly-available/images/poc-opnsense-diagram.png b/content/post/12-opnsense-virtualization-highly-available/images/poc-opnsense-diagram.png new file mode 100644 index 0000000..9bbfa82 Binary files /dev/null and b/content/post/12-opnsense-virtualization-highly-available/images/poc-opnsense-diagram.png differ diff --git a/content/post/12-opnsense-virtualization-highly-available/images/proxmox-create-poc-vm-opnsense.png b/content/post/12-opnsense-virtualization-highly-available/images/proxmox-create-poc-vm-opnsense.png new file mode 100644 index 0000000..f6c0c5e Binary files /dev/null and b/content/post/12-opnsense-virtualization-highly-available/images/proxmox-create-poc-vm-opnsense.png differ diff --git a/content/post/12-opnsense-virtualization-highly-available/images/proxmox-disable-secure-boot-option.png b/content/post/12-opnsense-virtualization-highly-available/images/proxmox-disable-secure-boot-option.png new file mode 100644 index 0000000..ed80a32 Binary files /dev/null and b/content/post/12-opnsense-virtualization-highly-available/images/proxmox-disable-secure-boot-option.png differ diff --git a/content/post/12-opnsense-virtualization-highly-available/images/proxmox-sdn-create-poc-vlans.png b/content/post/12-opnsense-virtualization-highly-available/images/proxmox-sdn-create-poc-vlans.png new file mode 100644 index 0000000..dccedcf Binary files /dev/null and b/content/post/12-opnsense-virtualization-highly-available/images/proxmox-sdn-create-poc-vlans.png differ diff --git a/content/post/12-opnsense-virtualization-highly-available/images/proxmox-upload-opnsense-iso.png b/content/post/12-opnsense-virtualization-highly-available/images/proxmox-upload-opnsense-iso.png new file mode 100644 index 0000000..97fd766 Binary files /dev/null and b/content/post/12-opnsense-virtualization-highly-available/images/proxmox-upload-opnsense-iso.png differ diff --git a/content/post/12-opnsense-virtualization-highly-available/index.fr.md b/content/post/12-opnsense-virtualization-highly-available/index.fr.md index 2306013..2c02bf2 100644 --- a/content/post/12-opnsense-virtualization-highly-available/index.fr.md +++ b/content/post/12-opnsense-virtualization-highly-available/index.fr.md @@ -29,7 +29,7 @@ Au sommet de mon installation, mon modem FAI, une _Freebox_ en mode bridge, reli Ce switch relie également mes trois nœuds Proxmox, chacun sur un port trunk avec le même VLAN natif. Chaque nœud dispose de deux cartes réseau : une pour le trafic général, et l’autre dédiée au réseau de stockage Ceph, connecté à un switch séparé de 2,5 Gbps. Depuis le crash d’OPNsense, j’ai simplifié l’architecture en supprimant le lien LACP, qui n’apportait pas de réelle valeur : -![Current homelab network diagram](img/homelan-current-physical-layout.png) +![Schéma réseau du homelab actuel](images/homelan-current-physical-layout.png) Jusqu’à récemment, le réseau Proxmox de mon cluster était très basique : chaque nœud était configuré individuellement sans véritable logique commune. Cela a changé après la découverte du SDN Proxmox, qui m’a permis de centraliser les définitions de VLAN sur l’ensemble du cluster. J’ai décrit cette étape dans [cet article]({{< ref "post/11-proxmox-cluster-networking-sdn" >}}). @@ -43,7 +43,7 @@ Place au lab. Voici les étapes principales : 4. Configurer la haute disponibilité 5. Tester la bascule -![Diagram of the POC for OPNsense high availability](img/poc-opnsense-diagram.png) +![Schéma du POC pour OPNsense en haute disponibilité](images/poc-opnsense-diagram.png) ### Ajouter des VLANs dans mon homelab @@ -53,7 +53,7 @@ Pour cette expérimentation, je crée trois nouveaux VLANs : - **VLAN 103** : _POC pfSync_ Dans l’interface Proxmox, je vais dans `Datacenter` > `SDN` > `VNets` et je clique sur `Create` : -![Create POC VLANs in the Proxmox SDN](img/proxmox-sdn-create-poc-vlans.png) +![Création des VLANs POC dans le SDN Proxmox](images/proxmox-sdn-create-poc-vlans.png) Une fois les trois VLANs créés, j’applique la configuration. @@ -114,7 +114,7 @@ La VM `fake-freebox` est maintenant prête à fournir du DHCP sur le VLAN 101, a ### Construire les VMs OPNsense Je commence par télécharger l’ISO d’OPNsense et je l’upload sur un de mes nœuds Proxmox : -![Upload de l’ISO OPNsense dans Proxmox](img/proxmox-upload-opnsense-iso.png) +![Upload de l’ISO OPNsense dans Proxmox](images/proxmox-upload-opnsense-iso.png) #### Création de la VM @@ -128,69 +128,69 @@ Je crée la première VM `poc-opnsense-1` avec les paramètres suivants : 1. VLAN 101 (_POC WAN_) 2. VLAN 102 (_POC LAN_) 3. VLAN 103 (_POC pfSync_) -![OPNsense VM settings in Proxmox](img/proxmox-create-poc-vm-opnsense.png) +![Paramètres de la VM OPNsense dans Proxmox](images/proxmox-create-poc-vm-opnsense.png) ℹ️ Avant de la démarrer, je clone cette VM pour préparer la seconde : `poc-opnsense-2` Au premier démarrage, je tombe sur une erreur “access denied”. Pour corriger, j’entre dans le BIOS, **Device Manager > Secure Boot Configuration**, je décoche _Attempt Secure Boot_ et je redémarre : -![Disable Secure Boot in Proxmox BIOS](img/proxmox-disable-secure-boot-option.png) +![Désactiver Secure Boot dans le BIOS de Proxmox](images/proxmox-disable-secure-boot-option.png) #### Installation d’OPNsense La VM démarre sur l’ISO, je ne touche à rien jusqu’à l’écran de login : -![OPNsense CLI login screen in LiveCD](img/opnsense-vm-installation-welcome.png) +![Écran de login OPNsense en mode LiveCD](images/opnsense-vm-installation-welcome.png) Je me connecte avec `installer` / `opnsense` et je lance l’installateur. Je sélectionne le disque QEMU de 20 Go comme destination et je démarre l’installation : -![Barre de progression de l’installation OPNsense](img/opnsense-vm-installation-progress-bar.png) +![Barre de progression de l’installation OPNsense](images/opnsense-vm-installation-progress-bar.png) Une fois terminé, je retire l’ISO du lecteur et je redémarre la machine. #### Configuration de Base d’OPNsense Au redémarrage, je me connecte avec `root` / `opnsense` et j’arrive au menu CLI : -![Menu CLI après une installation fraîche d’OPNsense](img/opnsense-vm-installation-cli-menu.png) +![Menu CLI après une installation fraîche d’OPNsense](images/opnsense-vm-installation-cli-menu.png) Avec l’option 1, je réassigne les interfaces : -![Configuration des interfaces dans OPNsense via le CLI](img/opnsense-vm-installation-assign-interfaces.png) +![Configuration des interfaces dans OPNsense via le CLI](images/opnsense-vm-installation-assign-interfaces.png) L’interface WAN récupère bien `10.101.0.150/24` depuis la `fake-freebox`. Je configure le LAN sur `10.102.0.2/24` et j’ajoute un pool DHCP de `10.102.0.10` à `10.102.0.99` : -![Interface WAN OPNsense recevant une IP depuis la VM `fake-freebox`](img/opnsense-vm-installation-interfaces-configured.png) +![Interface WAN OPNsense recevant une IP depuis la VM `fake-freebox`](images/opnsense-vm-installation-interfaces-configured.png) ✅ La première VM est prête, je reproduis l’opération pour la seconde OPNsense `poc-opnsense-2`, qui aura l’IP `10.102.0.3`. ### Configurer OPNsense en Haute Disponibilité Avec les deux VMs OPNsense opérationnelles, il est temps de passer à la configuration via le WebGUI. Pour y accéder, j’ai connecté une VM Windows au VLAN _POC LAN_ et ouvert l’IP de l’OPNsense sur le port 443 : -![OPNsense WebGUI depuis une VM Windows](img/opnsense-vm-webgui-from-poc-lan.png) +![OPNsense WebGUI depuis une VM Windows](images/opnsense-vm-webgui-from-poc-lan.png) #### Ajouter l’Interface pfSync La troisième carte réseau (`vtnet2`) est assignée à l’interface _pfSync_. Ce réseau dédié permet aux deux firewalls de synchroniser leurs états via le VLAN _POC pfSync_ : -![Add pfSync interface in OPNsense](img/opnsense-vm-assign-pfsync-interface.png) +![Ajouter l’interface pfSync dans OPNsense](images/opnsense-vm-assign-pfsync-interface.png) J’active l’interface sur chaque instance et je leur attribue une IP statique : - **poc-opnsense-1** : `10.103.0.2/24` - **poc-opnsense-2** : `10.103.0.3/24` Puis, j’ajoute une règle firewall sur chaque nœud pour autoriser tout le trafic provenant de ce réseau sur l’interface _pfSync_ : -![Create new firewall rule on pfSync interface to allow any traffic in that network](img/opnsense-vm-firewall-allow-pfsync.png) +![Règle firewall pour autoriser tout le trafic pfSync](images/opnsense-vm-firewall-allow-pfsync.png) #### Configurer la Haute Disponibilité Direction `System` > `High Availability` > `Settings`. - Sur le master (`poc-opnsense-1`), je configure les `General Settings` et les `Synchronization Settings`. - Sur le backup (`poc-opnsense-2`), seuls les `General Settings` suffisent (on ne veut pas qu’il écrase la config du master). -![OPNsense High Availability settings](img/opnsense-vm-high-availability-settings.png) +![Paramètres de Haute Disponibilité dans OPNsense](images/opnsense-vm-high-availability-settings.png) Une fois appliqué, je vérifie la synchro dans l’onglet `Status` : -![OPNsense High Availability status](img/opnsense-vm-high-availability-status.png) +![Statut de la Haute Disponibilité OPNsense](images/opnsense-vm-high-availability-status.png) #### Créer une IP Virtuelle Pour fournir une passerelle partagée aux clients, je crée une IP virtuelle (VIP) en **CARP** (Common Address Redundancy Protocol) sur l’interface LAN. L’IP est portée par le nœud actif et bascule automatiquement en cas de failover. Menu : `Interfaces` > `Virtual IPs` > `Settings` : -![Create CARP virtual IP in OPNsense](img/opnsense-vm-create-vip-carp.png) +![Création d’une VIP CARP dans OPNsense](images/opnsense-vm-create-vip-carp.png) Je réplique ensuite la config depuis `System > High Availability > Status` avec le bouton `Synchronize and reconfigure all`. @@ -205,7 +205,7 @@ Sur le master : - `DHCP ranges` : cocher aussi `Disable HA sync` - `DHCP options` : ajouter l’option `router [3]` avec la valeur `10.102.0.1` (VIP LAN) - `DHCP options` : cloner la règle pour `dns-server [6]` vers la même VIP. -![Edit DHCP options for Dnsmasq in OPNsense](img/opnsense-vm-dnsmasq-add-option.png) +![Options DHCP dans Dnsmasq](images/opnsense-vm-dnsmasq-add-option.png) Sur le backup : - `Services` > `Dnsmasq DNS & DHCP` > `General` : cocher `Disable HA sync` @@ -262,7 +262,7 @@ if ($type === "MASTER") { Passons aux tests ! OPNsense propose un _CARP Maintenance Mode_. Avec le master actif, seul lui avait son WAN monté. En activant le mode maintenance, les rôles basculent : le master devient backup, son WAN est désactivé et celui du backup est activé : -![Mode maintenance CARP dans OPNsense](img/opnsense-vm-carp-status.png) +![Mode maintenance CARP dans OPNsense](images/opnsense-vm-carp-status.png) Pendant mes pings vers l’extérieur, aucune perte de paquets au moment du basculement. diff --git a/content/post/12-opnsense-virtualization-highly-available/index.md b/content/post/12-opnsense-virtualization-highly-available/index.md index d34c062..121ccb0 100644 --- a/content/post/12-opnsense-virtualization-highly-available/index.md +++ b/content/post/12-opnsense-virtualization-highly-available/index.md @@ -29,7 +29,7 @@ On top of my setup, my ISP modem, a *Freebox* in bridge mode, connects directly The switch also connects my three Proxmox nodes, each on trunk ports with the same native VLAN. Every node has two NICs: one for general networking and the other dedicated to the Ceph storage network, which runs through a separate 2.5 Gbps switch. Since the OPNsense crash, I’ve simplified things by removing the LACP link, it wasn’t adding real value: -![Current homelab network diagram](img/homelan-current-physical-layout.png) +![Current homelab network diagram](images/homelan-current-physical-layout.png) Until recently, Proxmox networking on my cluster was very basic: each node was configured individually with no real overlay logic. That changed after I explored Proxmox SDN, where I centralized VLAN definitions across the cluster. I described that step in [this article]({{< ref "post/11-proxmox-cluster-networking-sdn" >}}). @@ -44,7 +44,7 @@ Time to move into the lab. Here are the main steps: 4. Configure high availability 5. Test failover -![Diagram of the POC for OPNsense high availability](img/poc-opnsense-diagram.png) +![Diagram of the POC for OPNsense high availability](images/poc-opnsense-diagram.png) ### Add VLANs in my Homelab @@ -54,7 +54,7 @@ For this experiment, I create 3 new VLANs: - **VLAN 103**: *POC pfSync* In the Proxmox UI, I navigate to `Datacenter` > `SDN` > `VNets` and I click `Create`: -![Create POC VLANs in the Proxmox SDN](img/proxmox-sdn-create-poc-vlans.png) +![Create POC VLANs in the Proxmox SDN](images/proxmox-sdn-create-poc-vlans.png) Once the 3 new VLAN have been created, I apply the configuration. @@ -115,7 +115,7 @@ The `fake-freebox` VM is now ready to serve DHCP on VLAN 101 and serve only one ### Build OPNsense VMs First I download the OPNsense ISO and upload it to one of my Proxmox nodes: -![Upload de l’ISO OPNsense dans Proxmox](img/proxmox-upload-opnsense-iso.png) +![Upload the OPNsense ISO into Proxmox](images/proxmox-upload-opnsense-iso.png) #### VM Creation @@ -129,69 +129,69 @@ I create the first VM `poc-opnsense-1`, with the following settings: 1. VLAN 101 (POC WAN) 2. VLAN 102 (POC LAN) 3. VLAN 103 (POC pfSync) -![OPNsense VM settings in Proxmox](img/proxmox-create-poc-vm-opnsense.png) +![OPNsense VM settings in Proxmox](images/proxmox-create-poc-vm-opnsense.png) ℹ️ Before booting it, I clone this VM to prepare the second one: `poc-opnsense-2` On first boot, I hit an “access denied” error. To fix this, I enter the BIOS, go to **Device Manager > Secure Boot Configuration**, uncheck _Attempt Secure Boot_, and restart the VM: -![Disable Secure Boot in Proxmox BIOS](img/proxmox-disable-secure-boot-option.png) +![Disable Secure Boot in Proxmox BIOS](images/proxmox-disable-secure-boot-option.png) #### OPNsense Installation The VM boots on the ISO, I touch nothing until I get into the login screen: -![OPNsense CLI login screen in LiveCD](img/opnsense-vm-installation-welcome.png) +![OPNsense CLI login screen in LiveCD](images/opnsense-vm-installation-welcome.png) I log in as `installer` / `opnsense` and launch the installer. I select the QEMU hard disk of 20GB as destination and launch the installation: -![Barre de progression de l’installation OPNsense](img/opnsense-vm-installation-progress-bar.png) +![OPNsense installation progress bar](images/opnsense-vm-installation-progress-bar.png) Once the installation is finished, I remove the ISO from the drive and restart the machine. #### OPNsense Basic Configuration After reboot, I log in as `root` / `opnsense` and get into the CLI menu: -![Menu CLI après une installation fraîche d’OPNsense](img/opnsense-vm-installation-cli-menu.png) +![OPNsense CLI login screen after fresh installation](images/opnsense-vm-installation-cli-menu.png) Using option 1, I reassigned interfaces: -![Configuration des interfaces dans OPNsense via le CLI](img/opnsense-vm-installation-assign-interfaces.png) +![OPNsense interface configuration using CLI](images/opnsense-vm-installation-assign-interfaces.png) The WAN interface successfully pulled `10.101.0.150/24` from the `fake-freebox`. I set the LAN interface to `10.102.0.2/24` and configured a DHCP pool from `10.102.0.10` to `10.102.0.99`: -![Interface WAN OPNsense recevant une IP depuis la VM `fake-freebox`](img/opnsense-vm-installation-interfaces-configured.png) +![OPNsense WAN interface getting IP from `fake-freebox` VM](images/opnsense-vm-installation-interfaces-configured.png) ✅ The first VM is ready, I start over for the second OPNsense VM, `poc-opnsense-2` which will have the IP `10.102.0.3` ### Configure OPNsense Highly Available With both OPNsense VMs operational, it’s time to configure them from the WebGUI. To access the interface, I connected a Windows VM into the _POC LAN_ VLAN and browsed to the OPNsense IP on port 443: -![OPNsense WebGUI depuis une VM Windows](img/opnsense-vm-webgui-from-poc-lan.png) +![OPNsense WebGUI from Windows VM](images/opnsense-vm-webgui-from-poc-lan.png) #### Add pfSync Interface The third NIC (`vtnet2`) is assigned to the _pfSync_ interface. This dedicated network allows the two firewalls to synchronize states on the VLAN *POC pfSync*: -![Add pfSync interface in OPNsense](img/opnsense-vm-assign-pfsync-interface.png) +![Add pfSync interface in OPNsense](images/opnsense-vm-assign-pfsync-interface.png) I enable the interface on each instance and configure it with a static IP address: - **poc-opnsense-1**: `10.103.0.2/24` - **poc-opnsense-2**: `10.103.0.3/24` Then, I add a firewall rule on each node to allow all traffic coming from this network on that *pfSync* interface: -![Create new firewall rule on pfSync interface to allow any traffic in that network](img/opnsense-vm-firewall-allow-pfsync.png) +![Create new firewall rule on pfSync interface to allow any traffic in that network](images/opnsense-vm-firewall-allow-pfsync.png) #### Setup High Availability Next, in `System` > `High Availability` > `Settings`. - On the master (`poc-opnsense-1`), I configure both the `General Settings` and the `Synchronization Settings`. - On the backup (`poc-opnsense-2`), only `General Settings` are needed, you don't want your backup overwrite the master config. -![OPNsense High Availability settings](img/opnsense-vm-high-availability-settings.png) +![OPNsense High Availability settings](images/opnsense-vm-high-availability-settings.png) Once applied, I verify synchronization on the `Status` page: -![OPNsense High Availability status](img/opnsense-vm-high-availability-status.png) +![OPNsense High Availability status](images/opnsense-vm-high-availability-status.png) #### Create Virtual IP Address To provide a shared gateway for clients, I create a CARP Virtual IP (VIP) on the LAN interface. It is using the Common Address Redundancy Protocol. This IP is claimed by the active node and automatically fails over. Navigate to `Interfaces` > `Virtual IPs` > `Settings`: -![Create CARP virtual IP in OPNsense](img/opnsense-vm-create-vip-carp.png) +![Create CARP virtual IP in OPNsense](images/opnsense-vm-create-vip-carp.png) To replicate the config, I go to `System > High Availability > Status` and click the button next to `Synchronize and reconfigure all`. @@ -206,7 +206,7 @@ On the master: - `DHCP ranges`: also tick the `Disable HA sync` box - `DHCP options`: add the option `router [3]` with the value `10.102.0.1` (LAN VIP) - `DHCP options`: clone the rule for `router [6]` pointing to the same VIP. -![Edit DHCP options for Dnsmasq in OPNsense](img/opnsense-vm-dnsmasq-add-option.png) +![Edit DHCP options for Dnsmasq in OPNsense](images/opnsense-vm-dnsmasq-add-option.png) On the backup: - `Services` > `Dnsmasq DNS & DHCP` > `General`: also tick the `Disable HA sync` box @@ -264,7 +264,7 @@ if ($type === "MASTER") { Time for the real test! OPNsense provides a _CARP Maintenance Mode_. With the master active, WAN was enabled only on that node. Entering maintenance mode flipped the roles: the master became backup, its WAN disabled, while the backup enabled its WAN: -![Mode maintenance CARP dans OPNsense](img/opnsense-vm-carp-status.png) +![OPNsense CARP maintenance mode](images/opnsense-vm-carp-status.png) While pinging outside the network, I observed zero packet loss during the failover. diff --git a/content/post/13-opnsense-full-configuration/images/opnsense-assign-interfaces.png b/content/post/13-opnsense-full-configuration/images/opnsense-assign-interfaces.png new file mode 100644 index 0000000..e2e6afb Binary files /dev/null and b/content/post/13-opnsense-full-configuration/images/opnsense-assign-interfaces.png differ diff --git a/content/post/13-opnsense-full-configuration/images/opnsense-create-alias-internalnetworks.png b/content/post/13-opnsense-full-configuration/images/opnsense-create-alias-internalnetworks.png new file mode 100644 index 0000000..806c0ef Binary files /dev/null and b/content/post/13-opnsense-full-configuration/images/opnsense-create-alias-internalnetworks.png differ diff --git a/content/post/13-opnsense-full-configuration/images/opnsense-dnsmasq-dhcp-hosts.png b/content/post/13-opnsense-full-configuration/images/opnsense-dnsmasq-dhcp-hosts.png new file mode 100644 index 0000000..50d38f1 Binary files /dev/null and b/content/post/13-opnsense-full-configuration/images/opnsense-dnsmasq-dhcp-hosts.png differ diff --git a/content/post/13-opnsense-full-configuration/images/opnsense-dnsmasq-dhcp-options.png b/content/post/13-opnsense-full-configuration/images/opnsense-dnsmasq-dhcp-options.png new file mode 100644 index 0000000..3ff8259 Binary files /dev/null and b/content/post/13-opnsense-full-configuration/images/opnsense-dnsmasq-dhcp-options.png differ diff --git a/content/post/13-opnsense-full-configuration/images/opnsense-dnsmasq-dhcp-ranges.png b/content/post/13-opnsense-full-configuration/images/opnsense-dnsmasq-dhcp-ranges.png new file mode 100644 index 0000000..825aecd Binary files /dev/null and b/content/post/13-opnsense-full-configuration/images/opnsense-dnsmasq-dhcp-ranges.png differ diff --git a/content/post/13-opnsense-full-configuration/images/opnsense-high-availability-status.png b/content/post/13-opnsense-full-configuration/images/opnsense-high-availability-status.png new file mode 100644 index 0000000..47e7974 Binary files /dev/null and b/content/post/13-opnsense-full-configuration/images/opnsense-high-availability-status.png differ diff --git a/content/post/13-opnsense-full-configuration/images/opnsense-interface-virtual-ips.png b/content/post/13-opnsense-full-configuration/images/opnsense-interface-virtual-ips.png new file mode 100644 index 0000000..66b6a47 Binary files /dev/null and b/content/post/13-opnsense-full-configuration/images/opnsense-interface-virtual-ips.png differ diff --git a/content/post/13-opnsense-full-configuration/images/opnsense-unbound-dns-query-forwarding.png b/content/post/13-opnsense-full-configuration/images/opnsense-unbound-dns-query-forwarding.png new file mode 100644 index 0000000..2aca2d3 Binary files /dev/null and b/content/post/13-opnsense-full-configuration/images/opnsense-unbound-dns-query-forwarding.png differ diff --git a/content/post/13-opnsense-full-configuration/images/opnsense-unbound-general-settings.png b/content/post/13-opnsense-full-configuration/images/opnsense-unbound-general-settings.png new file mode 100644 index 0000000..dc5bd86 Binary files /dev/null and b/content/post/13-opnsense-full-configuration/images/opnsense-unbound-general-settings.png differ diff --git a/content/post/13-opnsense-full-configuration/images/proxmox-opnsense-enable-qemu-guest-agent.png b/content/post/13-opnsense-full-configuration/images/proxmox-opnsense-enable-qemu-guest-agent.png new file mode 100644 index 0000000..337f11d Binary files /dev/null and b/content/post/13-opnsense-full-configuration/images/proxmox-opnsense-enable-qemu-guest-agent.png differ diff --git a/content/post/13-opnsense-full-configuration/index.fr.md b/content/post/13-opnsense-full-configuration/index.fr.md index 2c9db7d..5ed7518 100644 --- a/content/post/13-opnsense-full-configuration/index.fr.md +++ b/content/post/13-opnsense-full-configuration/index.fr.md @@ -84,7 +84,7 @@ Il est temps de mettre à jour, dans `System` > `Firmware` > `Status`, je v Une fois mis à jour et redémarré, je vais dans `System` > `Firmware` > `Plugins`, je coche l'option pour afficher les plugins communautaires. J'installe que le **QEMU Guest Agent**, `os-qemu-guest-agent`, pour permettre la communication entre la VM et l'hôte Proxmox. Cela nécessite un arrêt. Dans Proxmox, j'active le `QEMU Guest Agent` dans les options de la VM : -![Options d'une VM Proxmox avec QEMU Guest Agent activé](img/proxmox-opnsense-enable-qemu-guest-agent.png) +![Options d'une VM Proxmox avec QEMU Guest Agent activé](images/proxmox-opnsense-enable-qemu-guest-agent.png) Finalement je redémarre la VM. Une fois démarrée, depuis la WebGUI de Proxmox, je peux voir les IPs de la VM ce qui confirme que le guest agent fonctionne. @@ -92,7 +92,7 @@ Finalement je redémarre la VM. Une fois démarrée, depuis la WebGUI de Proxmox ## Interfaces Sur les deux pare‑feu, j'assigne les NIC restantes à de nouvelles interfaces en ajoutant une description. Les VMs ont 7 interfaces, je compare attentivement les adresses MAC pour éviter de mélanger les interfaces : -![Assign interfaces menu in OPNsense](img/opnsense-assign-interfaces.png) +![Assignement des interfaces dans OPNsense](images/opnsense-assign-interfaces.png) Au final, la configuration des interfaces ressemble à ceci : @@ -160,13 +160,13 @@ La HA est configurée dans `System` > `High Availability` > `Settings` ### Statut de la HA Dans `System` > `High Availability` > `Status`, je peux vérifier si la synchronisation fonctionne. Sur cette page je peux répliquer un ou tous les services du master vers le nœud backup : -![OPNsense high availability status page](img/opnsense-high-availability-status.png) +![Page de statut de la haute disponibilité dans OPNsense](images/opnsense-high-availability-status.png) --- ## IPs Virtuelles Maintenant que la HA est configurée, je peux attribuer à mes réseaux une IP virtuelle partagée entre mes nœuds. Dans `Interfaces` > `Virtual IPs` > `Settings`, je crée un VIP pour chacun de mes réseaux en utilisant **CARP** (Common Address Redundancy Protocol). L'objectif est de réutiliser les adresses IP utilisées par mon instance OPNsense actuelle, mais comme elle route encore mon réseau, j'utilise des IP différentes pour la phase de configuration : -![Liste des IPs virtuelles dans OPNsense](img/opnsense-interface-virtual-ips.png) +![Liste des IPs virtuelles dans OPNsense](images/opnsense-interface-virtual-ips.png) ℹ️ OPNsense permet CARP par défaut, aucune règle de pare‑feu spéciale requise @@ -242,7 +242,7 @@ Pour commencer, dans `Firewall` > `Groups`, je crée 2 zones pour regrouper m ### Network Aliases Ensuite, dans `Firewall` > `Aliases`, je crée un alias `InternalNetworks` pour regrouper tous mes réseaux internes : -![Création d'alias pour les réseaux locaux dansOPNsense](img/opnsense-create-alias-internalnetworks.png) +![Création d'alias pour les réseaux locaux dansOPNsense](images/opnsense-create-alias-internalnetworks.png) ### Règles de Pare-feu Rules @@ -345,17 +345,17 @@ Sur le nœud backup, je le configure de la même manière, la seule différence ### Plages DHCP Ensuite je configure les plages DHCP. Les deux pare‑feu auront des plages différentes, le nœud backup aura des plages plus petites (10 baux devraient suffire). Sur le master, elles sont configurées comme suit : -![OPNsense DHCP ranges in Dnsmasq](img/opnsense-dnsmasq-dhcp-ranges.png) +![Plages DHCP de Dnsmasq dans OPNsense](images/opnsense-dnsmasq-dhcp-ranges.png) ### Options DHCP Puis je définis quelques options DHCP pour chaque domaine : le `router`, le `dns-server` et le `domain-name`. Je pointe les adresses IP vers la VIP de l'interface : -![OPNsense DHCP options in Dnsmasq](img/opnsense-dnsmasq-dhcp-options.png) +![Options DHCP de Dnsmasq dans OPNsense](images/opnsense-dnsmasq-dhcp-options.png) ### Hôtes Enfin, dans l'onglet `Hosts`, je définis des mappings DHCP statiques mais aussi des IP statiques non gérées par le DHCP, pour qu'elles soient enregistrées dans le DNS : -![Hôtes DHCP de Dnsmasq dans OPNsense](img/opnsense-dnsmasq-dhcp-hosts.png) +![Hôtes DHCP de Dnsmasq dans OPNsense](images/opnsense-dnsmasq-dhcp-hosts.png) --- ## DNS @@ -372,7 +372,7 @@ Unbound est le résolveur récursif, pour les zones locales j'effectue un forwar ### Paramètres Généraux d'Unbound Configurons-le, dans `Services` > `Unbound DNS` > `General` : -![OPNsense Unbound DNS general settings](img/opnsense-unbound-general-settings.png) +![Paramètres généraux d'Unbound DNS dans OPNsense](images/opnsense-unbound-general-settings.png) ### Liste de Blocage DNS @@ -383,7 +383,7 @@ Pour maintenir le service à jour, dans `System` > `Settings` > `Cron`, j'a ### Transfert de Requêtes Enfin je configure le transfert de requêtes pour mes domaines locaux vers Dnsmasq. Dans `Services` > `Unbound DNS` > `Query Forwarding`, j'ajoute chacun de mes domaines locaux avec leurs reverse lookups (enregistrements PTR) : -![Configuration du transfert de requêtes d'Unbound DNS dans OPNsense](img/opnsense-unbound-dns-query-forwarding.png) +![Configuration du transfert de requêtes d'Unbound DNS dans OPNsense](images/opnsense-unbound-dns-query-forwarding.png) --- ## VPN diff --git a/content/post/13-opnsense-full-configuration/index.md b/content/post/13-opnsense-full-configuration/index.md index cc4a81e..eb6dec5 100644 --- a/content/post/13-opnsense-full-configuration/index.md +++ b/content/post/13-opnsense-full-configuration/index.md @@ -92,7 +92,7 @@ Finally I restart the VM. Once started, from the Proxmox WebGUI, I can see the I ## Interfaces On both firewalls, I assign the remaining NICs to new interfaces adding a description. The VMs have 7 interfaces, I carefully compare MAC addresses to avoid mixing interfaces: -![Assign interfaces menu in OPNsense](img/opnsense-assign-interfaces.png) +![Assign interfaces menu in OPNsense](images/opnsense-assign-interfaces.png) In the end, the interfaces configuration looks like this: @@ -157,13 +157,13 @@ The HA is setup in `System` > `High Availability` > `Settings` ### HA Status In the section `System` > `High Availability` > `Status`, I can verify if the synchronization is working. On this page I can replicate any or all services from my master to my backup node: -![OPNsense high availability status page](img/opnsense-high-availability-status.png) +![OPNsense high availability status page](images/opnsense-high-availability-status.png) --- ## Virtual IPs Now that HA is configured, I can give my networks a virtual IP shared across my nodes. In `Interfaces` > `Virtual IPs` > `Settings`, I create one VIP for each of my networks using **CARP** (Common Address Redundancy Protocol). The target is to reuse the IP addresses used by my current OPNsense instance, but as it is still routing my network, I use different IPs for the configuration phase: -![Liste des IPs virtuelles dans OPNsense](img/opnsense-interface-virtual-ips.png) +![OPNsense virtual IPs list](images/opnsense-interface-virtual-ips.png) ℹ️ OPNsense allows CARP by default, no special firewall rule required @@ -239,7 +239,7 @@ To begin, in `Firewall` > `Groups`, I create 2 zones to regroup my interfaces: ### Network Aliases Next, in `Firewall` > `Aliases`, I create an alias `InternalNetworks` to regroup all my internal networks: -![Création d'alias pour les réseaux locaux dansOPNsense](img/opnsense-create-alias-internalnetworks.png) +![OPNsense alias creation for internal networks ](images/opnsense-create-alias-internalnetworks.png) ### Firewall Rules @@ -343,17 +343,17 @@ On the backup node, I configure it the same, the only difference will be the **D ### DHCP Ranges Next I configure the DHCP ranges. Both firewalls will have different ranges, the backup node will have smaller ones (only 10 leases should be enough). On the master, they are configured as follow: -![OPNsense DHCP ranges in Dnsmasq](img/opnsense-dnsmasq-dhcp-ranges.png) +![OPNsense DHCP ranges in Dnsmasq](images/opnsense-dnsmasq-dhcp-ranges.png) ### DHCP Options Then I set some DHCP options for each domain: the `router`, the `dns-server` and the `domain-name`. I'm pointing the IP addresses to the interface's VIP: -![OPNsense DHCP options in Dnsmasq](img/opnsense-dnsmasq-dhcp-options.png) +![OPNsense DHCP options in Dnsmasq](images/opnsense-dnsmasq-dhcp-options.png) ### Hosts Finally in in the `Hosts` tab, I define static DHCP mappings but also static IP not managed by the DHCP, to have them registered in the DNS: -![Hôtes DHCP de Dnsmasq dans OPNsense](img/opnsense-dnsmasq-dhcp-hosts.png) +![OPNsense DHCP hosts in Dnsmasq](images/opnsense-dnsmasq-dhcp-hosts.png) --- ## DNS @@ -370,7 +370,7 @@ Unbound is the recursive resolver, for local zones I forward queries to Dnsmasq. ### Unbound General Settings Let's configure it, in `Services` > `Unbound DNS` > `General`: -![OPNsense Unbound DNS general settings](img/opnsense-unbound-general-settings.png) +![OPNsense Unbound DNS general settings](images/opnsense-unbound-general-settings.png) ### DNS Blocklist @@ -381,7 +381,7 @@ To maintain the service up to date, in `System` > `Settings` > `Cron`, I add my ### Query Forwarding Finally I configure query forwarding for my local domains to Dnsmasq. In `Services` > `Unbound DNS` > `Query Forwarding`, I add each of my local domains with their reverse lookup (PTR record): -![Configuration du transfert de requêtes d'Unbound DNS dans OPNsense](img/opnsense-unbound-dns-query-forwarding.png) +![OPNsense Unbound DNS query forwarding configuration](images/opnsense-unbound-dns-query-forwarding.png) --- ## VPN diff --git a/content/post/14-proxmox-cluster-upgrade-8-to-9-ceph/images/proxmox-ceph-status-osd-restart.png b/content/post/14-proxmox-cluster-upgrade-8-to-9-ceph/images/proxmox-ceph-status-osd-restart.png new file mode 100644 index 0000000..be28ab5 Binary files /dev/null and b/content/post/14-proxmox-cluster-upgrade-8-to-9-ceph/images/proxmox-ceph-status-osd-restart.png differ diff --git a/content/post/14-proxmox-cluster-upgrade-8-to-9-ceph/images/proxmox-ceph-version-upgrade.png b/content/post/14-proxmox-cluster-upgrade-8-to-9-ceph/images/proxmox-ceph-version-upgrade.png new file mode 100644 index 0000000..e1f80d4 Binary files /dev/null and b/content/post/14-proxmox-cluster-upgrade-8-to-9-ceph/images/proxmox-ceph-version-upgrade.png differ diff --git a/content/post/14-proxmox-cluster-upgrade-8-to-9-ceph/index.fr.md b/content/post/14-proxmox-cluster-upgrade-8-to-9-ceph/index.fr.md index 0ff828d..3b31f37 100644 --- a/content/post/14-proxmox-cluster-upgrade-8-to-9-ceph/index.fr.md +++ b/content/post/14-proxmox-cluster-upgrade-8-to-9-ceph/index.fr.md @@ -108,7 +108,7 @@ apt full-upgrade -y ``` Après la mise à niveau sur le premier nœud, la version Ceph affiche maintenant `19.2.3`, je peux voir mes OSD apparaître comme obsolètes, les moniteurs nécessitent soit une mise à niveau soit un redémarrage : -![Ceph storage status in Proxmox after first node Ceph package udpate](img/proxmox-ceph-version-upgrade.png) +![État du stockage Ceph dans Proxmox après la mise à jour des paquets Ceph du premier nœud](images/proxmox-ceph-version-upgrade.png) Je poursuis et mets à niveau les paquets sur les 2 autres nœuds. @@ -132,7 +132,7 @@ systemctl restart ceph-osd.target ``` Je surveille le statut Ceph avec la WebGUI Proxmox. Après le redémarrage, elle affiche quelques couleurs fancy. J’attends juste que les PG redeviennent verts, cela prend moins d’une minute : -![Ceph storage status in Proxmox during the first OSD restart](img/proxmox-ceph-status-osd-restart.png) +![État du stockage Ceph dans Proxmox lors du premier redémarrage d'un OSD](images/proxmox-ceph-status-osd-restart.png) Un avertissement apparaît : `HEALTH_WARN: all OSDs are running squid or later but require_osd_release < squid` diff --git a/content/post/14-proxmox-cluster-upgrade-8-to-9-ceph/index.md b/content/post/14-proxmox-cluster-upgrade-8-to-9-ceph/index.md index b77c6c9..8850643 100644 --- a/content/post/14-proxmox-cluster-upgrade-8-to-9-ceph/index.md +++ b/content/post/14-proxmox-cluster-upgrade-8-to-9-ceph/index.md @@ -108,7 +108,7 @@ apt full-upgrade -y ``` After the upgrade on the first node, the Ceph version now shows `19.2.3`, I can see my OSDs appear as outdated, the monitors need either an upgrade or a restart: -![Ceph storage status in Proxmox after first node Ceph package udpate](img/proxmox-ceph-version-upgrade.png) +![Ceph storage status in Proxmox after first node Ceph package udpate](images/proxmox-ceph-version-upgrade.png) I carry on and upgrade the packages on the 2 other nodes. @@ -132,7 +132,7 @@ systemctl restart ceph-osd.target ``` I monitor the Ceph status with the Proxmox WebGUI. After the restart, it is showing some fancy colors. I'm just waiting for the PGs to be back to green, it takes less than a minute: -![Ceph storage status in Proxmox during the first OSD restart](img/proxmox-ceph-status-osd-restart.png) +![Ceph storage status in Proxmox during the first OSD restart](images/proxmox-ceph-status-osd-restart.png) A warning shows up: `HEALTH_WARN: all OSDs are running squid or later but require_osd_release < squid` diff --git a/content/post/15-migration-opnsense-proxmox-highly-available/images/opnsense-ping-failover.png b/content/post/15-migration-opnsense-proxmox-highly-available/images/opnsense-ping-failover.png new file mode 100644 index 0000000..894d308 Binary files /dev/null and b/content/post/15-migration-opnsense-proxmox-highly-available/images/opnsense-ping-failover.png differ diff --git a/content/post/15-migration-opnsense-proxmox-highly-available/images/proxmox-add-vm-ha.png b/content/post/15-migration-opnsense-proxmox-highly-available/images/proxmox-add-vm-ha.png new file mode 100644 index 0000000..cdbdc83 Binary files /dev/null and b/content/post/15-migration-opnsense-proxmox-highly-available/images/proxmox-add-vm-ha.png differ diff --git a/content/post/15-migration-opnsense-proxmox-highly-available/images/proxmox-cerbere-vm-settings.png b/content/post/15-migration-opnsense-proxmox-highly-available/images/proxmox-cerbere-vm-settings.png new file mode 100644 index 0000000..6fef7d8 Binary files /dev/null and b/content/post/15-migration-opnsense-proxmox-highly-available/images/proxmox-cerbere-vm-settings.png differ diff --git a/content/post/15-migration-opnsense-proxmox-highly-available/images/proxmox-ha-resource-affinity-rule.png b/content/post/15-migration-opnsense-proxmox-highly-available/images/proxmox-ha-resource-affinity-rule.png new file mode 100644 index 0000000..ee05836 Binary files /dev/null and b/content/post/15-migration-opnsense-proxmox-highly-available/images/proxmox-ha-resource-affinity-rule.png differ diff --git a/content/post/15-migration-opnsense-proxmox-highly-available/images/proxmox-sdn-new-vnet-wan.png b/content/post/15-migration-opnsense-proxmox-highly-available/images/proxmox-sdn-new-vnet-wan.png new file mode 100644 index 0000000..7248de5 Binary files /dev/null and b/content/post/15-migration-opnsense-proxmox-highly-available/images/proxmox-sdn-new-vnet-wan.png differ diff --git a/content/post/15-migration-opnsense-proxmox-highly-available/images/unifi-add-vlan-for-wan.png b/content/post/15-migration-opnsense-proxmox-highly-available/images/unifi-add-vlan-for-wan.png new file mode 100644 index 0000000..c7abe4d Binary files /dev/null and b/content/post/15-migration-opnsense-proxmox-highly-available/images/unifi-add-vlan-for-wan.png differ diff --git a/content/post/15-migration-opnsense-proxmox-highly-available/images/unifi-enable-port-wan-vlan.png b/content/post/15-migration-opnsense-proxmox-highly-available/images/unifi-enable-port-wan-vlan.png new file mode 100644 index 0000000..8baf426 Binary files /dev/null and b/content/post/15-migration-opnsense-proxmox-highly-available/images/unifi-enable-port-wan-vlan.png differ diff --git a/content/post/15-migration-opnsense-proxmox-highly-available/index.fr.md b/content/post/15-migration-opnsense-proxmox-highly-available/index.fr.md index 2cb305d..c49651f 100644 --- a/content/post/15-migration-opnsense-proxmox-highly-available/index.fr.md +++ b/content/post/15-migration-opnsense-proxmox-highly-available/index.fr.md @@ -34,12 +34,12 @@ D'abord, je configure mon réseau de couche 2 qui est géré par UniFi. Là, je - _pfSync_ (44), communication entre mes nœuds OPNsense. Dans le contrôleur UniFi, dans `Paramètres` > `Réseaux`, j'ajoute un `New Virtual Network`. Je le nomme `WAN` et lui donne l'ID VLAN 20 : -![Creation of the WAN VLAN in the UniFi Controller](img/unifi-add-vlan-for-wan.png) +![Création du VLAN WAN dans le contrôleur UniFi](images/unifi-add-vlan-for-wan.png) Je fais la même chose pour le VLAN `pfSync` avec l'ID VLAN 44. Je prévois de brancher ma box FAI sur le port 15 de mon switch, qui est désactivé pour l'instant. Je l'active, définis le VLAN natif sur le nouveau `WAN (20)` et désactive le trunking : -![Configuration du port du switch UniFi pour la liaison WAN](img/unifi-enable-port-wan-vlan.png) +![Configuration du port du switch UniFi pour la liaison WAN](images/unifi-enable-port-wan-vlan.png) Une fois ce réglage appliqué, je m'assure que seules les ports où sont connectés mes nœuds Proxmox propagent ces VLANs sur leur trunk. @@ -50,7 +50,7 @@ J'ai fini la configuration UniFi. Maintenant que le VLAN peut atteindre mes nœuds, je veux le gérer dans le SDN de Proxmox. J'ai configuré le SDN dans [cet article]({{< ref "post/11-proxmox-cluster-networking-sdn" >}}). Dans `Datacenter` > `SDN` > `VNets`, je crée un nouveau VNet, je l'appelle `vlan20` pour suivre ma propre convention de nommage, je lui donne l'alias _WAN_ et j'utilise le tag (ID VLAN) 20 : -![Creation of the VNet for the WAN in the Proxmox SDN](img/proxmox-sdn-new-vnet-wan.png) +![Création du VNet pour le WAN dans le SDN Proxmox](images/proxmox-sdn-new-vnet-wan.png) Je crée aussi le `vlan44` pour le VLAN _pfSync_, puis j'applique cette configuration et nous avons terminé avec le SDN. @@ -75,7 +75,7 @@ La première VM s'appelle `cerbere-head1` (je ne vous l'ai pas dit ? Mon firew 6. `vlan55` _(DMZ)_ 7. `vlan66` _(Lab)_ -![Hardware settings of the OPNsense VM in Proxmox](img/proxmox-cerbere-vm-settings.png) +![Paramètres matériels de la VM OPNsense dans Proxmox](images/proxmox-cerbere-vm-settings.png) ℹ️ Maintenant je clone cette VM pour créer `cerbere-head2`, puis je procède à l'installation d'OPNsense. Je ne veux pas entrer trop dans les détails de l'installation d'OPNsense, je l'ai déjà documentée dans le [proof of concept]({{< ref "post/12-opnsense-virtualization-highly-available" >}}). @@ -117,7 +117,7 @@ Dans Proxmox VE 8, il était possible de créer des groupes HA, en fonction de l Le cluster Proxmox est capable de fournir de la HA pour les ressources, mais vous devez définir les règles. Dans `Datacenter` > `HA`, vous pouvez voir le statut et gérer les ressources. Dans le panneau `Resources` je clique sur `Add`. Je dois choisir la ressource à configurer en HA dans la liste, ici `cerbere-head1` avec l'ID 122. Puis dans l'infobulle je peux définir le maximum de redémarrages et de relocations, je laisse `Failback` activé et l'état demandé à `started` : -![Create HA resource in Proxmox](img/proxmox-add-vm-ha.png) +![Créer une ressource HA dans Proxmox](images/proxmox-add-vm-ha.png) Le cluster Proxmox s'assurera maintenant que cette VM est démarrée. Je fais de même pour l'autre VM OPNsense, `cerbere-head2`. @@ -126,7 +126,7 @@ Le cluster Proxmox s'assurera maintenant que cette VM est démarrée. Je fais de Super, mais je ne veux pas qu'elles tournent sur le même nœud. C'est là qu'intervient la nouvelle fonctionnalité des règles d'affinité HA de Proxmox VE 9. Proxmox permet de créer des règles d'affinité de nœud et de ressource. Peu m'importe sur quel nœud elles tournent, mais je ne veux pas qu'elles soient ensemble. J'ai besoin d'une règle d'affinité de ressource. Dans `Datacenter` > `HA` > `Affinity Rules`, j'ajoute une nouvelle règle d'affinité de ressource HA. Je sélectionne les deux VMs et choisis l'option `Keep Separate` : -![Create HA resource affinity in Proxmox](img/proxmox-ha-resource-affinity-rule.png) +![Créer une affinité de ressource HA dans Proxmox](images/proxmox-ha-resource-affinity-rule.png) ✅ Mes VMs OPNsense sont maintenant entièrement prêtes ! @@ -393,7 +393,7 @@ En entrant manuellement en mode maintenance CARP depuis l'interface WebGUI, aucu Pour simuler un failover, je tue la VM OPNsense active. Ici j'observe une seule perte de paquet. Génial. -![Ping test during OPNsense CARP failover](img/opnsense-ping-failover.png) +![Test de ping pendant le CARP failover d'OPNsense](images/opnsense-ping-failover.png) 3. **Reprise après sinistre** diff --git a/content/post/15-migration-opnsense-proxmox-highly-available/index.md b/content/post/15-migration-opnsense-proxmox-highly-available/index.md index 50f7021..34bc1dc 100644 --- a/content/post/15-migration-opnsense-proxmox-highly-available/index.md +++ b/content/post/15-migration-opnsense-proxmox-highly-available/index.md @@ -33,12 +33,12 @@ First, I configure my layer 2 network which is managed by UniFi. There I need to - *pfSync* (44), communication between my OPNsense nodes. In the UniFi controller, in `Settings` > `Networks`, I add a `New Virtual Network`. I name it `WAN` and give it the VLAN ID 20: -![Creation of the WAN VLAN in the UniFi Controller](img/unifi-add-vlan-for-wan.png) +![Creation of the WAN VLAN in the UniFi Controller](images/unifi-add-vlan-for-wan.png) I do the same thing again for the `pfSync` VLAN with the VLAN ID 44. I plan to plug my ISP box on the port 15 of my switch, which is disabled for now. I set it as active, set the native VLAN on the newly created one `WAN (20)` and disable trunking: -![Configuration du port du switch UniFi pour la liaison WAN](img/unifi-enable-port-wan-vlan.png) +![Configuration of the UniFi switch port for the WAN uplink](images/unifi-enable-port-wan-vlan.png) Once this setting applied, I make sure that only the ports where are connected my Proxmox nodes propagate these VLAN on their trunk. @@ -49,7 +49,7 @@ I'm done with UniFi configuration. Now that the VLAN can reach my nodes, I want to handle it in the Proxmox SDN. I've configured the SDN in [that article]({{< ref "post/11-proxmox-cluster-networking-sdn" >}}). In `Datacenter` > `SDN` > `VNets`, I create a new VNet, call it `vlan20` to follow my own naming convention, give it the *WAN* alias and use the tag (VLAN ID) 20: -![Creation of the VNet for the WAN in the Proxmox SDN](img/proxmox-sdn-new-vnet-wan.png) +![Creation of the VNet for the WAN in the Proxmox SDN](images/proxmox-sdn-new-vnet-wan.png) I also create the `vlan44` for the *pfSync* VLAN, then I apply this configuration and we are done with the SDN. @@ -74,7 +74,7 @@ The first VM is named `cerbere-head1` (I didn't tell you? My current firewall is 6. `vlan55` *(DMZ)* 7. `vlan66` *(Lab)* -![Hardware settings of the OPNsense VM in Proxmox](img/proxmox-cerbere-vm-settings.png) +![Hardware settings of the OPNsense VM in Proxmox](images/proxmox-cerbere-vm-settings.png) ℹ️ Now I clone that VM to create `cerbere-head2`, then I proceed with OPNsense installation. I don't want to go into much details about OPNsense installation, I already documented it in the [proof of concept]({{< ref "post/12-opnsense-virtualization-highly-available" >}}). @@ -115,7 +115,7 @@ In Proxmox VE 8, It was possible to create HA groups, depending of their resourc The Proxmox cluster is able to provide HA for the resources, but you need to define the rules. In `Datacenter` > `HA`, you can see the status and manage the resources. In the `Resources` panel I click on `Add`. I need to pick the resource to configure as HA in the list, here `cerbere-head1` with ID 122. Then in the tooltip I can define the maximum of restart and relocate, I keep `Failback` enabled and the requested state to `started`: -![Create HA resource in Proxmox](img/proxmox-add-vm-ha.png) +![Create HA resource in Proxmox](images/proxmox-add-vm-ha.png) The Proxmox cluster will now make sure this VM is started. I do the same for the other OPNsense VM, `cerbere-head2`. @@ -124,7 +124,7 @@ The Proxmox cluster will now make sure this VM is started. I do the same for the Great, but I don't want them on the same node. This is when the new feature HA affinity rules, of Proxmox VE 9, come in. Proxmox allows to create node affinity and resource affinity rules. I don't mind on which node they run, but I don't want them together. I need a resource affinity rule. In `Datacenter` > `HA` > `Affinity Rules`, I add a new HA resource affinity rule. I select both VMs and pick the option `Keep Separate`: -![Create HA resource affinity in Proxmox](img/proxmox-ha-resource-affinity-rule.png) +![Create HA resource affinity in Proxmox](images/proxmox-ha-resource-affinity-rule.png) ✅ My OPNsense VMs are now fully ready! @@ -390,7 +390,7 @@ When manually entering CARP maintenance mode from the WebGUI interface, no packe To simulate a failover, I kill the active OPNsense VM. Here I observe only one packet dropped. Awesome. -![Ping test during OPNsense CARP failover](img/opnsense-ping-failover.png) +![Ping test during OPNsense CARP failover](images/opnsense-ping-failover.png) 3. **Disaster Recovery** diff --git a/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-add-repository.png b/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-add-repository.png new file mode 100644 index 0000000..0019cee Binary files /dev/null and b/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-add-repository.png differ diff --git a/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-create-new-ansible-task-template.png b/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-create-new-ansible-task-template.png new file mode 100644 index 0000000..89f9e37 Binary files /dev/null and b/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-create-new-ansible-task-template.png differ diff --git a/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-create-new-ssh-key.png b/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-create-new-ssh-key.png new file mode 100644 index 0000000..660e2f3 Binary files /dev/null and b/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-create-new-ssh-key.png differ diff --git a/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-create-new-static-inventory.png b/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-create-new-static-inventory.png new file mode 100644 index 0000000..3d0e7ff Binary files /dev/null and b/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-create-new-static-inventory.png differ diff --git a/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-create-project.png b/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-create-project.png new file mode 100644 index 0000000..cebe148 Binary files /dev/null and b/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-create-project.png differ diff --git a/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-login-page.png b/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-login-page.png new file mode 100644 index 0000000..3c5a3dd Binary files /dev/null and b/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-login-page.png differ diff --git a/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-run-test-playbook.png b/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-run-test-playbook.png new file mode 100644 index 0000000..9f02e7e Binary files /dev/null and b/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-run-test-playbook.png differ diff --git a/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-running-terraform-code-options.png b/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-running-terraform-code-options.png new file mode 100644 index 0000000..2a89dff Binary files /dev/null and b/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-running-terraform-code-options.png differ diff --git a/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-task-template-terraform.png b/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-task-template-terraform.png new file mode 100644 index 0000000..0803c46 Binary files /dev/null and b/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-task-template-terraform.png differ diff --git a/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-terraform-task-working.png b/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-terraform-task-working.png new file mode 100644 index 0000000..50b3313 Binary files /dev/null and b/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-terraform-task-working.png differ diff --git a/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-ui-ansible-task-output.png b/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-ui-ansible-task-output.png new file mode 100644 index 0000000..d4f379c Binary files /dev/null and b/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-ui-ansible-task-output.png differ diff --git a/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-ui-create-variable-group.png b/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-ui-create-variable-group.png new file mode 100644 index 0000000..d8752f2 Binary files /dev/null and b/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-ui-create-variable-group.png differ diff --git a/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-ui-deploy-with-terraform.png b/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-ui-deploy-with-terraform.png new file mode 100644 index 0000000..a52514a Binary files /dev/null and b/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-ui-deploy-with-terraform.png differ diff --git a/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-ui-task-template-run-list.png b/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-ui-task-template-run-list.png new file mode 100644 index 0000000..e6d602a Binary files /dev/null and b/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-ui-task-template-run-list.png differ diff --git a/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-ui-test-nginx-page-playbook.png b/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-ui-test-nginx-page-playbook.png new file mode 100644 index 0000000..d351f83 Binary files /dev/null and b/content/post/17-semaphore-ui-interface-ansible-terraform/images/semaphore-ui-test-nginx-page-playbook.png differ diff --git a/content/post/17-semaphore-ui-interface-ansible-terraform/index.fr.md b/content/post/17-semaphore-ui-interface-ansible-terraform/index.fr.md index 7b1458f..6049967 100644 --- a/content/post/17-semaphore-ui-interface-ansible-terraform/index.fr.md +++ b/content/post/17-semaphore-ui-interface-ansible-terraform/index.fr.md @@ -109,23 +109,23 @@ Avec Semaphore en fonctionnement, faisons rapidement le tour de l'UI et connecto ## Discovery Après avoir démarré la stack, je peux atteindre la page de connexion à l'URL : -![Page de connexion de Semaphore UI](img/semaphore-login-page.png) +![Page de connexion de Semaphore UI](images/semaphore-login-page.png) Pour me connecter, j'utilise les identifiants définis par `SEMAPHORE_ADMIN_NAME`/`SEMAPHORE_ADMIN_PASSWORD`. Au premier accès, Semaphore me demande de créer un projet. J'ai créé le projet Homelab : -![Page de création de projet de Semaphore UI](img/semaphore-create-project.png) +![Page de création de projet de Semaphore UI](images/semaphore-create-project.png) La première chose que je veux faire est d'ajouter mon dépôt _homelab_ (vous pouvez trouver son miroir sur Github [ici](https://github.com/Vezpi/homelab)). Dans `Repository`, je clique sur le bouton `New Repository`, et j'ajoute l'URL du repo. Je ne spécifie pas d'identifiants car le dépôt est public : -![Page d'ajout de dépôt de Semaphore UI](img/semaphore-add-repository.png) +![Page d'ajout de dépôt de Semaphore UI](images/semaphore-add-repository.png) ℹ️ Avant de continuer, je déploie 3 VM à des fins de test : `sem01`, `sem02` et `sem03`. Je les ai créées avec Terraform via [ce projet](https://github.com/Vezpi/Homelab/tree/main/terraform/projects/semaphore-vms). Pour interagir avec ces VM, je dois configurer des identifiants. Dans le `Key Store`, j'ajoute la première donnée d'identification, une clé SSH pour mon utilisateur : -![Page d'ajout d'une nouvelle clé de Semaphore UI](img/semaphore-create-new-ssh-key.png) +![Page d'ajout d'une nouvelle clé de Semaphore UI](images/semaphore-create-new-ssh-key.png) Ensuite je crée un nouvel `Inventory`. J'utilise le format d'inventaire Ansible (le seul disponible). Je sélectionne la clé SSH créée précédemment et choisis le type `Static`. Dans les champs je renseigne les 3 hôtes créés avec leur FQDN : -![Page de création d'un inventaire statique de Semaphore UI](img/semaphore-create-new-static-inventory.png) +![Page de création d'un inventaire statique de Semaphore UI](images/semaphore-create-new-static-inventory.png) ✅ Avec un projet, un repo, des identifiants et un inventaire en place, je peux avancer et tester l'exécution d'un playbook Ansible. @@ -172,20 +172,20 @@ Je veux tester quelque chose de simple : installer un serveur web avec une page ``` Dans Semaphore UI, je peux maintenant créer mon premier `Task Template` pour un playbook Ansible. Je lui donne un nom, le chemin du playbook (depuis le dossier racine du repo), le dépôt et sa branche : -![Nouveau template de tâche Ansible dans Semaphore UI](img/semaphore-create-new-ansible-task-template.png) +![Nouveau template de tâche Ansible dans Semaphore UI](images/semaphore-create-new-ansible-task-template.png) Il est temps de lancer le playbook ! Dans la liste des task templates, je clique sur le bouton ▶️ : -![Lancement du template de tâche Ansible dans Semaphore UI](img/semaphore-run-test-playbook.png) +![Lancement du template de tâche Ansible dans Semaphore UI](images/semaphore-run-test-playbook.png) Le playbook se lance et je peux suivre la sortie en temps réel : -![Semaphore UI Ansible task output](img/semaphore-ui-ansible-task-output.png) +![Sortie de la tâche Ansible dans Semaphore UI](images/semaphore-ui-ansible-task-output.png) Je peux aussi consulter les exécutions précédentes : -![Liste des exécutions de tâches dans Semaphore UI](img/semaphore-ui-task-template-run-list.png) +![Liste des exécutions de tâches dans Semaphore UI](images/semaphore-ui-task-template-run-list.png) ✅ Enfin, je peux confirmer que le travail est fini en vérifiant l'URL sur le port 80 (http) : -![Test de l'URL après application du playbook sur les hôtes](img/semaphore-ui-test-nginx-page-playbook.png) +![Test de l'URL après application du playbook sur les hôtes](images/semaphore-ui-test-nginx-page-playbook.png) Gérer des playbooks Ansible dans Semaphore UI est assez simple et vraiment pratique. L'interface est très soignée. @@ -233,19 +233,19 @@ Avec cela en place, le playbook a réussi et j'ai pu créer l'utilisateur : ``` Ensuite je crée un variable group `pve_vm`. Un variable group me permet de définir plusieurs variables et secrets ensemble : -![Nouveau groupe de variables dans Semaphore UI](img/semaphore-ui-create-variable-group.png) +![Nouveau groupe de variables dans Semaphore UI](images/semaphore-ui-create-variable-group.png) Puis je crée un nouveau task template, cette fois de type Terraform Code. Je lui donne un nom, le chemin du projet Terraform, un workspace, le dépôt avec sa branche et le variable group : -![Nouveau template de tâche Terraform dans Semaphore UI](img/semaphore-task-template-terraform.png) +![Nouveau template de tâche Terraform dans Semaphore UI](images/semaphore-task-template-terraform.png) Lancer le template me donne quelques options supplémentaires liées à Terraform : -![Options d'exécution Terraform dans Semaphore UI](img/semaphore-running-terraform-code-options.png) +![Options d'exécution Terraform dans Semaphore UI](images/semaphore-running-terraform-code-options.png) Après le plan Terraform, il me propose d'appliquer, d'annuler ou d'arrêter : -![Plan Terraform dans Semaphore UI](img/semaphore-terraform-task-working.png) +![Plan Terraform dans Semaphore UI](images/semaphore-terraform-task-working.png) Enfin, après avoir cliqué sur ✅ pour appliquer, j'ai pu regarder Terraform construire les VM, comme avec le CLI. À la fin, les VM ont été déployées avec succès sur Proxmox : -![Déploiement Terraform terminé dans Semaphore UI](img/semaphore-ui-deploy-with-terraform.png) +![Déploiement Terraform terminé dans Semaphore UI](images/semaphore-ui-deploy-with-terraform.png) --- ## Conclusion diff --git a/content/post/17-semaphore-ui-interface-ansible-terraform/index.md b/content/post/17-semaphore-ui-interface-ansible-terraform/index.md index 26b6f99..02ddb03 100644 --- a/content/post/17-semaphore-ui-interface-ansible-terraform/index.md +++ b/content/post/17-semaphore-ui-interface-ansible-terraform/index.md @@ -109,23 +109,23 @@ With Semaphore running, let’s take a quick tour of the UI and wire it up to a ## Discovery After starting the stack, I can reach the login page at the URL: -![Page de connexion de Semaphore UI](img/semaphore-login-page.png) +![Semaphore UI login page](images/semaphore-login-page.png) To log in, I use the credentials defined by `SEMAPHORE_ADMIN_NAME`/`SEMAPHORE_ADMIN_PASSWORD`. On first login, Semaphore prompt me to create a project. I created the Homelab project: -![Page de création de projet de Semaphore UI](img/semaphore-create-project.png) +![Semaphore UI new project page](images/semaphore-create-project.png) The first thing I want to do is to add my *homelab* repository (you can find its mirror on Github [here](https://github.com/Vezpi/homelab)). In `Repository`, I click the `New Repository` button, and add the repo URL. I don't specify credentials because the repo is public: -![Page d'ajout de dépôt de Semaphore UI](img/semaphore-add-repository.png) +![Semaphore UI new repository page](images/semaphore-add-repository.png) ℹ️ Before continue, I deploy 3 VMs for testing purpose: `sem01`, `sem02` and `sem03`. I created them using Terraform with [this project](https://github.com/Vezpi/Homelab/tree/main/terraform/projects/semaphore-vms). To interact with these VMs I need to configure credentials. In the the `Key Store`, I add the first credential, a SSH key for my user: -![Page d'ajout d'une nouvelle clé de Semaphore UI](img/semaphore-create-new-ssh-key.png) +![Semaphore UI new key page](images/semaphore-create-new-ssh-key.png) Then I create a new `Inventory`. I'm using the Ansible inventory format (the only one available). I select the SSH key previously created and select the type as `Static`. In the fields I enter the 3 hosts created with their FQDN: -![Page de création d'un inventaire statique de Semaphore UI](img/semaphore-create-new-static-inventory.png) +![Semaphore UI new inventory page](images/semaphore-create-new-static-inventory.png) ✅ With a project, repo, credentials, and inventory in place, I can move forward and test to run an Ansible playbook. @@ -172,20 +172,20 @@ I want to test something simple, install a web server with a custom page on thes ``` In Semaphore UI, I can now create my first `Task Template` for Ansible playbook. I give it a name, the playbook path (from the root folder of the repo), the repository and its branch: -![Nouveau template de tâche Ansible dans Semaphore UI](img/semaphore-create-new-ansible-task-template.png) +![Semaphore UI new Ansible task template](images/semaphore-create-new-ansible-task-template.png) Time to launch the playbook! In the task templates list, I click on the ▶️ button: -![Lancement du template de tâche Ansible dans Semaphore UI](img/semaphore-run-test-playbook.png) +![Semaphore UI launch Ansible task template](images/semaphore-run-test-playbook.png) The playbook launches and I can follow the output in real time: -![Semaphore UI Ansible task output](img/semaphore-ui-ansible-task-output.png) +![Semaphore UI Ansible task output](images/semaphore-ui-ansible-task-output.png) I can also review previous runs: -![Liste des exécutions de tâches dans Semaphore UI](img/semaphore-ui-task-template-run-list.png) +![Semaphore UI tasks runs list](images/semaphore-ui-task-template-run-list.png) ✅ Finally I can confirm the job is done by checking the URL on port 80 (http): -![Test de l'URL après application du playbook sur les hôtes](img/semaphore-ui-test-nginx-page-playbook.png) +![Testing URL after applying playbook on hosts ](images/semaphore-ui-test-nginx-page-playbook.png) Managing Ansible playbooks in Semaphore UI is pretty simple and really convenient. The interface is really sleek. @@ -233,19 +233,19 @@ With that in place, the playbook succeeded and I could create the user: ``` Next I create a variable group `pve_vm`. A variable group let me define multiple variables and secrets together: -![Nouveau groupe de variables dans Semaphore UI](img/semaphore-ui-create-variable-group.png) +![Semaphore UI new variable group](images/semaphore-ui-create-variable-group.png) Then I create a new task template, this time with the kind Terraform Code. I give it a name, the path of the terraform [project](https://github.com/Vezpi/Homelab/tree/main/terraform/projects/semaphore-vms), a workspace, the repository along with its branch and. the variable group: -![Nouveau template de tâche Terraform dans Semaphore UI](img/semaphore-task-template-terraform.png) +![Semaphore UI new Terraform task template](images/semaphore-task-template-terraform.png) Running the template gives me some additional options related to Terraform: -![Options d'exécution Terraform dans Semaphore UI](img/semaphore-running-terraform-code-options.png) +![Semaphore UI run Terraform task](images/semaphore-running-terraform-code-options.png) After the Terraform plan, I'm proposed to apply, cancel or stop: -![Plan Terraform dans Semaphore UI](img/semaphore-terraform-task-working.png) +![Semaphore UI task Terraform plan](images/semaphore-terraform-task-working.png) Finally after hitting ✅ to apply, I could watch Terraform build the VMs, just like using the CLI. At the end, the VMs were successfully deployed on Proxmox: -![Déploiement Terraform terminé dans Semaphore UI](img/semaphore-ui-deploy-with-terraform.png) +![Semaphore UI Terraform deploy complete](images/semaphore-ui-deploy-with-terraform.png) --- ## Conclusion diff --git a/content/post/18-create-nas-server-with-truenas/images/nasdeck-android-app.png b/content/post/18-create-nas-server-with-truenas/images/nasdeck-android-app.png new file mode 100644 index 0000000..78487dd Binary files /dev/null and b/content/post/18-create-nas-server-with-truenas/images/nasdeck-android-app.png differ diff --git a/content/post/18-create-nas-server-with-truenas/images/truenas-config-change-hostname.png b/content/post/18-create-nas-server-with-truenas/images/truenas-config-change-hostname.png new file mode 100644 index 0000000..b6bd034 Binary files /dev/null and b/content/post/18-create-nas-server-with-truenas/images/truenas-config-change-hostname.png differ diff --git a/content/post/18-create-nas-server-with-truenas/images/truenas-create-dataset-files.png b/content/post/18-create-nas-server-with-truenas/images/truenas-create-dataset-files.png new file mode 100644 index 0000000..a231204 Binary files /dev/null and b/content/post/18-create-nas-server-with-truenas/images/truenas-create-dataset-files.png differ diff --git a/content/post/18-create-nas-server-with-truenas/images/truenas-create-new-user.png b/content/post/18-create-nas-server-with-truenas/images/truenas-create-new-user.png new file mode 100644 index 0000000..a80eed0 Binary files /dev/null and b/content/post/18-create-nas-server-with-truenas/images/truenas-create-new-user.png differ diff --git a/content/post/18-create-nas-server-with-truenas/images/truenas-create-periodic-snapshot.png b/content/post/18-create-nas-server-with-truenas/images/truenas-create-periodic-snapshot.png new file mode 100644 index 0000000..48fa385 Binary files /dev/null and b/content/post/18-create-nas-server-with-truenas/images/truenas-create-periodic-snapshot.png differ diff --git a/content/post/18-create-nas-server-with-truenas/images/truenas-data-protection-tab.png b/content/post/18-create-nas-server-with-truenas/images/truenas-data-protection-tab.png new file mode 100644 index 0000000..75285a7 Binary files /dev/null and b/content/post/18-create-nas-server-with-truenas/images/truenas-data-protection-tab.png differ diff --git a/content/post/18-create-nas-server-with-truenas/images/truenas-dataset-photos-nfs-share.png b/content/post/18-create-nas-server-with-truenas/images/truenas-dataset-photos-nfs-share.png new file mode 100644 index 0000000..384d4c2 Binary files /dev/null and b/content/post/18-create-nas-server-with-truenas/images/truenas-dataset-photos-nfs-share.png differ diff --git a/content/post/18-create-nas-server-with-truenas/images/truenas-datasets-layout.png b/content/post/18-create-nas-server-with-truenas/images/truenas-datasets-layout.png new file mode 100644 index 0000000..8283504 Binary files /dev/null and b/content/post/18-create-nas-server-with-truenas/images/truenas-datasets-layout.png differ diff --git a/content/post/18-create-nas-server-with-truenas/images/truenas-fresh-install-dashboard.png b/content/post/18-create-nas-server-with-truenas/images/truenas-fresh-install-dashboard.png new file mode 100644 index 0000000..bc6882f Binary files /dev/null and b/content/post/18-create-nas-server-with-truenas/images/truenas-fresh-install-dashboard.png differ diff --git a/content/post/18-create-nas-server-with-truenas/images/truenas-iso-enter-shell.png b/content/post/18-create-nas-server-with-truenas/images/truenas-iso-enter-shell.png new file mode 100644 index 0000000..0dfd935 Binary files /dev/null and b/content/post/18-create-nas-server-with-truenas/images/truenas-iso-enter-shell.png differ diff --git a/content/post/18-create-nas-server-with-truenas/images/truenas-iso-fix-installer.png b/content/post/18-create-nas-server-with-truenas/images/truenas-iso-fix-installer.png new file mode 100644 index 0000000..e0b947a Binary files /dev/null and b/content/post/18-create-nas-server-with-truenas/images/truenas-iso-fix-installer.png differ diff --git a/content/post/18-create-nas-server-with-truenas/images/truenas-iso-installation-splash.png b/content/post/18-create-nas-server-with-truenas/images/truenas-iso-installation-splash.png new file mode 100644 index 0000000..d73ec20 Binary files /dev/null and b/content/post/18-create-nas-server-with-truenas/images/truenas-iso-installation-splash.png differ diff --git a/content/post/18-create-nas-server-with-truenas/images/truenas-iso-installation.png b/content/post/18-create-nas-server-with-truenas/images/truenas-iso-installation.png new file mode 100644 index 0000000..31d5549 Binary files /dev/null and b/content/post/18-create-nas-server-with-truenas/images/truenas-iso-installation.png differ diff --git a/content/post/18-create-nas-server-with-truenas/images/truenas-login-page-change-password.png b/content/post/18-create-nas-server-with-truenas/images/truenas-login-page-change-password.png new file mode 100644 index 0000000..bebc77b Binary files /dev/null and b/content/post/18-create-nas-server-with-truenas/images/truenas-login-page-change-password.png differ diff --git a/content/post/18-create-nas-server-with-truenas/images/truenas-pool-creation-general.png b/content/post/18-create-nas-server-with-truenas/images/truenas-pool-creation-general.png new file mode 100644 index 0000000..8563afa Binary files /dev/null and b/content/post/18-create-nas-server-with-truenas/images/truenas-pool-creation-general.png differ diff --git a/content/post/18-create-nas-server-with-truenas/images/truenas-pool-creation-layout.png b/content/post/18-create-nas-server-with-truenas/images/truenas-pool-creation-layout.png new file mode 100644 index 0000000..d88d45a Binary files /dev/null and b/content/post/18-create-nas-server-with-truenas/images/truenas-pool-creation-layout.png differ diff --git a/content/post/18-create-nas-server-with-truenas/images/truenas-pool-creation-review.png b/content/post/18-create-nas-server-with-truenas/images/truenas-pool-creation-review.png new file mode 100644 index 0000000..345cf36 Binary files /dev/null and b/content/post/18-create-nas-server-with-truenas/images/truenas-pool-creation-review.png differ diff --git a/content/post/18-create-nas-server-with-truenas/images/truenas-start-smb-service.png b/content/post/18-create-nas-server-with-truenas/images/truenas-start-smb-service.png new file mode 100644 index 0000000..f76d917 Binary files /dev/null and b/content/post/18-create-nas-server-with-truenas/images/truenas-start-smb-service.png differ diff --git a/content/post/18-create-nas-server-with-truenas/images/truenas-storage-disks-unconfigured.png b/content/post/18-create-nas-server-with-truenas/images/truenas-storage-disks-unconfigured.png new file mode 100644 index 0000000..7e0771a Binary files /dev/null and b/content/post/18-create-nas-server-with-truenas/images/truenas-storage-disks-unconfigured.png differ diff --git a/content/post/18-create-nas-server-with-truenas/index.fr.md b/content/post/18-create-nas-server-with-truenas/index.fr.md index d46a421..0db55c7 100644 --- a/content/post/18-create-nas-server-with-truenas/index.fr.md +++ b/content/post/18-create-nas-server-with-truenas/index.fr.md @@ -68,7 +68,7 @@ J'ai considéré FreeNAS/TrueNAS, OpenMediaVault et Unraid. J'ai choisi TrueNAS L'installation ne s'est pas déroulée aussi bien que prévu... J'utilise [Ventoy](https://www.ventoy.net/en/index.html) pour garder plusieurs ISOs sur une clé USB. J'étais en version 1.0.99, et l'ISO ne se lançait pas. La mise à jour vers 1.1.10 a résolu le problème : -![TrueNAS installation splash screen](img/truenas-iso-installation-splash.png) +![Écran d'accueil d'installation de TrueNAS](images/truenas-iso-installation-splash.png) Mais là j'ai rencontré un autre problème lors du lancement de l'installation sur mon périphérique de stockage eMMC : ``` @@ -77,16 +77,16 @@ Failed to find partition number 2 on mmcblk0 J'ai trouvé une solution sur ce [post](https://forums.truenas.com/t/installation-failed-on-emmc-odroid-h4/15317/12) : - Entrer dans le shell -![Enter the shell in TrueNAS installer](img/truenas-iso-enter-shell.png) +![Entrer dans le shell de l'installateur TrueNAS](images/truenas-iso-enter-shell.png) - Éditer le fichier `/lib/python3/dist-packages/truenas_installer/utils.py` - Déplacer la ligne `await asyncio.sleep(1)` juste sous `for _try in range(tries):` - Modifier la ligne 46 pour ajouter `+ 'p'` : `for partdir in filter(lambda x: x.is_dir() and x.name.startswith(device + 'p'), dir_contents):` -![Fichier corrigé dans l'installateur TrueNAS](img/truenas-iso-fix-installer.png) +![Fichier corrigé dans l'installateur TrueNAS](images/truenas-iso-fix-installer.png) - Quitter le shell et lancer l'installation sans redémarrer L'installateur a finalement pu passer : -![Progression de l'installation de TrueNAS](img/truenas-iso-installation.png) +![Progression de l'installation de TrueNAS](images/truenas-iso-installation.png) Une fois l'installation terminée, j'ai éteint la machine. Ensuite je l'ai installée dans mon rack au-dessus des 3 nœuds Proxmox VE. J'ai branché les deux câbles Ethernet depuis mon switch et je l'ai mise sous tension. @@ -99,18 +99,18 @@ Par défaut, TrueNAS utilise DHCP. J'ai trouvé son adresse MAC dans mon interfa ### Paramètres généraux Pendant l'installation, je n'ai pas défini de mot de passe pour truenas_admin. La page de connexion m'a forcé à en choisir un : -![Page de connexion TrueNAS pour changer le mot de passe de `truenas_admin`](img/truenas-login-page-change-password.png) +![Page de connexion TrueNAS pour changer le mot de passe de `truenas_admin`](images/truenas-login-page-change-password.png) Une fois le mot de passe mis à jour, j'arrive sur le tableau de bord. L'interface donne une bonne impression au premier abord : -![Tableau de bord de TrueNAS](img/truenas-fresh-install-dashboard.png) +![Tableau de bord de TrueNAS](images/truenas-fresh-install-dashboard.png) J'explore rapidement l'interface, la première chose que je fais est de changer le hostname en `granite` et de cocher la case en dessous pour hériter du domaine depuis DHCP : -![Configuration du hostname dans TrueNAS](img/truenas-config-change-hostname.png) +![Configuration du hostname dans TrueNAS](images/truenas-config-change-hostname.png) Dans les `General Settings`, je change les paramètres de `Localization`. Je mets le Console Keyboard Map sur `French (AZERTY)` et le Fuseau horaire sur `Europe/Paris`. Je crée un nouvel utilisateur `vez`, avec le rôle `Full Admin` dans TrueNAS. J'autorise SSH uniquement pour l'authentification par clé, pas de mots de passe : -![Création d'un utilisateur dans TrueNAS](img/truenas-create-new-user.png) +![Création d'un utilisateur dans TrueNAS](images/truenas-create-new-user.png) Finalement je retire le rôle admin de `truenas_admin` et verrouille le compte. @@ -119,16 +119,16 @@ Finalement je retire le rôle admin de `truenas_admin` et verrouille le compte Dans TrueNAS, un pool est une collection de stockage créée en combinant plusieurs disques en un espace unifié géré par ZFS. Dans la page `Storage`, je trouve mes `Disks`, où je peux confirmer que TrueNAS voit mon couple de NVMe : -![List of available disks in TrueNAS](img/truenas-storage-disks-unconfigured.png) +![Liste des disques disponibles dans TrueNAS](images/truenas-storage-disks-unconfigured.png) De retour sur le `Storage Dashboard`, je clique sur le bouton `Create Pool`. Je nomme le pool `storage` parce que je suis vraiment inspiré pour lui donner un nom : -![Assistant de création de pool dans TrueNAS](img/truenas-pool-creation-general.png) +![Assistant de création de pool dans TrueNAS](images/truenas-pool-creation-general.png) Puis je sélectionne la disposition `Mirror` : -![Disk layout selection in the pool creation wizard in TrueNAS](img/truenas-pool-creation-layout.png) +![Sélection de la disposition des disques dans l'assistant de création de pool dans TrueNAS](images/truenas-pool-creation-layout.png) J'explore rapidement les configurations optionnelles, mais les valeurs par défaut me conviennent : autotrim, compression, pas de dedup, etc. À la fin, avant de créer le pool, il y a une section `Review` : -![Review section of the pool creation wizard in TrueNAS](img/truenas-pool-creation-review.png) +![Section de révision de l'assistant de création de pool dans TrueNAS](images/truenas-pool-creation-review.png) Après avoir cliqué sur `Create Pool`, on m'avertit que tout sur les disques sera effacé, ce que je confirme. Finalement le pool est créé. @@ -139,10 +139,10 @@ Un dataset est un système de fichiers à l'intérieur d'un pool. Il peut conten #### Partage SMB Créons maintenant mon premier dataset `files` pour partager des fichiers sur le réseau pour mes clients Windows, comme des ISOs, etc : -![Create a dataset in TrueNAS](img/truenas-create-dataset-files.png) +![Créer un dataset dans TrueNAS](images/truenas-create-dataset-files.png) Lors de la création de datasets SMB dans SCALE, définissez le Share Type sur SMB afin que les bons ACL/xattr par défaut s'appliquent. TrueNAS me demande alors de démarrer/activer le service SMB : -![Invite à démarrer le service SMB dans TrueNAS](img/truenas-start-smb-service.png) +![Invite à démarrer le service SMB dans TrueNAS](images/truenas-start-smb-service.png) Depuis mon portable Windows, j'essaie d'accéder à mon nouveau partage `\\granite.mgmt.vezpi.com\files`. Comme prévu on me demande des identifiants. @@ -157,7 +157,7 @@ Je crée un autre dataset : `media`, et un enfant `photos`. Je crée un partag Sur mon serveur NFS actuel, les fichiers photos sont possédés par `root` (gérés par _Immich_). Plus tard je verrai comment migrer vers une version sans root. ⚠️ Pour l'instant je définis, dans les `Advanced Options`, le `Maproot User` et le `Maproot Group` sur `root`. Cela équivaut à l'attribut NFS `no_squash_root`, le `root` local du client reste `root` sur le serveur, ne faites pas ça : -![NFS share permission in TrueNAS](img/truenas-dataset-photos-nfs-share.png) +![Permissions du partage NFS dans TrueNAS](images/truenas-dataset-photos-nfs-share.png) ✅ Je monte le partage NFS sur un client, cela fonctionne bien. @@ -178,14 +178,14 @@ J'ai mentionné les capacités VM dans mes exigences. Je ne couvrirais pas cela ### Protection des données Il est maintenant temps d'activer quelques fonctionnalités de protection des données : -![Data protection features in TrueNAS](img/truenas-data-protection-tab.png) +![Fonctionnalités de protection des données dans TrueNAS](images/truenas-data-protection-tab.png) Je veux créer des snapshots automatiques pour certains de mes datasets, ceux qui me tiennent le plus à cœur : mes fichiers cloud et les photos. Créons des tâches de snapshot. Je clique sur le bouton `Add` à côté de `Periodic Snapshot Tasks` : - cloud : snapshots quotidiens, conserver pendant 2 mois - photos : snapshots quotidiens, conserver pendant 7 jours -![Create periodic snapshot task in TrueNAS ](img/truenas-create-periodic-snapshot.png) +![Créer une tâche de snapshot périodique dans TrueNAS](images/truenas-create-periodic-snapshot.png) Je pourrais aussi configurer une `Cloud Sync Task`, mais Duplicati gère déjà les sauvegardes hors site. @@ -204,12 +204,12 @@ sudo rsync -a --info=progress2 /data/photo/ /new_photos ``` À la fin, je pourrais décommissionner mon ancien serveur NFS sur le LXC. La disposition des datasets après migration ressemble à ceci : -![Dataset layout in TrueNAS](img/truenas-datasets-layout.png) +![Disposition des datasets dans TrueNAS](images/truenas-datasets-layout.png) ### Application Android Par curiosité, j'ai cherché sur le Play Store une application pour gérer une instance TrueNAS. J'ai trouvé [Nasdeck](https://play.google.com/store/apps/details?id=com.strtechllc.nasdeck&hl=fr&pli=1), qui est plutôt sympa. Voici quelques captures d'écran : -![Captures d'écran de l'application Nasdeck](img/nasdeck-android-app.png) +![Captures d'écran de l'application Nasdeck](images/nasdeck-android-app.png) --- ## Conclusion diff --git a/content/post/18-create-nas-server-with-truenas/index.md b/content/post/18-create-nas-server-with-truenas/index.md index e7908b1..602fc5c 100644 --- a/content/post/18-create-nas-server-with-truenas/index.md +++ b/content/post/18-create-nas-server-with-truenas/index.md @@ -67,7 +67,7 @@ I considered FreeNAS/TrueNAS, OpenMediaVault, and Unraid. I chose TrueNAS SCALE The install didn’t go as smoothly as expected... I use [Ventoy](https://www.ventoy.net/en/index.html) to keep multiple ISOs on one USB stick. I was in version 1.0.99, and the ISO wouldn't launch. Updating to 1.1.10 fixed it: -![TrueNAS installation splash screen](img/truenas-iso-installation-splash.png) +![TrueNAS installation splash screen](images/truenas-iso-installation-splash.png) But here I encountered another problem when launching the installation on my eMMC storage device: ``` @@ -76,16 +76,16 @@ Failed to find partition number 2 on mmcblk0 I found a solution on this [post](https://forums.truenas.com/t/installation-failed-on-emmc-odroid-h4/15317/12): - Enter the shell -![Enter the shell in TrueNAS installer](img/truenas-iso-enter-shell.png) +![Enter the shell in TrueNAS installer](images/truenas-iso-enter-shell.png) - Edit the file `/lib/python3/dist-packages/truenas_installer/utils.py` - Move the line `await asyncio.sleep(1)` right beneath `for _try in range(tries):` - Edit line 46 to add `+ 'p'`: `for partdir in filter(lambda x: x.is_dir() and x.name.startswith(device + 'p'), dir_contents):` -![Fichier corrigé dans l'installateur TrueNAS](img/truenas-iso-fix-installer.png) +![Fixed file in the TrueNAS installer](images/truenas-iso-fix-installer.png) - Exit the shell and start the installation without reboot The installer was finally able to get through: -![Progression de l'installation de TrueNAS](img/truenas-iso-installation.png) +![TrueNAS installation progress](images/truenas-iso-installation.png) Once the installation was complete, I shut down the machine. Then I installed it into my rack on top of the 3 Proxmox VE nodes. I plugged both Ethernet cables from my switch and powered it up. @@ -97,18 +97,18 @@ By default, TrueNAS uses DHCP. I found its MAC address in my UniFi interface and ### General Settings During install, I didn’t set a password for truenas_admin. The login page forced me to pick one: -![Page de connexion TrueNAS pour changer le mot de passe de `truenas_admin`](img/truenas-login-page-change-password.png) +![TrueNAS login page to change `truenas_admin` password](images/truenas-login-page-change-password.png) Once the password is updated, I land on the dashboard. The UI feels great at first glance: -![Tableau de bord de TrueNAS](img/truenas-fresh-install-dashboard.png) +![TrueNAS dashboard](images/truenas-fresh-install-dashboard.png) I quickly explore the interface, the first thing I do is changing the hostname to `granite` and check the box below et it inherit domain from DHCP: -![Configuration du hostname dans TrueNAS](img/truenas-config-change-hostname.png) +![TrueNAS hostname configuration](images/truenas-config-change-hostname.png) In the `General Settings`, I change the `Localization` settings. I set the Console Keyboard Map to `French (AZERTY)` and the Timezone to `Europe/Paris`. I create a new user `vez`, with `Full Admin` role within TrueNAS. I allow SSH for key‑based auth only, no passwords: -![Création d'un utilisateur dans TrueNAS](img/truenas-create-new-user.png) +![TrueNAS user creation](images/truenas-create-new-user.png) Finally I remove the admin role from `truenas_admin` and lock the account. @@ -117,16 +117,16 @@ Finally I remove the admin role from `truenas_admin` and lock the account. In TrueNAS, a pool is a storage collection created by combining multiple disks into a unified ZFS‑managed space. In the `Storage` page, I can find my `Disks`, where I can confirm TrueNAS can see my couple of NVMe drives: -![List of available disks in TrueNAS](img/truenas-storage-disks-unconfigured.png) +![List of available disks in TrueNAS](images/truenas-storage-disks-unconfigured.png) Back in the `Storage Dashboard`, I click the `Create Pool` button. I name the pool `storage` because I'm really inspired to give it a name: -![Assistant de création de pool dans TrueNAS](img/truenas-pool-creation-general.png) +![Pool creation wizard in TrueNAS](images/truenas-pool-creation-general.png) Then I select the `Mirror` layout: -![Disk layout selection in the pool creation wizard in TrueNAS](img/truenas-pool-creation-layout.png) +![Disk layout selection in the pool creation wizard in TrueNAS](images/truenas-pool-creation-layout.png) I explore quickly the optional configurations, but the defaults are fine to me: autotrim, compression, no dedup, etc. At the end, before creating the pool, there is a `Review` section: -![Review section of the pool creation wizard in TrueNAS](img/truenas-pool-creation-review.png) +![Review section of the pool creation wizard in TrueNAS](images/truenas-pool-creation-review.png) After hitting `Create Pool`, I'm warned that everything on the disks will be wiped, which I confirm. Finally the pool is created. @@ -137,10 +137,10 @@ A dataset is a filesystem inside a pool. It can contains files, directories and #### SMB share Let's now create my first dataset `files` to share files over the network for my Windows clients, like ISOs, etc: -![Create a dataset in TrueNAS](img/truenas-create-dataset-files.png) +![Create a dataset in TrueNAS](images/truenas-create-dataset-files.png) When creating SMB datasets in SCALE, set Share Type to SMB so the right ACL/xattr defaults apply. TrueNAS then prompts me to start/enable the SMB service: -![Invite à démarrer le service SMB dans TrueNAS](img/truenas-start-smb-service.png) +![Prompt to start SMB service in TrueNAS](images/truenas-start-smb-service.png) From my Windows Laptop, I try to access my new share `\\granite.mgmt.vezpi.com\files`. As expected I'm prompt to give credentials. @@ -155,7 +155,7 @@ I create another dataset: `media`, and a child `photos`. I create a NFS share fr On my current NFS server, the files for the photos are owned by `root` (managed by *Immich*). Later I'll see how I can migrate towards a root-less version. ⚠️ For now I set, in `Advanced Options`, the `Maproot User` and `Maproot Group` to `root`. This is equivalent to the NFS attribute `no_squash_root`, the local `root` of the client stays `root` on the server, don't do that: -![NFS share permission in TrueNAS](img/truenas-dataset-photos-nfs-share.png) +![NFS share permission in TrueNAS](images/truenas-dataset-photos-nfs-share.png) ✅ I mount the NFS share on a client, this works fine. @@ -175,14 +175,14 @@ I mentioned VM capabilities in my requirements. I won't cover that is this post, ### Data protection Now time to enable some data protection features: -![Data protection features in TrueNAS](img/truenas-data-protection-tab.png) +![Data protection features in TrueNAS](images/truenas-data-protection-tab.png) I want to create automatic snapshots for some of my datasets, those I care the most: my cloud files and photos. Let's create snapshot tasks. I click on the `Add` button next to `Periodic Snapshot Tasks`: - cloud: daily snapshots, keep for 2 months - photos: daily snapshots, keep for 7 days -![Create periodic snapshot task in TrueNAS ](img/truenas-create-periodic-snapshot.png) +![Create periodic snapshot task in TrueNAS ](images/truenas-create-periodic-snapshot.png) I could also set up a `Cloud Sync Task`, but Duplicati already handles offsite backups. @@ -200,12 +200,12 @@ sudo rsync -a --info=progress2 /data/photo/ /new_photos ``` At the end, I could decommission my old NFS server on the LXC. The dataset layout after migration looks like this: -![Dataset layout in TrueNAS](img/truenas-datasets-layout.png) +![Dataset layout in TrueNAS](images/truenas-datasets-layout.png) ### Android application Out of curiosity, I've checked on the Google Play store for an app to manage a TrueNAS instance. I've found [Nasdeck](https://play.google.com/store/apps/details?id=com.strtechllc.nasdeck&hl=fr&pli=1), which is quite nice. Here some screenshots: -![Captures d'écran de l'application Nasdeck](img/nasdeck-android-app.png) +![Screenshots of Nasdeck application](images/nasdeck-android-app.png) --- ## Conclusion diff --git a/content/post/19-migrate-passive-opnsense-node-to-truenas/images/opnsense-update-dnsmasq-override-truenas-bridge.png b/content/post/19-migrate-passive-opnsense-node-to-truenas/images/opnsense-update-dnsmasq-override-truenas-bridge.png new file mode 100644 index 0000000..418b7b7 Binary files /dev/null and b/content/post/19-migrate-passive-opnsense-node-to-truenas/images/opnsense-update-dnsmasq-override-truenas-bridge.png differ diff --git a/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-create-new-vlan-interface.png b/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-create-new-vlan-interface.png new file mode 100644 index 0000000..5d2aaba Binary files /dev/null and b/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-create-new-vlan-interface.png differ diff --git a/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-network-bridge-switch-static-to-dhcp.png b/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-network-bridge-switch-static-to-dhcp.png new file mode 100644 index 0000000..504d86e Binary files /dev/null and b/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-network-bridge-switch-static-to-dhcp.png differ diff --git a/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-network-bridges-for-vlan.png b/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-network-bridges-for-vlan.png new file mode 100644 index 0000000..7943873 Binary files /dev/null and b/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-network-bridges-for-vlan.png differ diff --git a/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-network-changes-before-apply.png b/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-network-changes-before-apply.png new file mode 100644 index 0000000..2621347 Binary files /dev/null and b/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-network-changes-before-apply.png differ diff --git a/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-network-confirm-add-vlans.png b/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-network-confirm-add-vlans.png new file mode 100644 index 0000000..3664e41 Binary files /dev/null and b/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-network-confirm-add-vlans.png differ diff --git a/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-network-mgmt-bridge.png b/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-network-mgmt-bridge.png new file mode 100644 index 0000000..5c4ecc6 Binary files /dev/null and b/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-network-mgmt-bridge.png differ diff --git a/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-vm-create-new-summary.png b/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-vm-create-new-summary.png new file mode 100644 index 0000000..af392cb Binary files /dev/null and b/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-vm-create-new-summary.png differ diff --git a/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-vm-details.png b/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-vm-details.png new file mode 100644 index 0000000..c55ebc6 Binary files /dev/null and b/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-vm-details.png differ diff --git a/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-vm-disk-image-conversion.png b/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-vm-disk-image-conversion.png new file mode 100644 index 0000000..a4043de Binary files /dev/null and b/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-vm-disk-image-conversion.png differ diff --git a/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-vm-menu.png b/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-vm-menu.png new file mode 100644 index 0000000..84cb7b7 Binary files /dev/null and b/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-vm-menu.png differ diff --git a/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-vm-opnsense-start-shell.png b/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-vm-opnsense-start-shell.png new file mode 100644 index 0000000..ed0e130 Binary files /dev/null and b/content/post/19-migrate-passive-opnsense-node-to-truenas/images/truenas-vm-opnsense-start-shell.png differ diff --git a/content/post/19-migrate-passive-opnsense-node-to-truenas/index.md b/content/post/19-migrate-passive-opnsense-node-to-truenas/index.md index dac3250..583e700 100644 --- a/content/post/19-migrate-passive-opnsense-node-to-truenas/index.md +++ b/content/post/19-migrate-passive-opnsense-node-to-truenas/index.md @@ -70,11 +70,11 @@ To host an OPNsense VM properly, TrueNAS must be able to present the right netwo In TrueNAS, I went to `System` > `Network` and created VLAN interfaces (example with VLAN 13): -![truenas-create-new-vlan-interface.png](img/truenas-create-new-vlan-interface.png) +![truenas-create-new-vlan-interface.png](images/truenas-create-new-vlan-interface.png) TrueNAS is nice here: changes aren’t applied blindly. You can **test** them and you get a rollback window, which is exactly what you want when you’re touching the network config remotely: -![truenas-network-confirm-add-vlans.png](img/truenas-network-confirm-add-vlans.png) +![truenas-network-confirm-add-vlans.png](images/truenas-network-confirm-add-vlans.png) ### Management bridge @@ -85,21 +85,21 @@ I created a bridge `br1` for the management interface, shared between: And moved the IP configuration to the bridge: -![truenas-network-mgmt-bridge.png](img/truenas-network-mgmt-bridge.png) +![truenas-network-mgmt-bridge.png](images/truenas-network-mgmt-bridge.png) Final view before apply: -![truenas-network-changes-before-apply.png](img/truenas-network-changes-before-apply.png) +![truenas-network-changes-before-apply.png](images/truenas-network-changes-before-apply.png) ### Static IP vs DHCP (and why I stayed static) I initially tried switching the management bridge to DHCP by updating the MAC address in OPNsense (Dnsmasq override): -![opnsense-update-dnsmasq-override-truenas-bridge.png](img/opnsense-update-dnsmasq-override-truenas-bridge.png) +![opnsense-update-dnsmasq-override-truenas-bridge.png](images/opnsense-update-dnsmasq-override-truenas-bridge.png) Then I attempted to flip TrueNAS from static to DHCP: -![truenas-network-bridge-switch-static-to-dhcp.png](img/truenas-network-bridge-switch-static-to-dhcp.png) +![truenas-network-bridge-switch-static-to-dhcp.png](images/truenas-network-bridge-switch-static-to-dhcp.png) But DHCP didn’t behave as I expected: it kept receiving random IPs from the pool. I suspected existing leases played a role. I even tried manually editing leases and restarting the service, but after another change, it still ended up with a random address again. @@ -111,7 +111,7 @@ This became important later: I originally planned to attach VLAN interfaces dire So I created **one bridge per VLAN** (ex: `br13` with `vlan13` as the only member), and used those bridges for the VM NICs: -![truenas-network-bridges-for-vlan.png](img/truenas-network-bridges-for-vlan.png) +![truenas-network-bridges-for-vlan.png](images/truenas-network-bridges-for-vlan.png) That ended up being the difference between “split-brain chaos” and “stable HA”. @@ -178,7 +178,7 @@ Now the fun part: recreating the VM on TrueNAS with the same “spirit” as the From `Virtual Machines`: -![truenas-vm-menu.png](img/truenas-vm-menu.png) +![truenas-vm-menu.png](images/truenas-vm-menu.png) ### VM settings I used @@ -215,23 +215,23 @@ I created a new VM with: Summary screen: -![truenas-vm-create-new-summary.png](img/truenas-vm-create-new-summary.png) +![truenas-vm-create-new-summary.png](images/truenas-vm-create-new-summary.png) After saving, TrueNAS converted the imported image into a Zvol: -![truenas-vm-disk-image-conversion.png](img/truenas-vm-disk-image-conversion.png) +![truenas-vm-disk-image-conversion.png](images/truenas-vm-disk-image-conversion.png) ### Adding the additional NICs After the VM was created, I added the additional NICs in the VM device list: -![truenas-vm-details.png](img/truenas-vm-details.png) +![truenas-vm-details.png](images/truenas-vm-details.png) At first, I attached VLAN interfaces directly and started the VM… and instantly broke my network (great success). The VM itself booted fine though, and seeing OPNsense come up cleanly on TrueNAS was a good sign: -![truenas-vm-opnsense-start-shell.png](img/truenas-vm-opnsense-start-shell.png) +![truenas-vm-opnsense-start-shell.png](images/truenas-vm-opnsense-start-shell.png) But HA-wise, it was a mess: split-brain symptoms, with the TrueNAS-hosted node thinking it was MASTER on almost everything except Mgmt. diff --git a/content/post/2-blog-deployment-obisidan-hugo-gitea-actions/images/gitea-add-repo-secret.png b/content/post/2-blog-deployment-obisidan-hugo-gitea-actions/images/gitea-add-repo-secret.png new file mode 100644 index 0000000..14d6fbe Binary files /dev/null and b/content/post/2-blog-deployment-obisidan-hugo-gitea-actions/images/gitea-add-repo-secret.png differ diff --git a/content/post/2-blog-deployment-obisidan-hugo-gitea-actions/images/gitea-new-pat.png b/content/post/2-blog-deployment-obisidan-hugo-gitea-actions/images/gitea-new-pat.png new file mode 100644 index 0000000..d830326 Binary files /dev/null and b/content/post/2-blog-deployment-obisidan-hugo-gitea-actions/images/gitea-new-pat.png differ diff --git a/content/post/2-blog-deployment-obisidan-hugo-gitea-actions/images/gitea-runners-management.png b/content/post/2-blog-deployment-obisidan-hugo-gitea-actions/images/gitea-runners-management.png new file mode 100644 index 0000000..8685ff8 Binary files /dev/null and b/content/post/2-blog-deployment-obisidan-hugo-gitea-actions/images/gitea-runners-management.png differ diff --git a/content/post/2-blog-deployment-obisidan-hugo-gitea-actions/images/obsidian-blog-gitea-actions-workflow.png b/content/post/2-blog-deployment-obisidan-hugo-gitea-actions/images/obsidian-blog-gitea-actions-workflow.png new file mode 100644 index 0000000..a1a9d89 Binary files /dev/null and b/content/post/2-blog-deployment-obisidan-hugo-gitea-actions/images/obsidian-blog-gitea-actions-workflow.png differ diff --git a/content/post/2-blog-deployment-obisidan-hugo-gitea-actions/index.fr.md b/content/post/2-blog-deployment-obisidan-hugo-gitea-actions/index.fr.md index bc24643..a6e6e6b 100644 --- a/content/post/2-blog-deployment-obisidan-hugo-gitea-actions/index.fr.md +++ b/content/post/2-blog-deployment-obisidan-hugo-gitea-actions/index.fr.md @@ -60,7 +60,7 @@ L'idée est simple : De cette façon, je n'ai plus besoin de copier manuellement de fichiers ni de gérer les déploiements. Tout se déroule, de l'écriture de Markdown dans Obsidian au déploiement complet du site web. -![Workflow depuis l'écriture de notes sur Obsidian au Blog publié](img/obsidian-blog-gitea-actions-workflow.png) +![Workflow depuis l'écriture de notes sur Obsidian au Blog publié](images/obsidian-blog-gitea-actions-workflow.png) --- ## ⚙️ Implémentation @@ -101,17 +101,17 @@ container: ``` Le runner apparaît dans `Administration Area`, sous `Actions`>`Runners`. Pour obtenir le token d'enrôlement , on clique sur le bouton `Create new Runner` -![New runner visible in Gitea](img/gitea-runners-management.png) +![Nouveau runner visible dans Gitea](images/gitea-runners-management.png) ### Étape 3 : Configurer les Gitea Actions pour le dépôt Obsidian J'ai d'abord activé les Gitea Actions. Celles-ci sont désactivées par défaut. Cochez la case `Enable Repository Actions` dans les paramètres de ce dépôt. J'ai créé un nouveau PAT (Personal Access Token) avec autorisation RW sur les dépôts. -![New personal access token creation in Gitea](img/gitea-new-pat.png) +![Nouvelle création de token d'accès personnel dans Gitea](images/gitea-new-pat.png) J'ai ajouté le token comme secret `REPO_TOKEN` dans le dépôt. -![Add secret window for repository in Gitea](img/gitea-add-repo-secret.png) +![Fenêtre d'ajout de secret dans un dépôt Gitea](images/gitea-add-repo-secret.png) J'ai dû créer le workflow qui lancera un conteneur et effectuera les opérations suivantes : @@ -171,7 +171,7 @@ jobs: git push -u origin main ``` -Obsidian utilise des liens de type wiki pour les images, comme `![[nom_image.png]]`, ce qui n'est pas compatible avec Hugo par défaut. Voici comment j'ai automatisé une solution de contournement dans un workflow Gitea Actions : +Obsidian utilise des liens de type wiki pour les images, comme `![`, ce qui n'est pas compatible avec Hugo par défaut. Voici comment j'ai automatisé une solution de contournement dans un workflow Gitea Actions :](images/nom_image.png) - Je trouve toutes les références d'images utilisées dans des fichiers `.md`. - Pour chaque image référencée, je mets à jour le lien dans les fichiers `.md` correspondants, comme `![nom_image](img/nom_image.png)`. - Je copie ensuite ces images utilisées dans le répertoire statique du blog en remplaçant les espaces par des underscores. diff --git a/content/post/2-blog-deployment-obisidan-hugo-gitea-actions/index.md b/content/post/2-blog-deployment-obisidan-hugo-gitea-actions/index.md index 540ba8d..e032c16 100644 --- a/content/post/2-blog-deployment-obisidan-hugo-gitea-actions/index.md +++ b/content/post/2-blog-deployment-obisidan-hugo-gitea-actions/index.md @@ -59,7 +59,7 @@ The idea is simple: This way, I never need to manually copy files or trigger deployments. Everything flows from writing markdown in Obsidian to having a fully deployed website. -![Workflow depuis l'écriture de notes sur Obsidian au Blog publié](img/obsidian-blog-gitea-actions-workflow.png) +![Workflow from writing notes on Obsidian to Blog published](images/obsidian-blog-gitea-actions-workflow.png) --- ## ⚙️ Implementation @@ -100,17 +100,17 @@ container: ``` The runner appears in the `Administration Area`, under `Actions`>`Runners`. To obtain the registration token, click on the `Create new Runner` button -![New runner visible in Gitea](img/gitea-runners-management.png) +![New runner visible in Gitea](images/gitea-runners-management.png) ### Step 3: Set up Gitea Actions for Obsidian Repository First I enabled the Gitea Actions, this is disabled by default, tick the box `Enable Repository Actions` in the settings for that repository I created a new PAT (Personal Access Token) with RW permission on the repositories -![New personal access token creation in Gitea](img/gitea-new-pat.png) +![New personal access token creation in Gitea](images/gitea-new-pat.png) I added this token as secret `REPO_TOKEN` in the repository -![Add secret window for repository in Gitea](img/gitea-add-repo-secret.png) +![Add secret window for repository in Gitea](images/gitea-add-repo-secret.png) I needed to create the workflow that will spin-up a container and do the following: @@ -170,7 +170,7 @@ jobs: git push -u origin main ``` -Obsidian uses wiki-style links for images, like `![[image name.png]]`, which isn't compatible with Hugo out of the box. Here's how I automated a workaround in a Gitea Actions workflow: +Obsidian uses wiki-style links for images, like `![`, which isn't compatible with Hugo out of the box. Here's how I automated a workaround in a Gitea Actions workflow:](images/image_name.png) - I find all used image references in `.md` files. - For each referenced image, I update the link in relevant `.md` files like `![image name](img/image_name.png)`. - I then copy those used images to the blog's static directory while replacing white-spaces by underscores. diff --git a/content/post/3-terraform-create-vm-proxmox/images/proxmox-terraform-new-vm.png b/content/post/3-terraform-create-vm-proxmox/images/proxmox-terraform-new-vm.png new file mode 100644 index 0000000..2485502 Binary files /dev/null and b/content/post/3-terraform-create-vm-proxmox/images/proxmox-terraform-new-vm.png differ diff --git a/content/post/3-terraform-create-vm-proxmox/index.fr.md b/content/post/3-terraform-create-vm-proxmox/index.fr.md index e1c8e8a..82a1f1d 100644 --- a/content/post/3-terraform-create-vm-proxmox/index.fr.md +++ b/content/post/3-terraform-create-vm-proxmox/index.fr.md @@ -698,7 +698,7 @@ vm_ip = "192.168.66.156" ✅ Voilà, on vient de créer une VM sur Proxmox en quelques minutes. -![Résumé de la nouvelle VM crée sur Proxmox](img/proxmox-terraform-new-vm.png) +![Résumé de la nouvelle VM crée sur Proxmox](images/proxmox-terraform-new-vm.png) ### Connexion SSH diff --git a/content/post/3-terraform-create-vm-proxmox/index.md b/content/post/3-terraform-create-vm-proxmox/index.md index 5984244..e350953 100644 --- a/content/post/3-terraform-create-vm-proxmox/index.md +++ b/content/post/3-terraform-create-vm-proxmox/index.md @@ -697,7 +697,7 @@ vm_ip = "192.168.66.156" ✅ Done! We’ve successfully created our first VM on Proxmox using Terraform in just a few minutes. -![Résumé de la nouvelle VM crée sur Proxmox](img/proxmox-terraform-new-vm.png) +![Summary of the newly created VM on Proxmox](images/proxmox-terraform-new-vm.png) ### SSH Connection diff --git a/content/post/4-blog-deployment-ci-cd-pipeline-gitea-actions/images/gitea-actions-deploy-blog-workflow.png b/content/post/4-blog-deployment-ci-cd-pipeline-gitea-actions/images/gitea-actions-deploy-blog-workflow.png new file mode 100644 index 0000000..ece08c7 Binary files /dev/null and b/content/post/4-blog-deployment-ci-cd-pipeline-gitea-actions/images/gitea-actions-deploy-blog-workflow.png differ diff --git a/content/post/4-blog-deployment-ci-cd-pipeline-gitea-actions/images/gitea-create-new-branch.png b/content/post/4-blog-deployment-ci-cd-pipeline-gitea-actions/images/gitea-create-new-branch.png new file mode 100644 index 0000000..9edccf1 Binary files /dev/null and b/content/post/4-blog-deployment-ci-cd-pipeline-gitea-actions/images/gitea-create-new-branch.png differ diff --git a/content/post/4-blog-deployment-ci-cd-pipeline-gitea-actions/images/obsidian-blog-gitea-actions-workflow.png b/content/post/4-blog-deployment-ci-cd-pipeline-gitea-actions/images/obsidian-blog-gitea-actions-workflow.png new file mode 100644 index 0000000..a1a9d89 Binary files /dev/null and b/content/post/4-blog-deployment-ci-cd-pipeline-gitea-actions/images/obsidian-blog-gitea-actions-workflow.png differ diff --git a/content/post/4-blog-deployment-ci-cd-pipeline-gitea-actions/index.fr.md b/content/post/4-blog-deployment-ci-cd-pipeline-gitea-actions/index.fr.md index 47863bc..065bce6 100644 --- a/content/post/4-blog-deployment-ci-cd-pipeline-gitea-actions/index.fr.md +++ b/content/post/4-blog-deployment-ci-cd-pipeline-gitea-actions/index.fr.md @@ -22,13 +22,13 @@ Le blog étant redéployé de façon automatique à chaque modification du conte Aujourd'hui mon blog se redéploie automatiquement à chaque modification de la branche `main` du [dépôt Git](https://git.vezpi.com/Vezpi/Blog) de mon instance **Gitea** via une **Gitea Actions**. Chaque modification apportée à mon vault **Obsidian** est poussée automatiquement dans cette branche. -![Workflow depuis l'écriture de notes sur Obsidian au Blog publié](img/obsidian-blog-gitea-actions-workflow.png) +![Workflow depuis l'écriture de notes sur Obsidian au blog publié](images/obsidian-blog-gitea-actions-workflow.png) ### Créer une Nouvelle Branche La première partie, la plus simple, a donc été de créer une nouvelle branche qui allait recevoir ces modifications. J'ai donc crée la branche `preview` dans ce dépôt. Ensuite j'ai modifié la branche cible recevant les modifications dans le workflow de mon dépôt Git Obsidian. -![Create the preview branch from the main branch in Gitea](img/gitea-create-new-branch.png) +![Créer la branche preview depuis la branche main dans Gitea](images/gitea-create-new-branch.png) ### Containeriser le Blog @@ -211,7 +211,7 @@ Maintenant voici ce que le nouveau workflow fait : Voici un exemple de déploiement après un commit automatique généré par **Obsidian**, on peut voir ici que l'image Docker n'a pas été reconstruire car il n'y avait pas de nouvelle version d'Hugo disponible et que le dossier `docker` n'avait pas été modifié, de ce fait, le dernier job `Clean` n'était pas non plus nécessaire. -![Gitea Actions workflow for blog deployment](img/gitea-actions-deploy-blog-workflow.png) +![Workflow Gitea Actions du déploiement du blog](images/gitea-actions-deploy-blog-workflow.png) #### Code diff --git a/content/post/4-blog-deployment-ci-cd-pipeline-gitea-actions/index.md b/content/post/4-blog-deployment-ci-cd-pipeline-gitea-actions/index.md index 0ecf111..3d04e38 100644 --- a/content/post/4-blog-deployment-ci-cd-pipeline-gitea-actions/index.md +++ b/content/post/4-blog-deployment-ci-cd-pipeline-gitea-actions/index.md @@ -22,13 +22,13 @@ Since the blog is automatically redeployed every time I modify content in Obsidi Currently, my blog redeploys automatically on every change to the `main` branch of the [Git repository](https://git.vezpi.com/Vezpi/Blog) hosted on my **Gitea** instance, using a **Gitea Actions** workflow. Every change made in my **Obsidian** vault is automatically pushed to this branch. -![Workflow depuis l'écriture de notes sur Obsidian au Blog publié](img/obsidian-blog-gitea-actions-workflow.png) +![Workflow from writing notes on Obsidian to Blog published](images/obsidian-blog-gitea-actions-workflow.png) ### Create a New Branch The first and easiest step was to create a new branch to receive these changes. So I created a `preview` branch in this repository and then updated the target branch in the workflow of my Obsidian Git repo. -![Create the preview branch from the main branch in Gitea](img/gitea-create-new-branch.png) +![Create the preview branch from the main branch in Gitea](images/gitea-create-new-branch.png) ### Containerize the Blog @@ -211,7 +211,7 @@ Now, here’s what the new workflow does: Here’s an example of a deployment triggered by an automatic commit from **Obsidian**. You can see that the Docker image wasn’t rebuilt because no new Hugo version was available and the `docker` folder hadn’t changed, so the final `Clean` job wasn’t necessary either. -![Gitea Actions workflow for blog deployment](img/gitea-actions-deploy-blog-workflow.png) +![Gitea Actions workflow for blog deployment](images/gitea-actions-deploy-blog-workflow.png) #### Code diff --git a/content/post/5-notification-system-gotify-vs-ntfy/images/gitea-blog-ntfy-credentials.png b/content/post/5-notification-system-gotify-vs-ntfy/images/gitea-blog-ntfy-credentials.png new file mode 100644 index 0000000..effbb46 Binary files /dev/null and b/content/post/5-notification-system-gotify-vs-ntfy/images/gitea-blog-ntfy-credentials.png differ diff --git a/content/post/5-notification-system-gotify-vs-ntfy/images/gotify-android-first-login.png b/content/post/5-notification-system-gotify-vs-ntfy/images/gotify-android-first-login.png new file mode 100644 index 0000000..2be001e Binary files /dev/null and b/content/post/5-notification-system-gotify-vs-ntfy/images/gotify-android-first-login.png differ diff --git a/content/post/5-notification-system-gotify-vs-ntfy/images/gotify-android-test-messages.png b/content/post/5-notification-system-gotify-vs-ntfy/images/gotify-android-test-messages.png new file mode 100644 index 0000000..540cc6f Binary files /dev/null and b/content/post/5-notification-system-gotify-vs-ntfy/images/gotify-android-test-messages.png differ diff --git a/content/post/5-notification-system-gotify-vs-ntfy/images/gotify-application-list.png b/content/post/5-notification-system-gotify-vs-ntfy/images/gotify-application-list.png new file mode 100644 index 0000000..9ce2262 Binary files /dev/null and b/content/post/5-notification-system-gotify-vs-ntfy/images/gotify-application-list.png differ diff --git a/content/post/5-notification-system-gotify-vs-ntfy/images/gotify-create-new-application.png b/content/post/5-notification-system-gotify-vs-ntfy/images/gotify-create-new-application.png new file mode 100644 index 0000000..3dce8c2 Binary files /dev/null and b/content/post/5-notification-system-gotify-vs-ntfy/images/gotify-create-new-application.png differ diff --git a/content/post/5-notification-system-gotify-vs-ntfy/images/gotify-dashboard-no-messages.png b/content/post/5-notification-system-gotify-vs-ntfy/images/gotify-dashboard-no-messages.png new file mode 100644 index 0000000..9db3732 Binary files /dev/null and b/content/post/5-notification-system-gotify-vs-ntfy/images/gotify-dashboard-no-messages.png differ diff --git a/content/post/5-notification-system-gotify-vs-ntfy/images/gotify-login-page.png b/content/post/5-notification-system-gotify-vs-ntfy/images/gotify-login-page.png new file mode 100644 index 0000000..43b8672 Binary files /dev/null and b/content/post/5-notification-system-gotify-vs-ntfy/images/gotify-login-page.png differ diff --git a/content/post/5-notification-system-gotify-vs-ntfy/images/gotify-messages-received.png b/content/post/5-notification-system-gotify-vs-ntfy/images/gotify-messages-received.png new file mode 100644 index 0000000..06c688d Binary files /dev/null and b/content/post/5-notification-system-gotify-vs-ntfy/images/gotify-messages-received.png differ diff --git a/content/post/5-notification-system-gotify-vs-ntfy/images/ntfy-android-app.png b/content/post/5-notification-system-gotify-vs-ntfy/images/ntfy-android-app.png new file mode 100644 index 0000000..95ab4f4 Binary files /dev/null and b/content/post/5-notification-system-gotify-vs-ntfy/images/ntfy-android-app.png differ diff --git a/content/post/5-notification-system-gotify-vs-ntfy/images/ntfy-login-dashboard.png b/content/post/5-notification-system-gotify-vs-ntfy/images/ntfy-login-dashboard.png new file mode 100644 index 0000000..31e4635 Binary files /dev/null and b/content/post/5-notification-system-gotify-vs-ntfy/images/ntfy-login-dashboard.png differ diff --git a/content/post/5-notification-system-gotify-vs-ntfy/images/ntfy-testing-blog-notifications.png b/content/post/5-notification-system-gotify-vs-ntfy/images/ntfy-testing-blog-notifications.png new file mode 100644 index 0000000..32c9b03 Binary files /dev/null and b/content/post/5-notification-system-gotify-vs-ntfy/images/ntfy-testing-blog-notifications.png differ diff --git a/content/post/5-notification-system-gotify-vs-ntfy/images/ntfy-testing-gitea-blog-user.png b/content/post/5-notification-system-gotify-vs-ntfy/images/ntfy-testing-gitea-blog-user.png new file mode 100644 index 0000000..fbd1d53 Binary files /dev/null and b/content/post/5-notification-system-gotify-vs-ntfy/images/ntfy-testing-gitea-blog-user.png differ diff --git a/content/post/5-notification-system-gotify-vs-ntfy/images/ntfy-topic-messages.png b/content/post/5-notification-system-gotify-vs-ntfy/images/ntfy-topic-messages.png new file mode 100644 index 0000000..93f8818 Binary files /dev/null and b/content/post/5-notification-system-gotify-vs-ntfy/images/ntfy-topic-messages.png differ diff --git a/content/post/5-notification-system-gotify-vs-ntfy/index.fr.md b/content/post/5-notification-system-gotify-vs-ntfy/index.fr.md index e05823c..60f40df 100644 --- a/content/post/5-notification-system-gotify-vs-ntfy/index.fr.md +++ b/content/post/5-notification-system-gotify-vs-ntfy/index.fr.md @@ -95,10 +95,10 @@ $ docker compose up -d ``` ✅ Atteindre l’URL [https://gotify.vezpi.me](https://gotify.vezpi.me) m’affiche la page de connexion Gotify : -![Gotify login page](img/gotify-login-page.png) +![Page de connexion Gotify](images/gotify-login-page.png) Après connexion, j’accède au tableau de bord, sans messages évidemment : -![Gotify dashboard on a fresh installation](img/gotify-dashboard-no-messages.png) +![Tableau de bord Gotify sur une nouvelle installation](images/gotify-dashboard-no-messages.png) ### Créer une Application @@ -107,10 +107,10 @@ Pour permettre l’envoi de messages, je dois d’abord créer une application p - **REST-API** Pour le test, j’utiliserai la WebUI, je clique sur le bouton `APPS` en haut puis `CREATE APPLICATION`. Je choisis un magnifique nom d'application et une description. -![Create an application on Gotify](img/gotify-create-new-application.png) +![Créer une application sur Gotify](images/gotify-create-new-application.png) Une fois mon application créée, un token est généré pour celle-ci. Je peux modifier l’application pour changer quoi que ce soit, je peux aussi uploader une icône. -![Gotify application list showing my new Potato application](img/gotify-application-list.png) +![Liste des applications Gotify affichant ma nouvelle application Potato](images/gotify-application-list.png) ### Tests @@ -122,15 +122,15 @@ curl "https://gotify.vezpi.me/message?token=" -F "title=Cooked!" -F "m Je reçois instantanément la notification sur mon mobile et dans mon navigateur. Je renvoie un autre message mais avec une priorité plus basse : `-2`. Je ne reçois pas de notification dans mon navigateur, je remarque une légère différence entre les deux messages. Sur mon mobile, seule ma montre la reçoit, je ne la vois pas sur l’écran, mais je la retrouve dans le centre de notifications. -![Messages received on Gotify WebUI](img/gotify-messages-received.png) +![Messages reçus sur l’interface Web Gotify](images/gotify-messages-received.png) ### Application Android Voici quelques captures d’écran depuis mon appareil Android : -![Capture d’écran de l’application Android Gotify pour la page de connexion](img/gotify-android-first-login.png) +![Capture d’écran de l’application Android Gotify pour la page de connexion](images/gotify-android-first-login.png) Pour une raison inconnue, une notification apparaît aléatoirement pour me dire que je suis connecté à Gotify : -![Capture d’écran de l’application Android Gotify avec les messages de test](img/gotify-android-test-messages.png) +![Capture d’écran de l’application Android Gotify avec les messages de test](images/gotify-android-test-messages.png) ### Conclusion @@ -205,7 +205,7 @@ $ docker compose up -d ``` ✅ L’URL [https://ntfy.vezpi.me](https://ntfy.vezpi.me) me donne accès au tableau de bord Ntfy : -![Ntfy dashboard](img/ntfy-login-dashboard.png) +![Tableau de bord Ntfy](images/ntfy-login-dashboard.png) Au départ je n’ai aucun utilisateur et aucun n’est créé par défaut. Comme j’ai interdit tout accès anonyme dans la config, je dois en créer un. @@ -228,7 +228,7 @@ Je peux maintenant me connecter à l’interface Web, et passer en mode sombre, ### Topics Dans Ntfy, il n’y a pas d’applications à créer, mais les messages sont regroupés dans des topics, plus lisibles qu’un token lors de l’envoi. Une fois le topic créé, je peux changer le nom d’affichage ou envoyer des messages de test. Sur l’interface Web, cependant, je ne trouve aucune option pour changer l’icône, alors que c’est possible depuis l’application Android, ce qui n’est pas très pratique. -![Example messages in Ntfy](img/ntfy-topic-messages.png) +![Exemple de messages dans Ntfy](images/ntfy-topic-messages.png) ### Tests Envoyer un message est en fait plus difficile que prévu. Comme j’ai activé l’authentification, je dois aussi m’authentifier pour envoyer des messages : @@ -244,7 +244,7 @@ curl \ ### Application Android Voici quelques captures de l’application Android Ntfy : -![Captures de l’application Android Ntfy](img/ntfy-android-app.png) +![Captures de l’application Android Ntfy](images/ntfy-android-app.png) ### Conclusion @@ -287,7 +287,7 @@ $ curl -u gitea_blog: -d "Message test from gitea_blog!" https://ntfy. {"id":"xIgwz9dr1w9Z","time":1749587681,"expires":1749630881,"event":"message","topic":"blog","message":"Message test from gitea_blog!"} ``` -![Test d’envoi de messages sur le topic blog avec Ntfy ](img/ntfy-testing-gitea-blog-user.png) +![Test d’envoi de messages sur le topic blog avec Ntfy ](images/ntfy-testing-gitea-blog-user.png) ✅ Message reçu ! Je tente aussi un envoi sur mon topic de test : @@ -319,7 +319,7 @@ Maintenant que mes utilisateurs sont prêts, je veux ajouter un job `Notify` dan #### Créer un Secret Pour permettre à mon Gitea Runner d’utiliser l’utilisateur `gitea_blog` dans ses jobs, je veux créer un secret. J’explore le dépôt Gitea `Blog` dans `Settings`, puis `Actions` > `Secrets` > `Add Secret`. J’y mets la valeur du secret au format `:` : -![Add a secret in the blog Gitea repository](img/gitea-blog-ntfy-credentials.png) +![Ajout d’un secret dans le dépôt Gitea du blog](images/gitea-blog-ntfy-credentials.png) ### Écrire le Code `Notify` @@ -369,7 +369,7 @@ Si quelque chose échoue, je veux être notifié sur mon mobile avec une priorit ``` ✅ Test des deux cas, fonctionne comme prévu : -![Checking both test scenario in Ntfy WebUI](img/ntfy-testing-blog-notifications.png) +![Vérification des deux scénarios de test dans Ntfy WebUI](images/ntfy-testing-blog-notifications.png) ## Conclusion diff --git a/content/post/5-notification-system-gotify-vs-ntfy/index.md b/content/post/5-notification-system-gotify-vs-ntfy/index.md index 302cda2..152551b 100644 --- a/content/post/5-notification-system-gotify-vs-ntfy/index.md +++ b/content/post/5-notification-system-gotify-vs-ntfy/index.md @@ -95,10 +95,10 @@ $ docker compose up -d ``` ✅ Reaching the URL https://gotify.vezpi.me gives me the Gotify login page: -![Gotify login page](img/gotify-login-page.png) +![Gotify login page](images/gotify-login-page.png) After login, I can access the dashboard, with no messages obviously: -![Gotify dashboard on a fresh installation](img/gotify-dashboard-no-messages.png) +![Gotify dashboard on a fresh installation](images/gotify-dashboard-no-messages.png) ### Creating an Application @@ -107,10 +107,10 @@ To allow messages to be pushed, I before need to create an application for which - **REST-API** For the test, I will use the WebUI, I click on the `APPS` button at the top and `CREATE APPLICATION`. I choose a wonderful application name and description. -![Create an application on Gotify](img/gotify-create-new-application.png) +![Create an application on Gotify](images/gotify-create-new-application.png) Once my application in created, a token is generated for it. I can edit the application to change anything, I can also upload an icon. -![Gotify application list showing my new Potato application](img/gotify-application-list.png) +![Gotify application list showing my new Potato application](images/gotify-application-list.png) ### Testing @@ -122,15 +122,15 @@ curl "https://gotify.vezpi.me/message?token=" -F "title=Cooked!" -F "m I instantly received the notification on my mobile and on my browser. I retried to send another message but with a lower priority: `-2`. I didn't get any notification in my browser, I see a slight differences between the two messages. On my mobile, only my watch received it, I don't see it on my screen, but I can find it on the notification center. -![Messages received on Gotify WebUI](img/gotify-messages-received.png) +![Messages received on Gotify WebUI](images/gotify-messages-received.png) ### Android App Here some screenshots from my Android device: -![Capture d’écran de l’application Android Gotify pour la page de connexion](img/gotify-android-first-login.png) +![Gotify's Android App screenshot for the login page](images/gotify-android-first-login.png) For some reason, a notification randomly pops up to tell me that I'm connected to Gotify: -![Capture d’écran de l’application Android Gotify avec les messages de test](img/gotify-android-test-messages.png) +![Gotify's Android App screenshot for test messages](images/gotify-android-test-messages.png) ### Conclusion On the [documentation](https://gotify.net/docs/msgextras), I found some extras features, like adding images or click actions. In summary, it does the job, that's it. Easy installation process, the utilization is not hard, but I need to create an application for a token, then add this token anytime I want to push messages there. @@ -204,7 +204,7 @@ $ docker compose up -d ``` ✅ The URL https://ntfy.vezpi.me gives me to the Ntfy dashboard: -![Ntfy dashboard](img/ntfy-login-dashboard.png) +![Ntfy dashboard](images/ntfy-login-dashboard.png) At start I don't have any user and none is created by default, as I denied all access to anonymous in the config, I need to create one. @@ -227,7 +227,7 @@ I can now login into the WebUI, and I can now switch to dark mode, my eyes are g ### Topics In Ntfy there are no applications to create, but messages are grouped into topics, more readable than a token when sending messages. When the topic is created I can change the display name or send test messages. On the WebUI though I don't find any option to change the icon, where I can find this option in the Android App which is not really convenient. -![Example messages in Ntfy](img/ntfy-topic-messages.png) +![Example messages in Ntfy](images/ntfy-topic-messages.png) ### Testing @@ -244,7 +244,7 @@ curl \ ### Android App Here are some screenshots of Ntfy Android App: -![Captures de l’application Android Ntfy](img/ntfy-android-app.png) +![Ntfy's Android App screenshots](images/ntfy-android-app.png) ### Conclusion Ntfy is a beautiful application with a really strong [documentation](https://docs.ntfy.sh/). The possibilities are endless and the list of integration is impressive. The installation was not hard but required a bit of more setup. The needs for CLI to configure users and permissions is not really convenient. @@ -286,7 +286,7 @@ $ curl -u gitea_blog: -d "Message test from gitea_blog!" https://ntfy. {"id":"xIgwz9dr1w9Z","time":1749587681,"expires":1749630881,"event":"message","topic":"blog","message":"Message test from gitea_blog!"} ``` -![Test d’envoi de messages sur le topic blog avec Ntfy ](img/ntfy-testing-gitea-blog-user.png) +![Testing Ntfy messages in the blog topic](images/ntfy-testing-gitea-blog-user.png) ✅ Message received! I also try to send a message on my test topic: @@ -318,7 +318,7 @@ Now my users are setup, I want to add a `Notify` job in my CI/CD pipeline for th #### Create a Secret To allow my Gitea Runner to use my `gitea_blog` user in its job, I want to create a secret. I explore the `Blog` Gitea repository `Settings`, then `Actions` > `Secrets` > `Add Secret`. Here I set the secret value with the `:` format: -![Add a secret in the blog Gitea repository](img/gitea-blog-ntfy-credentials.png) +![Add a secret in the blog Gitea repository](images/gitea-blog-ntfy-credentials.png) ### Write the `Notify` Code @@ -368,7 +368,7 @@ If anything fails, I want to be notified on my mobile with higher priority. Ntfy ``` ✅ Testing both cases, work as expected: -![Checking both test scenario in Ntfy WebUI](img/ntfy-testing-blog-notifications.png) +![Checking both test scenario in Ntfy WebUI](images/ntfy-testing-blog-notifications.png) ## Conclusion diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/home-assistant-temperature-room-sliders.png b/content/post/6-ac-automation-home-assistant-node-red/images/home-assistant-temperature-room-sliders.png new file mode 100644 index 0000000..48d1745 Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/home-assistant-temperature-room-sliders.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/node-red-call-service-node-notification.png b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-call-service-node-notification.png new file mode 100644 index 0000000..f4ac085 Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-call-service-node-notification.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/node-red-call-service-node-set-fan-mode.png b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-call-service-node-set-fan-mode.png new file mode 100644 index 0000000..e7dca2d Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-call-service-node-set-fan-mode.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/node-red-call-service-node-set-hvac-mode.png b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-call-service-node-set-hvac-mode.png new file mode 100644 index 0000000..d916488 Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-call-service-node-set-hvac-mode.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/node-red-call-service-node-set-temperature-service.png b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-call-service-node-set-temperature-service.png new file mode 100644 index 0000000..b78a7ca Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-call-service-node-set-temperature-service.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/node-red-call-service-node-start-timer.png b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-call-service-node-start-timer.png new file mode 100644 index 0000000..3e5baed Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-call-service-node-start-timer.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/node-red-call-service-node-start-unit-timer.png b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-call-service-node-start-unit-timer.png new file mode 100644 index 0000000..12513ee Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-call-service-node-start-unit-timer.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/node-red-call-service-node-turn-off.png b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-call-service-node-turn-off.png new file mode 100644 index 0000000..65d1728 Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-call-service-node-turn-off.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/node-red-call-service-node-turn-on.png b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-call-service-node-turn-on.png new file mode 100644 index 0000000..b330f81 Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-call-service-node-turn-on.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/node-red-change-node-room-partout.png b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-change-node-room-partout.png new file mode 100644 index 0000000..f77cf08 Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-change-node-room-partout.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/node-red-current-state-node-climatisation-enabled.png b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-current-state-node-climatisation-enabled.png new file mode 100644 index 0000000..67d0256 Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-current-state-node-climatisation-enabled.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/node-red-current-state-node-get-unit-state.png b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-current-state-node-get-unit-state.png new file mode 100644 index 0000000..5dcbc38 Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-current-state-node-get-unit-state.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/node-red-current-state-node-lock-timer.png b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-current-state-node-lock-timer.png new file mode 100644 index 0000000..5c08fc6 Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-current-state-node-lock-timer.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/node-red-delay-node-1-msg-per-second.png b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-delay-node-1-msg-per-second.png new file mode 100644 index 0000000..22be537 Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-delay-node-1-msg-per-second.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/node-red-filter-node-blocker.png b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-filter-node-blocker.png new file mode 100644 index 0000000..3b9eb10 Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-filter-node-blocker.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/node-red-ha-ac-automation-before.png b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-ha-ac-automation-before.png new file mode 100644 index 0000000..e1e2edd Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-ha-ac-automation-before.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/node-red-new-ac-workflow-with-legend.png b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-new-ac-workflow-with-legend.png new file mode 100644 index 0000000..2e6e0d7 Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-new-ac-workflow-with-legend.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/node-red-switch-node-check-user-id.png b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-switch-node-check-user-id.png new file mode 100644 index 0000000..bd7ef7c Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-switch-node-check-user-id.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/node-red-switch-node-compare-speed.png b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-switch-node-compare-speed.png new file mode 100644 index 0000000..8c711d8 Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-switch-node-compare-speed.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/node-red-switch-node-fan-speed.png b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-switch-node-fan-speed.png new file mode 100644 index 0000000..c671129 Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-switch-node-fan-speed.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/node-red-switch-node-room-config.png b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-switch-node-room-config.png new file mode 100644 index 0000000..6c42531 Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-switch-node-room-config.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/node-red-switch-node-room-selector-watchdog.png b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-switch-node-room-selector-watchdog.png new file mode 100644 index 0000000..a1ff5b6 Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-switch-node-room-selector-watchdog.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/node-red-switch-node-select-action.png b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-switch-node-select-action.png new file mode 100644 index 0000000..9882219 Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-switch-node-select-action.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/node-red-switch-node-set-temp.png b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-switch-node-set-temp.png new file mode 100644 index 0000000..bce5964 Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-switch-node-set-temp.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/node-red-switch-node-user-id.png b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-switch-node-user-id.png new file mode 100644 index 0000000..48e181f Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-switch-node-user-id.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/node-red-temperature-sensor-join-node.png b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-temperature-sensor-join-node.png new file mode 100644 index 0000000..41ab2c8 Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-temperature-sensor-join-node.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/node-red-temperature-sensors-trigger-node.png b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-temperature-sensors-trigger-node.png new file mode 100644 index 0000000..6ad1fdf Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-temperature-sensors-trigger-node.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/node-red-trigger-node-window-watchdog.png b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-trigger-node-window-watchdog.png new file mode 100644 index 0000000..ae1134a Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-trigger-node-window-watchdog.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/node-red-trigger-state-mode-for-sliders.png b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-trigger-state-mode-for-sliders.png new file mode 100644 index 0000000..46082b8 Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-trigger-state-mode-for-sliders.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/node-red-trigger-state-node-toggles.png b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-trigger-state-node-toggles.png new file mode 100644 index 0000000..8fe9d52 Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-trigger-state-node-toggles.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/node-red-trigger-state-node-windows.png b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-trigger-state-node-windows.png new file mode 100644 index 0000000..dc474f9 Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-trigger-state-node-windows.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/images/node-red-trigger-state-unit-change.png b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-trigger-state-unit-change.png new file mode 100644 index 0000000..df362a9 Binary files /dev/null and b/content/post/6-ac-automation-home-assistant-node-red/images/node-red-trigger-state-unit-change.png differ diff --git a/content/post/6-ac-automation-home-assistant-node-red/index.fr.md b/content/post/6-ac-automation-home-assistant-node-red/index.fr.md index a1ca51c..d60e1b9 100644 --- a/content/post/6-ac-automation-home-assistant-node-red/index.fr.md +++ b/content/post/6-ac-automation-home-assistant-node-red/index.fr.md @@ -37,7 +37,7 @@ Node-RED ne remplace pas Home Assistant, il le renforce. Je ne détaillerai pas ## Ancien Workflow J’avais déjà une solution plutôt efficace pour contrôler ma climatisation via Home Assistant et Node-RED, mais je voulais l’améliorer pour qu’elle prenne aussi en compte le taux d’humidité dans l’appartement. Mon workflow actuel, bien qu’il fonctionne, n’était pas vraiment évolutif et assez difficile à maintenir : -![Ancien workflow Node-RED pour contrôler la climatisation](img/node-red-ha-ac-automation-before.png) +![Ancien workflow Node-RED pour contrôler la climatisation](images/node-red-ha-ac-automation-before.png) ## Nouveau Workflow @@ -54,12 +54,12 @@ Pour m’aider à faire tout ça, j’utilise 4 [capteurs de température et d ### Workflow Laissez-moi vous présenter mon nouveau workflow de climatisation dans Node-RED, et vous expliquer en détail comment il fonctionne : -![New Node-RED air conditioning workflow](img/node-red-new-ac-workflow-with-legend.png) +![Nouveau workflow Node-RED pour la climatisation](images/node-red-new-ac-workflow-with-legend.png) #### #### 1. Capteurs de Température Dans le premier nœud, j’ai regroupé tous les capteurs thermiques dans un seul `trigger state node`, en ajoutant non seulement la température mais aussi le taux d’humidité géré par chaque capteur. Ce nœud contient donc une liste de 8 entités (2 pour chaque capteur). À chaque fois qu’une de ces 8 valeurs change, le nœud est déclenché : -![Nœud trigger state dans Node-RED avec les 8 entités](img/node-red-temperature-sensors-trigger-node.png) +![Nœud trigger state dans Node-RED avec les 8 entités](images/node-red-temperature-sensors-trigger-node.png) Chacun de mes capteurs thermiques porte un nom de couleur en français, car ils ont tous un autocollant coloré pour les distinguer : - **Jaune** : Salon @@ -93,7 +93,7 @@ return msg; ``` Pour le dernier nœud, dans la majorité des cas, les capteurs envoient deux messages simultanés : l’un pour la température, l’autre pour l’humidité. J’ai donc ajouté un `join node` pour fusionner ces deux messages s’ils sont envoyés dans la même seconde : -![Join node in Node-RED to merge temperature and humidity](img/node-red-temperature-sensor-join-node.png) +![Nœud join dans Node-RED pour fusionner température et humidité](images/node-red-temperature-sensor-join-node.png) #### 2. Notification @@ -132,17 +132,17 @@ return null; // Don't send anything now ``` Le second nœud est un `call service node` qui envoie une notification sur mon téléphone Android avec les informations fournies : -![Node-RED call service node for notification](img/node-red-call-service-node-notification.png) +![Nœud call service dans Node-RED pour envoyer une notification](images/node-red-call-service-node-notification.png) #### 3. Curseurs de Température Pour pouvoir ajuster la température sans avoir à modifier tout le workflow, j’ai créé deux entrées (ou helper) Home Assistant, de type number, pour chaque unité de climatisation, ce qui me fait un total de 6 entrées : -![Curseur de température dans Home Assistant pour chaque unité](img/home-assistant-temperature-room-sliders.png) +![Curseur de température dans Home Assistant pour chaque unité](images/home-assistant-temperature-room-sliders.png) Ces valeurs représentent la température de base utilisée pour le calcul des seuils, en fonction des offsets que je détaillerai plus loin. Le premier nœud est un `trigger state node` qui regroupe les 6 entités. Si je modifie l’une de ces valeurs, le nœud est déclenché : -![Node-RED trigger state node for sliders](img/node-red-trigger-state-mode-for-sliders.png) +![Nœud trigger state dans Node-RED pour les curseurs](images/node-red-trigger-state-mode-for-sliders.png) Le deuxième nœud est un `function node`, qui permet de déterminer la pièce concernée : ```js @@ -164,17 +164,17 @@ return msg; Dans Home Assistant, j’utilise d’autres entrées, mais cette fois sous forme de booléens. Le plus important est celui dédié à la climatisation, qui me permet de désactiver manuellement tout le workflow. J’en ai d’autres qui sont automatisés, par exemple pour le moment de la journée ou la détection de présence à la maison. J’utilise un autre `trigger state node` qui regroupe tous mes interrupteurs sous forme de booléens, y compris un bouton de test utilisé pour le débogage : -![Node-RED trigger state node for toggles](img/node-red-trigger-state-node-toggles.png) +![Nœud trigger state dans Node-RED pour les interrupteurs](images/node-red-trigger-state-node-toggles.png) Comme ces interrupteurs impactent tout l’appartement (et non une seule unité), le nœud suivant est un `change node` qui définit la valeur de la pièce à `partout` : -![Node-RED change node to set room to partout](img/node-red-change-node-room-partout.png) +![Nœud change dans Node-RED pour définir la pièce sur partout](images/node-red-change-node-room-partout.png) #### 5. Fenêtres Les derniers déclencheurs sont les fenêtres. Si j’ouvre ou ferme une fenêtre située près d’une unité, cela active le workflow. J’ai des capteurs d’ouverture sur certaines fenêtres, mais pour l’unité du couloir, j’utilise l’état des fenêtres Velux. Certaines pièces ayant plusieurs fenêtres, j’ai créé une entrée de type groupe pour les regrouper. Le premier nœud est le dernier `trigger state node`. La valeur retournée est une string qu’il faudra ensuite convertir en booléen : -![Node-RED trigger state node for windows](img/node-red-trigger-state-node-windows.png) +![Nœud trigger state dans Node-RED pour les fenêtres](images/node-red-trigger-state-node-windows.png) Juste après, un autre `function node` permet d’identifier la pièce concernée : ```js @@ -195,20 +195,20 @@ return msg; Quand j’ouvre une fenêtre, ce n’est pas forcément pour la laisser ouverte longtemps. Je peux simplement faire sortir le chat ou jeter un œil au portail. Je ne veux pas que la climatisation se coupe dès que j’ouvre une fenêtre. Pour contourner cela, j’ai mis en place un watchdog pour chaque unité, afin de retarder l’envoi du message pendant un certain temps. Le premier nœud est un `switch node`. En fonction de la pièce transmise par le nœud précédent, il envoie le message au _watchdog_ correspondant : -![Node-RED switch node based on the room for the watchdog](img/node-red-switch-node-room-selector-watchdog.png) +![Nœud “switch” dans Node-RED basé sur la pièce pour diriger vers le bon _watchdog_](images/node-red-switch-node-room-selector-watchdog.png) Viennent ensuite les _watchdogs_, des `trigger nodes`, qui retardent le message pendant un certain temps, et prolongent ce délai si un autre message est reçu entre-temps : -![Node-RED trigger node for window watchdog](img/node-red-trigger-node-window-watchdog.png) +![Nœud “trigger” dans Node-RED pour la surveillance des fenêtres](images/node-red-trigger-node-window-watchdog.png) #### 7. Climatisation Activée ? Tous ces déclencheurs arrivent maintenant dans la chaîne de traitement, qui va déterminer ce que le système doit faire. Mais avant cela, on vérifie si l’automatisation est activée. J’ai ajouté ce kill switch au cas où, même si je l’utilise rarement. Le premier nœud est un `delay node` qui régule le débit des messages entrants à 1 message par seconde : -![Node-RED delay node to limit the rate to 1 message per second](img/node-red-delay-node-1-msg-per-second.png) +![Nœud delay dans Node-RED pour limiter le débit à 1 message par seconde](images/node-red-delay-node-1-msg-per-second.png) Le deuxième nœud est un `current state node` qui vérifie si le booléen `climatisation` est activé : -![Node-RED current state node for climatisation](img/node-red-current-state-node-climatisation-enabled.png) +![Nœud current state dans Node-RED pour l’état de la climatisation](images/node-red-current-state-node-climatisation-enabled.png) #### 8. Configuration des pièces @@ -223,7 +223,7 @@ Les unités de climatisation disposent de 4 modes : Pour déterminer quel mode utiliser, j’utilise des seuils pour chaque mode et la vitesse de ventilation, avec différents offsets selon la situation. Je peux ainsi définir un offset spécifique la nuit ou en cas d’absence. Je peux aussi définir un offset sur `disabled`, ce qui forcera l’arrêt de l’unité. Le premier nœud est un `switch node`, basé sur la valeur `room`, qui oriente le message vers la configuration associée. Si la pièce est `partout`, le message est dupliqué vers les 3 configurations de pièce : -![Node-RED switch node for room configuration](img/node-red-switch-node-room-config.png) +![Nœud “switch” dans Node-RED pour sélectionner la configuration en fonction de la pièce](images/node-red-switch-node-room-config.png) Il est ensuite connecté à un `change node`, qui ajoute la configuration dans `room_config`. Voici un exemple avec la configuration du salon : ```json @@ -445,13 +445,13 @@ return msg; ``` Le troisième nœud est un `filter node`, qui ignore les messages suivants ayant un contenu similaire : -![Node-RED filter node to block similar message](img/node-red-filter-node-blocker.png) +![Nœud de filtrage dans Node-RED pour bloquer les messages identiques](images/node-red-filter-node-blocker.png) Le quatrième nœud vérifie si un verrou est actif à l’aide d’un `current state node`. On regarde si le minuteur associé à l’unité est inactif. Si ce n’est pas le cas, le message est ignoré : -![Node-RED current state node for timer lock](img/node-red-current-state-node-lock-timer.png) +![Nœud current state dans Node-RED pour vérifier le verrou temporaire](images/node-red-current-state-node-lock-timer.png) Le dernier nœud est un autre `current state node` qui permet de récupérer l’état actuel de l’unité et ses propriétés : -![Node-RED current state node to get current unit state](img/node-red-current-state-node-get-unit-state.png) +![Nœud current state dans Node-RED pour obtenir l’état actuel de l’unité](images/node-red-current-state-node-get-unit-state.png) #### 10. État Cible @@ -608,17 +608,17 @@ return msg; #### 11. Choix de l'Action En fonction de l’action à effectuer, le `switch node` va router le message vers le bon chemin : -![Node-RED `switch node` pour sélectionner l’action](img/node-red-switch-node-select-action.png) +![Node-RED `switch node` pour sélectionner l’action](images/node-red-switch-node-select-action.png) #### 12. Démarrage Lorsque l’action est `start`, il faut d’abord allumer l’unité. Cela prend entre 20 et 40 secondes selon le modèle, et une fois démarrée, l’unité est verrouillée pendant un court laps de temps pour éviter les messages suivants. Le premier nœud est un `call service node` utilisant le service `turn_on` sur l’unité de climatisation : -![Node-RED call service node with turn_on service](img/node-red-call-service-node-turn-on.png) +![Nœud `call service` dans Node-RED avec le service `turn_on`](images/node-red-call-service-node-turn-on.png) Le second nœud est un autre `call service node` qui va démarrer un minuteur de verrouillage (lock timer) pour cette unité pendant 45 secondes : -![Node-RED call service node to start the unit timer](img/node-red-call-service-node-start-timer.png) +![Nœud `call service` dans Node-RED pour démarrer le minuteur de l’unité](images/node-red-call-service-node-start-timer.png) Le dernier est un `delay node` de 5 secondes, pour laisser le temps à l’intégration Daikin de Home Assistant de refléter le nouvel état. @@ -629,12 +629,12 @@ Le dernier est un `delay node` de 5 secondes, pour laisser le temps à l’inté L’action `change` est utilisée pour passer d’un mode à un autre, mais aussi juste après l’allumage. Le premier nœud est un `call service node` utilisant le service `set_hvac_mode` sur l’unité de climatisation : -![Node-RED call service node with set_hvac_mode service](img/node-red-call-service-node-set-hvac-mode.png) +![Nœud `call service` dans Node-RED avec le service `set_hvac_mode`](images/node-red-call-service-node-set-hvac-mode.png) Le nœud suivant est un `delay node` de 5 secondes. Le dernier vérifie, avec un `switch node`, si la température cible doit être définie. Cela n’est nécessaire que pour les modes `cool` et `heat` : -![Node-RED switch node for set_temp](img/node-red-switch-node-set-temp.png) +![Nœud `switch` dans Node-RED pour définir la température cible](images/node-red-switch-node-set-temp.png) --- @@ -643,7 +643,7 @@ Le dernier vérifie, avec un `switch node`, si la température cible doit être La température cible est uniquement pertinente pour les modes `cool` et `heat`. Avec une climatisation classique, vous définissez une température à atteindre — c’est exactement ce qu’on fait ici. Mais comme chaque unité utilise son propre capteur interne pour vérifier cette température, je ne leur fais pas vraiment confiance. Si la température cible est déjà atteinte selon l’unité, elle ne soufflera plus du tout. Le premier nœud est un autre `call service node` utilisant le service `set_temperature` : -![Node-RED call service node with set_temperature service](img/node-red-call-service-node-set-temperature-service.png) +![Nœud `call service` dans Node-RED avec le service `set_temperature`](images/node-red-call-service-node-set-temperature-service.png) Encore une fois, ce nœud est suivi d’un `delay node` de 5 secondes. @@ -652,20 +652,20 @@ Encore une fois, ce nœud est suivi d’un `delay node` de 5 secondes. L’action `check` est utilisée presque tout le temps. Elle consiste uniquement à vérifier et comparer la vitesse de ventilation souhaitée, et à la modifier si nécessaire. Le premier nœud est un `switch node` qui vérifie si la valeur `speed` est définie : -![Node-RED switch node to test if speed is defined](img/node-red-switch-node-fan-speed.png) +![Nœud switch dans Node-RED pour tester si la vitesse est définie](images/node-red-switch-node-fan-speed.png) Le deuxième est un autre `switch node` qui compare la valeur `speed` avec la vitesse actuelle : -![Node-Red switch node to compare speed](img/node-red-switch-node-compare-speed.png) +![Nœud switch dans Node-RED pour comparer la vitesse](images/node-red-switch-node-compare-speed.png) Enfin, le dernier nœud est un `call service node` utilisant le service `set_fan_mode` pour définir la vitesse du ventilateur : -![Node-RED call service node with set_fan_mode](img/node-red-call-service-node-set-fan-mode.png) +![Nœud `call service` dans Node-RED avec le service `set_fan_mode`](images/node-red-call-service-node-set-fan-mode.png) #### 16. Arrêt Lorsque l’action est `stop`, l’unité de climatisation est simplement arrêtée. Le premier nœud est un `call service node` utilisant le service `turn_off` : -![Node-RED call service node with turn_off service](img/node-red-call-service-node-turn-off.png) +![Nœud `call service` dans Node-RED avec le service `turn_off`](images/node-red-call-service-node-turn-off.png) Le deuxième nœud est un autre `call service node` qui va démarrer le minuteur de verrouillage de cette unité pour 45 secondes. @@ -675,7 +675,7 @@ Parfois, pour une raison ou une autre, on souhaite utiliser la climatisation man Node-RED utilise son propre utilisateur dans Home Assistant, donc si une unité change d’état sans cet utilisateur, c’est qu’une intervention manuelle a eu lieu. Le premier nœud est un `trigger state node`, qui envoie un message dès qu’une unité AC change d’état : -![node-red-trigger-state-unit-change.png](img/node-red-trigger-state-unit-change.png) +![node-red-trigger-state-unit-change.png](images/node-red-trigger-state-unit-change.png) Le deuxième est un `function node` qui associe l’unité avec son minuteur : ```js @@ -690,13 +690,13 @@ return msg; ``` Le troisième est un `switch node` qui laisse passer le message uniquement si le `user_id` **n’est pas** celui de Node-RED : -![Node-RED switch node not specific user_id](img/node-red-switch-node-user-id.png) +![Nœud `switch` dans Node-RED pour vérifier que ce n’est pas l’ID utilisateur Node-RED](images/node-red-switch-node-user-id.png) Le quatrième est un autre `switch node` qui vérifie que le champ `user_id` **est bien défini** : -![Node-RED switch node check user_id not null](img/node-red-switch-node-check-user-id.png) +![Nœud `switch` dans Node-RED pour vérifier que `user_id` n’est pas nul](images/node-red-switch-node-check-user-id.png) Enfin, le dernier nœud est un `call service node` utilisant le service `start` sur le minuteur de l’unité, avec sa durée par défaut (60 minutes) : -![Node-RED call service node start timer with default duration](img/node-red-call-service-node-start-unit-timer.png) +![Nœud `call service` dans Node-RED pour démarrer le minuteur avec la durée par défaut](images/node-red-call-service-node-start-unit-timer.png) ## TL;DR diff --git a/content/post/6-ac-automation-home-assistant-node-red/index.md b/content/post/6-ac-automation-home-assistant-node-red/index.md index 7b49f43..e675fdb 100644 --- a/content/post/6-ac-automation-home-assistant-node-red/index.md +++ b/content/post/6-ac-automation-home-assistant-node-red/index.md @@ -37,7 +37,7 @@ Node-RED does not replace Home Assistant, it empowers it. I won't cover the inst ## Previous Workflow I was already having a good solution to control my AC from Home Assistant with Node-RED, but I wanted to enhance it to also handle the humidity level at home. My current workflow, despite being functional, was not really scalable and quite hard to maintain: -![Ancien workflow Node-RED pour contrôler la climatisation](img/node-red-ha-ac-automation-before.png) +![Old Node-RED workflow to control air conditioning](images/node-red-ha-ac-automation-before.png) ## New Workflow @@ -54,12 +54,12 @@ To help me achieve that, I'm using 4 [Aqara temperature and humidity sensors](ht ### Workflow Let me introduce my new AC workflow within Node-RED and explain what it does in detail: -![New Node-RED air conditioning workflow](img/node-red-new-ac-workflow-with-legend.png) +![New Node-RED air conditioning workflow](images/node-red-new-ac-workflow-with-legend.png) #### 1. Temperature Sensors In the first node, I combined all the temperature sensors together in one `trigger state node`, but I also added humidity levels in addition to the temperature, managed by the sensor. The node then contains 8 entities in a list (2 for each of my sensor). Each time one value change out of these 8 entities, the node is triggered: -![Nœud trigger state dans Node-RED avec les 8 entités](img/node-red-temperature-sensors-trigger-node.png) +![Trigger state node in Node-RED with all 8 entities](images/node-red-temperature-sensors-trigger-node.png) Each of my temperature sensors are named with a color in French, because each has its own color sticker to distinguish them: - **Jaune**: Living room @@ -93,7 +93,7 @@ return msg; ``` For the last node, most of the time, the sensors will send two messages at the same time, one containing the temperature value and the other, the humidity level. I added a `join node` to combined the two messages if they are sent within the same second: -![Join node in Node-RED to merge temperature and humidity](img/node-red-temperature-sensor-join-node.png) +![Join node in Node-RED to merge temperature and humidity](images/node-red-temperature-sensor-join-node.png) #### 2. Notification @@ -132,17 +132,17 @@ return null; // Don't send anything now ``` The second node is a `call service node` which send a notification on my Android device with the value given: -![Node-RED call service node for notification](img/node-red-call-service-node-notification.png) +![Node-RED call service node for notification](images/node-red-call-service-node-notification.png) #### 3. Temperature Sliders To have a control over the temperature without having to change the workflow, I created two Home Assistant helper, as number, which I can adjust for each unit, giving me 6 helpers in total: -![Curseur de température dans Home Assistant pour chaque unité](img/home-assistant-temperature-room-sliders.png) +![Home Assistant temperature slider for each unit](images/home-assistant-temperature-room-sliders.png) These values are the base temperature used for the calculation of the threshold, depending off the offset which I will detail further. The first node is a `trigger state node`, with all 6 entities combined. If I change one value, the node is triggered: -![Node-RED trigger state node for sliders](img/node-red-trigger-state-mode-for-sliders.png) +![Node-RED trigger state node for sliders](images/node-red-trigger-state-mode-for-sliders.png) The second node is a `function node`, to determine the room affected: ```js @@ -164,17 +164,17 @@ return msg; In Home Assistant, I'm using other helper but as boolean, the most important is the AC one, where I can manually disable the whole workflow. I have other which are automated, for the time of the day or for detect presence at home. I have another `trigger state node` with all my toggles as boolean, including a test button, for debug purpose: -![Node-RED trigger state node for toggles](img/node-red-trigger-state-node-toggles.png) +![Node-RED trigger state node for toggles](images/node-red-trigger-state-node-toggles.png) As toggles affect the whole apartment and not a single unit, the next node is a `change node`, which set the room value to `partout` (everywhere): -![Node-RED change node to set room to partout](img/node-red-change-node-room-partout.png) +![Node-RED change node to set room to partout](images/node-red-change-node-room-partout.png) #### 5. Windows The last triggers are my windows, if I open or close a window next to my unit, it triggers the workflow. I have door sensor for some of my doors, but for the hallway unit, I'm using the Velux windows state. Some rooms have more than one, I created a group helper for them. The first node is the last `trigger state node`, the returned value is a string which I will have to convert later into boolean: -![Node-RED trigger state node for windows](img/node-red-trigger-state-node-windows.png) +![Node-RED trigger state node for windows](images/node-red-trigger-state-node-windows.png) Connected to it, again a `function node` to select the affect room: ```js @@ -195,20 +195,20 @@ return msg; When I open a window, it is not necessarily to let it open for a long time. I could just let the cat out or having a look at my portal. I don't want my AC tuned off as soon as open it. To workaround that I created a watchdog for each unit, to delay the message for some time. The first node is a `switch node`, based on the room given by the previous node, it will send the message to the associated watchdog: -![Node-RED switch node based on the room for the watchdog](img/node-red-switch-node-room-selector-watchdog.png) +![Node-RED switch node based on the room for the watchdog](images/node-red-switch-node-room-selector-watchdog.png) After are the watchdogs, `trigger nodes`, which will delay the message by some time and extend the delay if another message if received: -![Node-RED trigger node for window watchdog](img/node-red-trigger-node-window-watchdog.png) +![Node-RED trigger node for window watchdog](images/node-red-trigger-node-window-watchdog.png) #### 7. AC Enabled ? All these triggers are now entering the computing pipeline, to determine what the system must do with the action. But before, it is checking if the automation is even enabled. I add this kill switch, just in case, but I rarely use it anyway. The first node is a `delay node` which regulate the rate of every incoming messages to 1 per second: -![Node-RED delay node to limit the rate to 1 message per second](img/node-red-delay-node-1-msg-per-second.png) +![Node-RED delay node to limit the rate to 1 message per second](images/node-red-delay-node-1-msg-per-second.png) The second node is a `current state node` which checks if the `climatisation` boolean is enabled: -![Node-RED current state node for climatisation](img/node-red-current-state-node-climatisation-enabled.png) +![Node-RED current state node for climatisation](images/node-red-current-state-node-climatisation-enabled.png) #### 8. Room Configuration The idea here is to attach the configuration of the room to the message. Each room have their own configuration, which unit is used, which sensors and more importantly, when should they be turned on and off. @@ -222,7 +222,7 @@ AC units have 4 mode which can be used: To determine which mode should be used, I'm using threshold for each mode and unit fan's speed, with different offset depending the situation. I can then define a offset during the night or when I'm away. I can also set the offset to `disabled`, which will force the unit to shut down. The first node is a `switch node`, based on the `room` value, which will route the message to the associated room configuration. When the room is `partout` (everywhere), the message is split to all 3 room configuration: -![Node-RED switch node for room configuration](img/node-red-switch-node-room-config.png) +![Node-RED switch node for room configuration](images/node-red-switch-node-room-config.png) It is connected to a `change node` which will attach the configuration to the `room_config`, here an example with the living-room configuration: ```json @@ -443,13 +443,13 @@ return msg; ``` The third node is a `filter node`, which drops subsequent messages with similar payload: -![Node-RED filter node to block similar message](img/node-red-filter-node-blocker.png) +![Node-RED filter node to block similar message](images/node-red-filter-node-blocker.png) The fourth node checks if any lock is set, with a `current state node`, we verify if the timer associated to the unit is idle. If not, the message is discarded: -![Node-RED current state node for timer lock](img/node-red-current-state-node-lock-timer.png) +![Node-RED current state node for timer lock](images/node-red-current-state-node-lock-timer.png) The last node is another `current state node` which will fetch the unit state and properties: -![Node-RED current state node to get current unit state](img/node-red-current-state-node-get-unit-state.png) +![Node-RED current state node to get current unit state](images/node-red-current-state-node-get-unit-state.png) #### 10. Target State @@ -606,17 +606,17 @@ return msg; #### 11. Action Switch Based on the action to take, the `switch node` will route the message accordingly: -![Node-RED `switch node` pour sélectionner l’action](img/node-red-switch-node-select-action.png) +![Node-RED switch node to select the action](images/node-red-switch-node-select-action.png) #### 12. Start When the action is `start`, we first need to turn the unit online, while this takes between 20 to 40 seconds depending on the unit model, it is also locking the unit for a short period for future messages. The first node is a `call service node` using the `turn_on` service on the AC unit: -![Node-RED call service node with turn_on service](img/node-red-call-service-node-turn-on.png) +![Node-RED call service node with turn_on service](images/node-red-call-service-node-turn-on.png) The second node is another `call service node` which will start the lock timer of this unit for 45 seconds: -![Node-RED call service node to start the unit timer](img/node-red-call-service-node-start-timer.png) +![Node-RED call service node to start the unit timer](images/node-red-call-service-node-start-timer.png) The last one is a `delay node` of 5 seconds, to give the time to the Home Assistant Daikin integration to resolve the new state. @@ -625,19 +625,19 @@ The last one is a `delay node` of 5 seconds, to give the time to the Home Assist The `change` action is used to change from one mode to another, but also used right after the start action. The first node is a `call service node` using `the set_hvac_mode` service on the AC unit: -![Node-RED call service node with set_hvac_mode service](img/node-red-call-service-node-set-hvac-mode.png) +![Node-RED call service node with set_hvac_mode service](images/node-red-call-service-node-set-hvac-mode.png) The following node is another delay of 5 seconds. The last one verify with a `switch node` if the target temperature needs to be set, this is only required for the modes `cool` and `heat`: -![Node-RED switch node for set_temp](img/node-red-switch-node-set-temp.png) +![Node-RED switch node for set_temp](images/node-red-switch-node-set-temp.png) #### 14. Set Target Temperature The target temperature is only relevant for `cool` and `heat` mode, when you use a normal AC unit, you define a temperature to reach. This is exactly what is defined here. But because each unit is using its own internal sensor to verify, I don't trust it. If the value is already reached, the unit won't blow anything. The first node is another `call service node` using the `set_temperature` service: -![Node-RED call service node with set_temperature service](img/node-red-call-service-node-set-temperature-service.png) +![Node-RED call service node with set_temperature service](images/node-red-call-service-node-set-temperature-service.png) Again, this node is followed by a `delay node` of 5 seconds @@ -646,20 +646,20 @@ Again, this node is followed by a `delay node` of 5 seconds The `check` action is almost used everytime, it is actually only checks and compare the desired fan speed, it changes the fan speed if needed. The first node is a `switch node` which verify if the `speed` is defined: -![Node-RED switch node to test if speed is defined](img/node-red-switch-node-fan-speed.png) +![Node-RED switch node to test if speed is defined](images/node-red-switch-node-fan-speed.png) The second is another `switch node` to compare the `speed` value with the current speed: -![Node-Red switch node to compare speed](img/node-red-switch-node-compare-speed.png) +![Node-Red switch node to compare speed](images/node-red-switch-node-compare-speed.png) Finally the last node is a `call service node` using the `set_fan_mode` to set the fan speed: -![Node-RED call service node with set_fan_mode](img/node-red-call-service-node-set-fan-mode.png) +![Node-RED call service node with set_fan_mode](images/node-red-call-service-node-set-fan-mode.png) #### 16. Stop When the `action` is stop, the AC unit is simply turned off The first node is a `call service noded` using the service `turn_off`: -![Node-RED call service node with turn_off service](img/node-red-call-service-node-turn-off.png) +![Node-RED call service node with turn_off service](images/node-red-call-service-node-turn-off.png) The second node is another `call service node` which will start the lock timer of this unit for 45 seconds @@ -668,7 +668,7 @@ The second node is another `call service node` which will start the lock timer o Sometime, for some reason, we want to use the AC manually. When we do, we don't want the workflow to change our manual setting, at least for some time. Node-RED is using its own user in Home Assistant, so when an AC unit change state without this user, this was manually done. The first node is a `trigger state node`, which will send a message when any AC unit is changing state: -![node-red-trigger-state-unit-change.png](img/node-red-trigger-state-unit-change.png) +![node-red-trigger-state-unit-change.png](images/node-red-trigger-state-unit-change.png) The second is a `function node` which willassociate the unit with its timer: ```js @@ -683,13 +683,13 @@ return msg; ``` The third is a `switch node` that will let through the message when the user_id is not the Node-RED user's one: -![Node-RED switch node not specific user_id](img/node-red-switch-node-user-id.png) +![Node-RED switch node not specific user_id](images/node-red-switch-node-user-id.png) The fourth is another `switch node` which checks if there are any `user_id`: -![Node-RED switch node check user_id not null](img/node-red-switch-node-check-user-id.png) +![Node-RED switch node check user_id not null](images/node-red-switch-node-check-user-id.png) Lastly, the final node is a `call service node` using `start` service on the unit's timer with its default duration (60 minutes): -![Node-RED call service node start timer with default duration](img/node-red-call-service-node-start-unit-timer.png) +![Node-RED call service node start timer with default duration](images/node-red-call-service-node-start-unit-timer.png) ## TL;DR diff --git a/content/post/7-terraform-create-proxmox-module/images/proxmox-vm-deployed-using-terraform-module.png b/content/post/7-terraform-create-proxmox-module/images/proxmox-vm-deployed-using-terraform-module.png new file mode 100644 index 0000000..ab77fb3 Binary files /dev/null and b/content/post/7-terraform-create-proxmox-module/images/proxmox-vm-deployed-using-terraform-module.png differ diff --git a/content/post/7-terraform-create-proxmox-module/index.fr.md b/content/post/7-terraform-create-proxmox-module/index.fr.md index efcbf25..bded2f3 100644 --- a/content/post/7-terraform-create-proxmox-module/index.fr.md +++ b/content/post/7-terraform-create-proxmox-module/index.fr.md @@ -594,7 +594,7 @@ vm_ip = "192.168.66.159" ✅ La VM est maintenant prête ! -![VM on Proxmox WebUI deployed using a Terraform module](img/proxmox-vm-deployed-using-terraform-module.png) +![VM sur l'interface Proxmox déployé avec le module Terraform](images/proxmox-vm-deployed-using-terraform-module.png) 🕗 _Ne faites pas attention à l’uptime, j’ai pris la capture d’écran le lendemain._ diff --git a/content/post/7-terraform-create-proxmox-module/index.md b/content/post/7-terraform-create-proxmox-module/index.md index 9dd889c..f36778e 100644 --- a/content/post/7-terraform-create-proxmox-module/index.md +++ b/content/post/7-terraform-create-proxmox-module/index.md @@ -589,7 +589,7 @@ vm_ip = "192.168.66.159" ✅ The VM is now ready! -![VM on Proxmox WebUI deployed using a Terraform module](img/proxmox-vm-deployed-using-terraform-module.png) +![VM on Proxmox WebUI deployed using a Terraform module](images/proxmox-vm-deployed-using-terraform-module.png) 🕗 *Don't pay attention to the uptime, I took the screenshot the next day* diff --git a/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/ingress-controller-nginx-test-simple-webserver.png b/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/ingress-controller-nginx-test-simple-webserver.png new file mode 100644 index 0000000..bb0d1b8 Binary files /dev/null and b/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/ingress-controller-nginx-test-simple-webserver.png differ diff --git a/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/k8s-deploy-test-service-tls-certificate-lets-encrypt.png b/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/k8s-deploy-test-service-tls-certificate-lets-encrypt.png new file mode 100644 index 0000000..ec2e50e Binary files /dev/null and b/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/k8s-deploy-test-service-tls-certificate-lets-encrypt.png differ diff --git a/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/k8s-test-deploy-service-tls-certificate-staging-lets-encrypt.png b/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/k8s-test-deploy-service-tls-certificate-staging-lets-encrypt.png new file mode 100644 index 0000000..6e214dc Binary files /dev/null and b/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/k8s-test-deploy-service-tls-certificate-staging-lets-encrypt.png differ diff --git a/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/k8s-test-loadbalancer-service-with-bgp.png b/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/k8s-test-loadbalancer-service-with-bgp.png new file mode 100644 index 0000000..22e7d11 Binary files /dev/null and b/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/k8s-test-loadbalancer-service-with-bgp.png differ diff --git a/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/opnsense-add-os-frr-plugin.png b/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/opnsense-add-os-frr-plugin.png new file mode 100644 index 0000000..3d4e273 Binary files /dev/null and b/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/opnsense-add-os-frr-plugin.png differ diff --git a/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/opnsense-bgp-create-neighbor.png b/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/opnsense-bgp-create-neighbor.png new file mode 100644 index 0000000..ee06797 Binary files /dev/null and b/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/opnsense-bgp-create-neighbor.png differ diff --git a/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/opnsense-bgp-neighbor-list.png b/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/opnsense-bgp-neighbor-list.png new file mode 100644 index 0000000..2275945 Binary files /dev/null and b/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/opnsense-bgp-neighbor-list.png differ diff --git a/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/opnsense-caddy-create-layer4-route-http.png b/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/opnsense-caddy-create-layer4-route-http.png new file mode 100644 index 0000000..a807534 Binary files /dev/null and b/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/opnsense-caddy-create-layer4-route-http.png differ diff --git a/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/opnsense-create-firewall-rule-bgp-peering.png b/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/opnsense-create-firewall-rule-bgp-peering.png new file mode 100644 index 0000000..00457a5 Binary files /dev/null and b/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/opnsense-create-firewall-rule-bgp-peering.png differ diff --git a/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/opnsense-enable-bgp.png b/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/opnsense-enable-bgp.png new file mode 100644 index 0000000..1f6c90f Binary files /dev/null and b/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/opnsense-enable-bgp.png differ diff --git a/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/opnsense-enable-routing-frr-plugin.png b/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/opnsense-enable-routing-frr-plugin.png new file mode 100644 index 0000000..b775fc9 Binary files /dev/null and b/content/post/9-expose-kubernetes-pods-externally-ingress-tls/images/opnsense-enable-routing-frr-plugin.png differ diff --git a/content/post/9-expose-kubernetes-pods-externally-ingress-tls/index.fr.md b/content/post/9-expose-kubernetes-pods-externally-ingress-tls/index.fr.md index fe5d070..e623d5d 100644 --- a/content/post/9-expose-kubernetes-pods-externally-ingress-tls/index.fr.md +++ b/content/post/9-expose-kubernetes-pods-externally-ingress-tls/index.fr.md @@ -97,31 +97,31 @@ BGP est désactivé par défaut, aussi bien sur OPNsense que sur Cilium. Activon D’après la [documentation officielle OPNsense](https://docs.opnsense.org/manual/dynamic_routing.html#bgp-section), l’activation de BGP nécessite d’installer un plugin. Va dans `System` > `Firmware` > `Plugins` et installe le plugin **os-frr** : -![ ](img/opnsense-add-os-frr-plugin.png) +![ ](images/opnsense-add-os-frr-plugin.png) Installer le plugin `os-frr` dans OPNsense Une fois installé, active le plugin dans `Routing` > `General` : -![ ](img/opnsense-enable-routing-frr-plugin.png) +![ ](images/opnsense-enable-routing-frr-plugin.png) Activer le routage dans OPNsense Ensuite, rends-toi dans la section **BGP**. Dans l’onglet **General** : - Coche la case pour activer BGP. - Défini ton **ASN BGP**. J’ai choisi `64512`, le premier ASN privé de la plage réservée (voir [ASN table](https://en.wikipedia.org/wiki/Autonomous_system_\(Internet\)#ASN_Table)) : -![ ](img/opnsense-enable-bgp.png) +![Configuration générale de BGP dans OPNsense](images/opnsense-enable-bgp.png) Ajoute ensuite tes voisins BGP. Je ne fais le peering qu’avec mes **nœuds workers** (puisque seuls eux hébergent des workloads). Pour chaque voisin : - Mets l’IP du nœud dans `Peer-IP`. - Utilise `64513` comme **Remote AS** (celui de Cilium). - Configure `Update-Source Interface` sur `Lab`. - Coche `Next-Hop-Self`. -![ ](img/opnsense-bgp-create-neighbor.png) +![Configuration d’un voisin BGP dans OPNsense](images/opnsense-bgp-create-neighbor.png) Voici la liste de mes voisins une fois configurés : -![ ](img/opnsense-bgp-neighbor-list.png) +![ ](images/opnsense-bgp-neighbor-list.png) Liste des voisins BGP N’oublie pas la règle firewall pour autoriser BGP (port `179/TCP`) depuis le VLAN **Lab** vers le firewall : -![ ](img/opnsense-create-firewall-rule-bgp-peering.png) +![ ](images/opnsense-create-firewall-rule-bgp-peering.png) Autoriser TCP/179 de Lab vers OPNsense #### Dans Cilium @@ -294,7 +294,7 @@ test-lb LoadBalancer 10.100.167.198 192.168.55.20 80:31350/TCP 169m Le service a récupéré la première IP du pool défini : `192.168.55.20`. Depuis n’importe quel appareil du LAN, on peut tester l’accès sur le port 80 : -![Test LoadBalancer service with BGP](img/k8s-test-loadbalancer-service-with-bgp.png) +![Test du service LoadBalancer avec BGP](images/k8s-test-loadbalancer-service-with-bgp.png) ✅ Notre pod est joignable via une IP `LoadBalancer` routée en BGP. Première étape réussie ! @@ -451,10 +451,10 @@ Ensuite, j’applique le manifeste `Ingress` pour exposer le service en HTTP. Comme j’utilise le plugin **Caddy** dans OPNsense, j’ai encore besoin d’un routage local de type Layer 4 pour rediriger le trafic de `test.vezpi.me` vers l’adresse IP de l’Ingress Controller (`192.168.55.55`). Je crée donc une nouvelle règle dans le plugin Caddy. -![Create Layer4 router in Caddy plugin for OPNsense](img/opnsense-caddy-create-layer4-route-http.png) +![Créer un routeur Layer4 dans le plugin Caddy d’OPNsense](images/opnsense-caddy-create-layer4-route-http.png) Puis je teste l’accès dans le navigateur : -![ ](img/ingress-controller-nginx-test-simple-webserver.png) +![ ](images/ingress-controller-nginx-test-simple-webserver.png) Test d’un Ingress en HTTP ✅ Mon pod est désormais accessible via son URL HTTP en utilisant un Ingress. Deuxième étape complétée ! @@ -558,7 +558,7 @@ En arrière-plan, Cert-Manager suit ce flux pour émettre le certificat : - L’Ingress utilise automatiquement ce Secret pour servir en HTTPS. ✅ Une fois ce processus terminé, votre Ingress est sécurisé avec un certificat TLS. -![Certificat TLS validé avec le serveur de staging de Let’s Encrypt](img/k8s-test-deploy-service-tls-certificate-staging-lets-encrypt.png) +![Certificat TLS validé avec le serveur de staging de Let’s Encrypt](images/k8s-test-deploy-service-tls-certificate-staging-lets-encrypt.png) ### Passer aux certificats de production @@ -614,7 +614,7 @@ kubectl delete secret test-vezpi-me-tls ``` 🎉 Mon `Ingress` est désormais sécurisé avec un certificat TLS valide délivré par Let’s Encrypt. Les requêtes vers `https://test.vezpi.me` sont chiffrées de bout en bout et routées par le NGINX Ingress Controller jusqu’à mon pod `nginx` : -![Ingress HTTPS avec certificat validé par Let’s Encrypt](img/k8s-deploy-test-service-tls-certificate-lets-encrypt.png) +![Ingress HTTPS avec certificat validé par Let’s Encrypt](images/k8s-deploy-test-service-tls-certificate-lets-encrypt.png) --- diff --git a/content/post/9-expose-kubernetes-pods-externally-ingress-tls/index.md b/content/post/9-expose-kubernetes-pods-externally-ingress-tls/index.md index 0f266a2..3e2a3b8 100644 --- a/content/post/9-expose-kubernetes-pods-externally-ingress-tls/index.md +++ b/content/post/9-expose-kubernetes-pods-externally-ingress-tls/index.md @@ -93,17 +93,17 @@ BGP is disabled by default on both OPNsense and Cilium. Let’s enable it on bot According to the [official OPNsense documentation](https://docs.opnsense.org/manual/dynamic_routing.html#bgp-section), enabling BGP requires installing a plugin. Head to `System` > `Firmware` > `Plugins` and install the `os-frr` plugin: -![ ](img/opnsense-add-os-frr-plugin.png) +![ ](images/opnsense-add-os-frr-plugin.png) Install `os-frr` plugin in OPNsense Once installed, enable the plugin under `Routing` > `General`: -![ ](img/opnsense-enable-routing-frr-plugin.png) +![ ](images/opnsense-enable-routing-frr-plugin.png) Enable routing in OPNsense Then navigate to the `BGP` section. In the **General** tab: - Tick the box to enable BGP. - Set your **BGP ASN**. I used `64512`, the first private ASN from the reserved range (see [ASN table](https://en.wikipedia.org/wiki/Autonomous_system_\(Internet\)#ASN_Table)): -![ ](img/opnsense-enable-bgp.png) +![ ](images/opnsense-enable-bgp.png) General BGP configuration in OPNsense Now create your BGP neighbors. I’m only peering with my **worker nodes** (since only they run workloads). For each neighbor: @@ -111,15 +111,15 @@ Now create your BGP neighbors. I’m only peering with my **worker nodes** (sinc - Use `64513` as the **Remote AS** (Cilium’s ASN) - Set `Update-Source Interface` to `Lab` - Tick `Next-Hop-Self`: -![ ](img/opnsense-bgp-create-neighbor.png) +![ ](images/opnsense-bgp-create-neighbor.png) BGP neighbor configuration in OPNsense Here’s how my neighbors list looks once complete: -![ ](img/opnsense-bgp-neighbor-list.png) +![ ](images/opnsense-bgp-neighbor-list.png) BGP neighbor list Don’t forget to create a firewall rule allowing BGP (port `179/TCP`) from the **Lab** VLAN to the firewall: -![ ](img/opnsense-create-firewall-rule-bgp-peering.png) +![ ](images/opnsense-create-firewall-rule-bgp-peering.png) Allow TCP/179 from Lab to OPNsense #### In Cilium @@ -292,7 +292,7 @@ test-lb LoadBalancer 10.100.167.198 192.168.55.20 80:31350/TCP 169m The service got the first IP from our defined pool: `192.168.55.20`. Now from any device on the LAN, try to reach that IP on port 80: -![Test LoadBalancer service with BGP](img/k8s-test-loadbalancer-service-with-bgp.png) +![Test LoadBalancer service with BGP](images/k8s-test-loadbalancer-service-with-bgp.png) ✅ Our pod is reachable through BGP-routed `LoadBalancer` IP, first step successful! @@ -449,10 +449,10 @@ Then I apply the `Ingress` manifest as shown earlier to expose the service over Since I'm using the Caddy plugin on OPNsense, I still need a local Layer 4 route to forward traffic for `test.vezpi.me` to the NGINX Ingress Controller IP (`192.168.55.55`). I simply create a new rule in the Caddy plugin. -![Create Layer4 router in Caddy plugin for OPNsense](img/opnsense-caddy-create-layer4-route-http.png) +![Create Layer4 router in Caddy plugin for OPNsense](images/opnsense-caddy-create-layer4-route-http.png) Now let’s test it in the browser: -![ ](img/ingress-controller-nginx-test-simple-webserver.png) +![ ](images/ingress-controller-nginx-test-simple-webserver.png) Test Ingress on HTTP ✅ Our pod is now reachable on its HTTP URL using an Ingress. Second step complete! @@ -556,7 +556,7 @@ Behind the scenes, Cert-Manager goes through this workflow to issue the certific - The Ingress automatically uses the Secret to serve HTTPS. ✅ Once this process completes, your Ingress is secured with a TLS certificate. -![Certificat TLS validé avec le serveur de staging de Let’s Encrypt](img/k8s-test-deploy-service-tls-certificate-staging-lets-encrypt.png) +![TLS certificate verified with the staging Let's Encrypt server](images/k8s-test-deploy-service-tls-certificate-staging-lets-encrypt.png) ### Switch to Production Certificates @@ -612,7 +612,7 @@ kubectl delete secret test-vezpi-me-tls ``` 🎉 My `Ingress` is now secured with a valid TLS certificate from Let’s Encrypt. Requests to `https://test.vezpi.me` are encrypted end-to-end and routed by the NGINX Ingress Controller to my `nginx` pod: -![Ingress HTTPS avec certificat validé par Let’s Encrypt](img/k8s-deploy-test-service-tls-certificate-lets-encrypt.png) +![Ingress HTTPS with certificate verified by Let's Encrypt](images/k8s-deploy-test-service-tls-certificate-lets-encrypt.png) --- diff --git a/content/post/random-post/index.md b/content/post/random-post/index.md index 9b538ef..63548ae 100644 --- a/content/post/random-post/index.md +++ b/content/post/random-post/index.md @@ -27,4 +27,6 @@ Checklist: - [ ] Not Checked - [x] Checked -Look this is ~~strike~~ ! \ No newline at end of file +Look this is ~~strike~~ ! + +What else? A fix! \ No newline at end of file