summaryrefslogtreecommitdiff
path: root/services/ddns.nix
diff options
context:
space:
mode:
authorJakub Stachurski <jakub@wilkuu.xyz>2026-06-09 15:08:54 +0200
committerJakub Stachurski <jakub@wilkuu.xyz>2026-06-09 15:08:54 +0200
commitd033778fca80f564c8897df4b79664245a95be84 (patch)
treed36f359b42c8326f74a24312e8bbe29c546b8adf /services/ddns.nix
parent898d1709a1aee731d037e8f8739bc9b72ef87b71 (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/ddns.nix')
-rw-r--r--services/ddns.nix109
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;
+ };
+}