Tons of stuff, including 23.05 -> 23.11
This commit is contained in:
parent
0027566304
commit
7a73028ad2
|
@ -4,7 +4,8 @@ with lib;
|
||||||
let
|
let
|
||||||
hostname = config.instance.hostname;
|
hostname = config.instance.hostname;
|
||||||
localDomain = "fudo.org";
|
localDomain = "fudo.org";
|
||||||
serviceSecrets = config.fudo.secrets.files.service-secrets."${hostname}";
|
|
||||||
|
domainSecrets = config.fudo.secrets.files.domain-secrets."${localDomain}";
|
||||||
|
|
||||||
inherit (pkgs.lib) getDomainHosts getHostIpv4 getHostIpv6 getHostFqdn;
|
inherit (pkgs.lib) getDomainHosts getHostIpv4 getHostIpv6 getHostFqdn;
|
||||||
|
|
||||||
|
@ -16,7 +17,10 @@ let
|
||||||
|
|
||||||
defaultHost = "germany";
|
defaultHost = "germany";
|
||||||
|
|
||||||
mastodonHostname = "mastodon.fudo.org";
|
mastodonHostname = "fudo.live";
|
||||||
|
|
||||||
|
lemmyHost = "germany";
|
||||||
|
lemmyHostname = "fudo.social";
|
||||||
|
|
||||||
servedDomains = [
|
servedDomains = [
|
||||||
"fudo.org"
|
"fudo.org"
|
||||||
|
@ -24,50 +28,54 @@ let
|
||||||
"selby.ca"
|
"selby.ca"
|
||||||
"fudo.ca"
|
"fudo.ca"
|
||||||
"fudo.im"
|
"fudo.im"
|
||||||
|
"fudo.live"
|
||||||
|
"fudo.social"
|
||||||
"stewartsoundservices.ca"
|
"stewartsoundservices.ca"
|
||||||
];
|
];
|
||||||
|
|
||||||
in {
|
in {
|
||||||
imports = [
|
imports = [
|
||||||
(import ./fudo.org/authentik.nix { inherit authentikHost; })
|
(import ./fudo.org/authentik.nix {
|
||||||
|
inherit authentikHost;
|
||||||
|
authentikImage = "ghcr.io/goauthentik/server:2023.10.6";
|
||||||
|
})
|
||||||
(import ./fudo.org/mastodon.nix {
|
(import ./fudo.org/mastodon.nix {
|
||||||
mastodonHost = "legatus";
|
mastodonHost = "germany";
|
||||||
mastodonHostname = mastodonHostname;
|
mastodonHostname = mastodonHostname;
|
||||||
mastodonWebDomain = "fudo.org";
|
mastodonWebDomain = mastodonHostname;
|
||||||
mastodonOidcClientId = serviceSecrets."mastodon-oidc.clientid";
|
mastodonOidcClientId = domainSecrets."mastodon-oidc.clientid";
|
||||||
mastodonOidcClientSecret = serviceSecrets."mastodon-oidc.secret";
|
mastodonOidcClientSecret = domainSecrets."mastodon-oidc.secret";
|
||||||
})
|
})
|
||||||
(import ./fudo.org/nextcloud.nix {
|
(import ./fudo.org/nextcloud.nix {
|
||||||
nextcloudHost = "legatus";
|
nextcloudHost = "legatus";
|
||||||
nextcloudHostname = "cloud.fudo.org";
|
nextcloudHostname = "cloud.fudo.org";
|
||||||
nextcloudPackage = pkgs.nextcloud27;
|
nextcloudPackage = pkgs.nextcloud28;
|
||||||
})
|
})
|
||||||
(import ./fudo.org/matrix.nix {
|
(import ./fudo.org/matrix.nix {
|
||||||
matrixHost = "legatus";
|
matrixHost = "germany";
|
||||||
matrixServerName = "fudo.org";
|
matrixServerName = "fudo.im";
|
||||||
openIdClientId = readFile serviceSecrets."matrix-oidc.clientid";
|
openIdClientId = readFile domainSecrets."matrix-oidc.clientid";
|
||||||
openIdClientSecret = readFile serviceSecrets."matrix-oidc.secret";
|
openIdClientSecret = readFile domainSecrets."matrix-oidc.secret";
|
||||||
})
|
})
|
||||||
(import ./fudo.org/mail-server.nix (rec {
|
(import ./fudo.org/mail-server.nix (rec {
|
||||||
primaryMailserver = "germany";
|
primaryMailserver = "france";
|
||||||
primaryDomain = "test.fudo.org";
|
primaryDomain = "fudo.org";
|
||||||
authentikServer = "authentik.fudo.org";
|
authentikServer = "authentik.fudo.org";
|
||||||
ldapBase = "dc=fudo,dc=org";
|
ldapBase = "dc=fudo,dc=org";
|
||||||
ldapBindDn = "cn=userdb,ou=users,${ldapBase}";
|
ldapBindDn = "cn=userdb,ou=users,${ldapBase}";
|
||||||
ldapBindPwFile =
|
ldapBindPwFile = domainSecrets."ldap-bind.passwd";
|
||||||
config.fudo.secrets.files.domain-secrets."${primaryDomain}"."ldap-bind.passwd";
|
|
||||||
saslDomain = "FUDO.ORG";
|
saslDomain = "FUDO.ORG";
|
||||||
authentikOutpostToken =
|
authentikOutpostToken = domainSecrets."authentik-ldap.token";
|
||||||
config.fudo.secrets.files.domain-secrets."${primaryDomain}"."authentik-ldap.token";
|
|
||||||
inherit servedDomains;
|
inherit servedDomains;
|
||||||
# TODO: FIXME!
|
dkimRecord = ''
|
||||||
dkimRecord = "";
|
mail._domainkey IN TXT ( "v=DKIM1;k=rsa;p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwoCgHwsfuu0lhj9Ayj4ntoy0bdcGBNsV46qoKbd8E8FKsJF5rL4EoytwXEFcKJwT3E+o3/BsZGi9J5irtjlfIhnxnPlhVRS3R/834NDSQyuwGTxAfhPOklhA0cTYA+4x2oGwAuraz+On2REDeSymMccXFDsTugEHVvn6qaeqkJwIDAQAB" );'';
|
||||||
}))
|
}))
|
||||||
];
|
];
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
# All Fudo hosts should redirect selby.ca to the selbyhomecentre website.
|
# All Fudo hosts should redirect selby.ca to the selbyhomecentre website.
|
||||||
services.nginx.virtualHosts = {
|
services = {
|
||||||
|
nginx.virtualHosts = {
|
||||||
# Pass requests to selby on to selbyhomecentre
|
# Pass requests to selby on to selbyhomecentre
|
||||||
"selby.ca".locations."/".return =
|
"selby.ca".locations."/".return =
|
||||||
"301 https://selbyhomecentre.com$request_uri";
|
"301 https://selbyhomecentre.com$request_uri";
|
||||||
|
@ -86,24 +94,51 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
lemmyDocker = {
|
||||||
|
enable = config.instance.hostname == lemmyHost;
|
||||||
|
hostname = lemmyHostname;
|
||||||
|
site-name = "Fudo Lemmy";
|
||||||
|
version = "0.19.2";
|
||||||
|
smtp-server = "mail.fudo.org:587";
|
||||||
|
docker-images = {
|
||||||
|
pictrs = "asonix/pictrs:0.5.1";
|
||||||
|
postgres = "postgres:15-alpine";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
fudo = {
|
fudo = {
|
||||||
services = {
|
services = {
|
||||||
|
# TEMPORARY
|
||||||
|
mail-server.enable = false;
|
||||||
|
|
||||||
jabber = {
|
jabber = {
|
||||||
domain = "jabber.fudo.org";
|
domain = "jabber.fudo.org";
|
||||||
ldap.servers =
|
ldap.servers =
|
||||||
map (host: "${host}.${localDomain}") domain.ldap-servers;
|
map (host: "${host}.${localDomain}") domain.ldap-servers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
metrics.grafana = {
|
||||||
|
oauth = {
|
||||||
|
hostname = "authentik.fudo.org";
|
||||||
|
client-id = domainSecrets."grafana-oid-client-id";
|
||||||
|
client-secret = domainSecrets."grafana-oid-client-secret";
|
||||||
|
slug = "grafana-metrics";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
authoritative-dns = {
|
authoritative-dns = {
|
||||||
enable = hostname == primaryNameserver;
|
enable = hostname == primaryNameserver;
|
||||||
|
|
||||||
|
enable-notifications = true;
|
||||||
|
|
||||||
container = {
|
container = {
|
||||||
hostname = "nameserver";
|
hostname = "nameserver";
|
||||||
interface = "enp5s0f0";
|
interface = "enp5s0f0";
|
||||||
};
|
};
|
||||||
|
|
||||||
nameservers = {
|
nameservers = {
|
||||||
primary = primaryNameserver;
|
primary = "nameserver";
|
||||||
external = map (hostname: {
|
external = map (hostname: {
|
||||||
inherit (config.fudo.zones."fudo.org".hosts."${hostname}")
|
inherit (config.fudo.zones."fudo.org".hosts."${hostname}")
|
||||||
ipv4-address ipv6-address description;
|
ipv4-address ipv6-address description;
|
||||||
|
@ -124,9 +159,10 @@ in {
|
||||||
description = "fudo.org";
|
description = "fudo.org";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# TODO: Fix email FFS!
|
||||||
fudoMailservers = {
|
fudoMailservers = {
|
||||||
smtp-servers = [ "smtp.fudo.org." ];
|
smtp-servers = [ "mail.fudo.org." ];
|
||||||
imap-servers = [ "imap.fudo.org." ];
|
imap-servers = [ "mail.fudo.org." ];
|
||||||
};
|
};
|
||||||
|
|
||||||
mkDomain = domain: extraConfig:
|
mkDomain = domain: extraConfig:
|
||||||
|
@ -147,6 +183,7 @@ in {
|
||||||
"stewartsoundservices.ca" =
|
"stewartsoundservices.ca" =
|
||||||
mkDomain "stewartsoundservices.ca" { mail = fudoMailservers; };
|
mkDomain "stewartsoundservices.ca" { mail = fudoMailservers; };
|
||||||
"fudo.live" = mkDomain "fudo.live" { mail = fudoMailservers; };
|
"fudo.live" = mkDomain "fudo.live" { mail = fudoMailservers; };
|
||||||
|
"fudo.social" = mkDomain "fudo.social" { mail = fudoMailservers; };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{ authentikHost, ... }:
|
{ authentikHost, authentikImage, ... }:
|
||||||
|
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ in {
|
||||||
authentikContainer = mkIf isAuthentik {
|
authentikContainer = mkIf isAuthentik {
|
||||||
enable = true;
|
enable = true;
|
||||||
images = {
|
images = {
|
||||||
authentik = "ghcr.io/goauthentik/server:2023.8.3";
|
authentik = authentikImage;
|
||||||
postgres = "docker.io/library/postgres:12-alpine";
|
postgres = "docker.io/library/postgres:12-alpine";
|
||||||
redis = "docker.io/library/redis:alpine";
|
redis = "docker.io/library/redis:alpine";
|
||||||
};
|
};
|
||||||
|
@ -50,32 +50,8 @@ in {
|
||||||
proxyWebsockets = true;
|
proxyWebsockets = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
"fudo.ldap.fudo.org" = {
|
|
||||||
enableACME = true;
|
|
||||||
forceSSL = true;
|
|
||||||
locations."/".return = "403 Forbidden";
|
|
||||||
};
|
|
||||||
"selby.ldap.fudo.org" = {
|
|
||||||
enableACME = true;
|
|
||||||
forceSSL = true;
|
|
||||||
locations."/".return = "403 Forbidden";
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
security.acme.certs = mkIf isAuthentik
|
|
||||||
(genAttrs [ authentikHostname "fudo.ldap.fudo.org" "selby.ldap.fudo.org" ]
|
|
||||||
(domain: {
|
|
||||||
postRun = let
|
|
||||||
dst =
|
|
||||||
"${config.services.authentikContainer.state-directory}/certs/${domain}";
|
|
||||||
in ''
|
|
||||||
mkdir -p ${dst}
|
|
||||||
cp -v {cert,chain,fullchain,full,key}.pem ${dst}/
|
|
||||||
cp -v key.pem ${dst}/privkey.pem
|
|
||||||
chown -R authentik ${dst}
|
|
||||||
'';
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,19 +16,17 @@ in {
|
||||||
after = [ "podman.service" ];
|
after = [ "podman.service" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
fudo = {
|
# security.acme.certs = {
|
||||||
acme.host-domains = {
|
# "imap.${primaryDomain}".extraDomainNames = [ "mail.${primaryDomain}" ];
|
||||||
"imap.${primaryDomain}".extra-domain = [ "mail.${primaryDomain}" ];
|
# "smtp.${primaryDomain}".extraDomainNames = [ "mail.${primaryDomain}" ];
|
||||||
"smtp.${primaryDomain}".extra-domain = [ "mail.${primaryDomain}" ];
|
# };
|
||||||
};
|
|
||||||
|
|
||||||
|
fudo = {
|
||||||
zones."${primaryDomain}" = let
|
zones."${primaryDomain}" = let
|
||||||
mailserverDomain = config.fudo.hosts."${primaryMailserver}".domain;
|
mailserverDomain = config.fudo.hosts."${primaryMailserver}".domain;
|
||||||
mailserver =
|
|
||||||
config.fudo.domains."${mailserverDomain}".primary-mailserver;
|
|
||||||
mailserverIps = {
|
mailserverIps = {
|
||||||
ipv4-address = getHostIpv4 mailserver;
|
ipv4-address = getHostIpv4 primaryMailserver;
|
||||||
ipv6-address = getHostIpv6 mailserver;
|
ipv6-address = getHostIpv6 primaryMailserver;
|
||||||
};
|
};
|
||||||
srvRecord = host: port: [{ inherit host port; }];
|
srvRecord = host: port: [{ inherit host port; }];
|
||||||
in {
|
in {
|
||||||
|
@ -66,6 +64,7 @@ in {
|
||||||
enable = hostname == primaryMailserver;
|
enable = hostname == primaryMailserver;
|
||||||
debug = true;
|
debug = true;
|
||||||
primary-domain = primaryDomain;
|
primary-domain = primaryDomain;
|
||||||
|
extra-domains = servedDomains;
|
||||||
sasl-domain = saslDomain;
|
sasl-domain = saslDomain;
|
||||||
trusted-networks = config.instance.local-networks;
|
trusted-networks = config.instance.local-networks;
|
||||||
smtp = {
|
smtp = {
|
||||||
|
@ -110,12 +109,17 @@ in {
|
||||||
services.nginx = mkIf (hostname == primaryMailserver) {
|
services.nginx = mkIf (hostname == primaryMailserver) {
|
||||||
enable = true;
|
enable = true;
|
||||||
virtualHosts = {
|
virtualHosts = {
|
||||||
"smtp.${primaryDomain}" = {
|
"imap.${primaryDomain}" = {
|
||||||
enableACME = true;
|
enableACME = true;
|
||||||
forceSSL = true;
|
forceSSL = true;
|
||||||
locations."/".return = "301 https://webmail.${primaryDomain}";
|
locations."/".return = "301 https://webmail.${primaryDomain}";
|
||||||
};
|
};
|
||||||
"imap.${primaryDomain}" = {
|
"mail.${primaryDomain}" = {
|
||||||
|
enableACME = true;
|
||||||
|
forceSSL = true;
|
||||||
|
locations."/".return = "301 https://webmail.${primaryDomain}";
|
||||||
|
};
|
||||||
|
"smtp.${primaryDomain}" = {
|
||||||
enableACME = true;
|
enableACME = true;
|
||||||
forceSSL = true;
|
forceSSL = true;
|
||||||
locations."/".return = "301 https://webmail.${primaryDomain}";
|
locations."/".return = "301 https://webmail.${primaryDomain}";
|
||||||
|
|
|
@ -5,16 +5,18 @@
|
||||||
with lib;
|
with lib;
|
||||||
let
|
let
|
||||||
hostname = config.instance.hostname;
|
hostname = config.instance.hostname;
|
||||||
domainName = "fudo.org";
|
domainName = "fudo.im";
|
||||||
zoneName = config.fudo.domains."${domainName}".zone;
|
zoneName = config.fudo.domains."${domainName}".zone;
|
||||||
isMatrix = hostname == matrixHost;
|
isMatrix = hostname == matrixHost;
|
||||||
matrixFqdn = "matrix.${domainName}";
|
matrixFqdn = "matrix.${domainName}";
|
||||||
in {
|
in {
|
||||||
config = {
|
config = {
|
||||||
fudo = {
|
fudo = {
|
||||||
zones."${zoneName}".aliases = {
|
zones."${zoneName}".aliases =
|
||||||
element = matrixHost;
|
let matrixHostFqdn = pkgs.lib.getHostFqdn matrixHost;
|
||||||
matrix = matrixHost;
|
in {
|
||||||
|
web = "${matrixHostFqdn}.";
|
||||||
|
matrix = "${matrixHostFqdn}.";
|
||||||
};
|
};
|
||||||
|
|
||||||
services.matrix = mkIf isMatrix {
|
services.matrix = mkIf isMatrix {
|
||||||
|
@ -31,7 +33,7 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = [ 8008 8448 ];
|
networking.firewall.allowedTCPPorts = [ 80 443 8008 8448 ];
|
||||||
|
|
||||||
services.nginx.virtualHosts = mkIf isMatrix {
|
services.nginx.virtualHosts = mkIf isMatrix {
|
||||||
"${domainName}" = let
|
"${domainName}" = let
|
||||||
|
@ -42,6 +44,7 @@ in {
|
||||||
'';
|
'';
|
||||||
in {
|
in {
|
||||||
enableACME = true;
|
enableACME = true;
|
||||||
|
forceSSL = true;
|
||||||
listen = [
|
listen = [
|
||||||
{
|
{
|
||||||
addr = "0.0.0.0";
|
addr = "0.0.0.0";
|
||||||
|
@ -64,15 +67,20 @@ in {
|
||||||
ssl = true;
|
ssl = true;
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
locations."/.well-known/matrix/server".extraConfig =
|
locations = {
|
||||||
|
"/.well-known/matrix/server".extraConfig =
|
||||||
mkWellKnown { "m.server" = "${matrixFqdn}:443"; };
|
mkWellKnown { "m.server" = "${matrixFqdn}:443"; };
|
||||||
locations."/.well-known/matrix/client".extraConfig =
|
"/.well-known/matrix/client".extraConfig = mkWellKnown {
|
||||||
mkWellKnown { "m.homeserver".base_url = "https://${matrixFqdn}"; };
|
"m.homeserver".base_url = "https://${matrixFqdn}:443";
|
||||||
};
|
};
|
||||||
# "${matrixFqdn}" = {
|
"/.well-known/acme-challenge" = {
|
||||||
# locations."^/$".return = "301 https://element.${domainName}";
|
root = "/var/lib/acme/acme-challenge/";
|
||||||
# };
|
extraConfig = "auth_basic off;";
|
||||||
"element.${domainName}" = {
|
};
|
||||||
|
"/".return = "301 https://web.${domainName}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
"web.${domainName}" = {
|
||||||
enableACME = true;
|
enableACME = true;
|
||||||
forceSSL = true;
|
forceSSL = true;
|
||||||
root = pkgs.element-web.override {
|
root = pkgs.element-web.override {
|
||||||
|
@ -82,7 +90,7 @@ in {
|
||||||
"https://${matrixFqdn}";
|
"https://${matrixFqdn}";
|
||||||
brand = "Fudo";
|
brand = "Fudo";
|
||||||
room_directory.servers =
|
room_directory.servers =
|
||||||
[ "fudo.org" "matrix.org" "libera.chat" "gitter.im" ];
|
[ matrixFqdn "matrix.org" "libera.chat" "gitter.im" ];
|
||||||
map_style_url =
|
map_style_url =
|
||||||
"https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx";
|
"https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx";
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,8 +20,8 @@ in {
|
||||||
package = nextcloudPackage;
|
package = nextcloudPackage;
|
||||||
extra-apps =
|
extra-apps =
|
||||||
with config.services.nextcloudContainer.package.packages.apps; {
|
with config.services.nextcloudContainer.package.packages.apps; {
|
||||||
inherit news contacts calendar tasks maps memories mail bookmarks
|
inherit contacts calendar tasks maps mail bookmarks notes user_saml;
|
||||||
files_markdown notes unsplash user_saml;
|
# files_markdown memories news unsplash
|
||||||
};
|
};
|
||||||
timezone = "America/Winnipeg";
|
timezone = "America/Winnipeg";
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,13 +14,27 @@ let
|
||||||
|
|
||||||
in {
|
in {
|
||||||
config = {
|
config = {
|
||||||
fudo.zones."sea.fudo.org".aliases."frigate" = "zbox";
|
fudo.zones."sea.fudo.org".aliases = { "frigate" = "zbox"; };
|
||||||
fudo = {
|
fudo = {
|
||||||
services.mqtt.private.users.frigate = {
|
services = {
|
||||||
|
metrics = {
|
||||||
|
private-network = true;
|
||||||
|
grafana.oauth = {
|
||||||
|
hostname = "authentik.fudo.org";
|
||||||
|
client-id =
|
||||||
|
config.fudo.secrets.files.domain-secrets."fudo.org"."grafana-oid-client-id";
|
||||||
|
client-secret =
|
||||||
|
config.fudo.secrets.files.domain-secrets."fudo.org"."grafana-oid-client-secret";
|
||||||
|
slug = "grafana-metrics";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
mqtt.private.users.frigate = {
|
||||||
password-file = frigateMqttPassword;
|
password-file = frigateMqttPassword;
|
||||||
acl = [ "frigate/#" ];
|
acl = [ "frigate/#" ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
services = {
|
services = {
|
||||||
frigateContainer = {
|
frigateContainer = {
|
||||||
|
|
|
@ -73,6 +73,18 @@ in {
|
||||||
fsType = "btrfs";
|
fsType = "btrfs";
|
||||||
options = [ "subvol=@acme" "compress=zstd" "noatime" "noexec" ];
|
options = [ "subvol=@acme" "compress=zstd" "noatime" "noexec" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
"/state/services/mail/mail" = {
|
||||||
|
device = "/dev/disk/by-label/germany-data";
|
||||||
|
fsType = "btrfs";
|
||||||
|
options = [ "subvol=@mail" "compress=zstd" "noatime" "noexec" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
"/var/lib/containers/storage" = {
|
||||||
|
device = "/dev/disk/by-label/germany-data";
|
||||||
|
fsType = "btrfs";
|
||||||
|
options = [ "subvol=@container-data" "noatime" "compress=zstd" "noexec" ];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
swapDevices = [{ device = "/dev/disk/by-label/germany-swap"; }];
|
swapDevices = [{ device = "/dev/disk/by-label/germany-swap"; }];
|
||||||
|
@ -87,30 +99,4 @@ in {
|
||||||
cpu.intel.updateMicrocode = true;
|
cpu.intel.updateMicrocode = true;
|
||||||
enableAllFirmware = true;
|
enableAllFirmware = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
networking = {
|
|
||||||
useDHCP = false;
|
|
||||||
|
|
||||||
macvlans = {
|
|
||||||
extif0 = {
|
|
||||||
interface = "enp5s0f0";
|
|
||||||
mode = "bridge";
|
|
||||||
};
|
|
||||||
|
|
||||||
dnsif0 = {
|
|
||||||
interface = "enp5s0f0";
|
|
||||||
mode = "bridge";
|
|
||||||
};
|
|
||||||
|
|
||||||
extif1 = {
|
|
||||||
interface = "enp5s0f1";
|
|
||||||
mode = "bridge";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
interfaces = {
|
|
||||||
extif0.macAddress = generateMac config.instance.hostname "extif0";
|
|
||||||
extif1.macAddress = generateMac config.instance.hostname "extif1";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,6 +93,8 @@ in {
|
||||||
hosts.fimbria.external-interfaces = [ "enp1s0" ];
|
hosts.fimbria.external-interfaces = [ "enp1s0" ];
|
||||||
client.dns.external-interface = "enp1s0";
|
client.dns.external-interface = "enp1s0";
|
||||||
|
|
||||||
|
local-network.state-directory = "/state/services/local-network";
|
||||||
|
|
||||||
secrets.host-secrets."${hostname}" = {
|
secrets.host-secrets."${hostname}" = {
|
||||||
sea-cam-auth-proxy-env = {
|
sea-cam-auth-proxy-env = {
|
||||||
source-file = let
|
source-file = let
|
||||||
|
@ -135,7 +137,16 @@ in {
|
||||||
|
|
||||||
security.acme.defaults.email = "niten@fudo.org";
|
security.acme.defaults.email = "niten@fudo.org";
|
||||||
|
|
||||||
systemd.services.nginx.requires = [ "bind.service" ];
|
systemd.services = {
|
||||||
|
nginx = {
|
||||||
|
after = [ "bind.service" ];
|
||||||
|
requires = [ "bind.service" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
podman-sea-cam-auth-proxy.after = [ "network-online.service" ];
|
||||||
|
|
||||||
|
podman-sea-red-auth-proxy.after = [ "network-online.service" ];
|
||||||
|
};
|
||||||
|
|
||||||
services = {
|
services = {
|
||||||
## TODO: enable when ready
|
## TODO: enable when ready
|
||||||
|
@ -223,6 +234,20 @@ in {
|
||||||
target = "http://node-red.sea.fudo.org/";
|
target = "http://node-red.sea.fudo.org/";
|
||||||
authPort = 9001;
|
authPort = 9001;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
"metrics.fudo.link" = {
|
||||||
|
enableACME = true;
|
||||||
|
forceSSL = true;
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://prometheus.sea.fudo.org";
|
||||||
|
extraConfig = let
|
||||||
|
trustedNetworkClauses = map (nw: "allow ${nw};")
|
||||||
|
(config.instance.local-networks
|
||||||
|
++ config.fudo.domains."fudo.org".local-networks);
|
||||||
|
in concatStringsSep "\n"
|
||||||
|
(trustedNetworkClauses ++ [ "deny all;" ]);
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,8 @@ let
|
||||||
secrets = config.fudo.secrets.host-secrets.france;
|
secrets = config.fudo.secrets.host-secrets.france;
|
||||||
secret-files = config.fudo.secrets.files;
|
secret-files = config.fudo.secrets.files;
|
||||||
|
|
||||||
letsencrypt-full-chain = name: chain: pkgs.stdenv.mkDerivation {
|
letsencrypt-full-chain = name: chain:
|
||||||
|
pkgs.stdenv.mkDerivation {
|
||||||
name = "${name}-letsencrypt-full-chain.pem";
|
name = "${name}-letsencrypt-full-chain.pem";
|
||||||
phases = "installPhase";
|
phases = "installPhase";
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
|
@ -88,21 +89,17 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
fudo = let
|
fudo = let
|
||||||
backplane-dns-password-file = pkgs.lib.passwd.stablerandom-passwd-file
|
backplane-dns-password-file =
|
||||||
"dns-service-backplane-passwd"
|
pkgs.lib.passwd.stablerandom-passwd-file "dns-service-backplane-passwd"
|
||||||
"dns-service-backplane-passwd-${config.instance.build-seed}";
|
"dns-service-backplane-passwd-${config.instance.build-seed}";
|
||||||
in {
|
in {
|
||||||
hosts.france.external-interfaces = [ "extif0" ];
|
hosts.france.external-interfaces = [ "extif0" ];
|
||||||
|
|
||||||
acme.host-domains.france."france.fudo.org" = {
|
acme.host-domains.france."france.fudo.org" = {
|
||||||
email = "admin@fudo.org";
|
admin-email = "admin@fudo.org";
|
||||||
local-copies = {
|
local-copies = {
|
||||||
postgres = {
|
postgres = { user = "postgres"; };
|
||||||
user = "postgres";
|
openldap = { user = config.services.openldap.user; };
|
||||||
};
|
|
||||||
openldap = {
|
|
||||||
user = config.services.openldap.user;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -240,12 +237,10 @@ in {
|
||||||
}];
|
}];
|
||||||
};
|
};
|
||||||
extif0 = {
|
extif0 = {
|
||||||
ipv4.addresses = [
|
ipv4.addresses = [{
|
||||||
{
|
|
||||||
address = primary-ip;
|
address = primary-ip;
|
||||||
prefixLength = 28;
|
prefixLength = 28;
|
||||||
}
|
}];
|
||||||
];
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,20 +14,25 @@ let
|
||||||
in {
|
in {
|
||||||
config = {
|
config = {
|
||||||
networking = {
|
networking = {
|
||||||
enableIPv6 = true;
|
enableIPv6 = false;
|
||||||
|
useDHCP = false;
|
||||||
nameservers = [ "1.1.1.1" ];
|
nameservers = [ "1.1.1.1" ];
|
||||||
defaultGateway = {
|
defaultGateway = {
|
||||||
interface = "extif0";
|
interface = "enp5s0f0";
|
||||||
address = site.gateway-v4;
|
address = site.gateway-v4;
|
||||||
};
|
};
|
||||||
interfaces = {
|
interfaces = {
|
||||||
extif0 = {
|
enp5s0f0 = {
|
||||||
ipv4.addresses = [{
|
ipv4.addresses = [{
|
||||||
address = primary-ip;
|
address = primary-ip;
|
||||||
prefixLength = 28;
|
prefixLength = 28;
|
||||||
}];
|
}];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
firewall = {
|
||||||
|
enable = false;
|
||||||
|
interfaces."podman+".allowedUDPPorts = [ 53 ];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd = {
|
systemd = {
|
||||||
|
@ -80,17 +85,19 @@ in {
|
||||||
arion.backend = "podman-socket";
|
arion.backend = "podman-socket";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
services.lemmyDocker.state-directory = "/state/services/lemmy";
|
||||||
|
|
||||||
fudo = {
|
fudo = {
|
||||||
client.dns = {
|
client.dns = {
|
||||||
ipv4 = true;
|
ipv4 = true;
|
||||||
ipv6 = true;
|
ipv6 = true;
|
||||||
user = "fudo-client";
|
user = "fudo-client";
|
||||||
external-interface = "extif0";
|
external-interface = "enp5s0f0";
|
||||||
};
|
};
|
||||||
|
|
||||||
mail.state-directory = "/state/services/mail";
|
mail.state-directory = "/state/services/mail";
|
||||||
|
|
||||||
nsd.zones."fudo.org".outgoingInterface = "extif0";
|
nsd.zones."fudo.org".outgoingInterface = "enp5s0f0";
|
||||||
|
|
||||||
# Necessary because germany isn't the default yet
|
# Necessary because germany isn't the default yet
|
||||||
postgresql = {
|
postgresql = {
|
||||||
|
@ -106,6 +113,7 @@ in {
|
||||||
authoritative-dns.state-directory = "/state/services/dns";
|
authoritative-dns.state-directory = "/state/services/dns";
|
||||||
jabber.state-directory = "/state/services/jabber";
|
jabber.state-directory = "/state/services/jabber";
|
||||||
logging.loki.state-directory = "/state/services/loki";
|
logging.loki.state-directory = "/state/services/loki";
|
||||||
|
mail-server.state-directory = "/state/services/mail";
|
||||||
metrics = {
|
metrics = {
|
||||||
prometheus.state-directory = "/state/services/prometheus";
|
prometheus.state-directory = "/state/services/prometheus";
|
||||||
grafana.state-directory = "/state/services/grafana";
|
grafana.state-directory = "/state/services/grafana";
|
||||||
|
@ -117,6 +125,7 @@ in {
|
||||||
principals = [ "postgres/${hostFqdn}" ];
|
principals = [ "postgres/${hostFqdn}" ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
matrix.state-directory = "/state/services/matrix";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -41,7 +41,7 @@ in {
|
||||||
fonts.fontconfig = {
|
fonts.fontconfig = {
|
||||||
hinting = {
|
hinting = {
|
||||||
enable = true;
|
enable = true;
|
||||||
style = "hintfull";
|
style = "full";
|
||||||
};
|
};
|
||||||
subpixel.lcdfilter = "default";
|
subpixel.lcdfilter = "default";
|
||||||
antialias = true;
|
antialias = true;
|
||||||
|
|
|
@ -49,8 +49,6 @@ in {
|
||||||
|
|
||||||
environment.systemPackages = local-packages;
|
environment.systemPackages = local-packages;
|
||||||
|
|
||||||
# networking.firewall.allowedTCPPorts = [ 80 443 ];
|
|
||||||
|
|
||||||
# informis.cl-gemini = {
|
# informis.cl-gemini = {
|
||||||
# enable = true;
|
# enable = true;
|
||||||
|
|
||||||
|
@ -63,24 +61,8 @@ in {
|
||||||
|
|
||||||
services = {
|
services = {
|
||||||
mastodonContainer.state-directory = "/state/services/mastodon";
|
mastodonContainer.state-directory = "/state/services/mastodon";
|
||||||
lemmyDocker = {
|
|
||||||
enable = true;
|
|
||||||
hostname = "lemmy.fudo.org";
|
|
||||||
site-name = "Fudo Lemmy";
|
|
||||||
version = "0.18";
|
|
||||||
state-directory = "/state/services/lemmy";
|
|
||||||
smtp-server = "mail.fudo.org:587";
|
|
||||||
docker-images = {
|
|
||||||
pictrs = "asonix/pictrs:0.4";
|
|
||||||
postgres = "postgres:15-alpine";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
authentikContainer.state-directory = "/state/services/authentik";
|
authentikContainer.state-directory = "/state/services/authentik";
|
||||||
nextcloudContainer.state-directory = "/state/services/nextcloud";
|
nextcloudContainer.state-directory = "/state/services/nextcloud";
|
||||||
nginx.virtualHosts."fudo.org" = {
|
|
||||||
enableACME = true;
|
|
||||||
forceSSL = true;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
virtualisation = {
|
virtualisation = {
|
||||||
|
@ -98,12 +80,8 @@ in {
|
||||||
|
|
||||||
services = {
|
services = {
|
||||||
auth = {
|
auth = {
|
||||||
ldap.state-directory = "/state/auth/ldap";
|
ldap.state-directory = "/state/services/ldap";
|
||||||
kerberos = {
|
kerberos.state-directory = "/state/services/heimdal-kdc";
|
||||||
state-directory = "/state/auth/kerberos";
|
|
||||||
# master-key-file = host-secrets.heimdal-master-key.target-file;
|
|
||||||
# ipropd-keytab = host-secrets.heimdal-ipropd-keytab.target-file;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
chat = {
|
chat = {
|
||||||
|
@ -112,40 +90,6 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
nexus.dns-server.listen-addresses = [ host-ipv4 ];
|
nexus.dns-server.listen-addresses = [ host-ipv4 ];
|
||||||
|
|
||||||
# lemmy = {
|
|
||||||
# enable = true;
|
|
||||||
# hostname = "lemmy.fudo.org";
|
|
||||||
# };
|
|
||||||
|
|
||||||
matrix.state-directory = "/state/services/matrix";
|
|
||||||
};
|
|
||||||
|
|
||||||
secrets.host-secrets.legatus = let files = config.fudo.secrets.files;
|
|
||||||
in {
|
|
||||||
# postgres-keytab = {
|
|
||||||
# source-file = files.service-keytabs.procul.postgres;
|
|
||||||
# target-file = "/srv/postgres/secure/postgres.keytab";
|
|
||||||
# user = "root";
|
|
||||||
# };
|
|
||||||
|
|
||||||
# gitea-database-password = {
|
|
||||||
# source-file = files.service-passwords.procul.gitea-database;
|
|
||||||
# target-file = "/srv/gitea/secure/database.passwd";
|
|
||||||
# user = config.fudo.git.user;
|
|
||||||
# };
|
|
||||||
|
|
||||||
# heimdal-master-key = {
|
|
||||||
# source-file = files.realm-master-keys."FUDO.ORG";
|
|
||||||
# target-file = "/run/heimdal/master-key";
|
|
||||||
# user = config.fudo.auth.kdc.user;
|
|
||||||
# };
|
|
||||||
|
|
||||||
# heimdal-ipropd-keytab = {
|
|
||||||
# source-file = files.service-keytabs.legatus.ipropd;
|
|
||||||
# target-file = "/run/heimdal/ipropd.keytab";
|
|
||||||
# user = config.fudo.auth.kdc.user;
|
|
||||||
# };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
client.dns = {
|
client.dns = {
|
||||||
|
|
|
@ -58,8 +58,12 @@ in {
|
||||||
# };
|
# };
|
||||||
|
|
||||||
firewall = {
|
firewall = {
|
||||||
|
enable = true;
|
||||||
allowedTCPPorts = [ 80 443 25565 config.services.murmur.port ];
|
allowedTCPPorts = [ 80 443 25565 config.services.murmur.port ];
|
||||||
allowedUDPPorts = [ 25565 34197 ];
|
allowedUDPPorts = [ 25565 34197 ];
|
||||||
|
extraCommands = ''
|
||||||
|
iptables -A INPUT -s 141.98.7.36 -j DROP
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
nat.forwardPorts = [
|
nat.forwardPorts = [
|
||||||
|
|
|
@ -75,20 +75,10 @@ in {
|
||||||
"export-projects.mount"
|
"export-projects.mount"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
grafana = {
|
|
||||||
requires = [ "postgresql.service" ];
|
|
||||||
bindsTo = [ "postgresql.service" ];
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
fudo = let
|
fudo = let host-secrets = config.fudo.secrets.host-secrets."${hostname}";
|
||||||
grafana-database-passwd-file = pkgs.lib.passwd.stablerandom-passwd-file
|
|
||||||
"grafana-database-nostromo-password"
|
|
||||||
"grafana-database-nostromo-password-${config.instance.build-seed}";
|
|
||||||
|
|
||||||
host-secrets = config.fudo.secrets.host-secrets.${hostname};
|
|
||||||
in {
|
in {
|
||||||
secrets.host-secrets.${hostname} = {
|
secrets.host-secrets.${hostname} = {
|
||||||
pricebot-auth-token = {
|
pricebot-auth-token = {
|
||||||
|
@ -117,7 +107,6 @@ in {
|
||||||
metrics.grafana = {
|
metrics.grafana = {
|
||||||
state-directory = "/state/services/grafana";
|
state-directory = "/state/services/grafana";
|
||||||
smtp.hostname = "mail.fudo.org";
|
smtp.hostname = "mail.fudo.org";
|
||||||
ldap.base-dn = "dc=fudo,dc=org";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
postgresql = {
|
postgresql = {
|
||||||
|
@ -135,8 +124,6 @@ in {
|
||||||
enable = true;
|
enable = true;
|
||||||
local-networks = config.instance.local-networks;
|
local-networks = config.instance.local-networks;
|
||||||
state-directory = "/state/services/postgresql";
|
state-directory = "/state/services/postgresql";
|
||||||
|
|
||||||
databases.grafana.users = config.instance.local-admins;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
services.gitea-container = {
|
services.gitea-container = {
|
||||||
|
@ -146,10 +133,6 @@ in {
|
||||||
state-directory = "/state/services/gitea";
|
state-directory = "/state/services/gitea";
|
||||||
trusted-networks = config.instance.local-networks;
|
trusted-networks = config.instance.local-networks;
|
||||||
openid-urls = [ "https://authentik.fudo.org/" ];
|
openid-urls = [ "https://authentik.fudo.org/" ];
|
||||||
secret-key-file =
|
|
||||||
pkgs.lib.passwd.stablerandom-passwd-file "gitea-seattle-secret-key"
|
|
||||||
config.instance.build-seed;
|
|
||||||
|
|
||||||
networking = {
|
networking = {
|
||||||
interface = "eno2";
|
interface = "eno2";
|
||||||
ipv4 = {
|
ipv4 = {
|
||||||
|
|
|
@ -193,16 +193,5 @@ in {
|
||||||
# loadLatestSave = true;
|
# loadLatestSave = true;
|
||||||
# package = pkgs.factorio-headless-experimental;
|
# package = pkgs.factorio-headless-experimental;
|
||||||
# };
|
# };
|
||||||
|
|
||||||
services.nginx.virtualHosts = {
|
|
||||||
"selby.ca" = {
|
|
||||||
enableACME = true;
|
|
||||||
locations."/".return = "301 https://selbyhomecentre.com$request_uri";
|
|
||||||
};
|
|
||||||
"www.selby.ca" = {
|
|
||||||
enableACME = true;
|
|
||||||
locations."/".return = "301 https://selbyhomecentre.com$request_uri";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,6 +138,7 @@ in {
|
||||||
groups = {
|
groups = {
|
||||||
wheel.members = [ "niten" "reaper" ];
|
wheel.members = [ "niten" "reaper" ];
|
||||||
dns = { members = [ "niten" "reaper" "named" ]; };
|
dns = { members = [ "niten" "reaper" "named" ]; };
|
||||||
|
fudo.members = [ "niten" "reaper" ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,17 +10,23 @@ let
|
||||||
config = {
|
config = {
|
||||||
containers.tester = {
|
containers.tester = {
|
||||||
autoStart = true;
|
autoStart = true;
|
||||||
# hostAddress = "10.0.0.14";
|
# localAddress = "10.0.0.14";
|
||||||
additionalCapabilities = [ "CAP_NET_ADMIN" ];
|
additionalCapabilities = [ "CAP_NET_ADMIN" ];
|
||||||
# privateNetwork = true;
|
# privateNetwork = true;
|
||||||
macvlans = [ "enp7s0" ];
|
macvlans = [ "enp7s0" ];
|
||||||
# hostBridge = "tester0";
|
#hostBridge = "tester0";
|
||||||
|
#hostAddress = "10.0.0.14";
|
||||||
|
#privateNetwork = true;
|
||||||
config = {
|
config = {
|
||||||
imports = [ pkgs.moduleRegistry.authoritativeDns ];
|
imports = [ pkgs.moduleRegistry.authoritativeDns ];
|
||||||
|
|
||||||
services.openssh.enable = true;
|
services.openssh.enable = true;
|
||||||
|
|
||||||
users.users.niten = config.users.users.niten;
|
users = let groupName = config.users.users.niten.group;
|
||||||
|
in {
|
||||||
|
users.niten = config.users.users.niten;
|
||||||
|
groups."${groupName}" = config.users.groups."${groupName}";
|
||||||
|
};
|
||||||
|
|
||||||
services.authoritative-dns = {
|
services.authoritative-dns = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
@ -40,8 +46,13 @@ let
|
||||||
allowedTCPPorts = [ 22 53 ];
|
allowedTCPPorts = [ 22 53 ];
|
||||||
allowedUDPPorts = [ 53 ];
|
allowedUDPPorts = [ 53 ];
|
||||||
};
|
};
|
||||||
interfaces = {
|
# interfaces.eth0 = {
|
||||||
mv-enp7s0.ipv4.addresses = [{
|
# ipv4.addresses = [{
|
||||||
|
# address = "10.0.0.14";
|
||||||
|
# prefixLength = 24;
|
||||||
|
# }];
|
||||||
|
# };
|
||||||
|
interfaces.mv-enp7s0.ipv4.addresses = [{
|
||||||
address = "10.0.0.14";
|
address = "10.0.0.14";
|
||||||
prefixLength = 24;
|
prefixLength = 24;
|
||||||
}];
|
}];
|
||||||
|
@ -50,7 +61,6 @@ let
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
in {
|
in {
|
||||||
imports = [ vmConfig ];
|
imports = [ vmConfig ];
|
||||||
|
@ -118,7 +128,7 @@ in {
|
||||||
fonts.fontconfig = {
|
fonts.fontconfig = {
|
||||||
hinting = {
|
hinting = {
|
||||||
enable = true;
|
enable = true;
|
||||||
style = "hintfull";
|
style = "full";
|
||||||
};
|
};
|
||||||
subpixel.lcdfilter = "default";
|
subpixel.lcdfilter = "default";
|
||||||
antialias = true;
|
antialias = true;
|
||||||
|
@ -132,7 +142,7 @@ in {
|
||||||
hardware = {
|
hardware = {
|
||||||
bluetooth = {
|
bluetooth = {
|
||||||
enable = true;
|
enable = true;
|
||||||
package = pkgs.bluezFull;
|
package = pkgs.bluez;
|
||||||
};
|
};
|
||||||
xpadneo.enable = true;
|
xpadneo.enable = true;
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,6 +20,7 @@ in {
|
||||||
prefixLength = 16;
|
prefixLength = 16;
|
||||||
}];
|
}];
|
||||||
};
|
};
|
||||||
|
firewall.enable = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
security.sudo.extraConfig = ''
|
security.sudo.extraConfig = ''
|
||||||
|
|
|
@ -47,8 +47,6 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
nixpkgs.config.allowUnfree = true;
|
|
||||||
|
|
||||||
hardware.enableAllFirmware = true;
|
hardware.enableAllFirmware = true;
|
||||||
|
|
||||||
services = {
|
services = {
|
||||||
|
|
|
@ -46,6 +46,7 @@ let
|
||||||
imports = [ pkgs.moduleRegistry.authoritativeDns ];
|
imports = [ pkgs.moduleRegistry.authoritativeDns ];
|
||||||
nixpkgs.pkgs = pkgs;
|
nixpkgs.pkgs = pkgs;
|
||||||
networking = {
|
networking = {
|
||||||
|
enableIPv6 = false;
|
||||||
defaultGateway = {
|
defaultGateway = {
|
||||||
address = getSiteGatewayV4 siteName;
|
address = getSiteGatewayV4 siteName;
|
||||||
interface = "mv-${cfg.container.interface}";
|
interface = "mv-${cfg.container.interface}";
|
||||||
|
@ -57,8 +58,7 @@ let
|
||||||
};
|
};
|
||||||
interfaces."mv-${cfg.container.interface}" = {
|
interfaces."mv-${cfg.container.interface}" = {
|
||||||
ipv4.addresses = optional (nameserverDeets.ipv4-address != null) {
|
ipv4.addresses = optional (nameserverDeets.ipv4-address != null) {
|
||||||
address = trace "IP ADDRESS: ${nameserverDeets.ipv4-address}"
|
address = nameserverDeets.ipv4-address;
|
||||||
nameserverDeets.ipv4-address;
|
|
||||||
prefixLength = getSiteV4PrefixLength siteName;
|
prefixLength = getSiteV4PrefixLength siteName;
|
||||||
};
|
};
|
||||||
ipv6.addresses = optional (nameserverDeets.ipv6-address != null) {
|
ipv6.addresses = optional (nameserverDeets.ipv6-address != null) {
|
||||||
|
@ -224,6 +224,7 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
default = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
enable-notifications =
|
enable-notifications =
|
||||||
|
@ -283,7 +284,6 @@ in {
|
||||||
nameValuePair (zoneKeySecret zone) {
|
nameValuePair (zoneKeySecret zone) {
|
||||||
source-file = zoneCfg.ksk.private-key;
|
source-file = zoneCfg.ksk.private-key;
|
||||||
target-file = "/run/nsd/${baseNameOf zoneCfg.ksk.private-key}";
|
target-file = "/run/nsd/${baseNameOf zoneCfg.ksk.private-key}";
|
||||||
user = config.fudo.nsd.user;
|
|
||||||
}) (filterAttrs (_: zoneCfg: zoneCfg.ksk != null) cfg.zones);
|
}) (filterAttrs (_: zoneCfg: zoneCfg.ksk != null) cfg.zones);
|
||||||
|
|
||||||
zones = mapAttrs (zone-name: zoneCfg:
|
zones = mapAttrs (zone-name: zoneCfg:
|
||||||
|
|
|
@ -22,12 +22,6 @@ in {
|
||||||
description = "Path at which to store Gitea state.";
|
description = "Path at which to store Gitea state.";
|
||||||
};
|
};
|
||||||
|
|
||||||
secret-key-file = mkOption {
|
|
||||||
type = str;
|
|
||||||
description =
|
|
||||||
"Path to file containing Gitea secret key, for encrypting secrets.";
|
|
||||||
};
|
|
||||||
|
|
||||||
trusted-networks = mkOption {
|
trusted-networks = mkOption {
|
||||||
type = listOf str;
|
type = listOf str;
|
||||||
description =
|
description =
|
||||||
|
@ -131,7 +125,6 @@ in {
|
||||||
service.DISABLE_REGISTRATION = true;
|
service.DISABLE_REGISTRATION = true;
|
||||||
security = {
|
security = {
|
||||||
INSTALL_LOCK = true;
|
INSTALL_LOCK = true;
|
||||||
SECRET_KEY = "file:${cfg.secret-key-file}";
|
|
||||||
LOGIN_REMEMBER_DAYS = 30;
|
LOGIN_REMEMBER_DAYS = 30;
|
||||||
};
|
};
|
||||||
metrics.ENABLED = cfg.trusted-networks != [ ];
|
metrics.ENABLED = cfg.trusted-networks != [ ];
|
||||||
|
@ -153,11 +146,12 @@ in {
|
||||||
};
|
};
|
||||||
openid = {
|
openid = {
|
||||||
ENABLE_OPENID_SIGNIN = true;
|
ENABLE_OPENID_SIGNIN = true;
|
||||||
WHITELISTED_URIS = cfg.openid-urls;
|
WHITELISTED_URIS = concatStringsSep "," cfg.openid-urls;
|
||||||
};
|
};
|
||||||
oauth2_client = {
|
oauth2_client = {
|
||||||
REGISTER_EMAIL_CONFIRM = false;
|
REGISTER_EMAIL_CONFIRM = false;
|
||||||
OPENID_CONNECT_SCOPES = [ "email" "profile" ];
|
OPENID_CONNECT_SCOPES =
|
||||||
|
concatStringsSep "," [ "email" "profile" ];
|
||||||
ENABLE_AUTO_REGISTRATION = true;
|
ENABLE_AUTO_REGISTRATION = true;
|
||||||
USERNAME = "email";
|
USERNAME = "email";
|
||||||
UPDATE_AVATAR = true;
|
UPDATE_AVATAR = true;
|
||||||
|
@ -194,11 +188,14 @@ in {
|
||||||
# enableACME = true;
|
# enableACME = true;
|
||||||
# forceSSL = true;
|
# forceSSL = true;
|
||||||
locations."/".proxyPass = "http://127.0.0.1:8080";
|
locations."/".proxyPass = "http://127.0.0.1:8080";
|
||||||
locations."/metrics" = mkIf (cfg.trusted-networks != [ ]) (let
|
locations."/metrics" = mkIf (cfg.trusted-networks != [ ]) {
|
||||||
|
proxyPass = "http://127.0.0.1:8080/metrics";
|
||||||
|
extraConfig = let
|
||||||
networkAllowClauses =
|
networkAllowClauses =
|
||||||
map (net: "allow ${net};") cfg.trusted-networks;
|
map (net: "allow ${net};") cfg.trusted-networks;
|
||||||
in concatStringsSep "\n"
|
in concatStringsSep "\n"
|
||||||
(networkAllowClauses ++ [ "deny all;" ]));
|
(networkAllowClauses ++ [ "deny all;" ]);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,7 +20,7 @@ let
|
||||||
|
|
||||||
isLocalMailserver = domain-name == mailserver-domain-name;
|
isLocalMailserver = domain-name == mailserver-domain-name;
|
||||||
|
|
||||||
metricsEnabled = mailserver-domain.prometheus-hosts != [ ];
|
metricsEnabled = !isNull mailserver-domain.metrics;
|
||||||
|
|
||||||
host-certs = config.fudo.acme.host-domains.${hostname};
|
host-certs = config.fudo.acme.host-domains.${hostname};
|
||||||
|
|
||||||
|
@ -28,13 +28,20 @@ in {
|
||||||
options.fudo.services.mail-server = with types; {
|
options.fudo.services.mail-server = with types; {
|
||||||
debug = mkEnableOption "Enable debug options for mailserver.";
|
debug = mkEnableOption "Enable debug options for mailserver.";
|
||||||
|
|
||||||
|
enable = mkOption {
|
||||||
|
type = bool;
|
||||||
|
default = true;
|
||||||
|
description =
|
||||||
|
"Temporary -- allow disabling mail server (in favor of mail container).";
|
||||||
|
};
|
||||||
|
|
||||||
state-directory = mkOption {
|
state-directory = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "Directory at which to store mailserver state.";
|
description = "Directory at which to store mailserver state.";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf hasMailServer {
|
config = mkIf (hasMailServer && cfg.enable) {
|
||||||
services.nginx = mkIf (isMailServer && metricsEnabled) {
|
services.nginx = mkIf (isMailServer && metricsEnabled) {
|
||||||
enable = true;
|
enable = true;
|
||||||
recommendedOptimisation = true;
|
recommendedOptimisation = true;
|
||||||
|
@ -106,17 +113,6 @@ in {
|
||||||
in {
|
in {
|
||||||
aliases = mkIf metricsEnabled { mail-stats = "${mailserver-fqdn}."; };
|
aliases = mkIf metricsEnabled { mail-stats = "${mailserver-fqdn}."; };
|
||||||
|
|
||||||
# srv-records.tcp = {
|
|
||||||
# pop3 = srv-record mailserver-fqdn 110;
|
|
||||||
# pop3s = srv-record mailserver-fqdn 995;
|
|
||||||
|
|
||||||
# imap = srv-record mailserver-fqdn 143;
|
|
||||||
# imaps = srv-record mailserver-fqdn 993;
|
|
||||||
|
|
||||||
# smtp = srv-record mailserver-fqdn 25;
|
|
||||||
# submission = srv-record mailserver-fqdn 587;
|
|
||||||
# };
|
|
||||||
|
|
||||||
metric-records = mkIf metricsEnabled
|
metric-records = mkIf metricsEnabled
|
||||||
(genAttrs [ "dovecot" "postfix" "rspamd" ]
|
(genAttrs [ "dovecot" "postfix" "rspamd" ]
|
||||||
(_: srv-record "mail-stats" 443));
|
(_: srv-record "mail-stats" 443));
|
||||||
|
|
|
@ -3,54 +3,28 @@
|
||||||
with lib;
|
with lib;
|
||||||
let
|
let
|
||||||
hostname = config.instance.hostname;
|
hostname = config.instance.hostname;
|
||||||
domain-name = config.fudo.hosts."${hostname}".domain;
|
domainName = config.fudo.hosts."${hostname}".domain;
|
||||||
domain = config.fudo.domains."${domain-name}";
|
domain = config.fudo.domains."${domainName}";
|
||||||
|
|
||||||
host-secrets = config.fudo.secrets.host-secrets."${hostname}";
|
inherit (pkgs.lib) getHostIpv4 getHostIpv6 getHostFqdn;
|
||||||
|
|
||||||
notEmpty = lst: (length lst) > 0;
|
hostSecrets = config.fudo.secrets.host-secrets."${hostname}";
|
||||||
|
|
||||||
metricsEnabled = notEmpty domain.prometheus-hosts;
|
metricsEnabled = !isNull domain.metrics;
|
||||||
metricsScraper = elem hostname domain.prometheus-hosts;
|
isPrometheus = hostname == domain.metrics.prometheus-host;
|
||||||
metricsMonitor = elem hostname domain.grafana-hosts;
|
isGrafana = hostname == domain.metrics.grafana-host;
|
||||||
|
|
||||||
prometheus-cfg = config.fudo.services.metrics.prometheus;
|
grafanaHost = domain.metrics.grafana-host;
|
||||||
grafana-cfg = config.fudo.services.metrics.grafana;
|
prometheusHost = domain.metrics.prometheus-host;
|
||||||
|
|
||||||
host-fqdn = hostname:
|
prometheusCfg = config.fudo.services.metrics.prometheus;
|
||||||
let host-domain = config.fudo.hosts.${hostname}.domain;
|
grafanaCfg = config.fudo.services.metrics.grafana;
|
||||||
in "${hostname}.${host-domain}";
|
privateNetwork = config.fudo.services.metrics.private-network;
|
||||||
|
|
||||||
host-auth-fqdn = hostname: "${host-fqdn hostname}.";
|
|
||||||
|
|
||||||
make-alias-map = type: hosts:
|
|
||||||
listToAttrs
|
|
||||||
(imap0 (i: hostname: nameValuePair hostname "${type}-${toString i}") hosts);
|
|
||||||
|
|
||||||
headOrNull = lst: if notEmpty lst then head lst else null;
|
|
||||||
|
|
||||||
metrics-master = headOrNull domain.prometheus-hosts;
|
|
||||||
|
|
||||||
monitor-master = headOrNull domain.grafana-hosts;
|
|
||||||
|
|
||||||
metrics-alias-map = make-alias-map "metrics" domain.prometheus-hosts;
|
|
||||||
|
|
||||||
monitor-alias-map = make-alias-map "monitor" domain.grafana-hosts;
|
|
||||||
|
|
||||||
alias-map-to-cnames =
|
|
||||||
mapAttrs' (hostname: alias: nameValuePair alias (host-auth-fqdn hostname));
|
|
||||||
|
|
||||||
alias-map-to-hostnames =
|
|
||||||
mapAttrsToList (hostname: alias: "${alias}.${domain-name}");
|
|
||||||
|
|
||||||
grafana-smtp-password-file =
|
grafana-smtp-password-file =
|
||||||
pkgs.lib.passwd.stablerandom-passwd-file "grafana-smtp-passwd"
|
pkgs.lib.passwd.stablerandom-passwd-file "grafana-smtp-passwd"
|
||||||
config.instance.build-seed;
|
config.instance.build-seed;
|
||||||
|
|
||||||
grafana-auth-password-file =
|
|
||||||
pkgs.lib.passwd.stablerandom-passwd-file "grafana-auth-passwd"
|
|
||||||
config.instance.build-seed;
|
|
||||||
|
|
||||||
grafana-admin-password-file =
|
grafana-admin-password-file =
|
||||||
pkgs.lib.passwd.stablerandom-passwd-file "grafana-admin-passwd"
|
pkgs.lib.passwd.stablerandom-passwd-file "grafana-admin-passwd"
|
||||||
config.instance.build-seed;
|
config.instance.build-seed;
|
||||||
|
@ -59,25 +33,14 @@ let
|
||||||
pkgs.lib.passwd.stablerandom-passwd-file "grafana-secret-key"
|
pkgs.lib.passwd.stablerandom-passwd-file "grafana-secret-key"
|
||||||
config.instance.build-seed;
|
config.instance.build-seed;
|
||||||
|
|
||||||
grafana-database-password-file =
|
|
||||||
pkgs.lib.passwd.stablerandom-passwd-file "grafana-database-postgres"
|
|
||||||
config.instance.build-seed;
|
|
||||||
|
|
||||||
site = let site-name = config.fudo.hosts."${hostname}".site;
|
|
||||||
in config.fudo.sites."${site-name}";
|
|
||||||
|
|
||||||
is-private-network = site.local-gateway != null;
|
|
||||||
|
|
||||||
domainToBaseDn = domain:
|
|
||||||
concatStringsSep "," (map (el: "dc=${el}") (splitString "." domain));
|
|
||||||
|
|
||||||
ldapEnabled = domain.ldap-servers != [ ];
|
|
||||||
|
|
||||||
isPostgresServer = config.instance.hostname == domain.postgresql-server;
|
|
||||||
postgresServer = pkgs.lib.getHostFqdn domain.postgresql-server;
|
|
||||||
|
|
||||||
in {
|
in {
|
||||||
options.fudo.services.metrics = with types; {
|
options.fudo.services.metrics = with types; {
|
||||||
|
private-network = mkOption {
|
||||||
|
type = bool;
|
||||||
|
description = "Network is private, encryption not required.";
|
||||||
|
default = false;
|
||||||
|
};
|
||||||
|
|
||||||
prometheus = {
|
prometheus = {
|
||||||
static-targets = mkOption {
|
static-targets = mkOption {
|
||||||
type = attrsOf (listOf str);
|
type = attrsOf (listOf str);
|
||||||
|
@ -86,6 +49,7 @@ in {
|
||||||
example = { dovecot = [ "my.host.name:1111" ]; };
|
example = { dovecot = [ "my.host.name:1111" ]; };
|
||||||
default = { };
|
default = { };
|
||||||
};
|
};
|
||||||
|
|
||||||
state-directory = mkOption {
|
state-directory = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "Path at which to store Prometheus state.";
|
description = "Path at which to store Prometheus state.";
|
||||||
|
@ -99,6 +63,7 @@ in {
|
||||||
description = "Username from which to send Grafana alerts.";
|
description = "Username from which to send Grafana alerts.";
|
||||||
default = "monitor";
|
default = "monitor";
|
||||||
};
|
};
|
||||||
|
|
||||||
hostname = mkOption {
|
hostname = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "Hostname of the SMTP host.";
|
description = "Hostname of the SMTP host.";
|
||||||
|
@ -106,49 +71,34 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
ldap = let base-dn = domainToBaseDn config.instance.local-domain;
|
oauth = let
|
||||||
in {
|
oauthOpts.options = {
|
||||||
base-dn = mkOption {
|
hostname = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "DN under which to search for users.";
|
description = "Host of the OAuth server.";
|
||||||
default = base-dn;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bind-user = mkOption {
|
client-id = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "DN as which to bind to the LDAP server.";
|
description =
|
||||||
default = "grafana_reader";
|
"Path to file containing the Grafana OAuth client ID.";
|
||||||
};
|
};
|
||||||
|
|
||||||
bind-passwd = mkOption {
|
client-secret = mkOption {
|
||||||
type = nullOr str;
|
type = str;
|
||||||
description = "Path to file with bind password. Generated if null.";
|
description =
|
||||||
|
"Path to file containing the Grafana OAuth client secret.";
|
||||||
|
};
|
||||||
|
|
||||||
|
slug = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "The application slug on the OAuth server.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in mkOption {
|
||||||
|
type = nullOr (submodule oauthOpts);
|
||||||
default = null;
|
default = null;
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
# database = {
|
|
||||||
# hostname = mkOption {
|
|
||||||
# type = str;
|
|
||||||
# description = "Hostname of the postgresql database.";
|
|
||||||
# default = "localhost";
|
|
||||||
# };
|
|
||||||
# user = mkOption {
|
|
||||||
# type = str;
|
|
||||||
# description =
|
|
||||||
# "Username as which to authenticate to the postgresql database.";
|
|
||||||
# };
|
|
||||||
# password-file = mkOption {
|
|
||||||
# type = str;
|
|
||||||
# description =
|
|
||||||
# "Password file (on the target host) which to authenticate to the postgresql database.";
|
|
||||||
# };
|
|
||||||
# name = mkOption {
|
|
||||||
# type = str;
|
|
||||||
# description = "Database name.";
|
|
||||||
# default = "grafana";
|
|
||||||
# };
|
|
||||||
# };
|
|
||||||
|
|
||||||
state-directory = mkOption {
|
state-directory = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
|
@ -159,187 +109,129 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf metricsEnabled {
|
config = mkIf metricsEnabled {
|
||||||
|
|
||||||
fudo = {
|
fudo = {
|
||||||
system-users = {
|
|
||||||
"${grafana-cfg.smtp.username}" = {
|
|
||||||
description = "Grafana Alerts";
|
|
||||||
ldap-hashed-password =
|
|
||||||
pkgs.lib.passwd.hash-ldap-passwd "grafana-smtp-passwd"
|
|
||||||
grafana-smtp-password-file;
|
|
||||||
};
|
|
||||||
|
|
||||||
"${grafana-cfg.ldap.bind-user}" = mkIf ((domain.ldap-servers != [ ])
|
|
||||||
&& (grafana-cfg.ldap.bind-passwd == null)) {
|
|
||||||
description = "Grafana Authentication Reader";
|
|
||||||
ldap-hashed-password =
|
|
||||||
pkgs.lib.passwd.hash-ldap-passwd "grafana-auth-passwd"
|
|
||||||
grafana-auth-password-file;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
secrets.host-secrets =
|
secrets.host-secrets =
|
||||||
let grafana-user = config.systemd.services.grafana.serviceConfig.User;
|
let grafana-user = config.systemd.services.grafana.serviceConfig.User;
|
||||||
in {
|
in {
|
||||||
"${hostname}" = {
|
"${hostname}" = {
|
||||||
grafana-smtp-password = mkIf metricsMonitor {
|
grafana-admin-password = mkIf isGrafana {
|
||||||
source-file = grafana-smtp-password-file;
|
|
||||||
target-file = "/run/metrics/grafana/smtp.passwd";
|
|
||||||
user = grafana-user;
|
|
||||||
};
|
|
||||||
|
|
||||||
grafana-admin-password = mkIf metricsMonitor {
|
|
||||||
source-file = grafana-admin-password-file;
|
source-file = grafana-admin-password-file;
|
||||||
target-file = "/run/metrics/grafana/admin.passwd";
|
target-file = "/run/metrics/grafana/admin.passwd";
|
||||||
user = grafana-user;
|
user = grafana-user;
|
||||||
};
|
};
|
||||||
|
|
||||||
grafana-secret-key = mkIf metricsMonitor {
|
grafana-secret-key = mkIf isGrafana {
|
||||||
source-file = grafana-secret-key-file;
|
source-file = grafana-secret-key-file;
|
||||||
target-file = "/run/metrics/grafana/secret.key";
|
target-file = "/run/metrics/grafana/secret.key";
|
||||||
user = grafana-user;
|
user = grafana-user;
|
||||||
};
|
};
|
||||||
|
|
||||||
grafana-postgresql-password = mkIf metricsMonitor {
|
grafana-client-id = mkIf (isGrafana && !isNull grafanaCfg.oauth) {
|
||||||
source-file = grafana-database-password-file;
|
source-file = grafanaCfg.oauth.client-id;
|
||||||
target-file = "/run/metrics/grafana/postgres.passwd";
|
target-file = "/run/metrics/grafana/oauth-client-id";
|
||||||
user = grafana-user;
|
user = grafana-user;
|
||||||
};
|
};
|
||||||
|
|
||||||
postgresql-grafana-password = mkIf isPostgresServer {
|
grafana-client-secret =
|
||||||
source-file = grafana-database-password-file;
|
mkIf (isGrafana && !isNull grafanaCfg.oauth) {
|
||||||
target-file = "/run/postgres-users/grafana.passwd";
|
source-file = grafanaCfg.oauth.client-secret;
|
||||||
user = config.systemd.services.postgresql.serviceConfig.User;
|
target-file = "/run/metrics/grafana/oauth-client-secret";
|
||||||
|
user = grafana-user;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
zones."${domain.zone}" = {
|
zones."${domain.zone}" = {
|
||||||
aliases = let
|
hosts = {
|
||||||
metrics-aliases = alias-map-to-cnames metrics-alias-map;
|
grafana = {
|
||||||
monitor-aliases = alias-map-to-cnames monitor-alias-map;
|
ipv4-address = getHostIpv4 grafanaHost;
|
||||||
metrics-master-cname = optionalAttrs (metrics-master != null) {
|
ipv6-address = getHostIpv6 grafanaHost;
|
||||||
metrics = "${metrics-master}.${domain-name}.";
|
description = "Grafana Metrics Analysis on ${grafanaHost}.";
|
||||||
};
|
};
|
||||||
monitor-master-cname = optionalAttrs (monitor-master != null) {
|
prometheus = {
|
||||||
monitor = "${monitor-master}.${domain-name}.";
|
ipv4-address = getHostIpv4 prometheusHost;
|
||||||
|
ipv6-address = getHostIpv6 prometheusHost;
|
||||||
|
description = "Prometheus Metrics Aggregator on ${prometheusHost}.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
aliases = {
|
||||||
|
metrics = "prometheus.${domainName}";
|
||||||
|
monitor = "grafana.${domainName}";
|
||||||
};
|
};
|
||||||
in metrics-aliases // monitor-aliases // metrics-master-cname
|
|
||||||
// monitor-master-cname;
|
|
||||||
|
|
||||||
metric-records = let
|
metric-records = let
|
||||||
domain-hosts = filterAttrs (hostname: hostOpts:
|
domainHosts = filterAttrs (hostname: hostOpts:
|
||||||
hostOpts.domain == domain-name && hostOpts.nixos-system)
|
hostOpts.domain == domainName && hostOpts.nixos-system)
|
||||||
config.fudo.hosts;
|
config.fudo.hosts;
|
||||||
in {
|
in {
|
||||||
node = map (hostname: {
|
node = map (hostname: {
|
||||||
host = "${hostname}.${domain-name}";
|
host = getHostFqdn hostname;
|
||||||
port = if is-private-network then 80 else 443;
|
port = if privateNetwork then 80 else 443;
|
||||||
}) (attrNames domain-hosts);
|
}) (attrNames domainHosts);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
postgresql = mkIf isPostgresServer {
|
|
||||||
users.grafana = {
|
|
||||||
password-file = host-secrets.postgresql-grafana-password.target-file;
|
|
||||||
databases.grafana = {
|
|
||||||
access = "CONNECT";
|
|
||||||
entity-access = {
|
|
||||||
"ALL TABLES IN SCHEMA public" = "ALL PRIVILEGES";
|
|
||||||
# "SELECT,INSERT,UPDATE,DELETE";
|
|
||||||
"ALL SEQUENCES IN SCHEMA public" = "ALL PRIVILEGES";
|
|
||||||
# "SELECT, UPDATE";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
databases.grafana.users = config.instance.local-admins;
|
|
||||||
};
|
|
||||||
|
|
||||||
metrics = {
|
metrics = {
|
||||||
node-exporter = {
|
node-exporter = {
|
||||||
enable = true;
|
enable = true;
|
||||||
hostname = host-fqdn hostname;
|
hostname = getHostFqdn hostname;
|
||||||
private-network = is-private-network;
|
private-network = privateNetwork;
|
||||||
};
|
};
|
||||||
|
|
||||||
prometheus = mkIf metricsScraper {
|
prometheus = mkIf isPrometheus {
|
||||||
enable = true;
|
enable = true;
|
||||||
service-discovery-dns = {
|
service-discovery-dns = {
|
||||||
node = [ "node._metrics._tcp.${domain-name}" ];
|
node = [ "node._metrics._tcp.${domainName}" ];
|
||||||
|
};
|
||||||
|
static-targets = prometheusCfg.static-targets;
|
||||||
|
hostname = "prometheus.${domainName}";
|
||||||
|
state-directory = prometheusCfg.state-directory;
|
||||||
|
private-network = privateNetwork;
|
||||||
};
|
};
|
||||||
static-targets = prometheus-cfg.static-targets;
|
|
||||||
hostname = let alias = metrics-alias-map.${hostname};
|
|
||||||
in "${alias}.${domain-name}";
|
|
||||||
state-directory = prometheus-cfg.state-directory;
|
|
||||||
private-network = is-private-network;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
grafana = mkIf metricsMonitor {
|
services.grafana = mkIf isGrafana {
|
||||||
enable = true;
|
enable = true;
|
||||||
hostname = let alias = monitor-alias-map.${hostname};
|
state-directory = grafanaCfg.state-directory;
|
||||||
in "${alias}.${domain-name}";
|
base-url = let scheme = if privateNetwork then "http" else "https";
|
||||||
smtp = let cfg = grafana-cfg.smtp;
|
in "${scheme}://grafana.${domainName}";
|
||||||
in {
|
admin-password-file = hostSecrets.grafana-admin-password.target-file;
|
||||||
username = cfg.username;
|
secret-key-file = hostSecrets.grafana-secret-key.target-file;
|
||||||
password-file = host-secrets.grafana-smtp-password.target-file;
|
datasources = {
|
||||||
hostname = cfg.hostname;
|
"${domainName}" = {
|
||||||
email = "${cfg.username}@${domain-name}";
|
url = let scheme = if privateNetwork then "http" else "https";
|
||||||
};
|
in "${scheme}://prometheus.${domainName}";
|
||||||
database = let cfg = grafana-cfg.database;
|
|
||||||
in {
|
|
||||||
name = "grafana";
|
|
||||||
user = "grafana";
|
|
||||||
password-file =
|
|
||||||
host-secrets.grafana-postgresql-password.target-file;
|
|
||||||
hostname = postgresServer;
|
|
||||||
};
|
|
||||||
ldap = mkIf (domain.ldap-servers != [ ]) {
|
|
||||||
hosts = map host-fqdn domain.ldap-servers;
|
|
||||||
base-dn = grafana-cfg.ldap.base-dn;
|
|
||||||
bind-dn =
|
|
||||||
"cn=${grafana-cfg.ldap.bind-user},${grafana-cfg.ldap.base-dn}";
|
|
||||||
bind-passwd = if (grafana-cfg.ldap.bind-passwd != null) then
|
|
||||||
grafana-cfg.ldap.bind-passwd
|
|
||||||
else
|
|
||||||
(readFile grafana-auth-password-file);
|
|
||||||
};
|
|
||||||
admin-password-file = host-secrets.grafana-admin-password.target-file;
|
|
||||||
secret-key-file = host-secrets.grafana-secret-key.target-file;
|
|
||||||
datasources = let
|
|
||||||
scheme = if is-private-network then "http" else "https";
|
|
||||||
host-config = hostname: {
|
|
||||||
url = "${scheme}://${hostname}.${domain-name}";
|
|
||||||
type = "prometheus";
|
type = "prometheus";
|
||||||
default = hostname == "metrics-0";
|
default = true;
|
||||||
};
|
};
|
||||||
in listToAttrs
|
};
|
||||||
(map (host: nameValuePair "prometheus-${host}" (host-config host))
|
oauth = mkIf (!isNull grafanaCfg.oauth) {
|
||||||
(attrValues metrics-alias-map));
|
inherit (grafanaCfg.oauth) hostname slug;
|
||||||
state-directory = grafana-cfg.state-directory;
|
client-id = hostSecrets.grafana-client-id.target-file;
|
||||||
private-network = is-private-network;
|
client-secret = hostSecrets.grafana-client-secret.target-file;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
services.nginx =
|
services.nginx = mkIf (isPrometheus || isGrafana) {
|
||||||
mkIf (hostname == metrics-master || hostname == monitor-master) {
|
|
||||||
enable = true;
|
enable = true;
|
||||||
recommendedOptimisation = true;
|
recommendedOptimisation = true;
|
||||||
recommendedProxySettings = true;
|
recommendedProxySettings = true;
|
||||||
|
|
||||||
virtualHosts =
|
virtualHosts = let scheme = if privateNetwork then "http" else "https";
|
||||||
let scheme = if is-private-network then "http" else "https";
|
|
||||||
in {
|
in {
|
||||||
"metrics.${domain-name}" = mkIf (hostname == metrics-master) {
|
"metrics.${domainName}".locations."/".return =
|
||||||
enableACME = !is-private-network;
|
"302 http://prometheus.${domainName}";
|
||||||
forceSSL = !is-private-network;
|
"monitor.${domainName}".locations."/".return =
|
||||||
locations."/".return = let alias = metrics-alias-map.${hostname};
|
"302 http://grafana.${domainName}";
|
||||||
in "301 ${scheme}://${alias}.${domain-name}$request_uri";
|
|
||||||
};
|
"grafana.${domainName}" = {
|
||||||
"monitor.${domain-name}" = mkIf (hostname == monitor-master) {
|
enableACME = !privateNetwork;
|
||||||
enableACME = !is-private-network;
|
forceSSL = !privateNetwork;
|
||||||
forceSSL = !is-private-network;
|
locations."/".proxyPass =
|
||||||
locations."/".return = let alias = monitor-alias-map.${hostname};
|
"http://localhost:${toString config.fudo.services.grafana.port}";
|
||||||
in "301 ${scheme}://${alias}.${domain-name}$request_uri";
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,14 +3,6 @@
|
||||||
with lib;
|
with lib;
|
||||||
let local-domain = "sea.fudo.org";
|
let local-domain = "sea.fudo.org";
|
||||||
in {
|
in {
|
||||||
# imports = [ ./seattle/authelia.nix ./seattle/keycloak.nix ];
|
|
||||||
imports = [
|
|
||||||
# (import ./seattle/authentik.nix {
|
|
||||||
# authentikHost = "nostromo";
|
|
||||||
# proxyHost = "limina";
|
|
||||||
# externalHostname = "authentik.fudo.link";
|
|
||||||
# })
|
|
||||||
];
|
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
fudo = {
|
fudo = {
|
||||||
|
@ -63,16 +55,6 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
fileSystems = {
|
fileSystems = {
|
||||||
# "/mnt/documents" = {
|
|
||||||
# device = "whitedwarf.${local-domain}:/volume1/Documents";
|
|
||||||
# fsType = "nfs4";
|
|
||||||
# options = [ "comment=systemd.automount" ];
|
|
||||||
# };
|
|
||||||
# "/mnt/downloads" = {
|
|
||||||
# device = "whitedwarf.${local-domain}:/volume1/Downloads";
|
|
||||||
# fsType = "nfs4";
|
|
||||||
# options = [ "comment=systemd.automount" ];
|
|
||||||
# };
|
|
||||||
"/mnt/music" = {
|
"/mnt/music" = {
|
||||||
device = "doraemon.${local-domain}:/volume1/Music";
|
device = "doraemon.${local-domain}:/volume1/Music";
|
||||||
fsType = "nfs";
|
fsType = "nfs";
|
||||||
|
@ -83,10 +65,6 @@ in {
|
||||||
fsType = "nfs";
|
fsType = "nfs";
|
||||||
options = [ "comment=systemd.automount" ];
|
options = [ "comment=systemd.automount" ];
|
||||||
};
|
};
|
||||||
# fileSystems."/mnt/security" = {
|
|
||||||
# device = "panopticon.${local-domain}:/srv/kerberos/data";
|
|
||||||
# fsType = "nfs4";
|
|
||||||
# };
|
|
||||||
"/mnt/cargo_video" = {
|
"/mnt/cargo_video" = {
|
||||||
device = "cargo.${local-domain}:/volume1/video";
|
device = "cargo.${local-domain}:/volume1/video";
|
||||||
fsType = "nfs4";
|
fsType = "nfs4";
|
||||||
|
@ -98,41 +76,21 @@ in {
|
||||||
options = [ "sec=krb5i" "x-systemd.automount" ];
|
options = [ "sec=krb5i" "x-systemd.automount" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
# "proto=tcp"
|
|
||||||
|
|
||||||
# # NOTE: these are pointing directly to nostromo so the krb lookup works
|
# # NOTE: these are pointing directly to nostromo so the krb lookup works
|
||||||
"/net/documents" = {
|
"/net/documents" = {
|
||||||
device = "nostromo.${local-domain}:/export/documents";
|
device = "nostromo.${local-domain}:/export/documents";
|
||||||
fsType = "nfs4";
|
fsType = "nfs4";
|
||||||
options = [
|
options = [ "sec=krb5p" "x-systemd.automount" ];
|
||||||
"sec=krb5p"
|
|
||||||
"x-systemd.automount"
|
|
||||||
# "vers=4"
|
|
||||||
# "minorversion=2"
|
|
||||||
# "proto=tcp"
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
"/net/downloads" = {
|
"/net/downloads" = {
|
||||||
device = "nostromo.${local-domain}:/export/downloads";
|
device = "nostromo.${local-domain}:/export/downloads";
|
||||||
fsType = "nfs4";
|
fsType = "nfs4";
|
||||||
options = [
|
options = [ "sec=krb5i" "x-systemd.automount" ];
|
||||||
"sec=krb5i"
|
|
||||||
"x-systemd.automount"
|
|
||||||
# "vers=4"
|
|
||||||
# "minorversion=2"
|
|
||||||
# "proto=tcp"
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
"/net/projects" = {
|
"/net/projects" = {
|
||||||
device = "nostromo.${local-domain}:/export/projects";
|
device = "nostromo.${local-domain}:/export/projects";
|
||||||
fsType = "nfs4";
|
fsType = "nfs4";
|
||||||
options = [
|
options = [ "sec=krb5p" "x-systemd.automount" ];
|
||||||
"sec=krb5p"
|
|
||||||
"x-systemd.automount"
|
|
||||||
# "vers=4"
|
|
||||||
# "minorversion=2"
|
|
||||||
# "proto=tcp"
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib; {
|
||||||
{
|
|
||||||
config = let
|
config = let
|
||||||
filterExistingUsers = users: group-members:
|
filterExistingUsers = users: group-members:
|
||||||
let user-list = attrNames users;
|
let user-list = attrNames users;
|
||||||
in filter (username: elem username user-list)
|
in filter (username: elem username user-list) group-members;
|
||||||
group-members;
|
|
||||||
|
|
||||||
hostname = config.instance.hostname;
|
hostname = config.instance.hostname;
|
||||||
host-cfg = config.fudo.hosts.${hostname};
|
host-cfg = config.fudo.hosts.${hostname};
|
||||||
|
@ -14,8 +12,8 @@ with lib;
|
||||||
sys = config.instance;
|
sys = config.instance;
|
||||||
in {
|
in {
|
||||||
fudo.auth.ldap-server = {
|
fudo.auth.ldap-server = {
|
||||||
users = filterAttrs
|
users =
|
||||||
(username: userOpts: userOpts.ldap-hashed-passwd != null)
|
filterAttrs (username: userOpts: userOpts.ldap-hashed-passwd != null)
|
||||||
config.fudo.users;
|
config.fudo.users;
|
||||||
|
|
||||||
groups = config.fudo.groups;
|
groups = config.fudo.groups;
|
||||||
|
@ -29,14 +27,10 @@ with lib;
|
||||||
'';
|
'';
|
||||||
|
|
||||||
environment.etc = mapAttrs' (username: userOpts:
|
environment.etc = mapAttrs' (username: userOpts:
|
||||||
nameValuePair
|
nameValuePair "ssh/private_keys.d/${username}" {
|
||||||
"ssh/private_keys.d/${username}"
|
|
||||||
{
|
|
||||||
text = concatStringsSep "\n"
|
text = concatStringsSep "\n"
|
||||||
(map (keypair: readFile keypair.public-key)
|
(map (keypair: readFile keypair.public-key) userOpts.ssh-keys);
|
||||||
userOpts.ssh-keys);
|
}) sys.local-users;
|
||||||
})
|
|
||||||
sys.local-users;
|
|
||||||
|
|
||||||
users = {
|
users = {
|
||||||
users = mapAttrs (username: userOpts: {
|
users = mapAttrs (username: userOpts: {
|
||||||
|
@ -57,8 +51,7 @@ with lib;
|
||||||
gid = groupOpts.gid;
|
gid = groupOpts.gid;
|
||||||
members = filterExistingUsers sys.local-users groupOpts.members;
|
members = filterExistingUsers sys.local-users groupOpts.members;
|
||||||
}) sys.local-groups) // {
|
}) sys.local-groups) // {
|
||||||
wheel = { members = sys.local-admins; };
|
wheel.members = sys.local-admins;
|
||||||
docker = mkIf (host-cfg.docker-server) { members = sys.local-admins; };
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -73,9 +66,7 @@ with lib;
|
||||||
# Domain = local-domain;
|
# Domain = local-domain;
|
||||||
"Local-Realms" = local-realm;
|
"Local-Realms" = local-realm;
|
||||||
};
|
};
|
||||||
Translation = {
|
Translation = { GSS-Methods = "static"; };
|
||||||
GSS-Methods = "static";
|
|
||||||
};
|
|
||||||
Static = let
|
Static = let
|
||||||
generate-admin-entry = admin: userOpts:
|
generate-admin-entry = admin: userOpts:
|
||||||
nameValuePair "${admin}/root@${local-realm}" "root";
|
nameValuePair "${admin}/root@${local-realm}" "root";
|
||||||
|
@ -84,8 +75,7 @@ with lib;
|
||||||
|
|
||||||
admin-entries =
|
admin-entries =
|
||||||
mapAttrs' generate-admin-entry (getAttrs local-admins local-users);
|
mapAttrs' generate-admin-entry (getAttrs local-admins local-users);
|
||||||
user-entries =
|
user-entries = mapAttrs' generate-user-entry local-users;
|
||||||
mapAttrs' generate-user-entry local-users;
|
|
||||||
in admin-entries // user-entries;
|
in admin-entries // user-entries;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -94,6 +84,7 @@ with lib;
|
||||||
groups-with-members = attrNames
|
groups-with-members = attrNames
|
||||||
(filterAttrs (group: groupOpts: (length groupOpts.members) > 0)
|
(filterAttrs (group: groupOpts: (length groupOpts.members) > 0)
|
||||||
sys.local-groups);
|
sys.local-groups);
|
||||||
in map (group: "d /home/${group} 550 root ${group} - -") groups-with-members;
|
in map (group: "d /home/${group} 550 root ${group} - -")
|
||||||
|
groups-with-members;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ with lib; {
|
||||||
users = {
|
users = {
|
||||||
niten = {
|
niten = {
|
||||||
uid = 10000;
|
uid = 10000;
|
||||||
primary-group = "admin";
|
primary-group = "fudo";
|
||||||
common-name = "Peter Selby";
|
common-name = "Peter Selby";
|
||||||
given-name = "Peter";
|
given-name = "Peter";
|
||||||
surname = "Selby";
|
surname = "Selby";
|
||||||
|
@ -139,7 +139,7 @@ with lib; {
|
||||||
|
|
||||||
reaper = {
|
reaper = {
|
||||||
uid = 10049;
|
uid = 10049;
|
||||||
primary-group = "admin";
|
primary-group = "fudo";
|
||||||
common-name = "Jonathan Stewart";
|
common-name = "Jonathan Stewart";
|
||||||
given-name = "Jonathan";
|
given-name = "Jonathan";
|
||||||
surname = "Stewart";
|
surname = "Stewart";
|
||||||
|
|
842
flake.lock
842
flake.lock
File diff suppressed because it is too large
Load Diff
24
flake.nix
24
flake.nix
|
@ -2,7 +2,7 @@
|
||||||
description = "Fudo Host Configuration";
|
description = "Fudo Host Configuration";
|
||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "nixpkgs/nixos-23.05";
|
nixpkgs.url = "nixpkgs/nixos-23.11";
|
||||||
|
|
||||||
fudo-home = {
|
fudo-home = {
|
||||||
url = "git+https://git.fudo.org/fudo-nix/home.git";
|
url = "git+https://git.fudo.org/fudo-nix/home.git";
|
||||||
|
@ -39,8 +39,6 @@
|
||||||
|
|
||||||
nixpkgsUnstable.url = "nixpkgs/nixos-unstable";
|
nixpkgsUnstable.url = "nixpkgs/nixos-unstable";
|
||||||
|
|
||||||
nixpkgs2111.url = "nixpkgs/nixos-21.11";
|
|
||||||
|
|
||||||
wallfly = {
|
wallfly = {
|
||||||
url = "git+https://git.fudo.org/fudo-public/wallfly.git";
|
url = "git+https://git.fudo.org/fudo-public/wallfly.git";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
@ -136,6 +134,11 @@
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
grafana-module = {
|
||||||
|
url = "git+https://git.fudo.org/fudo-public/grafana-module.git";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
|
|
||||||
textfiles = {
|
textfiles = {
|
||||||
url = "git+https://git.informis.land/informis/textfiles.git";
|
url = "git+https://git.informis.land/informis/textfiles.git";
|
||||||
flake = false;
|
flake = false;
|
||||||
|
@ -143,11 +146,11 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = { self, nixpkgs, fudo-home, fudo-lib, fudo-entities, fudo-pkgs
|
outputs = { self, nixpkgs, fudo-home, fudo-lib, fudo-entities, fudo-pkgs
|
||||||
, fudo-secrets, chute, chuteUnstable, nixpkgsUnstable, nixpkgs2111, pricebot
|
, fudo-secrets, chute, chuteUnstable, nixpkgsUnstable, pricebot, wallfly
|
||||||
, wallfly, objectifier, nexus, suanni, snooper, tattler, lemmy-docker
|
, objectifier, nexus, suanni, snooper, tattler, lemmy-docker
|
||||||
, tesla-mate-container, mastodon-container, authentik-container
|
, tesla-mate-container, mastodon-container, authentik-container
|
||||||
, nextcloud-container, textfiles, matrix-module, mail-server
|
, nextcloud-container, textfiles, matrix-module, mail-server
|
||||||
, authoritative-dns, frigate-container, ... }@inputs:
|
, authoritative-dns, frigate-container, grafana-module, ... }@inputs:
|
||||||
with nixpkgs.lib;
|
with nixpkgs.lib;
|
||||||
let
|
let
|
||||||
fudo-nixos-hosts = filterAttrs (hostname: hostOpts: hostOpts.nixos-system)
|
fudo-nixos-hosts = filterAttrs (hostname: hostOpts: hostOpts.nixos-system)
|
||||||
|
@ -185,13 +188,7 @@
|
||||||
chute = chute.packages.${arch}.chute;
|
chute = chute.packages.${arch}.chute;
|
||||||
chuteUnstable = chuteUnstable.packages.${arch}.chute;
|
chuteUnstable = chuteUnstable.packages.${arch}.chute;
|
||||||
})
|
})
|
||||||
(final: prev: {
|
(final: prev: { pkgsUnstable = unstable; })
|
||||||
pkgs2111 = import nixpkgs2111 {
|
|
||||||
system = arch;
|
|
||||||
config.allowUnfree = true;
|
|
||||||
};
|
|
||||||
pkgsUnstable = unstable;
|
|
||||||
})
|
|
||||||
(final: prev: {
|
(final: prev: {
|
||||||
signal-desktop = unstable.signal-desktop;
|
signal-desktop = unstable.signal-desktop;
|
||||||
factorio-experimental = unstable.factorio-experimental;
|
factorio-experimental = unstable.factorio-experimental;
|
||||||
|
@ -234,6 +231,7 @@
|
||||||
mail-server.nixosModules.default
|
mail-server.nixosModules.default
|
||||||
authoritative-dns.nixosModules.default
|
authoritative-dns.nixosModules.default
|
||||||
frigate-container.nixosModules.default
|
frigate-container.nixosModules.default
|
||||||
|
grafana-module.nixosModules.default
|
||||||
|
|
||||||
nexus.nixosModules.nexus-client
|
nexus.nixosModules.nexus-client
|
||||||
nexus.nixosModules.nexus-server
|
nexus.nixosModules.nexus-server
|
||||||
|
|
Loading…
Reference in New Issue