--- - name: Configure bridges community.routeros.api_modify: path: interface bridge data: - name: bridge1 vlan-filtering: true - name: containers - name: nat64 handle_absent_entries: remove handle_entries_content: remove_as_much_as_possible - name: Configure VLAN interfaces community.routeros.api_modify: path: interface vlan data: - name: vlan2 comment: LAN (PC, WIFI) interface: bridge1 vlan-id: 2 - name: vlan3 comment: KAMERY interface: bridge1 vlan-id: 3 - name: vlan4 comment: SERVER LAN interface: bridge1 vlan-id: 4 - name: vlan5 comment: IOT interface: bridge1 vlan-id: 5 - name: vlan6 comment: OPENWRT UPLINK interface: bridge1 vlan-id: 6 handle_absent_entries: remove handle_entries_content: remove_as_much_as_possible - name: Configure interface lists community.routeros.api_modify: path: interface list data: - name: wan comment: contains interfaces facing internet handle_absent_entries: remove handle_entries_content: remove_as_much_as_possible - name: Configure interface list members community.routeros.api_modify: path: interface list member data: - interface: pppoe-gpon list: wan - interface: sit1 list: wan - interface: vlan6 list: wan handle_absent_entries: remove handle_entries_content: remove_as_much_as_possible - name: Configure bridge ports community.routeros.api_modify: path: interface bridge port data: - bridge: containers interface: veth-tailscale comment: Tailscale container interface - bridge: containers interface: veth-coredns comment: CoreDNS container interface - bridge: nat64 interface: veth-tayga comment: Tayga NAT64 container interface - bridge: bridge1 interface: ether1 pvid: 2 - bridge: bridge1 interface: ether2 pvid: 2 - bridge: bridge1 interface: ether3 comment: OpenWrt AP (dlink) - bridge: bridge1 interface: ether8 pvid: 4 - bridge: bridge1 interface: ether9 pvid: 2 - bridge: bridge1 interface: ether10 pvid: 3 - bridge: bridge1 interface: sfp-sfpplus2 - bridge: bridge1 interface: ether11 handle_absent_entries: remove handle_entries_content: remove_as_much_as_possible - name: Configure bridge VLAN membership community.routeros.api_modify: path: interface bridge vlan data: - bridge: bridge1 tagged: sfp-sfpplus2,ether3 untagged: ether1,ether2,ether9 vlan-ids: 2 - bridge: bridge1 tagged: bridge1,ether3 vlan-ids: 5 - bridge: bridge1 tagged: bridge1,ether3 vlan-ids: 6 - bridge: bridge1 tagged: sfp-sfpplus2 untagged: ether10 vlan-ids: 3 - bridge: bridge1 untagged: ether8 vlan-ids: 4 handle_absent_entries: remove handle_entries_content: remove_as_much_as_possible - name: Configure IPv4 pools community.routeros.api_modify: path: ip pool data: - name: dhcp_pool0 ranges: 192.168.0.50-192.168.0.250 comment: LAN DHCP pool - name: dhcp_pool1 ranges: 192.168.255.1-192.168.255.9,192.168.255.11-192.168.255.254 comment: MGMT DHCP pool - name: dhcp_pool2 ranges: 192.168.5.50-192.168.5.250 comment: IOT DHCP pool handle_absent_entries: remove handle_entries_content: remove_as_much_as_possible - name: Configure DHCP servers community.routeros.api_modify: path: ip dhcp-server data: - name: dhcp1 address-pool: dhcp_pool0 interface: vlan2 lease-time: 30m comment: LAN - name: dhcp2 address-pool: dhcp_pool1 interface: bridge1 lease-time: 30m comment: MGMT - name: dhcp3 address-pool: dhcp_pool2 interface: vlan5 lease-time: 30m comment: IOT handle_absent_entries: remove handle_entries_content: remove_as_much_as_possible # Pool is no longer referenced — vlan2/vlan5 now use static addresses # (addressing.yml) so the RDNSS addresses in ND config are deterministic. # Kept defined for one run after migration; safe to delete afterwards. - name: Configure IPv6 pools community.routeros.api_modify: path: ipv6 pool data: - name: pool1 prefix: 2001:470:61a3::/48 prefix-length: 64 handle_absent_entries: remove handle_entries_content: remove_as_much_as_possible - name: Configure DNS community.routeros.api_find_and_modify: ignore_dynamic: false path: ip dns find: {} values: allow-remote-requests: true cache-size: 20480 # CoreDNS container provides DNS64; it forwards upstream to 1.1.1.1/8.8.8.8. servers: 172.20.0.3 - name: Configure DNS static entries community.routeros.api_modify: path: ip dns static data: - name: ts.net type: FWD forward-to: 100.100.100.100 match-subdomain: true comment: Tailscale MagicDNS - name: lumpiasty.xyz type: FWD forward-to: 1.1.1.1 match-subdomain: true comment: lumpiasty.xyz bypass nat64 handle_absent_entries: remove handle_entries_content: remove_as_much_as_possible - name: Configure NAT-PMP global settings community.routeros.api_find_and_modify: ignore_dynamic: false path: ip nat-pmp find: {} values: enabled: true - name: Configure NAT-PMP interfaces community.routeros.api_modify: path: ip nat-pmp interfaces data: - interface: containers type: internal - interface: pppoe-gpon type: external - interface: vlan2 type: internal handle_absent_entries: remove handle_entries_content: remove_as_much_as_possible - name: Configure UPnP global settings community.routeros.api_find_and_modify: ignore_dynamic: false path: ip upnp find: {} values: enabled: true - name: Configure UPnP interfaces community.routeros.api_modify: path: ip upnp interfaces data: - interface: containers type: internal - interface: pppoe-gpon type: external - interface: vlan2 type: internal handle_absent_entries: remove handle_entries_content: remove_as_much_as_possible # Option 108 (IPv6-only preferred, RFC 8925). Without force=yes RouterOS only # includes the option for clients that request code 108 in their Parameter # Request List — i.e. RFC 8925-capable clients. Clients that receive it drop # IPv4 and rely on CLAT/NAT64, which REQUIRES pref64 in RA (see ND tasks below). - name: Configure DHCP server options (IPv6-only preferred, RFC 8925) community.routeros.api_modify: path: ip dhcp-server option data: # 32-bit seconds timer (V6ONLY_WAIT) — how long the client suppresses # IPv4. Refreshed on every renewal; acts as automatic fallback if the # DHCP server disappears. 0x00015180 = 86400 s (1 day). # Quoted to prevent YAML from parsing the hex literal as integer 86400. - name: v6only-preferred code: 108 value: "0x00015180" handle_absent_entries: remove handle_entries_content: remove_as_much_as_possible - name: Configure DHCP networks community.routeros.api_modify: path: ip dhcp-server network data: - address: 192.168.0.0/24 dns-server: 192.168.0.1 gateway: 192.168.0.1 dhcp-option: v6only-preferred - address: 192.168.255.0/24 dns-none: true gateway: 192.168.255.10 - address: 192.168.5.0/24 dns-server: 192.168.5.1 gateway: 192.168.5.1 dhcp-option: v6only-preferred handle_absent_entries: remove handle_entries_content: remove_as_much_as_possible - name: Configure IPv6 ND defaults community.routeros.api_find_and_modify: ignore_dynamic: false path: ipv6 nd find: default: true values: advertise-dns: true # Per-interface ND entries must be CREATED — only the interface=all default # exists out of the box. The previous api_find_and_modify approach silently # matched zero entries and never applied pref64. # # pref64: NAT64 prefix discovery (RFC 8781) — required by clients honouring # DHCP option 108 to activate CLAT. Without it they go IPv6-only with no # working translation and appear stuck while "obtaining IP address". # # dns: RDNSS (RFC 8106) — IPv6-only clients ignore DHCPv4 entirely, including # its dns-server. They need an IPv6 DNS address from RA. We advertise the # router's own per-VLAN IPv6 address; RouterOS DNS forwards to CoreDNS. - name: Configure IPv6 ND per-interface (pref64 + RDNSS) community.routeros.api_modify: path: ipv6 nd data: # advertise-dns must be explicitly enabled — RouterOS creates new ND # entries with advertise-dns=no, which suppresses the RDNSS option # entirely even when a static dns= list is configured. - interface: vlan2 advertise-dns: true pref64: 64:ff9b::/96 dns: 2001:470:61a3:9:ffff:ffff:ffff:ffff - interface: vlan5 advertise-dns: true pref64: 64:ff9b::/96 dns: 2001:470:61a3:a:ffff:ffff:ffff:ffff