flatcar resolvers

This commit is contained in:
Graham McIntire 2026-06-22 15:52:51 -05:00
parent d6cf15165a
commit c85be1d56c
No known key found for this signature in database
GPG key ID: F4ABF488E6029E59
16 changed files with 2000 additions and 527 deletions

View file

@ -13,22 +13,30 @@ This is a multi-environment infrastructure-as-code repository managing:
### Proxmox VM Provisioning
BIND9 and future infrastructure VMs are provisioned using the main Ansible playbook:
Infrastructure VMs are provisioned using OpenTofu and configured via Butane/Ignition (Flatcar) or Ansible (traditional Linux):
```bash
cd ansible
source .envrc # Load Proxmox credentials from .envrc
# Infrastructure VMs are managed by OpenTofu (tofu/proxmox.tf)
cd tofu && tofu plan && tofu apply
# Provision and configure BIND9 nameserver at 204.110.191.222
# Post-provision configuration via Ansible
cd ansible && source .envrc
# Configure BIND9 nameserver at 204.110.191.222
ansible-playbook playbook.yml --tags provision,bind9
```
# VM settings (aligned with terraform/variables.tf):
# - Node: vm2-380 (var.proxmox_host)
# - Template: debian-13-cloudinit (VMID 9000)
# - Storage: local-lvm (for BIND9 and general infrastructure VMs)
# - Network: vmbr0
#
# Note: Talos nodes use a different template (Talos Linux) and do not use Longhorn
**Flatcar Linux VMs** (managed by `lucidsolns/flatcar-vm/proxmox` module):
- No manual template needed — module downloads the Flatcar image automatically
- VM definition: `tofu/proxmox.tf` (module `flatcar_resolver`, VMID 110)
- Configuration: `tofu/flatcar-resolver.bu` (Butane → Ignition)
- Config files: `tofu/unbound.conf` (rendered from group_vars), `tofu/blocklist.rpz`
- Static IP: 10.0.0.30/24, 8GB RAM, 2 cores, UEFI boot
- Default user: `core` (passwordless sudo)
- Unbound runs as a Docker container (`mvance/unbound`) with config + blocklist mounted
- DoH endpoint on 127.0.0.1:8080 for future Caddy proxy
- To deploy: update `flatcar-resolver.bu` or config files, then `tofu apply`
- Proxmox storage `local` must have `snippets` and `import` content types enabled (`/etc/pve/storage.cfg`)
```
### Ansible Operations

View file

@ -6,6 +6,8 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
This is an Ansible infrastructure management repository that manages a mixed environment including network services, monitoring, VPN infrastructure, and web applications. The codebase supports multiple operating systems (Debian, Ubuntu, AlmaLinux) and uses a role-based architecture for modularity.
Note: Flatcar Container Linux VMs are provisioned by OpenTofu and configured via Butane/Ignition — they are NOT managed by Ansible.
## Common Commands
### Bootstrap New Hosts

View file

@ -1,48 +0,0 @@
#!/usr/bin/env bash
# Build a NixOS qcow2 image for Proxmox template and upload to Proxmox host.
# Run on a Linux host with nix installed.
set -euo pipefail
PROXMOX_HOST="10.0.0.2"
TEMPLATE_VMID="9010"
TEMPLATE_NAME="nixos-cloud-init"
STORAGE="local-lvm"
NIXOS_CONFIG="./nixos-template-config.nix"
echo "==> Building NixOS qcow2 image..."
NIX_PATH="nixpkgs=https://flakehub.com/f/DeterminateSystems/nixpkgs-weekly/*.tar.gz"
IMAGE=$(nix-build '<nixpkgs/nixos>' \
--argstr system x86_64-linux \
-A config.system.build.qcow2 \
--arg configuration "$(readlink -f "$NIXOS_CONFIG")" \
2>&1 | tail -1)
echo "==> Image built: $IMAGE"
QCOW2_PATH="$IMAGE/nixos.qcow2"
if [ ! -f "$QCOW2_PATH" ]; then
echo "ERROR: qcow2 not found at $QCOW2_PATH"
ls -la "$IMAGE/" 2>/dev/null || echo "No files in image dir"
exit 1
fi
echo "==> Uploading to Proxmox..."
scp "$QCOW2_PATH" "root@${PROXMOX_HOST}:/tmp/nixos-template.qcow2"
echo "==> Importing as VM disk..."
ssh "root@${PROXMOX_HOST}" bash -s << 'EOF'
set -e
qm destroy 9010 --purge 2>/dev/null || true
qm create 9010 --name nixos-cloud-init --memory 2048 --cores 2 \
--net0 virtio,bridge=vmbr0 --scsihw virtio-scsi-pci \
--ide2 local-lvm:cloudinit --boot c --bootdisk scsi0 \
--serial0 socket --vga serial0
qm importdisk 9010 /tmp/nixos-template.qcow2 local-lvm
qm set 9010 --scsi0 "local-lvm:vm-9010-disk-0"
qm template 9010
rm /tmp/nixos-template.qcow2
echo "Template VM 9010 created successfully."
qm config 9010
EOF
echo "==> Done. Template VMID 9010 is ready."

View file

@ -1,32 +0,0 @@
# NixOS template configuration for Proxmox cloud-init VMs.
# Built into a qcow2 image and imported as a Proxmox template.
{ config, pkgs, lib, ... }:
{
# Boot
boot.loader.grub.device = "/dev/sda";
boot.loader.timeout = 0;
# Network — cloud-init will configure (override proxmox-image default)
networking.useDHCP = lib.mkForce true;
networking.hostName = "nixos";
# SSH for Ansible
services.openssh.enable = true;
services.openssh.settings.PermitRootLogin = lib.mkForce "prohibit-password";
# QEMU guest agent for Proxmox integration
services.qemuGuest.enable = true;
# cloud-init — consumes Proxmox config drive (hostname, SSH keys, network)
services.cloud-init.enable = true;
services.cloud-init.network.enable = true;
# Python for Ansible management
environment.systemPackages = [ pkgs.python3 ];
# Minimal system
documentation.enable = false;
system.stateVersion = "26.05";
}

View file

@ -1,4 +0,0 @@
---
ansible_user: root
ansible_python_interpreter: /run/current-system/sw/bin/python3
ansible_ssh_common_args: '-o StrictHostKeyChecking=accept-new'

View file

@ -65,6 +65,3 @@ db.w5isp.com
us.manero.org ansible_host=manero-us
ca.manero.org ansible_host=manero-ca
[nixos_resolvers]
nixos-resolver1 ansible_host=nixos-resolver1

View file

@ -202,248 +202,6 @@
- role: ns
tags: ns
- name: Build and upload NixOS template to Proxmox
hosts: localhost
gather_facts: false
tags:
- template
- never
vars:
proxmox_node: "{{ lookup('env', 'PROXMOX_NODE') | default('vm2-380', true) }}"
proxmox_api_host: 10.0.0.2
proxmox_api_user: "{{ lookup('env', 'PROXMOX_API_USER') | default('root@pam', true) }}"
proxmox_api_password: "{{ lookup('env', 'PROXMOX_API_PASSWORD') }}"
nixos_template_vmid: 9010
build_host: ci
tasks:
- name: Upload NixOS config to build host
ansible.builtin.copy:
src: files/nixos-template-config.nix
dest: /tmp/nixos-template-config.nix
delegate_to: "{{ build_host }}"
- name: Build NixOS proxmox image
ansible.builtin.shell: >
nixos-generate -f proxmox
-o /tmp/nixos-template.vma.zst
-c /tmp/nixos-template-config.nix
args:
chdir: /tmp
environment:
PATH: "/run/current-system/sw/bin:{{ ansible_env.PATH }}"
delegate_to: "{{ build_host }}"
register: _nixos_build
- name: Find built VMA file in nix store
ansible.builtin.shell: >
nix-shell -p nixos-generators --run
"nixos-generate -f proxmox -o /tmp/nixos-template.vma.zst -c /tmp/nixos-template-config.nix" 2>&1
| grep '^/' | tail -1
args:
chdir: /tmp
delegate_to: "{{ build_host }}"
register: _vma_path
changed_when: false
- name: Copy VMA from build host to Proxmox
ansible.builtin.shell: >
scp {{ build_host }}:'{{ _vma_path.stdout }}' /tmp/nixos-template.vma.zst &&
scp /tmp/nixos-template.vma.zst root@{{ proxmox_api_host }}:/tmp/nixos-template.vma.zst
- name: Destroy existing template VM
community.proxmox.proxmox_kvm:
node: "{{ proxmox_node }}"
vmid: "{{ nixos_template_vmid }}"
api_user: "{{ proxmox_api_user }}"
api_password: "{{ proxmox_api_password }}"
api_host: "{{ proxmox_api_host }}"
validate_certs: false
state: absent
force: true
- name: Create VM and import disk on Proxmox
ansible.builtin.shell: >
set -e;
vma extract /tmp/nixos-template.vma.zst /tmp/nixos-vma;
qm create {{ nixos_template_vmid }} --name nixos-cloud-init
--memory 2048 --cores 2 --net0 virtio,bridge=vmbr0
--scsihw virtio-scsi-pci --ide2 local-lvm:cloudinit
--boot c --bootdisk scsi0 --serial0 socket --vga serial0;
qm importdisk {{ nixos_template_vmid }}
/tmp/nixos-vma/disk-drive-virtio0.raw local-lvm;
qm set {{ nixos_template_vmid }}
--scsi0 "local-lvm:vm-{{ nixos_template_vmid }}-disk-0";
qm template {{ nixos_template_vmid }};
rm -rf /tmp/nixos-vma /tmp/nixos-template.vma.zst
delegate_to: "{{ proxmox_node }}"
- name: Provision NixOS VM on Proxmox
hosts: localhost
gather_facts: false
tags:
- nixos
- provision
- never
vars:
proxmox_node: "{{ lookup('env', 'PROXMOX_NODE') | default('vm2-380', true) }}"
proxmox_api_host: 10.0.0.2
proxmox_api_user: "{{ lookup('env', 'PROXMOX_API_USER') | default('root@pam', true) }}"
proxmox_api_password: "{{ lookup('env', 'PROXMOX_API_PASSWORD') }}"
proxmox_storage: local-lvm
proxmox_template_vmid: 9010
proxmox_template_name: nixos-cloud-init
vm_name: nixos-resolver
vm_vmid: 110
vm_cores: 2
vm_memory: 4096
vm_disk_size: 64
vm_ssh_keys: |
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHLyVSEEAEbGZZqwPwEup0XrlTpu3x3iF9ExvvQPA4xN
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOzrDMNn3nINGdIogzRxY05fkn05LSYi98BGW1Bz5yXD
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIER/8suIKcrT3a/NZHjvOpRosPC5uX4kcznIJHt/98qj
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEEKtgXwoW8HZGqC+KJok9iNpI/lK4glvoryL4Ng/AL+
tasks:
- name: Clone NixOS template
community.proxmox.proxmox_kvm:
node: "{{ proxmox_node }}"
vmid: "{{ proxmox_template_vmid }}"
clone: "{{ proxmox_template_name }}"
newid: "{{ vm_vmid }}"
name: "{{ vm_name }}"
api_user: "{{ proxmox_api_user }}"
api_password: "{{ proxmox_api_password }}"
api_host: "{{ proxmox_api_host }}"
validate_certs: false
storage: "{{ proxmox_storage }}"
timeout: 90
full: true
agent: true
- name: Configure VM resources
community.proxmox.proxmox_kvm:
node: "{{ proxmox_node }}"
vmid: "{{ vm_vmid }}"
name: "{{ vm_name }}"
api_user: "{{ proxmox_api_user }}"
api_password: "{{ proxmox_api_password }}"
api_host: "{{ proxmox_api_host }}"
validate_certs: false
cores: "{{ vm_cores }}"
memory: "{{ vm_memory }}"
update: true
- name: Resize disk
community.proxmox.proxmox_disk:
vmid: "{{ vm_vmid }}"
api_user: "{{ proxmox_api_user }}"
api_password: "{{ proxmox_api_password }}"
api_host: "{{ proxmox_api_host }}"
validate_certs: false
disk: scsi0
size: "{{ vm_disk_size }}G"
state: resized
register: _disk_resize
failed_when:
- _disk_resize.failed
- '"shrinking disks is not supported" not in (_disk_resize.msg | default(""))'
- name: Configure cloud-init
community.proxmox.proxmox_kvm:
node: "{{ proxmox_node }}"
vmid: "{{ vm_vmid }}"
name: "{{ vm_name }}"
api_user: "{{ proxmox_api_user }}"
api_password: "{{ proxmox_api_password }}"
api_host: "{{ proxmox_api_host }}"
validate_certs: false
ciuser: root
sshkeys: "{{ vm_ssh_keys }}"
ipconfig:
ipconfig0: "ip=dhcp"
nameservers:
- 1.1.1.1
onboot: true
update: true
- name: Start VM
community.proxmox.proxmox_kvm:
node: "{{ proxmox_node }}"
vmid: "{{ vm_vmid }}"
name: "{{ vm_name }}"
api_user: "{{ proxmox_api_user }}"
api_password: "{{ proxmox_api_password }}"
api_host: "{{ proxmox_api_host }}"
validate_certs: false
state: started
- name: Wait for VM IP via QEMU agent
ansible.builtin.shell: >
python3 -c "
import urllib3, json, time
urllib3.disable_warnings()
from proxmoxer import ProxmoxAPI
proxmox = ProxmoxAPI('{{ proxmox_api_host }}',
user='{{ proxmox_api_user }}', password='{{ proxmox_api_password }}',
verify_ssl=False)
for _ in range(48):
try:
nets = proxmox.nodes('{{ proxmox_node }}').qemu('{{ vm_vmid }}').agent('network-get-interfaces').get()
for iface in nets.get('result', []):
for addr in iface.get('ip-addresses', []):
if addr.get('ip-address-type') == 'ipv4' and addr['ip-address'] != '127.0.0.1':
print(addr['ip-address'])
exit(0)
time.sleep(5)
except Exception:
time.sleep(5)
exit(1)
"
register: _agent_ip
changed_when: false
retries: 1
delay: 0
- name: Add VM to in-memory inventory
ansible.builtin.add_host:
name: "{{ vm_name }}"
ansible_host: "{{ _agent_ip.stdout | trim }}"
groups: nixos_resolvers
- name: Configure NixOS Unbound resolver
hosts: nixos_resolvers
become: true
gather_facts: true
tags:
- nixos
- unbound
- never
tasks:
- name: Load resolver group variables
ansible.builtin.include_vars:
file: group_vars/resolvers/main.yml
- name: Deploy NixOS configuration with Unbound
ansible.builtin.template:
src: roles/resolvers/templates/nixos-unbound.nix.j2
dest: /etc/nixos/unbound.nix
owner: root
group: root
mode: '0644'
register: _nixos_config
- name: Import unbound module in configuration.nix
ansible.builtin.lineinfile:
path: /etc/nixos/configuration.nix
line: "./unbound.nix"
regexp: '^./unbound\.nix'
insertafter: '^\{ config,'
state: present
register: _nixos_import
- name: Rebuild NixOS
ansible.builtin.command: nixos-rebuild switch
when: _nixos_config.changed or _nixos_import.changed
- name: Apply general configuration to all nodes
hosts: all
become: true

View file

@ -1,114 +0,0 @@
# Managed by Ansible (roles/resolvers/templates/nixos-unbound.nix.j2)
# Settings derived from unbound.conf.j2 — same configuration as resolver1.
{ config, pkgs, lib, ... }:
let
accessControl = [
"0.0.0.0/0 refuse"
"::0/0 refuse"
{%- for netblock in resolver_allowed_netblocks %}
"{{ netblock }} allow"
{%- endfor %}
];
blocklistZone = pkgs.writeText "blocklist.rpz" ''
$TTL 3600
$ORIGIN blocklist.rpz.
@ IN SOA localhost. root.localhost. 1 3600 600 86400 3600
@ IN NS localhost.
{%- for domain in resolver_blocked_domains | default([]) %}
{{ domain }} CNAME .
*.{{ domain }} CNAME .
{%- endfor %}
'';
in
{
services.unbound = {
enable = true;
settings = {
server = {
interface = [ "0.0.0.0" "::0" ];
port = 53;
# DoH endpoint via loopback (Caddy terminates TLS upstream)
interface-auto = false;
https-port = 8080;
http-endpoint = "/dns-query";
http-notls-downstream = true;
access-control = accessControl;
# Performance tuning
num-threads = 4;
msg-cache-size = "512m";
rrset-cache-size = "512m";
key-cache-size = "512m";
msg-cache-slabs = 8;
rrset-cache-slabs = 8;
infra-cache-slabs = 8;
key-cache-slabs = 8;
num-queries-per-thread = 1024;
outgoing-port-permit = "32768-60999";
outgoing-num-tcp = 100;
incoming-num-tcp = 600;
# Prefetch and serve-expired
prefetch = true;
prefetch-key = true;
serve-expired = true;
serve-expired-ttl = 86400;
serve-expired-client-timeout = 1800;
# Socket tuning
so-reuseport = true;
so-rcvbuf = "4m";
ip-transparent = true;
edns-buffer-size = 1232;
edns-tcp-keepalive = true;
# Hardening
harden-short-bufsize = true;
harden-large-queries = true;
harden-glue = true;
harden-dnssec-stripped = true;
harden-below-nxdomain = true;
aggressive-nsec = true;
qname-minimisation = true;
# Logging
log-time-ascii = true;
# Statistics
extended-statistics = true;
shm-enable = false;
};
remote-control = {
control-enable = true;
control-interface = "127.0.0.1";
control-port = 8953;
control-use-cert = false;
};
rpz = {
name = "blocklist.rpz";
zonefile = "${blocklistZone}";
rpz-action-override = "nxdomain";
rpz-log = true;
rpz-log-name = "blocklist";
};
};
# DNSSEC root trust anchor
enableRootTrustAnchor = true;
};
# Python for Ansible management (appended, doesn't clobber other packages)
environment.systemPackages = lib.mkAfter [ pkgs.python3 ];
# Open DNS ports
networking.firewall.allowedTCPPorts = [ 53 ];
networking.firewall.allowedUDPPorts = [ 53 ];
}

137
tofu/.terraform.lock.hcl generated
View file

@ -3,7 +3,7 @@
provider "registry.opentofu.org/bpg/proxmox" {
version = "0.110.0"
constraints = "~> 0.73"
constraints = ">= 0.100.0"
hashes = [
"h1:CmD2DUi0wm0QrmOo0+y9AWo0IHVnbBusJyXZUfJygog=",
"h1:GyRZ1NI0nZD0MRsL2fwzkM4js4wZMPrSS54culEoVL8=",
@ -36,29 +36,130 @@ provider "registry.opentofu.org/bpg/proxmox" {
}
provider "registry.opentofu.org/cloudflare/cloudflare" {
version = "5.19.1"
version = "5.21.0"
constraints = "~> 5.0"
hashes = [
"h1:HkKPMZ/n+QiExkRUSLjGMTGnuIaph+k932LiTp7CKZM=",
"h1:LicdZu3hugYpWuCAprg2EslbVP0zANnV9n9/2KiOnYc=",
"h1:VvnqJUTXlbKrB/6X2K9dc7lE3CQj3KX055gr+bMyXsg=",
"h1:XYVRvCG+auhkY1NnSe6pK7ClqKW5GX8BgUnMQwfC7mQ=",
"h1:Xf1PHfUfK690caJYZvoudKKBppfleJ6RcqsEQWqKVCw=",
"h1:i6pbudcLi1X2MVeN9IV3bDeiGWnWhn+v9dMrMzAN+l8=",
"h1:mopYISyLkUVUwMjJbuPenxIUVDrna1/7ACB1hfMfciU=",
"h1:xfoTAyKkR12F8nuVC96DwBA2Fva38o5BnYHLXZzmDP4=",
"zh:0651618000db705564dab5a25322b9d76ea54b7dd78931ed3565497b559babeb",
"zh:1a7847e9479fb6d21a65ef933ffae1416b1e4b44ca940c0d6c50fc4248cc4a0d",
"zh:5597cee5854131045eb9f201ae3a70b59c51955d31a647d9616863c746d902cb",
"zh:580786830d93e35b957754fd4c62d4681a3b19abc28b757e41acba26455663b1",
"zh:83c4bdfb0e74fd50e56fff3c461d76c1c1ec61af3f679e4de1aa70b5ed05a09f",
"zh:abb4d1052cee61d80f9cb51e5421e3c118312403afb7104b98bd7e310ac736ee",
"zh:b0aeeb3d66ea4d719989875e778c477065ba941e3a76e9a8caacc3be08208dd9",
"zh:e43b4b2dfcec1ce2115f5a5c86042d432deb49bee8eae103eb56d97ea02e2e3b",
"h1:+7djyAe6nvtc4TycI5Udq7a/Aqr8zenKz9pSTCoLJ0U=",
"h1:77Q23JFkPXtq6d9nil44e3VZfJEWLQ4Z8gtRlddHUaM=",
"h1:GHS9VFEa0rXjux9Cipqy2QGEmQ0bst6Xqd5WUUJsOwI=",
"h1:TJQJrskWa1FJ8gk6BAhj4X6fa5TFqI255T6Y6ZKrFkU=",
"h1:iZFpxcWJD+sJ+OSCcXEbqj3KEf8F404IVokpoajkltk=",
"h1:m0J0Nylz7e/fj8tLeSBFLfyzDcXtqh0yPi8eAsjt0Y0=",
"h1:oJGD4xrT2Fs3sIxfQSfrR++nL2S5BbHZrBKT1vKC5OQ=",
"h1:sea8uqcGOPqVVWWXltTknp2iJ8oi62G4MVKuWvgt/8U=",
"zh:2d3dc17f27dcf308f52bdede3b7bb00e6cda6c1a9fbdafd1bfe4a915e75fdc44",
"zh:413e3569ad0cc89f8ac425d8a197d9e892ff356ac24dedde386820cf5880a48e",
"zh:59f262b9af9a8845afeb2734a6bd83b260aa2c521e5c318850745823ef62b38d",
"zh:7d42963a47ff6dda8aada0cb73a26eb6807c7ff6bb4419cb91b32ce2412c8362",
"zh:89cad3906c9affa0f2947607d316d70c38541c399d0519ebee1f1ccc8aaf5675",
"zh:d5c7ff6c39d895e5746fed74ecc3f284c91c8c1f502da2e93f5c581f41f87f25",
"zh:dc425b5f40e94165e563dc55bd6e49cedfe879a03e668168610459ef071b1a87",
"zh:f0665907dd24ae93f9511216052d653bba0823c933e888cf02a4abf95f73dfe0",
"zh:f809ab383cca0a5f83072981c64208cbd7fa67e986a86ee02dd2c82333221e32",
]
}
provider "registry.opentofu.org/hashicorp/http" {
version = "3.6.0"
constraints = ">= 3.5.0"
hashes = [
"h1:0n4RBz9zNw6TTddh5+x7E8L2+qzPXNwKhK4uoZ/DUwE=",
"h1:22Ob7lpzMBSqdrCvoFN5EgmhGPHPBovV/9qo0c/Cd+A=",
"h1:2IRBvmWOYrq/ooaYYn2i86jZb7iIUvlg0KlmOMfDHoQ=",
"h1:5mucXikk4OcW3un3u94QnMx4AB4Wfih+sXeMd5QxSNk=",
"h1:5oU7Zm+2gAVGmxqtJ9E8uTudUkYy/DEn/y3IWphdv4k=",
"h1:5w0R4b1/VSzpqQF1tXXPr/qmaQLPVRXamOmPKWFcTk4=",
"h1:AEVeJr8xGmwad+JUUQ833C3x5d4W+W2szF5DfwxYppw=",
"h1:CPHJ+0zQbS/cX1m55Y90jIOgf1jV3ocUUnqsXAh+9Eg=",
"h1:JPewnGDOJudNer5+ghqwXoaJkfot3QRq9uiEYvo+JHU=",
"h1:QzbluV2vQLxsJYxjpziQCmPndIoJ/UGS4/UHH/GpwUM=",
"h1:TjUNbUdqweRBq/ycQ4ixpNkx5qaYwpXEOn9QCpqNZP8=",
"h1:XNbcODP60ajj21N/OO7af8bBg1ltIsYkq9egn7BYbiY=",
"h1:tgrbgmX7WYQz9G9ncgu7TkpVB+RlLjJA/Rvp9KPlZH8=",
"h1:vLxthX/ZWsOZ+aHKbAMqmNKqD0K5f4nJ8ppy0Ioyup0=",
"h1:wZOdGBAZkY8OKEPjKz82j1HloAKOmmvtjWyTxM+I110=",
"zh:0f719fa5426bc883e9fa6abf7f6498e48025edafbc29015e2f5c028f1cca3b9d",
"zh:1b4d7dafefd6c61764b2f9ed6943ceb9a200dee3590d18747e3a5f6b20ce85e0",
"zh:1d23a712984866d29f7b07028a4e99c783c71f1a5dddf08bc3d4e7da9d91a1fa",
"zh:257d23d58c3bb024b6bc8eb88736eaf912e934ad47c639d0c3c742bddda849a1",
"zh:479860e1a5468f5e04013b9364c9496d7ed0804bf9a1acd8e07558d57609993d",
"zh:4cb5e681bf599b411b27c4a2c4066a5fb2ed79aaa3a1a3cb5a30002fec062ce9",
"zh:4fb35c3f643dae9f3670d719397a415f815a0b95f8ed7bd8a72f27a94ba78092",
"zh:59ba40825ab38db5b4a0989a2db0df35cc15d8984f898176011ba352f27d77b7",
"zh:61fc1252eb88088638f4c69ea4e2171cde2e5089fa632ac1e943b13787348f73",
"zh:7c5d6dd5f7cbc460e95d368be35c29b4e0402069b8912dbd5d1cd7fa9acef216",
"zh:7f76d756240d4284642f359ad470226e5378670239aadc366ef54d9d914d4d2e",
"zh:8133ad0814098177e0d067c816ccf1bf48bbadacd18f6f2c808c90447505723b",
"zh:c93be06269bb728f1968f8c50506de56c887017ac1d6e4be1f925651d8437eb6",
"zh:ef47b78a10a82e6cf53344a6a85a94041c28286c10a70541c564d762f1cfede0",
"zh:f5796a53a74999135bd9087aff50fddda59129d09b2f9b1902ff8c0c1e047e48",
]
}
provider "registry.opentofu.org/hashicorp/null" {
version = "3.3.0"
constraints = ">= 3.2.4"
hashes = [
"h1:0r7+t8CqzjfBgHgEiJGBCw+McEUdRXliMdF+Hk29d8o=",
"h1:EvvCOc4FJY3NitSm6BpzCcUPU53LayVCB/tPOxYmy7U=",
"h1:IDVnZXNCh0u4LfeSazc9z1v/kNz+92Eej7ePWV6SbyE=",
"h1:Iw2c0n9/4fS92N5WnJ3CCSwSUXZO953oHp9gj3pWCaM=",
"h1:JofS1og3hPN0ANjH+gNjxrJyyk6znodpC/F0qhp4eEk=",
"h1:QIBhsJ4+5+t0vFEgJwtezNLT31tsptFHOEyGAAhLR1o=",
"h1:RjjoL9qRPwNTwLdtJsYUaFvunbPM2/oujf2DcUcitOE=",
"h1:SSirA+z2VWTs1s+TCAx8vVKg9jh6cRjxqc8LYi2iQTI=",
"h1:U2XZc7hxcpcWp/C2S9LtuGUimhMOD2UT5xAEJJQQQaU=",
"h1:bPG+xE5UonkJv3y/Yn9Q7OfbP2qHU/QKiS31nwfe7S0=",
"h1:eODLdk/pARc4yxChAFtwseVmBr+r5fF9yGOvUhwGEyM=",
"h1:iFj1oM5ZPENspsPqK1kcvZzyP95jJE/CM0rlu0MfIss=",
"h1:mdu+qpyVmjDDLMrcL1JFy+cSyF58I3TFJwB5NssCZ58=",
"h1:tJmep6aoBeDH77XsYU65HAbi0RAjxtsmbCOXmnqT13U=",
"h1:tdMTn1evBLd6KCeLqWdQXCpF07hBu3n5rY6N3rXw3Rc=",
"zh:083dcc0bec53f8abfa3f2aa2ce9d732a9675338fd60ae7d61162e25db7cb08bf",
"zh:19f7456b5a2ad16595860974714bfdb25b87bc16356ea9d5c7453892aaa27864",
"zh:222c0ed1fed4e4c677ebe626104dbfdba66763e264de0d9c27c58ce60104ee69",
"zh:271711d6caa7dd5a4e9b79fe8c679fab61a840bcf80040a0f5ebb425d1b27d97",
"zh:5adcf35f30baaea13f80c2a2c774deb9369892719493049687e23476c9dff40f",
"zh:5bcfd19df16e73d7f0ad75bd09e2b3b86cf6700d09822d585d68304b71de1d97",
"zh:604edecf263e38674decb35bb4e0e048fdc951f26fa103c33065ff9728f0313b",
"zh:782acbfb4fa4807e273e588fe45b4aaea9dd0fd1136f76ec3200f6f4db3af8d6",
"zh:84411a596d528fe67294e5c1cfd0c2036b08802497bcc4215ce518924f3c9a4a",
"zh:85e79eecf3f5348975cffec3016b0eba3baf605646102d4348796ccd2df2e5f6",
"zh:95669535ca17aeefef307ebfd59ce6930953173baae5637e8cbbf0297ec7ad58",
"zh:d04d9b177747bfd66b4a45b5d911a2a7822aa8451f5e35621971fb7a4206b530",
"zh:e6d9c924475283e90833450a14a732f4deb6d9bb131db8f86ab856e894270836",
"zh:ebcab0c8a1334c86ed7cfa53f571a17ad6d27e9901f27a8854ea622a74b54bb6",
"zh:ef9c757bb2c83d2103811a3d86b6ec5be06b0ffc337b84db1582d023bce7cdcd",
]
}
provider "registry.opentofu.org/keisukeyamashita/butane" {
version = "0.1.4"
constraints = ">= 0.1.4"
hashes = [
"h1:3OeT9ayfTkI+pAGfBezNBcgANw16akfQWLF9BDpn5Jo=",
"h1:4oH/JLPHRzyEttGbFZ1UJAOGXLz0JOt/EdqZdzG63f0=",
"h1:63e3IT3wlge6KGl0sOghwNZt/BgNb3e9I4oHTmkpd8Q=",
"h1:7Klrf52dRn0fzGj3k9G5lTYvmOHsZ0EZeieI/SlQ2Uw=",
"h1:NCBrdGKtux44ilMvqPeK5K+gdPaz0zkLr+ZIYSMF1IA=",
"h1:ZGu2r4cNo3n+VNakwzpRRR6MiS6WtFMzJ1g2w/h1YOA=",
"h1:kXuJMtzhK+Ty8VfjOW9pMw4AnUn22uddA76NRgR5Cro=",
"h1:pT5MIFJGc8BNGOr2fyPMldlSqxvPPBQaljw1h3AqWNw=",
"h1:vrQItrLZKiRnkoe+w7jsRlNNh6BnNzWj3gNyQWVdfJc=",
"h1:w8PqNRqGCmhMhvS1nGC/6a/qjFS50EhbT56pbJVtxSU=",
"zh:1200ab28af1c883f19e2bf06fd9223a6b7363d92b968bd01b090775738362e12",
"zh:477cd45f1ad76ed96499ce54cecb56fa0ca8c6ce066c64f3a5f4c9ded1365248",
"zh:49e02a35caab94fd7c3344541e2880ea87b3381e39ea1206ef927e4789bb7854",
"zh:4ae5c00b72a629ded0f2674a4d8c121810febb577764a9b4673071ee13a0d255",
"zh:60e6e2e1ee514649bfae02acd431e70cdd007c80df1f4d1a2893e9cbe9066480",
"zh:73790134582375ebfc267f728518aae9da88fba3d99c72c452414907d550ceb3",
"zh:840f47f3bc17633b1817eaa4f2718828ea7a8f6c0d6e95cd6d3b301182c8cb83",
"zh:b3155fe813d31d988e65da8e4d7e820ab51eae5547acab473449ded4c6c43647",
"zh:c333ad73a5f7afcbf7c66fa5d0af04bf15a6cd025b55c59ac828f0ffdad9b0e4",
"zh:fb803155799e7f466bb8eeacb16f45844cefe69a17237c14bee96eaff5afa8ac",
]
}
provider "registry.opentofu.org/marcfrederick/porkbun" {
version = "1.3.3"
constraints = "~> 1.3"

27
tofu/blocklist.rpz Normal file
View file

@ -0,0 +1,27 @@
; Managed by Ansible (roles/resolvers) — do not edit by hand.
; Source of truth: resolver_blocked_domains in group_vars/resolvers/main.yml
;
; Response Policy Zone. Each listed name and its subdomains resolve to
; NXDOMAIN (forced by rpz-action-override in unbound.conf), and matches are
; logged to syslog under rpz-log-name "blocklist". Names are relative to the
; $ORIGIN below, per RPZ convention (the zone suffix is the policy trigger).
$TTL 3600
$ORIGIN blocklist.rpz.
@ IN SOA localhost. root.localhost. 1 3600 600 86400 3600
@ IN NS localhost.
proxyjs.brdtnet.com CNAME .
*.proxyjs.brdtnet.com CNAME .
proxyjs.luminatinet.com CNAME .
*.proxyjs.luminatinet.com CNAME .
proxyjs.bright-sdk.com CNAME .
*.proxyjs.bright-sdk.com CNAME .
clientsdk.bright-sdk.com CNAME .
*.clientsdk.bright-sdk.com CNAME .
clientsdk.brdtnet.com CNAME .
*.clientsdk.brdtnet.com CNAME .

View file

@ -511,9 +511,9 @@ resource "cloudflare_zone_setting" "gridmap_org_security_header" {
# =============================================================================
resource "cloudflare_bot_management" "zones" {
for_each = cloudflare_zone.zones
for_each = { for k, v in cloudflare_zone.zones : k => v.id }
zone_id = each.value.id
zone_id = each.value
is_robots_txt_managed = false
}

195
tofu/flatcar-resolver.bu Normal file
View file

@ -0,0 +1,195 @@
variant: flatcar
version: 1.1.0
passwd:
users:
- name: core
ssh_authorized_keys:
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHLyVSEEAEbGZZqwPwEup0XrlTpu3x3iF9ExvvQPA4xN
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOzrDMNn3nINGdIogzRxY05fkn05LSYi98BGW1Bz5yXD
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIER/8suIKcrT3a/NZHjvOpRosPC5uX4kcznIJHt/98qj
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEEKtgXwoW8HZGqC+KJok9iNpI/lK4glvoryL4Ng/AL+
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFghGMnDdkfNC6JPEhMxrKhYDmNcXjHXp/y/mf3uLtzb
storage:
files:
- path: /etc/hostname
mode: 0644
overwrite: true
contents:
inline: flatcar-resolver1
- path: /etc/systemd/network/00-eth0.network
mode: 0644
contents:
inline: |
[Match]
Name=eth0
[Network]
Address=204.110.191.240/26
Gateway=204.110.191.254
DNS=9.9.9.9
DNS=1.1.1.1
- path: /etc/unbound/unbound.conf
mode: 0644
contents:
local: unbound.conf
- path: /etc/unbound/blocklist.rpz
mode: 0644
contents:
local: blocklist.rpz
- path: /etc/caddy/Caddyfile
mode: 0644
contents:
inline: |
{
admin off
persist_config off
}
resolver1.vntx.net {
@allowed remote_ip 127.0.0.0/8 204.110.188.0/22 10.0.0.0/8 172.1.0.0/15 100.64.0.0/10 192.168.0.0/16 ::1 2606:1c80::/32
handle /dns-query {
handle @allowed {
reverse_proxy 127.0.0.1:8080 {
transport http {
versions h2c 2
}
}
}
respond "Forbidden" 403
}
handle {
respond "DNS-over-HTTPS endpoint: /dns-query" 200
}
log {
output file /var/log/caddy/resolver1.log
format json
}
}
- path: /etc/telegraf/telegraf.conf
mode: 0644
contents:
inline: |
[agent]
interval = "30s"
[[inputs.exec]]
commands = ["/etc/telegraf/unbound-stats.sh"]
data_format = "influx"
timeout = "10s"
[[outputs.prometheus_client]]
listen = ":9273"
metric_version = 2
path = "/metrics"
expiration_interval = "60s"
- path: /etc/telegraf/unbound-stats.sh
mode: 0755
contents:
inline: |
#!/bin/sh
OUT=$(/usr/bin/docker exec unbound /opt/unbound/sbin/unbound-control stats_noreset 2>/dev/null)
[ $? -ne 0 ] && exit 1
echo "$OUT" | while IFS="=" read -r k v; do
[ -z "$k" ] && continue
case "$k" in histogram.*) continue ;; esac
m=$(echo "$k" | tr "." "_" | tr "-" "_")
case "$v" in
*.*) echo "unbound $${m}=$v" ;;
*) echo "unbound $${m}=$${v}i" ;;
esac
done
systemd:
units:
- name: docker.service
enabled: true
- name: unbound.service
enabled: true
contents: |
[Unit]
Description=Unbound DNS Resolver
After=docker.service network-online.target
Requires=docker.service
Wants=network-online.target
[Service]
ExecStartPre=-/usr/bin/docker stop unbound
ExecStartPre=-/usr/bin/docker rm unbound
ExecStartPre=/usr/bin/docker pull mvance/unbound:latest
ExecStart=/usr/bin/docker run \
--name unbound \
-p 204.110.191.240:53:53/udp \
-p 204.110.191.240:53:53/tcp \
-p 127.0.0.1:8953:8953/tcp \
-p 127.0.0.1:8080:8080/tcp \
-v /etc/unbound:/opt/unbound/etc/unbound:ro \
mvance/unbound:latest
ExecStop=/usr/bin/docker stop unbound
ExecStopPost=-/usr/bin/docker rm unbound
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
- name: telegraf.service
enabled: true
contents: |
[Unit]
Description=Telegraf Metrics Collector
After=docker.service network-online.target unbound.service
Requires=docker.service
BindsTo=unbound.service
[Service]
ExecStartPre=-/usr/bin/docker stop telegraf
ExecStartPre=-/usr/bin/docker rm telegraf
ExecStartPre=/usr/bin/docker pull telegraf:latest
ExecStart=/usr/bin/docker run \
--name telegraf \
--entrypoint /usr/bin/telegraf \
--user 0:0 \
--network host \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-v /usr/bin/docker:/usr/bin/docker:ro \
-v /etc/telegraf:/etc/telegraf:ro \
telegraf:latest --config /etc/telegraf/telegraf.conf
ExecStop=/usr/bin/docker stop telegraf
ExecStopPost=-/usr/bin/docker rm telegraf
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
- name: caddy.service
enabled: true
contents: |
[Unit]
Description=Caddy Web Server (DoH)
After=docker.service network-online.target unbound.service
Requires=docker.service
Wants=network-online.target
[Service]
ExecStartPre=-/usr/bin/docker stop caddy
ExecStartPre=-/usr/bin/docker rm caddy
ExecStartPre=/usr/bin/docker pull caddy:latest
ExecStartPre=-/usr/bin/mkdir -p /var/lib/caddy /var/log/caddy
ExecStart=/usr/bin/docker run \
--name caddy \
--network host \
-v /etc/caddy/Caddyfile:/etc/caddy/Caddyfile:ro \
-v /var/lib/caddy:/data \
-v /var/log/caddy:/var/log/caddy \
caddy:latest /usr/bin/caddy run --config /etc/caddy/Caddyfile
ExecStop=/usr/bin/docker stop caddy
ExecStopPost=-/usr/bin/docker rm caddy
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target

195
tofu/flatcar-resolver2.bu Normal file
View file

@ -0,0 +1,195 @@
variant: flatcar
version: 1.1.0
passwd:
users:
- name: core
ssh_authorized_keys:
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHLyVSEEAEbGZZqwPwEup0XrlTpu3x3iF9ExvvQPA4xN
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOzrDMNn3nINGdIogzRxY05fkn05LSYi98BGW1Bz5yXD
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIER/8suIKcrT3a/NZHjvOpRosPC5uX4kcznIJHt/98qj
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEEKtgXwoW8HZGqC+KJok9iNpI/lK4glvoryL4Ng/AL+
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFghGMnDdkfNC6JPEhMxrKhYDmNcXjHXp/y/mf3uLtzb
storage:
files:
- path: /etc/hostname
mode: 0644
overwrite: true
contents:
inline: flatcar-resolver2
- path: /etc/systemd/network/00-eth0.network
mode: 0644
contents:
inline: |
[Match]
Name=eth0
[Network]
Address=204.110.191.250/26
Gateway=204.110.191.254
DNS=9.9.9.9
DNS=1.1.1.1
- path: /etc/unbound/unbound.conf
mode: 0644
contents:
local: unbound.conf
- path: /etc/unbound/blocklist.rpz
mode: 0644
contents:
local: blocklist.rpz
- path: /etc/caddy/Caddyfile
mode: 0644
contents:
inline: |
{
admin off
persist_config off
}
resolver2.vntx.net {
@allowed remote_ip 127.0.0.0/8 204.110.188.0/22 10.0.0.0/8 172.1.0.0/15 100.64.0.0/10 192.168.0.0/16 ::1 2606:1c80::/32
handle /dns-query {
handle @allowed {
reverse_proxy 127.0.0.1:8080 {
transport http {
versions h2c 2
}
}
}
respond "Forbidden" 403
}
handle {
respond "DNS-over-HTTPS endpoint: /dns-query" 200
}
log {
output file /var/log/caddy/resolver2.log
format json
}
}
- path: /etc/telegraf/telegraf.conf
mode: 0644
contents:
inline: |
[agent]
interval = "30s"
[[inputs.exec]]
commands = ["/etc/telegraf/unbound-stats.sh"]
data_format = "influx"
timeout = "10s"
[[outputs.prometheus_client]]
listen = ":9273"
metric_version = 2
path = "/metrics"
expiration_interval = "60s"
- path: /etc/telegraf/unbound-stats.sh
mode: 0755
contents:
inline: |
#!/bin/sh
OUT=$(/usr/bin/docker exec unbound /opt/unbound/sbin/unbound-control stats_noreset 2>/dev/null)
[ $? -ne 0 ] && exit 1
echo "$OUT" | while IFS="=" read -r k v; do
[ -z "$k" ] && continue
case "$k" in histogram.*) continue ;; esac
m=$(echo "$k" | tr "." "_" | tr "-" "_")
case "$v" in
*.*) echo "unbound $${m}=$v" ;;
*) echo "unbound $${m}=$${v}i" ;;
esac
done
systemd:
units:
- name: docker.service
enabled: true
- name: unbound.service
enabled: true
contents: |
[Unit]
Description=Unbound DNS Resolver
After=docker.service network-online.target
Requires=docker.service
Wants=network-online.target
[Service]
ExecStartPre=-/usr/bin/docker stop unbound
ExecStartPre=-/usr/bin/docker rm unbound
ExecStartPre=/usr/bin/docker pull mvance/unbound:latest
ExecStart=/usr/bin/docker run \
--name unbound \
-p 204.110.191.250:53:53/udp \
-p 204.110.191.250:53:53/tcp \
-p 127.0.0.1:8953:8953/tcp \
-p 127.0.0.1:8080:8080/tcp \
-v /etc/unbound:/opt/unbound/etc/unbound:ro \
mvance/unbound:latest
ExecStop=/usr/bin/docker stop unbound
ExecStopPost=-/usr/bin/docker rm unbound
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
- name: telegraf.service
enabled: true
contents: |
[Unit]
Description=Telegraf Metrics Collector
After=docker.service network-online.target unbound.service
Requires=docker.service
BindsTo=unbound.service
[Service]
ExecStartPre=-/usr/bin/docker stop telegraf
ExecStartPre=-/usr/bin/docker rm telegraf
ExecStartPre=/usr/bin/docker pull telegraf:latest
ExecStart=/usr/bin/docker run \
--name telegraf \
--entrypoint /usr/bin/telegraf \
--user 0:0 \
--network host \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-v /usr/bin/docker:/usr/bin/docker:ro \
-v /etc/telegraf:/etc/telegraf:ro \
telegraf:latest --config /etc/telegraf/telegraf.conf
ExecStop=/usr/bin/docker stop telegraf
ExecStopPost=-/usr/bin/docker rm telegraf
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
- name: caddy.service
enabled: true
contents: |
[Unit]
Description=Caddy Web Server (DoH)
After=docker.service network-online.target unbound.service
Requires=docker.service
Wants=network-online.target
[Service]
ExecStartPre=-/usr/bin/docker stop caddy
ExecStartPre=-/usr/bin/docker rm caddy
ExecStartPre=/usr/bin/docker pull caddy:latest
ExecStartPre=-/usr/bin/mkdir -p /var/lib/caddy /var/log/caddy
ExecStart=/usr/bin/docker run \
--name caddy \
--network host \
-v /etc/caddy/Caddyfile:/etc/caddy/Caddyfile:ro \
-v /var/lib/caddy:/data \
-v /var/log/caddy:/var/log/caddy \
caddy:latest /usr/bin/caddy run --config /etc/caddy/Caddyfile
ExecStop=/usr/bin/docker stop caddy
ExecStopPost=-/usr/bin/docker rm caddy
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target

View file

@ -10,7 +10,7 @@ terraform {
}
proxmox = {
source = "bpg/proxmox"
version = "~> 0.73"
version = ">= 0.100.0"
}
}
}

View file

@ -1,65 +1,70 @@
# NixOS resolver VM Unbound DNS resolver on Proxmox
# Template (VMID 9010) must exist first; built via: ansible-playbook playbook.yml --tags template
# Flatcar Linux resolver VM Unbound DNS resolver on Proxmox.
# Uses lucidsolns/flatcar-vm/proxmox module for provisioning.
# Configuration via Butane/Ignition (flatcar-resolver.bu + unbound.conf).
#
# Module docs: https://github.com/lucidsolns/terraform-proxmox-flatcar-vm
locals {
nixos_ssh_keys = trimspace(<<-EOT
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHLyVSEEAEbGZZqwPwEup0XrlTpu3x3iF9ExvvQPA4xN
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOzrDMNn3nINGdIogzRxY05fkn05LSYi98BGW1Bz5yXD
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIER/8suIKcrT3a/NZHjvOpRosPC5uX4kcznIJHt/98qj
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEEKtgXwoW8HZGqC+KJok9iNpI/lK4glvoryL4Ng/AL+
EOT
)
}
module "flatcar_resolver1" {
source = "github.com/lucidsolns/terraform-proxmox-flatcar-vm"
resource "proxmox_virtual_environment_vm" "nixos_resolver" {
node_name = "vm2-380"
name = "nixos-resolver1"
vm_id = 110
vm_name = "flatcar-resolver1"
clone {
vm_id = 9010
full = true
cpu = {
cores = 16
}
cpu {
cores = 2
memory = {
dedicated = 8192
}
memory {
dedicated = 4096
}
boot_disk_size = 64
bridge = "vmbr0"
storage_root = "local-lvm"
storage_ignition = "local"
butane_conf = "${path.module}/flatcar-resolver.bu"
butane_snippet_path = "${path.module}"
disk {
datastore_id = "local-lvm"
interface = "scsi0"
size = 64
}
network_device {
bridge = "vmbr0"
}
initialization {
datastore_id = "local-lvm"
ip_config {
ipv4 {
address = "10.0.0.30/24"
gateway = "10.0.0.254"
}
network_devices = [
{
bridge = "vmbr0"
vlan_id = 9
}
]
dns {
servers = ["9.9.9.9"]
}
user_account {
username = "root"
keys = [local.nixos_ssh_keys]
}
}
agent {
enabled = true
}
flatcar_channel = "stable"
}
# Second Flatcar resolver resolver2.vntx.net
module "flatcar_resolver2" {
source = "github.com/lucidsolns/terraform-proxmox-flatcar-vm"
node_name = "vm2-380"
vm_id = 111
vm_name = "flatcar-resolver2"
cpu = {
cores = 16
}
memory = {
dedicated = 8192
}
boot_disk_size = 64
bridge = "vmbr0"
storage_root = "local-lvm"
storage_ignition = "local"
butane_conf = "${path.module}/flatcar-resolver2.bu"
butane_snippet_path = "${path.module}"
network_devices = [
{
bridge = "vmbr0"
vlan_id = 9
}
]
flatcar_channel = "stable"
}

1383
tofu/unbound.conf Normal file

File diff suppressed because it is too large Load diff