diff --git a/CLAUDE.md b/CLAUDE.md index 244e63b..46122c2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -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 diff --git a/ansible/CLAUDE.md b/ansible/CLAUDE.md index 66255b8..e789e2c 100644 --- a/ansible/CLAUDE.md +++ b/ansible/CLAUDE.md @@ -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 diff --git a/ansible/files/build-nixos-template.sh b/ansible/files/build-nixos-template.sh deleted file mode 100644 index a6cf803..0000000 --- a/ansible/files/build-nixos-template.sh +++ /dev/null @@ -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 '' \ - --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." diff --git a/ansible/files/nixos-template-config.nix b/ansible/files/nixos-template-config.nix deleted file mode 100644 index 4996c41..0000000 --- a/ansible/files/nixos-template-config.nix +++ /dev/null @@ -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"; -} diff --git a/ansible/host_vars/nixos-resolver1.yml b/ansible/host_vars/nixos-resolver1.yml deleted file mode 100644 index e9903e1..0000000 --- a/ansible/host_vars/nixos-resolver1.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -ansible_user: root -ansible_python_interpreter: /run/current-system/sw/bin/python3 -ansible_ssh_common_args: '-o StrictHostKeyChecking=accept-new' diff --git a/ansible/hosts b/ansible/hosts index 084f2e8..d3125e4 100755 --- a/ansible/hosts +++ b/ansible/hosts @@ -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 - diff --git a/ansible/playbook.yml b/ansible/playbook.yml index a156e61..2bdfd8c 100644 --- a/ansible/playbook.yml +++ b/ansible/playbook.yml @@ -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 diff --git a/ansible/roles/resolvers/templates/nixos-unbound.nix.j2 b/ansible/roles/resolvers/templates/nixos-unbound.nix.j2 deleted file mode 100644 index e28c8b3..0000000 --- a/ansible/roles/resolvers/templates/nixos-unbound.nix.j2 +++ /dev/null @@ -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 ]; -} diff --git a/tofu/.terraform.lock.hcl b/tofu/.terraform.lock.hcl index f7240e7..5042872 100644 --- a/tofu/.terraform.lock.hcl +++ b/tofu/.terraform.lock.hcl @@ -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" diff --git a/tofu/blocklist.rpz b/tofu/blocklist.rpz new file mode 100644 index 0000000..c0dc490 --- /dev/null +++ b/tofu/blocklist.rpz @@ -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 . + diff --git a/tofu/cloudflare.tf b/tofu/cloudflare.tf index 77ba8be..a8f1b36 100644 --- a/tofu/cloudflare.tf +++ b/tofu/cloudflare.tf @@ -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 } diff --git a/tofu/flatcar-resolver.bu b/tofu/flatcar-resolver.bu new file mode 100644 index 0000000..dda65b0 --- /dev/null +++ b/tofu/flatcar-resolver.bu @@ -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 diff --git a/tofu/flatcar-resolver2.bu b/tofu/flatcar-resolver2.bu new file mode 100644 index 0000000..ae63ca2 --- /dev/null +++ b/tofu/flatcar-resolver2.bu @@ -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 diff --git a/tofu/main.tf b/tofu/main.tf index 36299c2..e7f117d 100644 --- a/tofu/main.tf +++ b/tofu/main.tf @@ -10,7 +10,7 @@ terraform { } proxmox = { source = "bpg/proxmox" - version = "~> 0.73" + version = ">= 0.100.0" } } } diff --git a/tofu/proxmox.tf b/tofu/proxmox.tf index 5dfb941..62350af 100644 --- a/tofu/proxmox.tf +++ b/tofu/proxmox.tf @@ -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" } diff --git a/tofu/unbound.conf b/tofu/unbound.conf new file mode 100644 index 0000000..974a728 --- /dev/null +++ b/tofu/unbound.conf @@ -0,0 +1,1383 @@ +# +# Example configuration file. +# +# See unbound.conf(5) man page, version @version@. +# +# this is a comment. + +# Use this anywhere in the file to include other text into this file. +#include: "otherfile.conf" + +# Use this anywhere in the file to include other text, that explicitly starts a +# clause, into this file. Text after this directive needs to start a clause. +#include-toplevel: "otherfile.conf" + +# The server clause sets the main parameters. +server: + # whitespace is not necessary, but looks cleaner. + + # verbosity number, 0 is least verbose. 1 is default. + # verbosity: 1 + + # print statistics to the log (for every thread) every N seconds. + # Set to "" or 0 to disable. Default is disabled. + # statistics-interval: 0 + + # enable shm for stats, default no. if you enable also enable + # statistics-interval, every time it also writes stats to the + # shared memory segment keyed with shm-key. + # Disabled: nothing consumes the shm stats segment, and leaving it on + # with statistics-interval: 0 logs a warning at startup. Re-enable (with + # a non-zero statistics-interval) if an unbound stats exporter is added. + shm-enable: no + + # shm for stats uses this key, and key+1 for the shared mem segment. + # shm-key: 11777 + + # enable cumulative statistics, without clearing them after printing. + # statistics-cumulative: no + + # enable extended statistics (query types, answer codes, status) + # printed from unbound-control. Default off, because of speed. + # extended-statistics: no + extended-statistics: yes + + # Inhibits selected extended statistics (qtype, qclass, qopcode, rcode, + # rpz-actions) from printing if their value is 0. + # Default on. + # statistics-inhibit-zero: no + + # number of threads to create. 1 disables threading. + num-threads: 8 + + # specify the interfaces to answer queries from by ip-address. + # The default is to listen to localhost (127.0.0.1 and ::1). + # specify 0.0.0.0 and ::0 to bind to all available interfaces. + # specify every interface[@port] on a new 'interface:' labelled line. + # The listen interfaces are not changed on reload, only on restart. + # interface: 192.0.2.153 + # interface: 192.0.2.154 + # interface: 192.0.2.154@5003 + # interface: 2001:DB8::5 + # interface: eth0@5003 + interface: 0.0.0.0 + interface: ::0 + + # DNS-over-HTTPS endpoint. Cleartext HTTP/2 on loopback only; Caddy + # terminates TLS on :443 and reverse-proxies here. + interface: 127.0.0.1@8080 + https-port: 8080 + http-endpoint: "/dns-query" + http-notls-downstream: yes + + # enable this feature to copy the source address of queries to reply. + # Socket options are not supported on all platforms. experimental. + interface-automatic: yes + + # interface-automatic ignores manually-configured interface: lines for + # non-default ports, so the DoH listener port (8080) must be listed here + # or the 127.0.0.1@8080 socket is silently never bound. + interface-automatic-ports: "53 8080" + + # instead of the default port, open additional ports separated by + # spaces when interface-automatic is enabled, by listing them here. + # interface-automatic-ports: "53,443" + + # port to answer queries from + port: 53 + + # specify the interfaces to send outgoing queries to authoritative + # server from by ip-address. If none, the default (all) interface + # is used. Specify every interface on a 'outgoing-interface:' line. + # outgoing-interface: 192.0.2.153 + # outgoing-interface: 2001:DB8::5 + # outgoing-interface: 2001:DB8::6 + + # Specify a netblock to use remainder 64 bits as random bits for + # upstream queries. Uses freebind option (Linux). + # outgoing-interface: 2001:DB8::/64 + # Also (Linux:) ip -6 addr add 2001:db8::/64 dev lo + # And: ip -6 route add local 2001:db8::/64 dev lo + # And set prefer-ip6: yes to use the ip6 randomness from a netblock. + # Set this to yes to prefer ipv6 upstream servers over ipv4. + # prefer-ip6: no + + # Prefer ipv4 upstream servers, even if ipv6 is available. + # prefer-ip4: no + + # number of ports to allocate per thread, determines the size of the + # port range that can be open simultaneously. About double the + # num-queries-per-thread, or, use as many as the OS will allow you. + outgoing-range: 8192 + + # permit Unbound to use this port number or port range for + # making outgoing queries, using an outgoing interface. + # outgoing-port-permit: 32768 + outgoing-port-permit: 32768-60999 + + # deny Unbound the use this of port number or port range for + # making outgoing queries, using an outgoing interface. + # Use this to make sure Unbound does not grab a UDP port that some + # other server on this computer needs. The default is to avoid + # IANA-assigned port numbers. + # If multiple outgoing-port-permit and outgoing-port-avoid options + # are present, they are processed in order. + # outgoing-port-avoid: "3200-3208" + + # number of outgoing simultaneous tcp buffers to hold per thread. + # outgoing-num-tcp: 10 + outgoing-num-tcp: 100 + + # number of incoming simultaneous tcp buffers to hold per thread. + # incoming-num-tcp: 10 + incoming-num-tcp: 600 + + # buffer size for UDP port 53 incoming (SO_RCVBUF socket option). + # 0 is system default. Use 4m to catch query spikes for busy servers. + # so-rcvbuf: 0 + + # buffer size for UDP port 53 outgoing (SO_SNDBUF socket option). + # 0 is system default. Use 4m to handle spikes on very busy servers. + # so-sndbuf: 0 + + # use SO_REUSEPORT to distribute queries over threads. + # at extreme load it could be better to turn it off to distribute even. + # Enabled: lets the kernel hash UDP across per-thread sockets instead of + # waking all threads, balancing load and improving spike headroom. + so-reuseport: yes + + # use IP_TRANSPARENT so the interface: addresses can be non-local + # and you can config non-existing IPs that are going to work later on + # (uses IP_BINDANY on FreeBSD). + ip-transparent: yes + + # use IP_FREEBIND so the interface: addresses can be non-local + # and you can bind to nonexisting IPs and interfaces that are down. + # Linux only. On Linux you also have ip-transparent that is similar. + # ip-freebind: no + + # the value of the Differentiated Services Codepoint (DSCP) + # in the differentiated services field (DS) of the outgoing + # IP packets + # ip-dscp: 0 + + # EDNS reassembly buffer to advertise to UDP peers (the actual buffer + # is set with msg-buffer-size). + # 1232 is the DNS Flag Day 2020 default: it avoids IP fragmentation + # (fragmented UDP causes retransmits/TCP fallback and frag-based issues) + # at the cost of a marginally higher TCP-fallback rate. + edns-buffer-size: 1232 + + # Maximum UDP response size (not applied to TCP response). + # Suggested values are 512 to 4096. Default is 1232. 65536 disables it. + # max-udp-size: 1232 + + # max memory to use for stream(tcp and tls) waiting result buffers. + # stream-wait-size: 4m + + # buffer size for handling DNS data. No messages larger than this + # size can be sent or received, by UDP or TCP. In bytes. + # msg-buffer-size: 65552 + + # the amount of memory to use for the message cache. + # plain value in bytes or you can append k, m or G. default is "4Mb". + # msg-cache-size: 4m + msg-cache-size: 512m + + # the number of slabs to use for the message cache. + # the number of slabs must be a power of 2. + # more slabs reduce lock contention, but fragment memory usage. + # msg-cache-slabs: 4 + msg-cache-slabs: 8 + + # the number of queries that a thread gets to service. + num-queries-per-thread: 2048 + + # if very busy, 50% queries run to completion, 50% get timeout in msec + # jostle-timeout: 200 + + # msec to wait before close of port on timeout UDP. 0 disables. + # delay-close: 0 + + # perform connect for UDP sockets to mitigate ICMP side channel. + # udp-connect: yes + + # The number of retries, per upstream nameserver in a delegation, when + # a throwaway response (also timeouts) is received. + # outbound-msg-retry: 5 + + # Hard limit on the number of outgoing queries Unbound will make while + # resolving a name, making sure large NS sets do not loop. + # It resets on query restarts (e.g., CNAME) and referrals. + # max-sent-count: 32 + + # Hard limit on the number of times Unbound is allowed to restart a + # query upon encountering a CNAME record. + # max-query-restarts: 11 + + # msec for waiting for an unknown server to reply. Increase if you + # are behind a slow satellite link, to eg. 1128. + # unknown-server-time-limit: 376 + + # the amount of memory to use for the RRset cache. + # plain value in bytes or you can append k, m or G. default is "4Mb". + rrset-cache-size: 512m + + # the number of slabs to use for the RRset cache. + # the number of slabs must be a power of 2. + # more slabs reduce lock contention, but fragment memory usage. + # rrset-cache-slabs: 4 + rrset-cache-slabs: 8 + + # the time to live (TTL) value lower bound, in seconds. Default 0. + # If more than an hour could easily give trouble due to stale data. + # cache-min-ttl: 0 + + # the time to live (TTL) value cap for RRsets and messages in the + # cache. Items are not cached for longer. In seconds. + # cache-max-ttl: 86400 + + # the time to live (TTL) value cap for negative responses in the cache + # cache-max-negative-ttl: 3600 + + # the time to live (TTL) value for cached roundtrip times, lameness and + # EDNS version information for hosts. In seconds. + # infra-host-ttl: 900 + + # minimum wait time for responses, increase if uplink is long. In msec. + # infra-cache-min-rtt: 50 + + # maximum wait time for responses. In msec. + # infra-cache-max-rtt: 120000 + + # enable to make server probe down hosts more frequently. + # infra-keep-probing: no + + # the number of slabs to use for the Infrastructure cache. + # the number of slabs must be a power of 2. + # more slabs reduce lock contention, but fragment memory usage. + # infra-cache-slabs: 4 + infra-cache-slabs: 8 + + # the maximum number of hosts that are cached (roundtrip, EDNS, lame). + infra-cache-numhosts: 100000 + + # define a number of tags here, use with local-zone, access-control, + # interface-*. + # repeat the define-tag statement to add additional tags. + # define-tag: "tag1 tag2 tag3" + + # Enable IPv4, "yes" or "no". + do-ip4: yes + + # Enable IPv6, "yes" or "no". + do-ip6: yes + + # If running unbound on an IPv6-only host, domains that only have + # IPv4 servers would become unresolveable. If NAT64 is available in + # the network, unbound can use NAT64 to reach these servers with + # the following option. This is NOT needed for enabling DNS64 on a + # system that has IPv4 connectivity. + # Consider also enabling prefer-ip6 to prefer native IPv6 connections + # to nameservers. + # do-nat64: no + + # NAT64 prefix. Defaults to using dns64-prefix value. + # nat64-prefix: 64:ff9b::0/96 + + # Enable UDP, "yes" or "no". + # do-udp: yes + + # Enable TCP, "yes" or "no". + # do-tcp: yes + + # upstream connections use TCP only (and no UDP), "yes" or "no" + # useful for tunneling scenarios, default no. + # tcp-upstream: no + + # upstream connections also use UDP (even if do-udp is no). + # useful if if you want UDP upstream, but don't provide UDP downstream. + # udp-upstream-without-downstream: no + + # Maximum segment size (MSS) of TCP socket on which the server + # responds to queries. Default is 0, system default MSS. + # tcp-mss: 0 + + # Maximum segment size (MSS) of TCP socket for outgoing queries. + # Default is 0, system default MSS. + # outgoing-tcp-mss: 0 + + # Idle TCP timeout, connection closed in milliseconds + # tcp-idle-timeout: 30000 + + # Enable EDNS TCP keepalive option. + edns-tcp-keepalive: yes + + # Timeout for EDNS TCP keepalive, in msec. + # edns-tcp-keepalive-timeout: 120000 + + # UDP queries that have waited in the socket buffer for a long time + # can be dropped. Default is 0, disabled. In seconds, such as 3. + # sock-queue-timeout: 0 + + # Use systemd socket activation for UDP, TCP, and control sockets. + # use-systemd: no + + # Detach from the terminal, run in background, "yes" or "no". + # Set the value to "no" when Unbound runs as systemd service. + # do-daemonize: yes + + # control which clients are allowed to make (recursive) queries + # to this server. Specify classless netblocks with /size and action. + # By default everything is refused, except for localhost. + # Choose deny (drop message), refuse (polite error reply), + # allow (recursive ok), allow_setrd (recursive ok, rd bit is forced on), + # allow_snoop (recursive and nonrecursive ok) + # deny_non_local (drop queries unless can be answered from local-data) + # refuse_non_local (like deny_non_local but polite error reply). + # access-control: 127.0.0.0/8 allow + # access-control: ::1 allow + # access-control: ::ffff:127.0.0.1 allow + access-control: 0.0.0.0/0 refuse + access-control: ::0/0 refuse + + access-control: 127.0.0.0/8 allow + + access-control: 204.110.188.0/22 allow + + access-control: 10.0.0.0/8 allow + + access-control: 172.1.0.0/15 allow + + access-control: 100.64.0.0/10 allow + + access-control: 192.168.0.0/16 allow + + access-control: ::1 allow + + access-control: 2606:1c80::/32 allow + + + # Blocklist (NXDOMAIN + logging) is implemented as an RPZ at the end of + # this file so that only blocklist hits are logged. See the rpz: clause + # and /etc/unbound/blocklist.rpz (templated from resolver_blocked_domains). + + # tag access-control with list of tags (in "" with spaces between) + # Clients using this access control element use localzones that + # are tagged with one of these tags. + # access-control-tag: 192.0.2.0/24 "tag2 tag3" + + # set action for particular tag for given access control element. + # if you have multiple tag values, the tag used to lookup the action + # is the first tag match between access-control-tag and local-zone-tag + # where "first" comes from the order of the define-tag values. + # access-control-tag-action: 192.0.2.0/24 tag3 refuse + + # set redirect data for particular tag for access control element + # access-control-tag-data: 192.0.2.0/24 tag2 "A 127.0.0.1" + + # Set view for access control element + # access-control-view: 192.0.2.0/24 viewname + + # Similar to 'access-control:' but for interfaces. + # Control which listening interfaces are allowed to accept (recursive) + # queries for this server. + # The specified interfaces should be the same as the ones specified in + # 'interface:' followed by the action. + # The actions are the same as 'access-control:' above. + # By default all the interfaces configured are refused. + # Note: any 'access-control*:' setting overrides all 'interface-*:' + # settings for targeted clients. + # interface-action: 192.0.2.153 allow + # interface-action: 192.0.2.154 allow + # interface-action: 192.0.2.154@5003 allow + # interface-action: 2001:DB8::5 allow + # interface-action: eth0@5003 allow + + # Similar to 'access-control-tag:' but for interfaces. + # Tag interfaces with a list of tags (in "" with spaces between). + # Interfaces using these tags use localzones that are tagged with one + # of these tags. + # The specified interfaces should be the same as the ones specified in + # 'interface:' followed by the list of tags. + # Note: any 'access-control*:' setting overrides all 'interface-*:' + # settings for targeted clients. + # interface-tag: eth0@5003 "tag2 tag3" + + # Similar to 'access-control-tag-action:' but for interfaces. + # Set action for particular tag for a given interface element. + # If you have multiple tag values, the tag used to lookup the action + # is the first tag match between interface-tag and local-zone-tag + # where "first" comes from the order of the define-tag values. + # The specified interfaces should be the same as the ones specified in + # 'interface:' followed by the tag and action. + # Note: any 'access-control*:' setting overrides all 'interface-*:' + # settings for targeted clients. + # interface-tag-action: eth0@5003 tag3 refuse + + # Similar to 'access-control-tag-data:' but for interfaces. + # Set redirect data for a particular tag for an interface element. + # The specified interfaces should be the same as the ones specified in + # 'interface:' followed by the tag and the redirect data. + # Note: any 'access-control*:' setting overrides all 'interface-*:' + # settings for targeted clients. + # interface-tag-data: eth0@5003 tag2 "A 127.0.0.1" + + # Similar to 'access-control-view:' but for interfaces. + # Set view for an interface element. + # The specified interfaces should be the same as the ones specified in + # 'interface:' followed by the view name. + # Note: any 'access-control*:' setting overrides all 'interface-*:' + # settings for targeted clients. + # interface-view: eth0@5003 viewname + + # if given, a chroot(2) is done to the given directory. + # i.e. you can chroot to the working directory, for example, + # for extra security, but make sure all files are in that directory. + # + # If chroot is enabled, you should pass the configfile (from the + # commandline) as a full path from the original root. After the + # chroot has been performed the now defunct portion of the config + # file path is removed to be able to reread the config after a reload. + # + # All other file paths (working dir, logfile, roothints, and + # key files) can be specified in several ways: + # o as an absolute path relative to the new root. + # o as a relative path to the working directory. + # o as an absolute path relative to the original root. + # In the last case the path is adjusted to remove the unused portion. + # + # The pid file can be absolute and outside of the chroot, it is + # written just prior to performing the chroot and dropping permissions. + # + # Additionally, Unbound may need to access /dev/urandom (for entropy). + # How to do this is specific to your OS. + # + # If you give "" no chroot is performed. The path must not end in a /. + # chroot: "@UNBOUND_CHROOT_DIR@" + + # if given, user privileges are dropped (after binding port), + # and the given username is assumed. Default is user "unbound". + # If you give "" no privileges are dropped. + # username: "@UNBOUND_USERNAME@" + + # the working directory. The relative files in this config are + # relative to this directory. If you give "" the working directory + # is not changed. + # If you give a server: directory: dir before include: file statements + # then those includes can be relative to the working directory. + # directory: "@UNBOUND_RUN_DIR@" + + # the log file, "" means log to stderr. + # Use of this option sets use-syslog to "no". + # logfile: "" + + # Log to syslog(3) if yes. The log facility LOG_DAEMON is used to + # log to. If yes, it overrides the logfile. + # use-syslog: yes + + # Log identity to report. if empty, defaults to the name of argv[0] + # (usually "unbound"). + # log-identity: "" + + # print UTC timestamp in ascii to logfile, default is epoch in seconds. + log-time-ascii: yes + + # print one line with time, IP, name, type, class for every query. + # log-queries: no + + # print one line per reply, with time, IP, name, type, class, rcode, + # timetoresolve, fromcache and responsesize. + # log-replies: no + + # log with tag 'query' and 'reply' instead of 'info' for + # filtering log-queries and log-replies from the log. + # log-tag-queryreply: no + + # log the local-zone actions, like local-zone type inform is enabled + # also for the other local zone types. + # log-local-actions: no + + # print log lines that say why queries return SERVFAIL to clients. + # log-servfail: no + + # the pid file. Can be an absolute path outside of chroot/work dir. + # pidfile: "@UNBOUND_PIDFILE@" + + # file to read root hints from. + # get one from https://www.internic.net/domain/named.cache + # root-hints: "" + + # enable to not answer id.server and hostname.bind queries. + # hide-identity: no + + # enable to not answer version.server and version.bind queries. + # hide-version: no + + # enable to not answer trustanchor.unbound queries. + # hide-trustanchor: no + + # enable to not set the User-Agent HTTP header. + # hide-http-user-agent: no + + # the identity to report. Leave "" or default to return hostname. + # identity: "" + + # the version to report. Leave "" or default to return package version. + # version: "" + + # NSID identity (hex string, or "ascii_somestring"). default disabled. + # nsid: "aabbccdd" + + # User-Agent HTTP header to use. Leave "" or default to use package name + # and version. + # http-user-agent: "" + + # the target fetch policy. + # series of integers describing the policy per dependency depth. + # The number of values in the list determines the maximum dependency + # depth the recursor will pursue before giving up. Each integer means: + # -1 : fetch all targets opportunistically, + # 0: fetch on demand, + # positive value: fetch that many targets opportunistically. + # Enclose the list of numbers between quotes (""). + # target-fetch-policy: "3 2 1 0 0" + + # Harden against very small EDNS buffer sizes. + harden-short-bufsize: yes + + # Harden against unseemly large queries. + harden-large-queries: yes + + # Harden against out of zone rrsets, to avoid spoofing attempts. + harden-glue: yes + + # Harden against receiving dnssec-stripped data. If you turn it + # off, failing to validate dnskey data for a trustanchor will + # trigger insecure mode for that zone (like without a trustanchor). + # Default on, which insists on dnssec data for trust-anchored zones. + # harden-dnssec-stripped: yes + + # Harden against queries that fall under dnssec-signed nxdomain names. + # harden-below-nxdomain: yes + + # Harden the referral path by performing additional queries for + # infrastructure data. Validates the replies (if possible). + # Default off, because the lookups burden the server. Experimental + # implementation of draft-wijngaards-dnsext-resolver-side-mitigation. + # harden-referral-path: no + + # Harden against algorithm downgrade when multiple algorithms are + # advertised in the DS record. If no, allows the weakest algorithm + # to validate the zone. + # harden-algo-downgrade: no + + # Harden against unknown records in the authority section and the + # additional section. + # harden-unknown-additional: no + + # Sent minimum amount of information to upstream servers to enhance + # privacy. Only sent minimum required labels of the QNAME and set QTYPE + # to A when possible. + # qname-minimisation: yes + + # QNAME minimisation in strict mode. Do not fall-back to sending full + # QNAME to potentially broken nameservers. A lot of domains will not be + # resolvable when this option in enabled. + # This option only has effect when qname-minimisation is enabled. + # qname-minimisation-strict: no + + # Aggressive NSEC uses the DNSSEC NSEC chain to synthesize NXDOMAIN + # and other denials, using information from previous NXDOMAINs answers. + # aggressive-nsec: yes + + # Use 0x20-encoded random bits in the query to foil spoof attempts. + # This feature is an experimental implementation of draft dns-0x20. + # use-caps-for-id: no + + # Domains (and domains in them) without support for dns-0x20 and + # the fallback fails because they keep sending different answers. + # caps-exempt: "licdn.com" + # caps-exempt: "senderbase.org" + + # Enforce privacy of these addresses. Strips them away from answers. + # It may cause DNSSEC validation to additionally mark it as bogus. + # Protects against 'DNS Rebinding' (uses browser as network proxy). + # Only 'private-domain' and 'local-data' names are allowed to have + # these private addresses. No default. + # private-address: 10.0.0.0/8 + # private-address: 172.16.0.0/12 + # private-address: 192.168.0.0/16 + # private-address: 169.254.0.0/16 + # private-address: fd00::/8 + # private-address: fe80::/10 + # private-address: ::ffff:0:0/96 + + # Allow the domain (and its subdomains) to contain private addresses. + # local-data statements are allowed to contain private addresses too. + # private-domain: "example.com" + + # If nonzero, unwanted replies are not only reported in statistics, + # but also a running total is kept per thread. If it reaches the + # threshold, a warning is printed and a defensive action is taken, + # the cache is cleared to flush potential poison out of it. + # A suggested value is 10000000, the default is 0 (turned off). + # unwanted-reply-threshold: 0 + + # Do not query the following addresses. No DNS queries are sent there. + # List one address per entry. List classless netblocks with /size, + # do-not-query-address: 127.0.0.1/8 + # do-not-query-address: ::1 + + # if yes, the above default do-not-query-address entries are present. + # if no, localhost can be queried (for testing and debugging). + # do-not-query-localhost: yes + + # if yes, perform prefetching of almost expired message cache entries. + # prefetch: no + prefetch: yes + + # if yes, perform key lookups adjacent to normal lookups. + # prefetch-key: no + prefetch-key: yes + + # deny queries of type ANY with an empty response. + # deny-any: no + + # if yes, Unbound rotates RRSet order in response. + # rrset-roundrobin: yes + + # if yes, Unbound doesn't insert authority/additional sections + # into response messages when those sections are not required. + # minimal-responses: yes + + # true to disable DNSSEC lameness check in iterator. + # disable-dnssec-lame-check: no + + # module configuration of the server. A string with identifiers + # separated by spaces. Syntax: "[dns64] [validator] iterator" + # most modules have to be listed at the beginning of the line, + # except cachedb(just before iterator), and python (at the beginning, + # or, just before the iterator). + # module-config: "validator iterator" + # respip is required for the RPZ blocklist (rpz: clause at end of file). + module-config: "respip validator iterator" + + # File with trusted keys, kept uptodate using RFC5011 probes, + # initial file like trust-anchor-file, then it stores metadata. + # Use several entries, one per domain name, to track multiple zones. + # + # If you want to perform DNSSEC validation, run unbound-anchor before + # you start Unbound (i.e. in the system boot scripts). + # And then enable the auto-trust-anchor-file config item. + # Please note usage of unbound-anchor root anchor is at your own risk + # and under the terms of our LICENSE (see that file in the source). + # auto-trust-anchor-file: "@UNBOUND_ROOTKEY_FILE@" + + # trust anchor signaling sends a RFC8145 key tag query after priming. + # trust-anchor-signaling: yes + + # Root key trust anchor sentinel (draft-ietf-dnsop-kskroll-sentinel) + # root-key-sentinel: yes + + # File with trusted keys for validation. Specify more than one file + # with several entries, one file per entry. + # Zone file format, with DS and DNSKEY entries. + # Note this gets out of date, use auto-trust-anchor-file please. + # trust-anchor-file: "" + + # Trusted key for validation. DS or DNSKEY. specify the RR on a + # single line, surrounded by "". TTL is ignored. class is IN default. + # Note this gets out of date, use auto-trust-anchor-file please. + # (These examples are from August 2007 and may not be valid anymore). + # trust-anchor: "nlnetlabs.nl. DNSKEY 257 3 5 AQPzzTWMz8qSWIQlfRnPckx2BiVmkVN6LPupO3mbz7FhLSnm26n6iG9N Lby97Ji453aWZY3M5/xJBSOS2vWtco2t8C0+xeO1bc/d6ZTy32DHchpW 6rDH1vp86Ll+ha0tmwyy9QP7y2bVw5zSbFCrefk8qCUBgfHm9bHzMG1U BYtEIQ==" + # trust-anchor: "jelte.nlnetlabs.nl. DS 42860 5 1 14D739EB566D2B1A5E216A0BA4D17FA9B038BE4A" + + # File with trusted keys for validation. Specify more than one file + # with several entries, one file per entry. Like trust-anchor-file + # but has a different file format. Format is BIND-9 style format, + # the trusted-keys { name flag proto algo "key"; }; clauses are read. + # you need external update procedures to track changes in keys. + # trusted-keys-file: "" + + # Ignore chain of trust. Domain is treated as insecure. + # domain-insecure: "example.com" + + # Override the date for validation with a specific fixed date. + # Do not set this unless you are debugging signature inception + # and expiration. "" or "0" turns the feature off. -1 ignores date. + # val-override-date: "" + + # The time to live for bogus data, rrsets and messages. This avoids + # some of the revalidation, until the time interval expires. in secs. + # val-bogus-ttl: 60 + + # The signature inception and expiration dates are allowed to be off + # by 10% of the signature lifetime (expir-incep) from our local clock. + # This leeway is capped with a minimum and a maximum. In seconds. + # val-sig-skew-min: 3600 + # val-sig-skew-max: 86400 + + # The maximum number the validator should restart validation with + # another authority in case of failed validation. + # val-max-restart: 5 + + # Should additional section of secure message also be kept clean of + # unsecure data. Useful to shield the users of this validator from + # potential bogus data in the additional section. All unsigned data + # in the additional section is removed from secure messages. + # val-clean-additional: yes + + # Turn permissive mode on to permit bogus messages. Thus, messages + # for which security checks failed will be returned to clients, + # instead of SERVFAIL. It still performs the security checks, which + # result in interesting log files and possibly the AD bit in + # replies if the message is found secure. The default is off. + # val-permissive-mode: no + + # Ignore the CD flag in incoming queries and refuse them bogus data. + # Enable it if the only clients of Unbound are legacy servers (w2008) + # that set CD but cannot validate themselves. + # ignore-cd-flag: no + + # Serve expired responses from cache, with serve-expired-reply-ttl in + # the response, and then attempt to fetch the data afresh. + # serve-expired: no + # + # Limit serving of expired responses to configured seconds after + # expiration. 0 disables the limit. + # serve-expired-ttl: 0 + # + # Set the TTL of expired records to the serve-expired-ttl value after a + # failed attempt to retrieve the record from upstream. This makes sure + # that the expired records will be served as long as there are queries + # for it. + # serve-expired-ttl-reset: no + # + # TTL value to use when replying with expired data. + # serve-expired-reply-ttl: 30 + # + # Time in milliseconds before replying to the client with expired data. + # This essentially enables the serve-stale behavior as specified in + # RFC 8767 that first tries to resolve before + # immediately responding with expired data. 0 disables this behavior. + # A recommended value is 1800. + # serve-expired-client-timeout: 0 + + # Serve-stale (RFC 8767): on a cache miss for an expired record, try to + # resolve fresh for up to client-timeout ms, then answer immediately with + # the stale record while refreshing in the background. Gives clients fast + # answers during upstream slowness/outages. serve-expired-ttl caps how long + # (seconds) stale data may be served after expiry. + serve-expired: yes + serve-expired-ttl: 86400 + serve-expired-client-timeout: 1800 + + # Return the original TTL as received from the upstream name server rather + # than the decrementing TTL as stored in the cache. Enabling this feature + # does not impact cache expiry, it only changes the TTL Unbound embeds in + # responses to queries. Note that enabling this feature implicitly disables + # enforcement of the configured minimum and maximum TTL. + # serve-original-ttl: no + + # Have the validator log failed validations for your diagnosis. + # 0: off. 1: A line per failed user query. 2: With reason and bad IP. + # val-log-level: 0 + + # It is possible to configure NSEC3 maximum iteration counts per + # keysize. Keep this table very short, as linear search is done. + # A message with an NSEC3 with larger count is marked insecure. + # List in ascending order the keysize and count values. + # val-nsec3-keysize-iterations: "1024 150 2048 150 4096 150" + + # if enabled, ZONEMD verification failures do not block the zone. + # zonemd-permissive-mode: no + + # instruct the auto-trust-anchor-file probing to add anchors after ttl. + # add-holddown: 2592000 # 30 days + + # instruct the auto-trust-anchor-file probing to del anchors after ttl. + # del-holddown: 2592000 # 30 days + + # auto-trust-anchor-file probing removes missing anchors after ttl. + # If the value 0 is given, missing anchors are not removed. + # keep-missing: 31622400 # 366 days + + # debug option that allows very small holddown times for key rollover, + # otherwise the RFC mandates probe intervals must be at least 1 hour. + # permit-small-holddown: no + + # the amount of memory to use for the key cache. + # plain value in bytes or you can append k, m or G. default is "4Mb". + key-cache-size: 512m + + # the number of slabs to use for the key cache. + # the number of slabs must be a power of 2. + # more slabs reduce lock contention, but fragment memory usage. + # key-cache-slabs: 4 + key-cache-slabs: 8 + + # the amount of memory to use for the negative cache. + # plain value in bytes or you can append k, m or G. default is "1Mb". + # neg-cache-size: 1m + + # By default, for a number of zones a small default 'nothing here' + # reply is built-in. Query traffic is thus blocked. If you + # wish to serve such zone you can unblock them by uncommenting one + # of the nodefault statements below. + # You may also have to use domain-insecure: zone to make DNSSEC work, + # unless you have your own trust anchors for this zone. + # local-zone: "localhost." nodefault + # local-zone: "127.in-addr.arpa." nodefault + # local-zone: "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa." nodefault + # local-zone: "home.arpa." nodefault + # local-zone: "onion." nodefault + # local-zone: "test." nodefault + # local-zone: "invalid." nodefault + # local-zone: "10.in-addr.arpa." nodefault + # local-zone: "16.172.in-addr.arpa." nodefault + # local-zone: "17.172.in-addr.arpa." nodefault + # local-zone: "18.172.in-addr.arpa." nodefault + # local-zone: "19.172.in-addr.arpa." nodefault + # local-zone: "20.172.in-addr.arpa." nodefault + # local-zone: "21.172.in-addr.arpa." nodefault + # local-zone: "22.172.in-addr.arpa." nodefault + # local-zone: "23.172.in-addr.arpa." nodefault + # local-zone: "24.172.in-addr.arpa." nodefault + # local-zone: "25.172.in-addr.arpa." nodefault + # local-zone: "26.172.in-addr.arpa." nodefault + # local-zone: "27.172.in-addr.arpa." nodefault + # local-zone: "28.172.in-addr.arpa." nodefault + # local-zone: "29.172.in-addr.arpa." nodefault + # local-zone: "30.172.in-addr.arpa." nodefault + # local-zone: "31.172.in-addr.arpa." nodefault + # local-zone: "168.192.in-addr.arpa." nodefault + # local-zone: "0.in-addr.arpa." nodefault + # local-zone: "254.169.in-addr.arpa." nodefault + # local-zone: "2.0.192.in-addr.arpa." nodefault + # local-zone: "100.51.198.in-addr.arpa." nodefault + # local-zone: "113.0.203.in-addr.arpa." nodefault + # local-zone: "255.255.255.255.in-addr.arpa." nodefault + # local-zone: "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa." nodefault + # local-zone: "d.f.ip6.arpa." nodefault + # local-zone: "8.e.f.ip6.arpa." nodefault + # local-zone: "9.e.f.ip6.arpa." nodefault + # local-zone: "a.e.f.ip6.arpa." nodefault + # local-zone: "b.e.f.ip6.arpa." nodefault + # local-zone: "8.b.d.0.1.0.0.2.ip6.arpa." nodefault + # And for 64.100.in-addr.arpa. to 127.100.in-addr.arpa. + + # Add example.com into ipset + # local-zone: "example.com" ipset + + # If Unbound is running service for the local host then it is useful + # to perform lan-wide lookups to the upstream, and unblock the + # long list of local-zones above. If this Unbound is a dns server + # for a network of computers, disabled is better and stops information + # leakage of local lan information. + # unblock-lan-zones: no + + # The insecure-lan-zones option disables validation for + # these zones, as if they were all listed as domain-insecure. + # insecure-lan-zones: no + + # a number of locally served zones can be configured. + # local-zone: + # local-data: "" + # o deny serves local data (if any), else, drops queries. + # o refuse serves local data (if any), else, replies with error. + # o static serves local data, else, nxdomain or nodata answer. + # o transparent gives local data, but resolves normally for other names + # o redirect serves the zone data for any subdomain in the zone. + # o nodefault can be used to normally resolve AS112 zones. + # o typetransparent resolves normally for other types and other names + # o inform acts like transparent, but logs client IP address + # o inform_deny drops queries and logs client IP address + # o inform_redirect redirects queries and logs client IP address + # o always_transparent, always_refuse, always_nxdomain, always_nodata, + # always_deny resolve in that way but ignore local data for + # that name + # o block_a resolves all records normally but returns + # NODATA for A queries and ignores local data for that name + # o always_null returns 0.0.0.0 or ::0 for any name in the zone. + # o noview breaks out of that view towards global local-zones. + # + # defaults are localhost address, reverse for 127.0.0.1 and ::1 + # and nxdomain for AS112 zones. If you configure one of these zones + # the default content is omitted, or you can omit it with 'nodefault'. + # + # If you configure local-data without specifying local-zone, by + # default a transparent local-zone is created for the data. + # + # You can add locally served data with + # local-zone: "local." static + # local-data: "mycomputer.local. IN A 192.0.2.51" + # local-data: 'mytext.local TXT "content of text record"' + # + # You can override certain queries with + # local-data: "adserver.example.com A 127.0.0.1" + # + # You can redirect a domain to a fixed address with + # (this makes example.com, www.example.com, etc, all go to 192.0.2.3) + # local-zone: "example.com" redirect + # local-data: "example.com A 192.0.2.3" + # + # Shorthand to make PTR records, "IPv4 name" or "IPv6 name". + # You can also add PTR records using local-data directly, but then + # you need to do the reverse notation yourself. + # local-data-ptr: "192.0.2.3 www.example.com" + + # tag a localzone with a list of tag names (in "" with spaces between) + # local-zone-tag: "example.com" "tag2 tag3" + + # add a netblock specific override to a localzone, with zone type + # local-zone-override: "example.com" 192.0.2.0/24 refuse + + # service clients over TLS (on the TCP sockets) with plain DNS inside + # the TLS stream, and over HTTPS using HTTP/2 as specified in RFC8484. + # Give the certificate to use and private key. + # default is "" (disabled). requires restart to take effect. + # tls-service-key: "path/to/privatekeyfile.key" + # tls-service-pem: "path/to/publiccertfile.pem" + # tls-port: 853 + # https-port: 443 + + # cipher setting for TLSv1.2 + # tls-ciphers: "DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256" + # cipher setting for TLSv1.3 + # tls-ciphersuites: "TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_8_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256" + + # Pad responses to padded queries received over TLS + # pad-responses: yes + + # Padded responses will be padded to the closest multiple of this size. + # pad-responses-block-size: 468 + + # Use the SNI extension for TLS connections. Default is yes. + # Changing the value requires a reload. + # tls-use-sni: yes + + # Add the secret file for TLS Session Ticket. + # Secret file must be 80 bytes of random data. + # First key use to encrypt and decrypt TLS session tickets. + # Other keys use to decrypt only. + # requires restart to take effect. + # tls-session-ticket-keys: "path/to/secret_file1" + # tls-session-ticket-keys: "path/to/secret_file2" + + # request upstream over TLS (with plain DNS inside the TLS stream). + # Default is no. Can be turned on and off with unbound-control. + # tls-upstream: no + + # Certificates used to authenticate connections made upstream. + # tls-cert-bundle: "" + + # Add system certs to the cert bundle, from the Windows Cert Store + # tls-win-cert: no + # and on other systems, the default openssl certificates + # tls-system-cert: no + + # Pad queries over TLS upstreams + # pad-queries: yes + + # Padded queries will be padded to the closest multiple of this size. + # pad-queries-block-size: 128 + + # Also serve tls on these port numbers (eg. 443, ...), by listing + # tls-additional-port: portno for each of the port numbers. + + # HTTP endpoint to provide DNS-over-HTTPS service on. + # http-endpoint: "/dns-query" + + # HTTP/2 SETTINGS_MAX_CONCURRENT_STREAMS value to use. + # http-max-streams: 100 + + # Maximum number of bytes used for all HTTP/2 query buffers. + # http-query-buffer-size: 4m + + # Maximum number of bytes used for all HTTP/2 response buffers. + # http-response-buffer-size: 4m + + # Set TCP_NODELAY socket option on sockets used for DNS-over-HTTPS + # service. + # http-nodelay: yes + + # Disable TLS for DNS-over-HTTP downstream service. + # http-notls-downstream: no + + # The interfaces that use these listed port numbers will support and + # expect PROXYv2. For UDP and TCP/TLS interfaces. + # proxy-protocol-port: portno for each of the port numbers. + + # DNS64 prefix. Must be specified when DNS64 is use. + # Enable dns64 in module-config. Used to synthesize IPv6 from IPv4. + # dns64-prefix: 64:ff9b::0/96 + + # DNS64 ignore AAAA records for these domains and use A instead. + # dns64-ignore-aaaa: "example.com" + + # ratelimit for uncached, new queries, this limits recursion effort. + # ratelimiting is experimental, and may help against randomqueryflood. + # if 0(default) it is disabled, otherwise state qps allowed per zone. + # ratelimit: 0 + + # ratelimits are tracked in a cache, size in bytes of cache (or k,m). + # ratelimit-size: 4m + # ratelimit cache slabs, reduces lock contention if equal to cpucount. + # ratelimit-slabs: 4 + + # 0 blocks when ratelimited, otherwise let 1/xth traffic through + # ratelimit-factor: 10 + + # Aggressive rate limit when the limit is reached and until demand has + # decreased in a 2 second rate window. + # ratelimit-backoff: no + + # override the ratelimit for a specific domain name. + # give this setting multiple times to have multiple overrides. + # ratelimit-for-domain: example.com 1000 + # override the ratelimits for all domains below a domain name + # can give this multiple times, the name closest to the zone is used. + # ratelimit-below-domain: com 1000 + + # global query ratelimit for all ip addresses. + # feature is experimental. + # if 0(default) it is disabled, otherwise states qps allowed per ip address + # ip-ratelimit: 0 + + # ip ratelimits are tracked in a cache, size in bytes of cache (or k,m). + # ip-ratelimit-size: 4m + # ip ratelimit cache slabs, reduces lock contention if equal to cpucount. + # ip-ratelimit-slabs: 4 + + # 0 blocks when ip is ratelimited, otherwise let 1/xth traffic through + # ip-ratelimit-factor: 10 + + # Aggressive rate limit when the limit is reached and until demand has + # decreased in a 2 second rate window. + # ip-ratelimit-backoff: no + + # Limit the number of connections simultaneous from a netblock + # tcp-connection-limit: 192.0.2.0/24 12 + + # select from the fastest servers this many times out of 1000. 0 means + # the fast server select is disabled. prefetches are not sped up. + # fast-server-permil: 0 + # the number of servers that will be used in the fast server selection. + # fast-server-num: 3 + + # Enable to attach Extended DNS Error codes (RFC8914) to responses. + # ede: no + + # Enable to attach an Extended DNS Error (RFC8914) Code 3 - Stale + # Answer as EDNS0 option to expired responses. + # Note that the ede option above needs to be enabled for this to work. + # ede-serve-expired: no + + # Specific options for ipsecmod. Unbound needs to be configured with + # --enable-ipsecmod for these to take effect. + # + # Enable or disable ipsecmod (it still needs to be defined in + # module-config above). Can be used when ipsecmod needs to be + # enabled/disabled via remote-control(below). + # ipsecmod-enabled: yes + # + # Path to executable external hook. It must be defined when ipsecmod is + # listed in module-config (above). + # ipsecmod-hook: "./my_executable" + # + # When enabled Unbound will reply with SERVFAIL if the return value of + # the ipsecmod-hook is not 0. + # ipsecmod-strict: no + # + # Maximum time to live (TTL) for cached A/AAAA records with IPSECKEY. + # ipsecmod-max-ttl: 3600 + # + # Reply with A/AAAA even if the relevant IPSECKEY is bogus. Mainly used for + # testing. + # ipsecmod-ignore-bogus: no + # + # Domains for which ipsecmod will be triggered. If not defined (default) + # all domains are treated as being allowed. + # ipsecmod-allow: "example.com" + # ipsecmod-allow: "nlnetlabs.nl" + + # Timeout for REUSE entries in milliseconds. + # tcp-reuse-timeout: 60000 + # Max number of queries on a reuse connection. + # max-reuse-tcp-queries: 200 + # Timeout in milliseconds for TCP queries to auth servers. + # tcp-auth-query-timeout: 3000 + + +# Python config section. To enable: +# o use --with-pythonmodule to configure before compiling. +# o list python in the module-config string (above) to enable. +# It can be at the start, it gets validated results, or just before +# the iterator and process before DNSSEC validation. +# o and give a python-script to run. +python: + # Script file to load + # python-script: "@UNBOUND_SHARE_DIR@/ubmodule-tst.py" + +# Dynamic library config section. To enable: +# o use --with-dynlibmodule to configure before compiling. +# o list dynlib in the module-config string (above) to enable. +# It can be placed anywhere, the dynlib module is only a very thin wrapper +# to load modules dynamically. +# o and give a dynlib-file to run. If more than one dynlib entry is listed in +# the module-config then you need one dynlib-file per instance. +dynlib: + # Script file to load + # dynlib-file: "@UNBOUND_SHARE_DIR@/dynlib.so" + +# Remote control config section. +remote-control: + # Enable remote control with unbound-control(8) here. + # set up the keys and certificates with unbound-control-setup. + control-enable: yes + + # what interfaces are listened to for remote control. + # give 0.0.0.0 and ::0 to listen to all interfaces. + # set to an absolute path to use a unix local name pipe, certificates + # are not used for that, so key and cert files need not be present. + control-interface: 127.0.0.1 + # control-interface: ::1 + + # port number for remote control operations. + control-port: 8953 + + # for localhost, you can disable use of TLS by setting this to "no" + # For local sockets this option is ignored, and TLS is not used. + control-use-cert: "no" + + # Unbound server key file. + # server-key-file: "@UNBOUND_RUN_DIR@/unbound_server.key" + + # Unbound server certificate file. + # server-cert-file: "@UNBOUND_RUN_DIR@/unbound_server.pem" + + # unbound-control key file. + # control-key-file: "@UNBOUND_RUN_DIR@/unbound_control.key" + + # unbound-control certificate file. + # control-cert-file: "@UNBOUND_RUN_DIR@/unbound_control.pem" + +# Stub zones. +# Create entries like below, to make all queries for 'example.com' and +# 'example.org' go to the given list of nameservers. list zero or more +# nameservers by hostname or by ipaddress. If you set stub-prime to yes, +# the list is treated as priming hints (default is no). +# With stub-first yes, it attempts without the stub if it fails. +# Consider adding domain-insecure: name and local-zone: name nodefault +# to the server: section if the stub is a locally served zone. +# stub-zone: +# name: "example.com" +# stub-addr: 192.0.2.68 +# stub-prime: no +# stub-first: no +# stub-tcp-upstream: no +# stub-tls-upstream: no +# stub-no-cache: no +# stub-zone: +# name: "example.org" +# stub-host: ns.example.com. + +# Forward zones +# Create entries like below, to make all queries for 'example.com' and +# 'example.org' go to the given list of servers. These servers have to handle +# recursion to other nameservers. List zero or more nameservers by hostname +# or by ipaddress. Use an entry with name "." to forward all queries. +# If you enable forward-first, it attempts without the forward if it fails. +# forward-zone: +# name: "example.com" +# forward-addr: 192.0.2.68 +# forward-addr: 192.0.2.73@5355 # forward to port 5355. +# forward-first: no +# forward-tcp-upstream: no +# forward-tls-upstream: no +# forward-no-cache: no +# forward-zone: +# name: "example.org" +# forward-host: fwd.example.com + +# Authority zones +# The data for these zones is kept locally, from a file or downloaded. +# The data can be served to downstream clients, or used instead of the +# upstream (which saves a lookup to the upstream). The first example +# has a copy of the root for local usage. The second serves example.org +# authoritatively. zonefile: reads from file (and writes to it if you also +# download it), primary: fetches with AXFR and IXFR, or url to zonefile. +# With allow-notify: you can give additional (apart from primaries and urls) +# sources of notifies. +# auth-zone: +# name: "." +# primary: 199.9.14.201 # b.root-servers.net +# primary: 192.33.4.12 # c.root-servers.net +# primary: 199.7.91.13 # d.root-servers.net +# primary: 192.5.5.241 # f.root-servers.net +# primary: 192.112.36.4 # g.root-servers.net +# primary: 193.0.14.129 # k.root-servers.net +# primary: 192.0.47.132 # xfr.cjr.dns.icann.org +# primary: 192.0.32.132 # xfr.lax.dns.icann.org +# primary: 2001:500:200::b # b.root-servers.net +# primary: 2001:500:2::c # c.root-servers.net +# primary: 2001:500:2d::d # d.root-servers.net +# primary: 2001:500:2f::f # f.root-servers.net +# primary: 2001:500:12::d0d # g.root-servers.net +# primary: 2001:7fd::1 # k.root-servers.net +# primary: 2620:0:2830:202::132 # xfr.cjr.dns.icann.org +# primary: 2620:0:2d0:202::132 # xfr.lax.dns.icann.org +# fallback-enabled: yes +# for-downstream: no +# for-upstream: yes +# auth-zone: +# name: "example.org" +# for-downstream: yes +# for-upstream: yes +# zonemd-check: no +# zonemd-reject-absence: no +# zonefile: "example.org.zone" + +# Views +# Create named views. Name must be unique. Map views to requests using +# the access-control-view option. Views can contain zero or more local-zone +# and local-data options. Options from matching views will override global +# options. Global options will be used if no matching view is found. +# With view-first yes, it will try to answer using the global local-zone and +# local-data elements if there is no view specific match. +# view: +# name: "viewname" +# local-zone: "example.com" redirect +# local-data: "example.com A 192.0.2.3" +# local-data-ptr: "192.0.2.3 www.example.com" +# view-first: no +# view: +# name: "anotherview" +# local-zone: "example.com" refuse + +# DNSCrypt +# To enable, use --enable-dnscrypt to configure before compiling. +# Caveats: +# 1. the keys/certs cannot be produced by Unbound. You can use dnscrypt-wrapper +# for this: https://github.com/cofyc/dnscrypt-wrapper/blob/master/README.md#usage +# 2. dnscrypt channel attaches to an interface. you MUST set interfaces to +# listen on `dnscrypt-port` with the follo0wing snippet: +# server: +# interface: 0.0.0.0@443 +# interface: ::0@443 +# +# Finally, `dnscrypt` config has its own section. +# dnscrypt: +# dnscrypt-enable: yes +# dnscrypt-port: 443 +# dnscrypt-provider: 2.dnscrypt-cert.example.com. +# dnscrypt-secret-key: /path/unbound-conf/keys1/1.key +# dnscrypt-secret-key: /path/unbound-conf/keys2/1.key +# dnscrypt-provider-cert: /path/unbound-conf/keys1/1.cert +# dnscrypt-provider-cert: /path/unbound-conf/keys2/1.cert + +# CacheDB +# External backend DB as auxiliary cache. +# To enable, use --enable-cachedb to configure before compiling. +# Specify the backend name +# (default is "testframe", which has no use other than for debugging and +# testing) and backend-specific options. The 'cachedb' module must be +# included in module-config, just before the iterator module. +# cachedb: +# backend: "testframe" +# # secret seed string to calculate hashed keys +# secret-seed: "default" +# +# # For "redis" backend: +# # (to enable, use --with-libhiredis to configure before compiling) +# # redis server's IP address or host name +# redis-server-host: 127.0.0.1 +# # redis server's TCP port +# redis-server-port: 6379 +# # if the server uses a unix socket, set its path, or "" when not used. +# # redis-server-path: "/var/lib/redis/redis-server.sock" +# # if the server uses an AUTH password, specify here, or "" when not used. +# # redis-server-password: "" +# # timeout (in ms) for communication with the redis server +# redis-timeout: 100 +# # set timeout on redis records based on DNS response TTL +# redis-expire-records: no + +# IPSet +# Add specify domain into set via ipset. +# To enable: +# o use --enable-ipset to configure before compiling; +# o Unbound then needs to run as root user. +# ipset: +# # set name for ip v4 addresses +# name-v4: "list-v4" +# # set name for ip v6 addresses +# name-v6: "list-v6" +# + +# Dnstap logging support, if compiled in by using --enable-dnstap to configure. +# To enable, set the dnstap-enable to yes and also some of +# dnstap-log-..-messages to yes. And select an upstream log destination, by +# socket path, TCP or TLS destination. +# dnstap: +# dnstap-enable: no +# # if set to yes frame streams will be used in bidirectional mode +# dnstap-bidirectional: yes +# dnstap-socket-path: "@DNSTAP_SOCKET_PATH@" +# # if "" use the unix socket in dnstap-socket-path, otherwise, +# # set it to "IPaddress[@port]" of the destination. +# dnstap-ip: "" +# # if set to yes if you want to use TLS to dnstap-ip, no for TCP. +# dnstap-tls: yes +# # name for authenticating the upstream server. or "" disabled. +# dnstap-tls-server-name: "" +# # if "", it uses the cert bundle from the main Unbound config. +# dnstap-tls-cert-bundle: "" +# # key file for client authentication, or "" disabled. +# dnstap-tls-client-key-file: "" +# # cert file for client authentication, or "" disabled. +# dnstap-tls-client-cert-file: "" +# dnstap-send-identity: no +# dnstap-send-version: no +# # if "" it uses the hostname. +# dnstap-identity: "" +# # if "" it uses the package version. +# dnstap-version: "" +# dnstap-log-resolver-query-messages: no +# dnstap-log-resolver-response-messages: no +# dnstap-log-client-query-messages: no +# dnstap-log-client-response-messages: no +# dnstap-log-forwarder-query-messages: no +# dnstap-log-forwarder-response-messages: no + +# Response Policy Zones +# RPZ policies. Applied in order of configuration. QNAME, Response IP +# Address, nsdname, nsip and clientip triggers are supported. Supported +# actions are: NXDOMAIN, NODATA, PASSTHRU, DROP, Local Data, tcp-only +# and drop. Policies can be loaded from a file, or using zone +# transfer, or using HTTP. The respip module needs to be added +# to the module-config, e.g.: module-config: "respip validator iterator". +# rpz: +# name: "rpz.example.com" +# zonefile: "rpz.example.com" +# primary: 192.0.2.0 +# allow-notify: 192.0.2.0/32 +# url: http://www.example.com/rpz.example.org.zone +# rpz-action-override: cname +# rpz-cname-override: www.example.org +# rpz-log: yes +# rpz-log-name: "example policy" +# rpz-signal-nxdomain-ra: no +# for-downstream: no +# tags: "example" + +# Blocklist RPZ: returns NXDOMAIN for resolver_blocked_domains (and subdomains) +# and logs only these matches to syslog (tag "blocklist"). Zonefile is templated +# from group_vars/resolvers/main.yml. Requires respip in module-config (above). +rpz: + name: "blocklist.rpz" + zonefile: "blocklist.rpz" + rpz-action-override: nxdomain + rpz-log: yes + rpz-log-name: "blocklist"