1
Fork 0

Custom octodns setup!

This commit is contained in:
prescientmoon 2024-07-08 03:06:27 +02:00
parent 9e853e9684
commit fd36e012f9
Signed by: prescientmoon
SSH key fingerprint: SHA256:UUF9JT2s8Xfyv76b8ZuVL7XrmimH4o49p4b+iexbVH4
27 changed files with 434 additions and 59 deletions

74
dns/common.nix Normal file
View file

@ -0,0 +1,74 @@
# DNS entries which do not belong to a particular host
{ lib, ... }:
let
# {{{ Github pages helper
ghPage = at: [{
inherit at; type = "CNAME";
value = "prescientmoon.github.io.";
}];
# }}}
# {{{ Migadu mail DNS setup
migaduMail = at: verifyKey:
let atPrefix = prefix: if at == "" then prefix else "${prefix}.${at}";
in
[
{
inherit at;
ttl = 600;
type = "MX";
value = [
{
exchange = "aspmx1.migadu.com.";
preference = 10;
}
{
exchange = "aspmx2.migadu.com.";
preference = 20;
}
];
}
{
inherit at;
ttl = 600;
type = "TXT";
value = [
"v=spf1 include:spf.migadu.com -all"
"hosted-email-verify=${verifyKey}"
];
}
{
at = atPrefix "_dmarc";
type = "TXT";
value = ''v=DMARC1\; p=quarantine\;'';
ttl = 600;
}
{
at = atPrefix "key1._domainkey";
type = "CNAME";
value = "key1.orbit.moonythm.dev._domainkey.migadu.com.";
ttl = 600;
}
{
at = atPrefix "key2._domainkey";
type = "CNAME";
value = "key2.orbit.moonythm.dev._domainkey.migadu.com.";
ttl = 600;
}
{
at = atPrefix "key3._domainkey";
type = "CNAME";
value = "key3.orbit.moonythm.dev._domainkey.migadu.com.";
ttl = 600;
}
];
# }}}
in
{
satellite.dns.domain = "moonythm.dev";
satellite.dns.records = lib.flatten [
(ghPage "doffycup")
(ghPage "erratic-gate")
(migaduMail "" "kfkhyexd")
(migaduMail "orbit" "24s7lnum")
];
}

20
dns/octodns.yaml Normal file
View file

@ -0,0 +1,20 @@
manager:
max_workers: 10
providers:
zones:
class: octodns.provider.yaml.YamlProvider
default_ttl: 300
enforce_order: true
directory: this is set by nix :3
cloudflare:
class: octodns_cloudflare.CloudflareProvider
token: 'env/CLOUDFLARE_TOKEN'
zones:
moonythm.dev.:
sources:
- zones
targets:
- cloudflare

37
dns/pkgs.nix Normal file
View file

@ -0,0 +1,37 @@
{ pkgs, self, system, ... }: rec {
octodns-zones =
let
nixosConfigModules = pkgs.lib.mapAttrsToList
(_: current: { satellite.dns = current.config.satellite.dns; })
self.nixosConfigurations;
evaluated = pkgs.lib.evalModules {
specialArgs = { inherit pkgs; };
modules = [
../modules/nixos/dns.nix
../modules/common/octodns.nix
./common.nix
]
++ nixosConfigModules;
};
in
evaluated.config.satellite.dns.octodns;
octodns-sync =
pkgs.symlinkJoin {
name = "octodns-sync";
paths = [ self.packages.${system}.octodns ];
buildInputs = [ pkgs.makeWrapper pkgs.yq ];
postBuild = ''
cat ${./octodns.yaml} | yq '.providers.zones.directory="${octodns-zones}"' > $out/config.yaml
wrapProgram $out/bin/octodns-sync \
--run 'export CLOUDFLARE_TOKEN=$( \
sops \
--decrypt \
--extract "[\"cloudflare_dns_api_token\"]" \
./hosts/nixos/common/secrets.yaml \
)' \
--add-flags "--config-file $out/config.yaml"
'';
};
}

View file

@ -106,11 +106,12 @@
let let
pkgs = nixpkgs.legacyPackages.${system}; pkgs = nixpkgs.legacyPackages.${system};
upkgs = inputs.nixpkgs-unstable.legacyPackages.${system}; upkgs = inputs.nixpkgs-unstable.legacyPackages.${system};
myPkgs = import ./pkgs { inherit pkgs upkgs; };
in in
import ./pkgs { inherit pkgs upkgs; } // { myPkgs // {
octodns = upkgs.octodns.withProviders octodns = upkgs.octodns.withProviders
(ps: [ (import ./pkgs { inherit pkgs upkgs; }).octodns-cloudflare ]); (ps: [ myPkgs.octodns-cloudflare ]);
} } // (import ./dns/pkgs.nix) { inherit pkgs self system; }
); );
# }}} # }}}
# {{{ Bootstrapping and other pinned devshells # {{{ Bootstrapping and other pinned devshells

View file

@ -44,7 +44,7 @@ animations {
} }
# Execute apps at launch # Execute apps at launch
exec-once = wezterm & firefox & discocss & spot & obsidian & obsidiantui & smosgui exec-once = wezterm & firefox & discocss & spotify & obsidiantui & smostui
# Without this, xdg-open doesn't work # Without this, xdg-open doesn't work
exec = systemctl --user import-environment PATH && systemctl --user restart xdg-desktop-portal.service exec = systemctl --user import-environment PATH && systemctl --user restart xdg-desktop-portal.service

View file

@ -54,4 +54,7 @@ in
config.allowUnfree = true; config.allowUnfree = true;
}; };
# Root domain used throughout my config
satellite.dns.domain = "moonythm.dev";
} }

View file

@ -23,5 +23,6 @@
forgejo = 8419; forgejo = 8419;
jupyterhub = 8420; jupyterhub = 8420;
guacamole = 8421; guacamole = 8421;
syncthing = 8422;
}; };
} }

View file

@ -1,6 +1,5 @@
{ {
imports = [ ./acme.nix ]; imports = [ ./acme.nix ];
satellite.nginx.domain = "moonythm.dev"; # Root domain used throughout my config
services.nginx = { services.nginx = {
enable = true; enable = true;
recommendedGzipSettings = true; recommendedGzipSettings = true;

View file

@ -28,8 +28,15 @@ in
extraOptions.options.crashReportingEnabled = false; extraOptions.options.crashReportingEnabled = false;
}; };
guiAddress = "127.0.0.1:${toString config.satellite.ports.syncthing}";
settings.gui.insecureSkipHostcheck = true;
}; };
# Expose gui interface via nginx
satellite.nginx.at."syncthing.${config.networking.hostName}".port =
config.satellite.ports.syncthing;
# Syncthing seems to leak memory, so we want to restart it daily. # Syncthing seems to leak memory, so we want to restart it daily.
systemd.services.syncthing.serviceConfig.RuntimeMaxSec = "1d"; systemd.services.syncthing.serviceConfig.RuntimeMaxSec = "1d";

View file

@ -1,6 +1,6 @@
wireless: ENC[AES256_GCM,data:Ib0PdBd2r/DPyE6Ah9NffT8Tw8c2y+seGFrE0e9GkyRaStdYMiiIlWCiaBO0u1HHaVV+2MQ33MnMdqyCGRlqGk45kl0GIwVR5iAiSYnobj/6wcse+kx/+5mzNOHXD1kJRGJBm5+SN9ntiGABNkQXJdn/Qoc/ukY1uaGe2nBeFKmGdD9JL7KfgdI5jYjQYyDbCL9JUszxkXNcplIRBAAy8JDaBVeo9HgI0QDIZToPKwuEeQoA9XzdimrjbCazlZy3ZvjAuoQXmrc1nIRHF5GabSRGTFTnTfcBeW2fGpUxmIhLyucn2DIQBXLm+RDdMLWoqcGbKiLVqKyUXck3ZZyoHMf2b9N52xMUwcS7,iv:ozkDwWmurWTD8TZHGvWL9Yh8cOrP1PzSBkz+1bBZybo=,tag:iGPjRaOoGRcOWJMweTL2yA==,type:str] wireless: ENC[AES256_GCM,data:Ib0PdBd2r/DPyE6Ah9NffT8Tw8c2y+seGFrE0e9GkyRaStdYMiiIlWCiaBO0u1HHaVV+2MQ33MnMdqyCGRlqGk45kl0GIwVR5iAiSYnobj/6wcse+kx/+5mzNOHXD1kJRGJBm5+SN9ntiGABNkQXJdn/Qoc/ukY1uaGe2nBeFKmGdD9JL7KfgdI5jYjQYyDbCL9JUszxkXNcplIRBAAy8JDaBVeo9HgI0QDIZToPKwuEeQoA9XzdimrjbCazlZy3ZvjAuoQXmrc1nIRHF5GabSRGTFTnTfcBeW2fGpUxmIhLyucn2DIQBXLm+RDdMLWoqcGbKiLVqKyUXck3ZZyoHMf2b9N52xMUwcS7,iv:ozkDwWmurWTD8TZHGvWL9Yh8cOrP1PzSBkz+1bBZybo=,tag:iGPjRaOoGRcOWJMweTL2yA==,type:str]
pilot_password: ENC[AES256_GCM,data:PiKJCv5x68O9HFM4UvqLnsSPtqFslBLeAg67OkvFAbw7WaqbXh/p5SQblhPHcJ7jQDc4kI3XesOxruZrfJ0aZNDV1g7MWecgKg==,iv:EVs/m83Zfx2NRQMO52cF6pCe1ETpYfaR6lmXg2Na/DI=,tag:dl2x1aTsaTgtHEZYdW2lmg==,type:str] pilot_password: ENC[AES256_GCM,data:PiKJCv5x68O9HFM4UvqLnsSPtqFslBLeAg67OkvFAbw7WaqbXh/p5SQblhPHcJ7jQDc4kI3XesOxruZrfJ0aZNDV1g7MWecgKg==,iv:EVs/m83Zfx2NRQMO52cF6pCe1ETpYfaR6lmXg2Na/DI=,tag:dl2x1aTsaTgtHEZYdW2lmg==,type:str]
cloudflare_dns_api_token: ENC[AES256_GCM,data:SAIMCvKOpGb5g9s03Xapc08KpOgLI+qlT5oiH/uNGxV+9JFSX3nvmQ==,iv:HFKcmHRG4EEOuJ8gRD0ZWsE18SLaZjewMSLznboLUeI=,tag:z21GURSxvNmZ4qkbri9mDQ==,type:str] cloudflare_dns_api_token: ENC[AES256_GCM,data:QlLxQ/4AQsdqdWJC//FRgbMRqR0Ni51JgCDlyXfNe4pfPtiPs+Gb6Q==,iv:7SS+EzeHk0J1DzVvKxd40AuZUidV2asoQbSr5vyxl+U=,tag:T1KGXOsZ26sICYbrcmU8+w==,type:str]
backup_password: ENC[AES256_GCM,data:Tu7ODTALfQLX7Mbo/BqiM6gaErGv07urwN1iHwGgurKWDuuE1h5NMV5J0cJqW6orTIloVtoZTJgSJ2lZlMcfUQ==,iv:78ha833ZzgEDChIuGjCMVA89U4qY9lWqUmfPCiiQeQM=,tag:u8KWw/060UVP+OOoPhbjRA==,type:str] backup_password: ENC[AES256_GCM,data:Tu7ODTALfQLX7Mbo/BqiM6gaErGv07urwN1iHwGgurKWDuuE1h5NMV5J0cJqW6orTIloVtoZTJgSJ2lZlMcfUQ==,iv:78ha833ZzgEDChIuGjCMVA89U4qY9lWqUmfPCiiQeQM=,tag:u8KWw/060UVP+OOoPhbjRA==,type:str]
sops: sops:
kms: [] kms: []
@ -35,8 +35,8 @@ sops:
WFd4ZFNHWG5Cakw5cU9MRE9HWHQ4THMKr/S7v1Oj3zQziMtI/NuFVm6AaJF5JV5U WFd4ZFNHWG5Cakw5cU9MRE9HWHQ4THMKr/S7v1Oj3zQziMtI/NuFVm6AaJF5JV5U
sEr2nEptYFz4G6YL5psQGXHaKzQKBg+crgKRbYL4akhqT7pfYPC0bQ== sEr2nEptYFz4G6YL5psQGXHaKzQKBg+crgKRbYL4akhqT7pfYPC0bQ==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
lastmodified: "2024-05-29T22:07:18Z" lastmodified: "2024-07-08T00:25:56Z"
mac: ENC[AES256_GCM,data:HQJU1hZs8S4b8LAPdAg1/IuIX3VETXHrE/lKzODjCb/ndWV8Qh5v8OKg4X8xFw13PJpEeQqIznh6qplxMHJYGcYnUK/TSTP+399BZ3M0NLGWyF0vfFn1JIKu7zg8iHpi491/T+I6TDy5hp9+Y6V0sjpZ4pEzhZTwPW9t+NieSbQ=,iv:lNu0aLUO2P+2Mq7kVDGt6llshu5wgb++3VMX91w1a+8=,tag:WSoUh4XnRenvhb+vwLUpRg==,type:str] mac: ENC[AES256_GCM,data:v+p223kf9JLRMJ6moIpA5wZOemJY0+BSnX30MY8g28RBGaR+I7AbUHOrd+GUPAXLqwfqtrFdPt8pULT+fzuxL4wnlB9NPZxCYFMhSGGj8HysmDuytYXfSD1LZWD9fymE4KuyTZHv7I/coEM/iobbvutu9cmTKN05i1atjeh4B30=,iv:hPiQkvbeFjLyzTNoHMqqPikMPuDvT2X2iAo7JBlEpHY=,tag:fdHvvH+qPrv8UhwIA6aZSA==,type:str]
pgp: [] pgp: []
unencrypted_suffix: _unencrypted unencrypted_suffix: _unencrypted
version: 3.8.1 version: 3.8.1

View file

@ -1,4 +1,4 @@
{ { config, ... }: {
imports = [ imports = [
../common/global ../common/global
../common/users/pilot.nix ../common/users/pilot.nix
@ -7,6 +7,7 @@
../common/optional/services/kanata.nix ../common/optional/services/kanata.nix
../common/optional/services/nginx.nix ../common/optional/services/nginx.nix
../common/optional/services/postgres.nix ../common/optional/services/postgres.nix
../common/optional/services/syncthing.nix
../common/optional/services/restic ../common/optional/services/restic
# ./services/commafeed.nix # ./services/commafeed.nix
@ -30,7 +31,6 @@
./services/radicale.nix ./services/radicale.nix
./services/redlib.nix ./services/redlib.nix
./services/smos.nix ./services/smos.nix
./services/syncthing.nix
./services/vaultwarden.nix ./services/vaultwarden.nix
./services/whoogle.nix ./services/whoogle.nix
./services/zfs.nix ./services/zfs.nix
@ -49,4 +49,18 @@
# Bootloader # Bootloader
boot.loader.systemd-boot.enable = true; boot.loader.systemd-boot.enable = true;
# Tailscale internal IP DNS records
satellite.dns.records = [
{
at = config.networking.hostName;
type = "A";
value = "100.93.136.59";
}
{
at = config.networking.hostName;
type = "AAAA";
value = "fd7a:115c:a1e0::e75d:883b";
}
];
} }

View file

@ -1,17 +1,12 @@
{ lib, config, ... }: { lib, config, ... }:
let
port = config.satellite.ports.forgejo;
host = "git.moonythm.dev";
cfg = config.services.forgejo;
in
{ {
sops.secrets.forgejo_mail_password = { sops.secrets.forgejo_mail_password = {
sopsFile = ../secrets.yaml; sopsFile = ../secrets.yaml;
owner = cfg.user; owner = config.services.forgejo.user;
group = cfg.group; group = config.services.forgejo.group;
}; };
satellite.cloudflared.at.${host}.port = port; satellite.cloudflared.at.git.port = config.satellite.ports.forgejo;
services.forgejo = { services.forgejo = {
enable = true; enable = true;
@ -30,9 +25,9 @@ in
default.APP_NAME = "moonforge"; default.APP_NAME = "moonforge";
server = { server = {
DOMAIN = host; DOMAIN = config.satellite.cloudflared.at.git.host;
HTTP_PORT = port; HTTP_PORT = config.satellite.cloudflared.at.git.port;
ROOT_URL = "https://${host}"; ROOT_URL = config.satellite.cloudflared.at.git.host.url;
LANDING_PAGE = "prescientmoon"; # Make my profile the landing page LANDING_PAGE = "prescientmoon"; # Make my profile the landing page
}; };

View file

@ -55,7 +55,7 @@ in
name = "Syncthing"; name = "Syncthing";
subtitle = "File synchronization"; subtitle = "File synchronization";
logo = icon "syncthing.png"; logo = icon "syncthing.png";
url = "https://lapetus.syncthing.moonythm.dev"; url = "https://syncthing.lapetus.moonythm.dev";
} }
{ {
name = "Guacamole"; name = "Guacamole";

View file

@ -18,7 +18,7 @@ in
services.jupyterhub = { services.jupyterhub = {
enable = true; enable = true;
port = config.satellite.ports.jupyterhub; port = config.satellite.cloudflared.at.jupyter.port;
jupyterhubEnv = appEnv; jupyterhubEnv = appEnv;
jupyterlabEnv = appEnv; jupyterlabEnv = appEnv;
@ -71,7 +71,7 @@ in
}; };
# }}} # }}}
# {{{ Networking & storage # {{{ Networking & storage
satellite.cloudflared.at."jupyter.moonythm.dev".port = config.services.jupyterhub.port; satellite.cloudflared.at.jupyter.port = config.services.jupyterhub.port;
environment.persistence."/persist/state".directories = [ environment.persistence."/persist/state".directories = [
"/var/lib/${config.services.jupyterhub.stateDirectory}" "/var/lib/${config.services.jupyterhub.stateDirectory}"

View file

@ -1,11 +1,7 @@
{ config, lib, ... }: { config, lib, ... }:
let
port = config.satellite.ports.microbin;
host = "bin.moonythm.dev";
in
{ {
sops.secrets.microbin_env.sopsFile = ../secrets.yaml; sops.secrets.microbin_env.sopsFile = ../secrets.yaml;
satellite.cloudflared.at.${host}.port = port; satellite.cloudflared.at.bin.port = config.satellite.ports.microbin;
services.microbin = { services.microbin = {
enable = true; enable = true;
@ -16,8 +12,8 @@ in
settings = { settings = {
# High level settings # High level settings
MICROBIN_ADMIN_USERNAME = "prescientmoon"; MICROBIN_ADMIN_USERNAME = "prescientmoon";
MICROBIN_PORT = toString port; MICROBIN_PORT = toString config.satellite.cloudflared.at.bin.port;
MICROBIN_PUBLIC_PATH = "https://bin.moonythm.dev/"; MICROBIN_PUBLIC_PATH = config.satellite.cloudflared.at.bin.url;
MICROBIN_DEFAULT_EXPIRY = "1week"; MICROBIN_DEFAULT_EXPIRY = "1week";
# Disable online features # Disable online features

View file

@ -28,9 +28,22 @@ in
# Configure pounce # Configure pounce
services.pounce = { services.pounce = {
enable = true; enable = true;
externalHost = "irc.moonythm.dev"; externalHost = "irc.${config.satellite.dns.domain}";
bindHost = "irc.moonythm.dev"; bindHost = "irc.${config.satellite.dns.domain}";
certDir = "/var/lib/acme/wildcard-irc.moonythm.dev"; certDir = "/var/lib/acme/wildcard-irc.moonythm.dev";
networks.tilde.config = config.sops.templates."pounce-tilde.cfg".path; networks.tilde.config = config.sops.templates."pounce-tilde.cfg".path;
}; };
satellite.dns.records = [
{
type = "CNAME";
at = "*.irc";
to = "irc";
}
{
type = "CNAME";
at = "irc";
to = config.networking.hostName;
}
];
} }

View file

@ -1,12 +0,0 @@
{ config, ... }:
let port = 8384;
in
{
services.syncthing = {
settings.folders = { };
guiAddress = "127.0.0.1:${toString port}";
settings.gui.insecureSkipHostcheck = true;
};
satellite.nginx.at."lapetus.syncthing".port = port;
}

View file

@ -1,4 +1,4 @@
{ lib, pkgs, ... }: { { config, lib, pkgs, ... }: {
# {{{ Imports # {{{ Imports
imports = [ imports = [
../common/global ../common/global
@ -72,4 +72,18 @@
programs.dconf.enable = true; programs.dconf.enable = true;
services.gnome.evolution-data-server.enable = true; services.gnome.evolution-data-server.enable = true;
services.gnome.gnome-online-accounts.enable = true; services.gnome.gnome-online-accounts.enable = true;
# Tailscale internal IP DNS records
satellite.dns.records = [
# {
# at = config.networking.hostName;
# type = "A";
# value = "100.93.136.59";
# }
# {
# at = config.networking.hostName;
# type = "AAAA";
# value = "fd7a:115c:a1e0::e75d:883b";
# }
];
} }

View file

@ -0,0 +1,46 @@
{ config, pkgs, lib, ... }:
let
format = pkgs.formats.yaml { };
cfg = config.satellite.dns;
in
{
options.satellite.dns.octodns = lib.mkOption {
description = "Derivation building a directory containing all the zone files";
type = lib.types.path;
};
config.satellite.dns.octodns =
let
grouped = builtins.groupBy (entry: entry.zone) cfg.records;
cpLines = lib.mapAttrsToList
(zone: group:
let
grouped = builtins.groupBy (entry: entry.at) group;
contents = lib.mapAttrs
(at: entries: lib.lists.forEach entries
(entry:
let
content =
if builtins.typeOf entry.value == "list"
then { values = entry.value; }
else { inherit (entry) value; };
cloudflare =
if entry.enableCloudflareProxy then {
octodns.cloudflare.proxied = true;
} else { };
in
{ inherit (entry) ttl type; }
// content // cloudflare
))
grouped;
file = format.generate "${zone}.yaml" contents;
in
"cp ${file} $out/${zone}.yaml"
)
grouped;
in
pkgs.runCommand "octodns-zones" { } ''
mkdir $out
${lib.concatStringsSep "\n" cpLines}
'';
}

View file

@ -8,22 +8,44 @@ in
description = "Cloudflare tunnel id to use for the `satellite.cloudflared.at` helper"; description = "Cloudflare tunnel id to use for the `satellite.cloudflared.at` helper";
}; };
domain = lib.mkOption {
description = "Root domain to use as a default for configurations.";
type = lib.types.str;
default = config.satellite.dns.domain;
};
at = lib.mkOption { at = lib.mkOption {
description = "List of hosts to set up ingress rules for"; description = "List of hosts to set up ingress rules for";
default = { }; default = { };
type = lib.types.attrsOf (lib.types.submodule ({ name, ... }: { type = lib.types.attrsOf (lib.types.submodule ({ name, config, ... }: {
options = { options = {
subdomain = lib.mkOption {
description = ''
Subdomain to use for host generation.
Only required if `host` is not set manually.
'';
type = lib.types.str;
default = name;
};
port = lib.mkOption { port = lib.mkOption {
type = lib.types.port;
description = "Localhost port to point the tunnel at"; description = "Localhost port to point the tunnel at";
type = lib.types.port;
}; };
host = lib.mkOption { host = lib.mkOption {
default = name;
type = lib.types.str;
description = "Host to direct traffic from"; description = "Host to direct traffic from";
type = lib.types.str;
default = "${config.subdomain}.${cfg.domain}";
};
url = lib.mkOption {
description = "External https url used to access this host";
type = lib.types.str;
}; };
}; };
config.url = "https://${config.host}";
})); }));
}; };
}; };
@ -34,4 +56,13 @@ in
value = "http://localhost:${toString port}"; value = "http://localhost:${toString port}";
}) })
cfg.at; cfg.at;
config.satellite.dns.records =
let mkDnsRecord = { subdomain, ... }: {
type = "CNAME";
at = subdomain;
zone = cfg.domain;
value = "${cfg.tunnel}.cfargotunnel.com.";
};
in lib.attrsets.mapAttrsToList (_: mkDnsRecord) cfg.at;
} }

View file

@ -7,4 +7,6 @@
nginx = import ./nginx.nix; nginx = import ./nginx.nix;
pilot = import ./pilot.nix; pilot = import ./pilot.nix;
pounce = import ./pounce.nix; pounce = import ./pounce.nix;
dns = import ./dns.nix;
dns-assertions = import ./dns-assertions.nix;
} }

View file

@ -0,0 +1,17 @@
# This must only be loaded on actual Nixos, otherwise `assertions`
# won't be defined when running `evaluateModules`.
{ config, ... }:
let cfg = config.satellite.dns;
in
{
config.assertions =
let assertProperToUsage = config:
{
assertion = (config.to == null) || (config.type == "CNAME");
message = ''
The option `satellite.dns.records[*].to` can only be used with `CNAME` records.
This was not the case for ${config.type} record at ${config.at}.${config.zone}.
'';
};
in builtins.map assertProperToUsage cfg.records;
}

59
modules/nixos/dns.nix Normal file
View file

@ -0,0 +1,59 @@
{ config, pkgs, lib, ... }:
let
format = pkgs.formats.yaml { };
cfg = config.satellite.dns;
in
{
options.satellite.dns = {
domain = lib.mkOption {
description = "Default zone to include records in";
type = lib.types.str;
};
records = lib.mkOption {
description = "List of records to create";
default = [ ];
type = lib.types.listOf (lib.types.submodule ({ config, ... }: {
options = {
at = lib.mkOption {
description = "Subdomain to use for entry";
type = lib.types.nullOr lib.types.str;
};
zone = lib.mkOption {
description = "Zone this record is a part of";
type = lib.types.str;
default = cfg.domain;
};
type = lib.mkOption {
type = lib.types.enum [ "A" "AAAA" "TXT" "CNAME" "MX" ];
description = "The type of the DNS record";
};
to = lib.mkOption {
type = lib.types.nullOr lib.types.str;
description = "Shorthand for CNMAE-ing to a subdomain of the given zone";
default = null;
};
value = lib.mkOption {
type = format.type;
description = "The value assigned to the record, in octodns format";
};
ttl = lib.mkOption {
type = lib.types.int;
description = "The TTL assigned to the record";
default = 300;
};
enableCloudflareProxy = lib.mkEnableOption "proxying using cloudflare";
};
config.value = lib.mkIf (config.type == "CNAME" && config.to != null)
"${config.to}.${config.zone}.";
}));
};
};
}

View file

@ -6,24 +6,28 @@ in
domain = lib.mkOption { domain = lib.mkOption {
description = "Root domain to use as a default for configurations."; description = "Root domain to use as a default for configurations.";
type = lib.types.str; type = lib.types.str;
default = config.satellite.dns.domain;
}; };
at = lib.mkOption { at = lib.mkOption {
description = "Per-subdomain nginx configuration"; description = "Per-subdomain nginx configuration";
type = lib.types.attrsOf (lib.types.submodule ({ name, config, ... }: { type = lib.types.attrsOf (lib.types.submodule ({ name, config, ... }: {
options.name = lib.mkOption { options.subdomain = lib.mkOption {
description = "Attribute name leading to this submodule"; description = ''
Subdomain to use for host generation.
Only required if `host` is not set manually.
'';
type = lib.types.str; type = lib.types.str;
default = name;
}; };
config.name = name;
options.host = lib.mkOption { options.host = lib.mkOption {
description = "Host to route requests from"; description = "Host to route requests from";
type = lib.types.str; type = lib.types.str;
default = "${name}.${cfg.domain}";
}; };
config.host = "${config.subdomain}.${cfg.domain}";
options.url = lib.mkOption { options.url = lib.mkOption {
description = "External https url used to access this host"; description = "External https url used to access this host";
type = lib.types.str; type = lib.types.str;
@ -53,8 +57,8 @@ in
{ {
assertion = (config.port == null) == (config.files != null); assertion = (config.port == null) == (config.files != null);
message = '' message = ''
Precisely one of the options 'satellite.nginx.at.${config.name}.port' Precisely one of the options 'satellite.nginx.at.${config.subdomain}.port'
and 'satellite.nginx.at.${config.name}.files' must be specified. and 'satellite.nginx.at.${config.subdomain}.files' must be specified.
''; '';
}; };
in lib.mapAttrsToList (_: assertSingleTarget) cfg.at; in lib.mapAttrsToList (_: assertSingleTarget) cfg.at;
@ -81,5 +85,14 @@ in
} // extra; } // extra;
}; };
in lib.attrsets.mapAttrs' (_: mkNginxConfig) cfg.at; in lib.attrsets.mapAttrs' (_: mkNginxConfig) cfg.at;
satellite.dns.records =
let mkDnsRecord = { subdomain, ... }: {
type = "CNAME";
zone = cfg.domain;
at = subdomain;
to = config.networking.hostName;
};
in lib.attrsets.mapAttrsToList (_: mkDnsRecord) cfg.at;
}; };
} }

View file

@ -1,7 +1,7 @@
# Custom packages, that can be defined similarly to ones from nixpkgs # Custom packages, that can be defined similarly to ones from nixpkgs
# You can build them using 'nix build .#example' or (legacy) 'nix-build -A example' # You can build them using 'nix build .#example' or (legacy) 'nix-build -A example'
{ pkgs ? (import ../nixpkgs.nix) { }, upkgs ? pkgs }: { pkgs ? (import ../nixpkgs.nix) { }, upkgs ? pkgs, ... }:
let plymouthThemes = pkgs.callPackage (import ./plymouth-themes.nix) { }; in let plymouthThemes = pkgs.callPackage (import ./plymouth-themes.nix) { }; in
{ {
# example = pkgs.callPackage (import ./example.nix) {}; # example = pkgs.callPackage (import ./example.nix) {};

View file

@ -0,0 +1,45 @@
{ lib
, buildPythonPackage
, fetchFromGitHub
, octodns
, pytestCheckHook
, pythonOlder
, dnspython
, setuptools
, requests
, requests-mock
}:
buildPythonPackage rec {
pname = "octodns-cloudflare";
version = "unstable-2024-05-31";
pyproject = true;
disabled = pythonOlder "3.8";
src = fetchFromGitHub {
owner = "octodns";
repo = "octodns-cloudflare";
rev = "3c01938e280767f433eb276a75d6b02c152c02af";
sha256 = "1dnvyvf6mlpqcsrj11192li2mhqfs8w6pvaqmsy3jsqjqczmgmf5";
};
nativeBuildInputs = [
setuptools
];
propagatedBuildInputs = [
octodns
dnspython
requests
];
env.OCTODNS_RELEASE = 1;
pythonImportsCheck = [ "octodns_cloudflare" ];
nativeCheckInputs = [
pytestCheckHook
requests-mock
];
}

View file

@ -34,7 +34,7 @@ yt IN CNAME lapetus
*.irc IN CNAME irc *.irc IN CNAME irc
; Tunnel used by lapetus ; Tunnel used by lapetus
tunnel.lapetus IN CNAME 347d9ead-a523-4f8b-bca7-3066e31e2952.cfargotunnel.com tunnel.lapetus IN CNAME 347d9ead-a523-4f8b-bca7-3066e31e2952.cfargotunnel.com.
; lapetus services using cloudflare tunnels ; lapetus services using cloudflare tunnels
bin IN CNAME tunnel.lapetus bin IN CNAME tunnel.lapetus