diff options
| author | Jakub Stachurski <jakub@wilkuu.xyz> | 2026-06-09 15:08:54 +0200 |
|---|---|---|
| committer | Jakub Stachurski <jakub@wilkuu.xyz> | 2026-06-09 15:08:54 +0200 |
| commit | d033778fca80f564c8897df4b79664245a95be84 (patch) | |
| tree | d36f359b42c8326f74a24312e8bbe29c546b8adf /services | |
| parent | 898d1709a1aee731d037e8f8739bc9b72ef87b71 (diff) | |
feat: Desec dynamic DNS and DNS01 acme certs
This feature will allow for a more flexible DNS management through
Desec as opposed to OXXA/Ferox.
Diffstat (limited to 'services')
| -rw-r--r-- | services/ddns.nix | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/services/ddns.nix b/services/ddns.nix new file mode 100644 index 0000000..08135e1 --- /dev/null +++ b/services/ddns.nix @@ -0,0 +1,109 @@ +{ lib, config, ... }: +let + inherit (lib) + mkOption + types + mkEnableOption + mkIf + ; + + cfg = config.wilkuu.services.desecDyn; +in +{ + options.wilkuu.services.desecDyn = { + enable = mkEnableOption "Dynamic DNS management through desec.io"; + + domains = mkOption { + type = types.attrsOf ( + types.submodule { + options = { + # TODO: Decide on defaults + doWildcard = mkEnableOption "requesting a wildcard zone/cert"; + enableDDNS = mkEnableOption "setting A/AAAA records for the domain"; + enableACME = mkEnableOption "requesting certificates for the domain"; + }; + } + ); + description = "List of all domains to be managed through desec.io"; + example = { + "example.dedyn.io" = { + doWildcard = true; + enableDDNS = true; + enableACME = true; + }; + }; + default = { }; + }; + tokenSopsName = mkOption { + type = types.str; + description = "Sops-nix secret name"; + }; + }; + config = + let + ddns-updater-configs = builtins.concatLists ( + builtins.attrValues ( + lib.mapAttrs ( + _name: dcfg: + ( + lib.optional dcfg.doWildcard ({ + provider = "desec"; + domain = "*.${cfg.domain}"; + token = config.sops.placeholder.${cfg.tokenSopsName}; + ip_version = "ipv4"; + }) + ++ [ + { + provider = "desec"; + domain = cfg.domain; + token = config.sops.placeholder.${cfg.tokenSopsName}; + ip_version = "ipv4"; + } + ] + ) + ) (lib.filterAttrs (_: dcfg: dcfg.enableDDNS) cfg.domains) + ) + ); + enableDDNS = ddns-updater-configs != [ ]; + + acme-certs = ( + lib.mapAttrs (dname: dcfg: { + domain = dname; + # TODO: Make a special group so that you can give access to other stuff. + group = config.services.nginx.group; + dnsProvider = "desec"; + environmentFile = config.sops.templates.acme-envfile.path; + extraDomainNames = (lib.optional dcfg.doWildcard "*.${dname}"); + }) (lib.filterAttrs (_: dcfg: dcfg.enableACME) cfg.domains) + ); + + in + mkIf cfg.enable { + users.groups.ddns = mkIf enableDDNS { }; + sops.templates.ddns-updater-config = mkIf (enableDDNS) { + mode = "0440"; + group = "ddns"; + content = lib.generators.toJSON { } { + settings = ddns-updater-configs; + }; + }; + sops.templates.acme-envfile = { + content = '' + DESEC_TOKEN=${config.sops.placeholder.${cfg.tokenSopsName}} + ''; + }; + systemd.services.ddns-updater.serviceConfig = { + SupplementaryGroups = [ "ddns" ]; + }; + services.ddns-updater = { + enable = enableDDNS; + environment = { + SERVER_ENABLED = "no"; + PERIOD = "60m"; + CONFIG_FILEPATH = config.sops.templates.ddns-updater-config.path; + }; + }; + + security.acme.certs = acme-certs; + }; +} |
