Two Corefile changes: - Add lumpiasty.xyz server block without dns64. Replaces the manual RouterOS static FWD entry (\"bypass nat64\") which returned NOERROR with empty answer instead of relaying NXDOMAIN. Combined with ndots:5 and pod search domains this made getaddrinfo stop at the search-suffixed candidate and fail with ENOTFOUND for valid names (kaneo -> authentik OAuth fetch failures). CoreDNS relays rcodes faithfully; internal zone keeps real AAAA for native IPv6. - Add allow_ipv4 to dns64 (previously uncommitted): without it only queries arriving over IPv6 are synthesized, but all clients reach CoreDNS via RouterOS over IPv4, so translate_all never applied. The RouterOS static FWD entry must be removed after deploying the new image - ansible already declares only the ts.net entry, so a playbook run handles it.
Ansible
Idempotent configuration management for the home-lab network devices.
Devices
| Host | Group | IP | Playbook |
|---|---|---|---|
| crs418 (MikroTik CRS418) | mikrotik |
192.168.255.10 | playbooks/routeros.yml |
| dlink (OpenWrt AP) | openwrt |
192.168.255.11 | playbooks/openwrt.yml |
Both devices are reachable on the MGMT network (192.168.255.0/24) once fully set up.
Dependencies
ansible-galaxy collection install -r requirements.yml
pip install librouteros hvac
Collections used:
community.routeros >= 3.16.0— MikroTik API modulescommunity.hashi_vault >= 7.1.0— OpenBao/Vault secret lookupcommunity.openwrt >= 1.0.0— OpenWrt UCI and shell modules
MikroTik (routeros)
Secrets are fetched at runtime from OpenBao. No credentials are stored in files.
export VAULT_TOKEN=... # or OPENBAO_TOKEN
ansible-playbook playbooks/routeros.yml
Secret layout expected in OpenBao (KVv2, mount secret):
| Path | Fields |
|---|---|
routeros_api |
username, password |
wan_pppoe |
username, password |
OpenWrt dlink AP
The dlink needs a one-time initialisation before it can be managed through MikroTik. There are two playbooks:
Step 1 — dlink-init.yml (once, PC directly connected)
Run this while your PC is plugged into one of the dlink LAN ports with the device still on its factory IP (192.168.1.1) and your SSH key has been added in web ui. MikroTik must not be in the picture yet.
What it does:
- Reconfigures switch0 so the WAN port becomes a VLAN trunk:
- untagged → VLAN 1 (MGMT, 192.168.255.0/24)
- tagged → VLAN 2 (LAN, 192.168.0.0/24)
- Adds
mgmtinterface: static 192.168.255.11/24, gateway 192.168.255.10 - Reconfigures
lanto a bridge on eth0.2 with no IP (AP mode) - Removes routed
wan/wan6interfaces - Commits and reloads network in the background
After the reload the device is no longer reachable at 192.168.1.1.
ansible-playbook playbooks/dlink-init.yml
Step 2 — connect dlink WAN port to MikroTik ether3
Plug the dlink WAN port into MikroTik ether3.
If the MikroTik config hasn't been applied yet, do it now:
export VAULT_TOKEN=...
ansible-playbook playbooks/routeros.yml
MikroTik ether3 is configured to send MGMT traffic untagged and VLAN 2 (LAN) tagged, which matches what dlink expects on its WAN port.
Step 3 — openwrt.yml (ongoing, via MikroTik)
All subsequent runs connect to 192.168.255.11 through MikroTik:
ansible-playbook playbooks/openwrt.yml
This is the idempotent main playbook. Run it any time to converge configuration.