Home Explore Blog Models CI



nixpkgs

3rd chunk of `nixos/modules/security/acme/default.md`
92d357b3247968aa554479874c4cfd05924250649d101f0b0000000100000f6d
ACME servers will only hand out wildcard certs over DNS validation.
There are a number of supported DNS providers and servers you can utilise,
see the [lego docs](https://go-acme.github.io/lego/dns/)
for provider/server specific configuration values. For the sake of these
docs, we will provide a fully self-hosted example using bind.

```nix
{
  services.bind = {
    enable = true;
    extraConfig = ''
      include "/var/lib/secrets/dnskeys.conf";
    '';
    zones = [
      rec {
        name = "example.com";
        file = "/var/db/bind/${name}";
        master = true;
        extraConfig = "allow-update { key rfc2136key.example.com.; };";
      }
    ];
  };

  # Now we can configure ACME
  security.acme.acceptTerms = true;
  security.acme.defaults.email = "admin+acme@example.com";
  security.acme.certs."example.com" = {
    domain = "*.example.com";
    dnsProvider = "rfc2136";
    environmentFile = "/var/lib/secrets/certs.secret";
    # We don't need to wait for propagation since this is a local DNS server
    dnsPropagationCheck = false;
  };
}
```

The {file}`dnskeys.conf` and {file}`certs.secret`
must be kept secure and thus you should not keep their contents in your
Nix config. Instead, generate them one time with a systemd service:

```nix
{
  systemd.services.dns-rfc2136-conf = {
    requiredBy = [
      "acme-example.com.service"
      "bind.service"
    ];
    before = [
      "acme-example.com.service"
      "bind.service"
    ];
    unitConfig = {
      ConditionPathExists = "!/var/lib/secrets/dnskeys.conf";
    };
    serviceConfig = {
      Type = "oneshot";
      UMask = 77;
    };
    path = [ pkgs.bind ];
    script = ''
      mkdir -p /var/lib/secrets
      chmod 755 /var/lib/secrets
      tsig-keygen rfc2136key.example.com > /var/lib/secrets/dnskeys.conf
      chown named:root /var/lib/secrets/dnskeys.conf
      chmod 400 /var/lib/secrets/dnskeys.conf

      # extract secret value from the dnskeys.conf
      while read x y; do if [ "$x" = "secret" ]; then secret="''${y:1:''${#y}-3}"; fi; done < /var/lib/secrets/dnskeys.conf

      cat > /var/lib/secrets/certs.secret << EOF
      RFC2136_NAMESERVER='127.0.0.1:53'
      RFC2136_TSIG_ALGORITHM='hmac-sha256.'
      RFC2136_TSIG_KEY='rfc2136key.example.com'
      RFC2136_TSIG_SECRET='$secret'
      EOF
      chmod 400 /var/lib/secrets/certs.secret
    '';
  };
}
```

Now you're all set to generate certs! You should monitor the first invocation
by running `systemctl start acme-example.com.service &
journalctl -fu acme-example.com.service` and watching its log output.

## Using DNS validation with web server virtual hosts {#module-security-acme-config-dns-with-vhosts}

It is possible to use DNS-01 validation with all certificates,
including those automatically configured via the Nginx/Apache
[`enableACME`](#opt-services.nginx.virtualHosts._name_.enableACME)
option. This configuration pattern is fully
supported and part of the module's test suite for Nginx + Apache.

You must follow the guide above on configuring DNS-01 validation
first, however instead of setting the options for one certificate
(e.g. [](#opt-security.acme.certs._name_.dnsProvider))
you will set them as defaults
(e.g. [](#opt-security.acme.defaults.dnsProvider)).

```nix
{
  # Configure ACME appropriately
  security.acme.acceptTerms = true;
  security.acme.defaults.email = "admin+acme@example.com";
  security.acme.defaults = {
    dnsProvider = "rfc2136";
    environmentFile = "/var/lib/secrets/certs.secret";
    # We don't need to wait for propagation since this is a local DNS server
    dnsPropagationCheck = false;
  };

  # For each virtual host you would like to use DNS-01 validation with,
  # set acmeRoot = null
  services.nginx = {
    enable = true;
    virtualHosts = {
      "foo.example.com" = {
        enableACME = true;
        acmeRoot = null;
      };
    };
  };
}
```

And that's it! Next time your configuration is rebuilt, or when

Title: NixOS ACME DNS-01 Validation: BIND Setup and Virtual Host Integration
Summary
This chunk details configuring ACME (Automated Certificate Management Environment) for DNS-01 validation, specifically for wildcard certificates, using a self-hosted BIND DNS server in NixOS. It provides a Nix configuration for enabling BIND and setting up a zone for dynamic updates using TSIG keys. The ACME configuration is shown for a wildcard domain, specifying `rfc2136` as the DNS provider and an `environmentFile` for secrets. Crucially, it demonstrates how to securely generate and manage the `dnskeys.conf` and `certs.secret` files using a systemd service (`dns-rfc2136-conf`) to prevent exposing sensitive information directly in the Nix configuration. The chunk concludes by explaining how to integrate DNS-01 validation with web server virtual hosts (e.g., Nginx's `enableACME` option) by setting the DNS validation options as global `security.acme.defaults` and nullifying the `acmeRoot` for specific virtual hosts.