𝔩𝔢𝔩𝕠𝔭𝔢𝔷
Theme

Homelab

Talos Migration

Migrating Your Talos Cluster to an Isolated Lab VLAN

Overview

This article migrates the Talos cluster from the Network VLAN (192.168.1.x) to the isolated Lab VLAN (192.168.10.x). The migration maintains etcd quorum throughout by configuring dual-subnet communication before moving nodes.

Tip:Having trouble? See v1.1.0 for what your setup should look like after completing this article.

Before You Begin

Prerequisites

Temporary Firewall Rules Required

During migration, nodes are split across VLANs - some on Lab, others on Network (Core zone). etcd peers must communicate on port 2380 across zones.

The existing firewall rules don't cover this:

  • Core → Lab: Only allows Admin Devices (Talos nodes aren't Admin Devices)
  • Lab → Core: No rules exist

You'll create temporary rules allowing etcd traffic between zones, then remove them post-migration.

What Changes

ComponentBeforeAfter
Node IPs192.168.1.30-32192.168.10.30-32
Gateway192.168.1.1192.168.10.1
API endpoint192.168.1.30:6443192.168.10.30:6443

Why Dual-Subnet etcd Configuration

etcd stores peer URLs in its internal database. When node IPs change, etcd members can't find each other at the old addresses and quorum is lost1. The fix is to configure etcd to advertise on both subnets before we start moving nodes2.

With dual-subnet configuration:

  1. Node 1 migrates → still reaches nodes 2+3 on old subnet (quorum: 2/3)
  2. Node 2 migrates → reaches node 1 on new subnet, node 3 on old (quorum: 2/3)
  3. Node 3 migrates → all nodes on new subnet (quorum: 3/3)

Quorum is never lost because etcd peers communicate across both subnets during the transition.

How the Migration Works

  1. Configure etcd to advertise on both subnets
  2. Apply dual-subnet config and reboot all nodes
  3. Migrate nodes one at a time (apply new IP config → change VLAN)
  4. Remove old subnet from etcd config

Configure Dual-Subnet etcd

Before changing any IPs, configure etcd to communicate on both the old and new subnets.

Add Temporary Firewall Rules

During migration, nodes will be split across VLANs. etcd peers must communicate across zones.

In UniFi: Settings → Policy Engine → Zones → Create Policy

OrderZone SourceZone DestNameSrc FilterActionDst FilterDst PortProtocol
1LabCoreTemp: Lab to NetworkAnyAllowAnyAnyAll
1CoreLabTemp: Network to LabAnyAllowAnyAnyAll
Warning:Remove these rules after migration completes (Post-Migration).

Add etcd Advertised Subnets

talos/talconfig.yaml:

cniConfig:
    name: flannel

cluster: # ADD this section
    etcd:
        advertisedSubnets:
            - 192.168.1.0/24 # Current Network VLAN
            - 192.168.10.0/24 # Target Lab VLAN

controlPlane:
    patches:
Warning:This change requires a node reboot to take effect3. Plan for brief cluster disruption.

Git: Commit Dual-Subnet Config

git add talos/talconfig.yaml
git commit -m "feat(talos): add dual-subnet etcd for VLAN migration"

Regenerate and Apply

cd <homelab>/talos

SOPS_AGE_KEY_FILE=<(op document get "sops-key | homelab") \
  talhelper genconfig

Apply to all nodes:

talosctl apply-config \
  --nodes 192.168.1.30 \
  --endpoints 192.168.1.30 \
  --file clusterconfig/homelab-cluster-talos-node-1.yaml \
  --mode=reboot

talosctl apply-config \
  --nodes 192.168.1.31 \
  --endpoints 192.168.1.31 \
  --file clusterconfig/homelab-cluster-talos-node-2.yaml \
  --mode=reboot

talosctl apply-config \
  --nodes 192.168.1.32 \
  --endpoints 192.168.1.32 \
  --file clusterconfig/homelab-cluster-talos-node-3.yaml \
  --mode=reboot

Verify: Post-Reboot Health

Wait for all nodes to reboot:

talosctl health --nodes 192.168.1.30

Expected: All checks pass. etcd is now configured to communicate on both subnets.

Update Talos Configuration

Update IPs

Update all IP references from Network VLAN to Lab VLAN.

talos/talconfig.yaml:

endpoint: https://192.168.10.30:6443 # Was 192.168.1.30

nodes:
    - hostname: talos-node-1
      ipAddress: 192.168.10.30 # Was 192.168.1.30
      controlPlane: true
      networkInterfaces:
          - interface: enp172s0
            addresses:
                - 192.168.10.30/24 # Was 192.168.1.30/24
            routes:
                - network: 0.0.0.0/0
                  gateway: 192.168.10.1 # Was 192.168.1.1

    - hostname: talos-node-2
      ipAddress: 192.168.10.31 # Was 192.168.1.31
      controlPlane: true
      networkInterfaces:
          - interface: enp172s0
            addresses:
                - 192.168.10.31/24
            routes:
                - network: 0.0.0.0/0
                  gateway: 192.168.10.1

    - hostname: talos-node-3
      ipAddress: 192.168.10.32 # Was 192.168.1.32
      controlPlane: true
      networkInterfaces:
          - interface: enp172s0
            addresses:
                - 192.168.10.32/24
            routes:
                - network: 0.0.0.0/0
                  gateway: 192.168.10.1
Tip:In vim: :%s/192\.168\.1\./192.168.10./gc to confirm each replacement. Skip the advertisedSubnets line - keep the old subnet until post-migration.

Git: Commit IP Changes

git add talos/talconfig.yaml
git commit -m "feat(talos): migrate cluster to Lab VLAN"

Regenerate Configs

cd <homelab>/talos

SOPS_AGE_KEY_FILE=<(op document get "sops-key | homelab") \
  talhelper genconfig

Migrate Node 1

Warning:This causes brief cluster disruption. Migrate one node at a time.

Verify: Node 1 Before

talosctl version --nodes 192.168.1.30 --endpoints 192.168.1.30

Talosctl: Apply Node 1 Config

talosctl apply-config \
  --nodes 192.168.1.30 \
  --endpoints 192.168.1.30 \
  --file clusterconfig/homelab-cluster-talos-node-1.yaml \
  --mode=reboot

Node reboots with the new IP. It's now unreachable because it has a 192.168.10.x IP but is still on the Network VLAN.

UniFi: Change Node 1 to Lab

In UniFi: Devices → [Switch] → Ports → [Node 1 port] → Port Profile → Lab

Verify: Node 1 After

talosctl version --nodes 192.168.10.30 --endpoints 192.168.10.30

Verify: etcd After Node 1

talosctl health --nodes 192.168.10.30 --endpoints 192.168.10.30

Expected: All checks pass. etcd maintains quorum with nodes 2+3 on the old subnet.

Migrate Node 2

Verify: Node 2 Before

talosctl version --nodes 192.168.1.31 --endpoints 192.168.1.31

Talosctl: Apply Node 2 Config

talosctl apply-config \
  --nodes 192.168.1.31 \
  --endpoints 192.168.1.31 \
  --file clusterconfig/homelab-cluster-talos-node-2.yaml \
  --mode=reboot

UniFi: Change Node 2 to Lab

In UniFi: Set node 2's port to Lab profile.

Verify: Node 2 After

talosctl version --nodes 192.168.10.31 --endpoints 192.168.10.31

Verify: etcd After Node 2

talosctl health --nodes 192.168.10.30 --endpoints 192.168.10.30

Expected: All checks pass. etcd maintains quorum across both subnets.

Migrate Node 3

Verify: Node 3 Before

talosctl version --nodes 192.168.1.32 --endpoints 192.168.1.32

Talosctl: Apply Node 3 Config

talosctl apply-config \
  --nodes 192.168.1.32 \
  --endpoints 192.168.1.32 \
  --file clusterconfig/homelab-cluster-talos-node-3.yaml \
  --mode=reboot

UniFi: Change Node 3 to Lab

In UniFi: Set node 3's port to Lab profile.

Verify: Node 3 After

talosctl version --nodes 192.168.10.32 --endpoints 192.168.10.32

Verify: etcd After Node 3

talosctl health --nodes 192.168.10.30 --endpoints 192.168.10.30

Expected: All checks pass. All nodes are now on Lab VLAN.

Complete Post-Migration Steps

Update kubeconfig

talosctl kubeconfig --nodes 192.168.10.30 ~/.kube/config

Verify: Cluster Health

talosctl health --nodes 192.168.10.30

kubectl get nodes -o wide

Expected: All nodes Ready with 192.168.10.x IPs.

Remove Temporary Firewall Rules

In UniFi: Settings → Policy Engine → Zones

Delete both temporary rules created earlier - they're no longer needed since all nodes are on the same VLAN:

Zone SourceZone DestNameAction
LabCoreTemp: Lab to NetworkDelete
CoreLabTemp: Network to LabDelete

Remove Old Subnet

Now that all nodes are on the new subnet, remove the old subnet from etcd configuration.

talos/talconfig.yaml:

cniConfig:
    name: flannel

cluster:
    etcd:
        advertisedSubnets:
            - 192.168.10.0/24 # Only new subnet (remove old)

controlPlane:
    patches:

Commit, regenerate, and apply:

git add talos/talconfig.yaml
git commit -m "feat(talos): remove old subnet from etcd config"
SOPS_AGE_KEY_FILE=<(op document get "sops-key | homelab") \
  talhelper genconfig

talosctl apply-config \
  --nodes 192.168.10.30 \
  --file clusterconfig/homelab-cluster-talos-node-1.yaml \
  --mode=reboot

talosctl apply-config \
  --nodes 192.168.10.31 \
  --file clusterconfig/homelab-cluster-talos-node-2.yaml \
  --mode=reboot

talosctl apply-config \
  --nodes 192.168.10.32 \
  --file clusterconfig/homelab-cluster-talos-node-3.yaml \
  --mode=reboot

Final Verification

talosctl health --nodes 192.168.10.30

talosctl etcd members --nodes 192.168.10.30

Expected: All etcd members show 192.168.10.x peer URLs.

Next Steps

Nodes are on the isolated Lab VLAN, but both remote and local access need updates. Tailscale routes still advertise the old Network VLAN, so you can't reach the new node IPs remotely. For local services, MetalLB still assigns IPs from the Network VLAN and L2 ARP can't cross VLANs, so Plex may fall back to relay mode (480p).

Update Tailscale first to restore remote cluster management, then MetalLB for local service access.

See: Tailscale Migration

Resources

Footnotes

  1. etcd.io, "Runtime reconfiguration," etcd.io. Accessed: Feb. 22, 2026. [Online]. Available: https://etcd.io/docs/v3.3/op-guide/runtime-configuration/

  2. Sidero Labs, "Production Clusters," talos.dev. Accessed: Feb. 22, 2026. [Online]. Available: https://www.talos.dev/v1.9/introduction/prodnotes/

  3. Sidero Labs, "Changing machine.etcd.advertisedSubnets should work without reboot," GitHub. Accessed: Feb. 22, 2026. [Online]. Available: https://github.com/siderolabs/talos/issues/9605

Previous
Firewall Rules