# ── Site configuration ───────────────────────────────────────────────────────── hypervisors = { proxmox = { api_url = "https://192.168.0.240:8006/api2/json" node_name = "pve" storage = "local-lvm" } goose = { api_url = "https://192.168.0.241:8006/api2/json" node_name = "goose" storage = "local-lvm" } } ipam_endpoint = "https://ipam.example.net/api" network_subnets = { lan = "192.168.0.0/24" } ansible_user = "ansible" search_domain = "oswaldtheotter.lan" dns_nameservers = "1.1.1.1" technitium_host = "http://192.168.0.2:5380" # ── DNS (Technitium) ──────────────────────────────────────────────────────────── # Every declared node automatically gets an A record in the search_domain zone # (lan.oswaldtheotter.net). Define extra zones and manual records below. # Additional zones beyond the auto-managed search_domain zone. dns_zones = { # "internal.oswaldtheotter.net" = { type = "Primary" } # "10.168.192.in-addr.arpa" = { type = "Primary" } } # Manual records. In the search_domain zone, a record whose name matches an # auto-added host replaces that host's record instead of conflicting with it. dns_records = [ # { zone = "lan.oswaldtheotter.net", name = "router", type = "A", value = "192.168.0.1" }, # { zone = "lan.oswaldtheotter.net", name = "nas", type = "CNAME", value = "dev.lan.oswaldtheotter.net" }, # { zone = "lan.oswaldtheotter.net", name = "@", type = "MX", value = "mail.lan.oswaldtheotter.net", priority = 10 }, { zone = "oswaldtheotter.lan", name = "omada", type = "A", value = "192.168.0.110" }, { zone = "oswaldtheotter.lan", name = "portanas", type = "A", value = "192.168.0.4" }, { zone = "oswaldtheotter.lan", name = "proxmox", type = "A", value = "192.168.0.240" }, { zone = "oswaldtheotter.lan", name = "duck", type = "A", value = "192.168.0.241" }, { zone = "oswaldtheotter.lan", name = "goose", type = "A", value = "192.168.0.241" }, { zone = "oswaldtheotter.lan", name = "nas", type = "CNAME", value = "portanas.oswaldtheotter.lan" }, { zone = "oswaldtheotter.lan", name = "s3", type = "CNAME", value="portanas.oswaldtheotter.lan"}, { zone = "oswaldtheotter.lan", name = "hass", type = "A", value="192.168.0.70"}, { zone = "oswaldtheotter.lan", name = "homeassistant", type = "CNAME", value="hass.oswaldtheotter.lan"}, { zone = "oswaldtheotter.lan", name = "bookstack", type = "A", value="192.168.0.5"}, { zone = "oswaldtheotter.lan", name = "code", type = "A", value="192.168.0.5"}, ] # ── Reverse proxy (Caddy) ─────────────────────────────────────────────────────── # Managed on the caddy LXC (192.168.0.5). The admin API listens on loopback, so # reach it by tunneling SSH to the box as the ansible user. Clear caddy_host to # disable Caddy management entirely. caddy_host = "http://localhost:2019" caddy_ssh_host = "ansible@192.168.0.5:22" # From: ssh-keyscan 192.168.0.5 — must be refreshed if the LXC is rebuilt. # Must be the ECDSA key: the provider's (old) Go SSH client prefers # ecdsa-sha2-nistp256 during negotiation and pins the exact key it receives. caddy_ssh_host_key = "192.168.0.5 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBLjluBg9JCITeqG4NPad4VNTkAcZDY3y9FU9CP5BAuKIr3TDhTFYzuAdNnROCEhW1ddJI9ZFKI5y/3xqNTmkHbA=" # Each proxy serves plain HTTP on :80 by default; set protocol = "https" to # serve it on :443 instead. Note: .lan hostnames can't get public certificates, # so HTTPS sites use Caddy's internal CA — trust its root cert on your devices # to avoid browser warnings. caddy_proxies = { # dns = { # host = "dns.oswaldtheotter.lan" # upstreams = ["192.168.0.2:5380"] # } # secure-example = { # host = "secure.oswaldtheotter.lan" # upstreams = ["192.168.0.202:80"] # protocol = "https" # } bookstack = { host = "bookstack.oswaldtheotter.lan" upstreams = ["192.168.0.4:30214"] } code = { host = "code.oswaldtheotter.lan" upstreams = ["192.168.0.200:8080"] } } # ── Node definitions ─────────────────────────────────────────────────────────── nodes = { proxmox = { lxc = { "caddy" = { hostname = "caddy" vmid = 101 template = "local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst" unprivileged = true onboot = true tags = "" memory = 1024 swap = 0 disk_size = "8G" nic_name = "eth0" bridge = "vmbr0" ip = "192.168.0.5/24" nameserver = "192.168.0.2" gw = "192.168.0.1" } "audiopen" = { hostname = "audiopen" vmid = 801 template = "local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst" unprivileged = true onboot = true tags = "" memory = 512 swap = 0 disk_size = "8G" nic_name = "eth0" bridge = "vmbr0" ip = "192.168.0.202/24" gw = "192.168.0.1" } "remoteterm" = { hostname = "remoteterm" vmid = 117 template = "local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst" unprivileged = true onboot = false tags = "" memory = 2048 swap = 0 disk_size = "16G" nic_name = "eth0" bridge = "vmbr0" ip = "192.168.0.203/24" gw = "192.168.0.1" } "technitium" = { hostname = "technitium" vmid = 118 template = "local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst" unprivileged = true onboot = true tags = "" memory = 2048 swap = 0 disk_size = "8G" nic_name = "eth0" bridge = "vmbr0" ip = "192.168.0.2/24" gw = "192.168.0.1" } } machines = { } } goose = { lxc = { "dev" = { hostname = "dev" vmid = 200 template = "local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst" unprivileged = true onboot = true tags = "" memory = 4096 swap = 2048 disk_size = "32G" nic_name = "eth0" bridge = "vmbr0" ip = "192.168.0.200/24" nameserver = "192.168.0.2" gw = "192.168.0.1" } } machines = { "oswald-runner" = { hostname = "oswald-runner" vmid = 200 ip = "192.168.7.50" vlan = 7 template = "Debian13" full_clone = true onboot = true tags = "" agent = 1 memory = 4096 disk_size = "32" balloon = 1 cpu_type = "kvm64" cores = 4 sockets = 1 vcpus = 0 bios = "ovmf" machine = "q35" bridge = "vmbr0" } } } }