about summary refs log tree commit diff
path: root/nixos/modules/services/networking/acme-dns.nix
blob: 08e0e1d17317361f0d038de0fb1dc3e5ce980651 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
{ lib
, config
, pkgs
, ...
}:

let
  cfg = config.services.acme-dns;
  format = pkgs.formats.toml { };
  inherit (lib)
    literalExpression
    mkEnableOption
    mkOption
    mkPackageOption
    types
    ;
  domain = "acme-dns.example.com";
in
{
  options.services.acme-dns = {
    enable = mkEnableOption "acme-dns";

    package = mkPackageOption pkgs "acme-dns" { };

    settings = mkOption {
      description = ''
        Free-form settings written directly to the `acme-dns.cfg` file.
        Refer to <https://github.com/joohoi/acme-dns/blob/master/README.md#configuration> for supported values.
      '';

      default = { };

      type = types.submodule {
        freeformType = format.type;
        options = {
          general = {
            listen = mkOption {
              type = types.str;
              description = "IP+port combination to bind and serve the DNS server on.";
              default = "[::]:53";
              example = "127.0.0.1:53";
            };

            protocol = mkOption {
              type = types.enum [ "both" "both4" "both6" "udp" "udp4" "udp6" "tcp" "tcp4" "tcp6" ];
              description = "Protocols to serve DNS responses on.";
              default = "both";
            };

            domain = mkOption {
              type = types.str;
              description = "Domain name to serve the requests off of.";
              example = domain;
            };

            nsname = mkOption {
              type = types.str;
              description = "Zone name server.";
              example = domain;
            };

            nsadmin = mkOption {
              type = types.str;
              description = "Zone admin email address for `SOA`.";
              example = "admin.example.com";
            };

            records = mkOption {
              type = types.listOf types.str;
              description = "Predefined DNS records served in addition to the `_acme-challenge` TXT records.";
              example = literalExpression ''
                [
                  # replace with your acme-dns server's public IPv4
                  "${domain}. A 198.51.100.1"
                  # replace with your acme-dns server's public IPv6
                  "${domain}. AAAA 2001:db8::1"
                  # ${domain} should resolve any *.${domain} records
                  "${domain}. NS ${domain}."
                ]
              '';
            };
          };

          database = {
            engine = mkOption {
              type = types.enum [ "sqlite3" "postgres" ];
              description = "Database engine to use.";
              default = "sqlite3";
            };
            connection = mkOption {
              type = types.str;
              description = "Database connection string.";
              example = "postgres://user:password@localhost/acmedns";
              default = "/var/lib/acme-dns/acme-dns.db";
            };
          };

          api = {
            ip = mkOption {
              type = types.str;
              description = "IP to bind the HTTP API on.";
              default = "[::]";
              example = "127.0.0.1";
            };

            port = mkOption {
              type = types.port;
              description = "Listen port for the HTTP API.";
              default = 8080;
              # acme-dns expects this value to be a string
              apply = toString;
            };

            disable_registration = mkOption {
              type = types.bool;
              description = "Whether to disable the HTTP registration endpoint.";
              default = false;
              example = true;
            };

            tls = mkOption {
              type = types.enum [ "letsencrypt" "letsencryptstaging" "cert" "none" ];
              description = "TLS backend to use.";
              default = "none";
            };
          };


          logconfig = {
            loglevel = mkOption {
              type = types.enum [ "error" "warning" "info" "debug" ];
              description = "Level to log on.";
              default = "info";
            };
          };
        };
      };
    };
  };

  config = lib.mkIf cfg.enable {
    systemd.packages = [ cfg.package ];
    systemd.services.acme-dns = {
      wantedBy = [ "multi-user.target" ];
      serviceConfig = {
        ExecStart = [ "" "${lib.getExe cfg.package} -c ${format.generate "acme-dns.toml" cfg.settings}" ];
        StateDirectory = "acme-dns";
        WorkingDirectory = "%S/acme-dns";
        DynamicUser = true;
      };
    };
  };
}