Self-host your own digital island

support multiple DNS zones

+48 -46
modules/dns.nix
···
config.dns = lib.mkIf cfg.dns.enable {
enable = true;
-
soa.serial = lib.mkDefault 0;
-
records = builtins.concatMap (ns: [
-
{
-
name = "@";
-
type = "NS";
-
data = ns;
-
}
-
{
-
name = ns;
-
type = "A";
-
data = cfg.serverIpv4;
-
}
-
]) [ "ns1" "ns2" ] ++
-
[
-
{
-
name = "www";
-
type = "CNAME";
-
data = "@";
-
}
-
{
-
name = "@";
-
type = "A";
-
data = cfg.serverIpv4;
-
}
-
{
-
name = "@";
-
type = "AAAA";
-
data = cfg.serverIpv6;
-
}
-
{
-
name = "vps";
-
type = "A";
-
data = cfg.serverIpv4;
-
}
-
{
-
name = "vps";
-
type = "AAAA";
-
data = cfg.serverIpv6;
-
}
-
-
{
-
name = "@";
-
type = "LOC";
-
data = "52 12 40.4 N 0 5 31.9 E 22m 10m 10m 10m";
-
}
-
];
};
}
···
config.dns = lib.mkIf cfg.dns.enable {
enable = true;
+
zones.${config.networking.domain} = {
+
soa.serial = lib.mkDefault 0;
+
records = builtins.concatMap (ns: [
+
{
+
name = "@";
+
type = "NS";
+
data = ns;
+
}
+
{
+
name = ns;
+
type = "A";
+
data = cfg.serverIpv4;
+
}
+
]) [ "ns1" "ns2" ] ++
+
[
+
{
+
name = "www";
+
type = "CNAME";
+
data = "@";
+
}
+
{
+
name = "@";
+
type = "A";
+
data = cfg.serverIpv4;
+
}
+
{
+
name = "@";
+
type = "AAAA";
+
data = cfg.serverIpv6;
+
}
+
{
+
name = "vps";
+
type = "A";
+
data = cfg.serverIpv4;
+
}
+
{
+
name = "vps";
+
type = "AAAA";
+
data = cfg.serverIpv6;
+
}
+
+
{
+
name = "@";
+
type = "LOC";
+
data = "52 12 40.4 N 0 5 31.9 E 22m 10m 10m 10m";
+
}
+
];
+
};
};
}
+11 -8
modules/dns/bind.nix
···
enable = true;
# recursive resolver
# cacheNetworks = [ "0.0.0.0/0" ];
-
zones."${config.networking.domain}" = {
-
master = true;
-
file = import ./zonefile.nix { inherit pkgs config lib; };
-
# axfr zone transfer
-
slaves = [
-
"127.0.0.1"
-
];
-
};
};
}
···
enable = true;
# recursive resolver
# cacheNetworks = [ "0.0.0.0/0" ];
+
zones =
+
let mapZones = zonename: zone:
+
{
+
master = true;
+
file = import ./zonefile.nix { inherit pkgs config lib zonename zone; };
+
# axfr zone transfer
+
slaves = [
+
"127.0.0.1"
+
];
+
};
+
in builtins.mapAttrs mapZones cfg.zones;
};
}
+29 -28
modules/dns/default.nix
···
with lib;
-
{
-
imports = [ ./bind.nix ];
-
-
options.dns = {
-
enable = lib.mkEnableOption "DNS server";
-
server = mkOption {
-
type = types.enum [ "bind" ];
-
default = "bind";
-
};
-
domain = mkOption {
-
type = types.str;
-
default = config.networking.domain;
-
};
ttl = mkOption {
type = types.int;
default = 3600; # 1hr
···
};
};
records =
-
let recordOpts = {
-
options = {
-
name = mkOption {
-
type = types.str;
-
};
-
ttl = mkOption {
-
type = with types; nullOr int;
-
default = null;
-
};
-
type = mkOption {
-
type = types.str;
-
};
-
data = mkOption {
-
type = types.str;
-
};
};
};
in mkOption {
type = with types; listOf (submodule recordOpts);
default = [ ];
};
};
}
···
with lib;
+
let
+
zoneOptions.options = {
ttl = mkOption {
type = types.int;
default = 3600; # 1hr
···
};
};
records =
+
let recordOpts.options = {
+
name = mkOption {
+
type = types.str;
+
};
+
ttl = mkOption {
+
type = with types; nullOr int;
+
default = null;
+
};
+
type = mkOption {
+
type = types.str;
+
};
+
data = mkOption {
+
type = types.str;
};
};
in mkOption {
type = with types; listOf (submodule recordOpts);
default = [ ];
};
+
};
+
in
+
{
+
imports = [ ./bind.nix ];
+
+
options.dns = {
+
enable = lib.mkEnableOption "DNS server";
+
server = mkOption {
+
type = types.enum [ "bind" ];
+
default = "bind";
+
};
+
zones = mkOption {
+
type = with types; attrsOf (submodule zoneOptions);
+
};
};
}
+20 -12
modules/dns/zonefile.nix
···
-
{ pkgs, config, lib, ... }:
-
let cfg = config.dns; in pkgs.writeTextFile {
-
name = "zonefile";
text = ''
-
$ORIGIN ${cfg.domain}.
-
$TTL ${builtins.toString cfg.ttl}
-
@ IN SOA ${cfg.soa.ns} ${cfg.soa.email} (
-
${builtins.toString cfg.soa.serial}
-
${builtins.toString cfg.soa.refresh}
-
${builtins.toString cfg.soa.retry}
-
${builtins.toString cfg.soa.expire}
-
${builtins.toString cfg.soa.negativeCacheTtl}
)
${
lib.strings.concatStringsSep "\n"
-
(builtins.map (rr: "${rr.name} IN ${builtins.toString rr.ttl} ${rr.type} ${rr.data}") cfg.records)
}
'';
}
···
+
{
+
pkgs,
+
config,
+
lib,
+
zonename,
+
zone,
+
...
+
}:
+
pkgs.writeTextFile {
+
name = "zonefile-${zonename}";
+
destination = "/${zonename}";
text = ''
+
$ORIGIN ${zonename}.
+
$TTL ${builtins.toString zone.ttl}
+
@ IN SOA ${zone.soa.ns} ${zone.soa.email} (
+
${builtins.toString zone.soa.serial}
+
${builtins.toString zone.soa.refresh}
+
${builtins.toString zone.soa.retry}
+
${builtins.toString zone.soa.expire}
+
${builtins.toString zone.soa.negativeCacheTtl}
)
${
lib.strings.concatStringsSep "\n"
+
(builtins.map (rr: "${rr.name} IN ${builtins.toString rr.ttl} ${rr.type} ${rr.data}") zone.records)
}
'';
}
+1 -1
modules/gitea.nix
···
SystemCallFilter = lib.mkForce [];
};
-
dns.records = [
{
name = "git";
type = "CNAME";
···
SystemCallFilter = lib.mkForce [];
};
+
dns.zones.${config.networking.domain}.records = [
{
name = "git";
type = "CNAME";
+1 -1
modules/mailserver.nix
···
return 301 $scheme://${domain}$request_uri;
'';
-
dns.records = [
{
name = "mail";
type = "A";
···
return 301 $scheme://${domain}$request_uri;
'';
+
dns.zones.${config.networking.domain}.records = [
{
name = "mail";
type = "A";
+1 -1
modules/mastodon.nix
···
};
};
-
dns.records = [
{
name = "mastodon";
type = "CNAME";
···
};
};
+
dns.zones.${config.networking.domain}.records = [
{
name = "mastodon";
type = "CNAME";
+1 -1
modules/matrix.nix
···
];
};
-
dns.records = [
{
name = "matrix";
type = "CNAME";
···
];
};
+
dns.zones.${config.networking.domain}.records = [
{
name = "matrix";
type = "CNAME";
+1 -1
modules/turn.nix
···
};
users.groups."turnserver".members = [ config.services.nginx.user ];
-
dns.records = [
{
name = "turn";
type = "CNAME";
···
};
users.groups."turnserver".members = [ config.services.nginx.user ];
+
dns.zones.${config.networking.domain}.records = [
{
name = "turn";
type = "CNAME";