setup octodns for automatic dns records
This commit is contained in:
210
modules/services/octodns.nix
Normal file
210
modules/services/octodns.nix
Normal file
@@ -0,0 +1,210 @@
|
||||
{ pkgs, lib, config, ... }:
|
||||
let
|
||||
cfg = config.services.octodns;
|
||||
secrets = config.age.secrets;
|
||||
|
||||
types = {
|
||||
ttlOptions = default: {
|
||||
ttl = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default = default;
|
||||
};
|
||||
};
|
||||
defaults = lib.types.submodule {
|
||||
options = {
|
||||
A = lib.mkOption {
|
||||
type = lib.types.submodule {
|
||||
options = types.ttlOptions cfg.defaults.ttl;
|
||||
};
|
||||
default = { };
|
||||
};
|
||||
AAAA = lib.mkOption {
|
||||
type = lib.types.submodule {
|
||||
options = types.ttlOptions cfg.defaults.ttl;
|
||||
};
|
||||
default = { };
|
||||
};
|
||||
CNAME = lib.mkOption {
|
||||
type = lib.types.submodule {
|
||||
options = types.ttlOptions cfg.defaults.ttl;
|
||||
};
|
||||
default = { };
|
||||
};
|
||||
MX = lib.mkOption {
|
||||
type = lib.types.submodule {
|
||||
options = types.ttlOptions cfg.defaults.ttl;
|
||||
};
|
||||
default = { };
|
||||
};
|
||||
} // (types.ttlOptions 3600);
|
||||
};
|
||||
aRecord = lib.types.submodule {
|
||||
options = {
|
||||
values = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
};
|
||||
ttl = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default = cfg.defaults.A.ttl;
|
||||
};
|
||||
};
|
||||
};
|
||||
aaaaRecord = lib.types.submodule {
|
||||
options = {
|
||||
values = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
};
|
||||
ttl = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default = cfg.defaults.AAAA.ttl;
|
||||
};
|
||||
};
|
||||
};
|
||||
cnameRecord = lib.types.submodule {
|
||||
options = {
|
||||
target = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
};
|
||||
toRoot = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
};
|
||||
ttl = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default = cfg.defaults.CNAME.ttl;
|
||||
};
|
||||
};
|
||||
};
|
||||
mxValue = lib.types.submodule {
|
||||
options = {
|
||||
exchange = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
};
|
||||
preference = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default = 10;
|
||||
};
|
||||
};
|
||||
};
|
||||
mxRecord = lib.types.submodule {
|
||||
options = {
|
||||
values = lib.mkOption {
|
||||
type = lib.types.listOf types.mxValue;
|
||||
default = [ ];
|
||||
};
|
||||
ttl = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default = cfg.defaults.MX.ttl;
|
||||
};
|
||||
};
|
||||
};
|
||||
records = lib.types.submodule {
|
||||
options = {
|
||||
A = lib.mkOption {
|
||||
type = types.aRecord;
|
||||
default = { };
|
||||
};
|
||||
AAAA = lib.mkOption {
|
||||
type = types.aaaaRecord;
|
||||
default = { };
|
||||
};
|
||||
CNAME = lib.mkOption {
|
||||
type = types.cnameRecord;
|
||||
default = { };
|
||||
};
|
||||
MX = lib.mkOption {
|
||||
type = types.mxRecord;
|
||||
default = { };
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
yamlFormat = pkgs.formats.yaml { };
|
||||
|
||||
zoneFile = yamlFormat.generate "octodns-zone"
|
||||
(
|
||||
lib.filterAttrs (_: records: (lib.length records) > 0)
|
||||
(lib.mapAttrs
|
||||
(_: types:
|
||||
lib.filter
|
||||
({ values ? [ ], value ? null, ... }: (lib.length values) > 0 || !(builtins.isNull value))
|
||||
(lib.mapAttrsToList
|
||||
(type: { ttl, ... }@options:
|
||||
if (type == "CNAME")
|
||||
then
|
||||
let
|
||||
inherit (options) target toRoot;
|
||||
value = if toRoot then "${config.networking.domain}." else target;
|
||||
in
|
||||
{ inherit type ttl value; }
|
||||
else
|
||||
{ inherit type ttl; inherit (options) values; }
|
||||
)
|
||||
types
|
||||
)
|
||||
)
|
||||
cfg.records
|
||||
)
|
||||
);
|
||||
|
||||
zonesDir = pkgs.linkFarm "octodns-zones" {
|
||||
"${config.networking.domain}.yaml" = zoneFile;
|
||||
};
|
||||
|
||||
|
||||
configFile = yamlFormat.generate "octodns-config.yaml" {
|
||||
providers = {
|
||||
config = {
|
||||
class = "octodns.provider.yaml.YamlProvider";
|
||||
directory = zonesDir;
|
||||
default_ttl = cfg.defaults.ttl;
|
||||
};
|
||||
hetzner = {
|
||||
class = "octodns_hetzner.HetznerProvider";
|
||||
token = "env/HETZNER_TOKEN";
|
||||
};
|
||||
};
|
||||
|
||||
zones."*" = {
|
||||
sources = [ "config" ];
|
||||
targets = [ "hetzner" ];
|
||||
};
|
||||
};
|
||||
|
||||
octodns = pkgs.octodns.withProviders (_: [
|
||||
pkgs.octodns-providers.hetzner
|
||||
]);
|
||||
in
|
||||
{
|
||||
options.services.octodns = {
|
||||
enable = lib.mkEnableOption "Enable octodns";
|
||||
records = lib.mkOption {
|
||||
type = lib.types.attrsOf types.records;
|
||||
default = { };
|
||||
};
|
||||
defaults = lib.mkOption {
|
||||
type = types.defaults;
|
||||
default = { };
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
systemd.services.octodns = {
|
||||
enable = true;
|
||||
description = "OctoDNS";
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${octodns}/bin/octodns-sync --config-file ${configFile} --doit";
|
||||
DynamicUser = true;
|
||||
EnvironmentFile = secrets.octodns.path;
|
||||
RemainAfterExit = true;
|
||||
};
|
||||
wantedBy = lib.optionals config.services.nginx.enable [ "nginx.service" ];
|
||||
before = lib.optionals config.services.nginx.enable [ "nginx.service" ];
|
||||
};
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user