Lemmy broken on Germany

This commit is contained in:
niten 2024-02-10 16:53:55 -08:00
parent 7a73028ad2
commit cf10f910bd
18 changed files with 1501 additions and 920 deletions

View File

@ -6,22 +6,41 @@ let
localDomain = "fudo.org";
domainSecrets = config.fudo.secrets.files.domain-secrets."${localDomain}";
hostSecrets = config.fudo.secrets.host-secrets."${hostname}";
inherit (pkgs.lib) getDomainHosts getHostIpv4 getHostIpv6 getHostFqdn;
inherit (pkgs.lib)
getDomainHosts getHostIpv4 getHostIpv6 getHostFqdn getSiteV4PrefixLength;
domain = config.fudo.domains."${localDomain}";
authentikHost = "legatus";
authentikImage = "ghcr.io/goauthentik/server:2023.10.7";
primaryNameserver = "germany";
webmailHost = "germany";
defaultHost = "germany";
mastodonHost = "germany";
mastodonHostname = "fudo.live";
giteaHost = "germany";
giteaHostname = "fudo.dev";
giteaIpv4Address = "208.81.3.118";
cloudHost = "germany";
cloudHostname = "fudo.cloud";
lemmyHost = "germany";
lemmyHostname = "fudo.social";
matrixHost = "germany";
matrixHostname = "fudo.im";
immichHost = "germany";
immichHostname = "pics.fudo.org";
servedDomains = [
"fudo.org"
"test.fudo.org"
@ -30,35 +49,36 @@ let
"fudo.im"
"fudo.live"
"fudo.social"
"fudo.dev"
"fudo.cloud"
"stewartsoundservices.ca"
];
static = ../../static;
in {
imports = [
(import ./fudo.org/authentik.nix {
inherit authentikHost;
authentikImage = "ghcr.io/goauthentik/server:2023.10.6";
})
(import ./fudo.org/authentik.nix { inherit authentikHost authentikImage; })
(import ./fudo.org/mastodon.nix {
mastodonHost = "germany";
mastodonHost = mastodonHost;
mastodonHostname = mastodonHostname;
mastodonWebDomain = mastodonHostname;
mastodonOidcClientId = domainSecrets."mastodon-oidc.clientid";
mastodonOidcClientSecret = domainSecrets."mastodon-oidc.secret";
})
(import ./fudo.org/nextcloud.nix {
nextcloudHost = "legatus";
nextcloudHostname = "cloud.fudo.org";
nextcloudHost = cloudHost;
nextcloudHostname = cloudHostname;
nextcloudPackage = pkgs.nextcloud28;
})
(import ./fudo.org/matrix.nix {
matrixHost = "germany";
matrixServerName = "fudo.im";
matrixHost = matrixHost;
matrixServerName = matrixHostname;
openIdClientId = readFile domainSecrets."matrix-oidc.clientid";
openIdClientSecret = readFile domainSecrets."matrix-oidc.secret";
})
(import ./fudo.org/mail-server.nix (rec {
primaryMailserver = "france";
primaryMailserver = "germany";
primaryDomain = "fudo.org";
authentikServer = "authentik.fudo.org";
ldapBase = "dc=fudo,dc=org";
@ -73,8 +93,21 @@ in {
];
config = {
# All Fudo hosts should redirect selby.ca to the selbyhomecentre website.
systemd.services = { lemmy.after = [ "postgresql.service" ]; };
services = {
immichContainer = mkIf (hostname == immichHost) {
enable = true;
images = let immichVersion = "v1.94.1";
in {
immich = "ghcr.io/immich-app/immich-server:${immichVersion}";
immich-ml =
"ghcr.io/immich-app/immich-machine-learning:${immichVersion}";
redis = "redis:6.2-alpine";
postgresql = "tensorchord/pgvecto-rs:pg14-v0.1.11";
};
};
nginx.virtualHosts = {
# Pass requests to selby on to selbyhomecentre
"selby.ca".locations."/".return =
@ -82,34 +115,110 @@ in {
"www.selby.ca".locations."/".return =
"301 https://selbyhomecentre.com$request_uri";
# For Mastodon
"fudo.org".locations = {
"/.well-known/webfinger" = {
return = "301 http://${mastodonHostname}";
extraConfig = "add_header Access-Control-Allow-Origin '*';";
"pics.fudo.org" = mkIf (hostname == immichHost) {
enableACME = true;
forceSSL = true;
locations."/" = {
proxyPass = "http://localhost:${
toString config.services.immichContainer.port
}/";
proxyWebsockets = true;
};
"/.well-known/host-meta" = {
return = "301 https://${mastodonHostname}$request_uri";
};
"fudo.org" = mkIf (hostname == defaultHost) {
enableACME = true;
forceSSL = true;
locations = let
mkWellKnown = data: ''
add_header Content-Type application/json;
add_header Access-Control-Allow-Origin *;
return 200 '${builtins.toJSON data}';
'';
in {
# Mastodon
"/.well-known/webfinger" = {
return = "301 https://${mastodonHostname}";
extraConfig = "add_header Access-Control-Allow-Origin '*';";
};
"/.well-known/host-meta" = {
return = "301 https://${mastodonHostname}$request_uri";
};
# Matrix
"/.well-known/matrix/server".extraConfig =
mkWellKnown { "m.server" = "matrix.${matrixHostname}:443"; };
"/.well-known/matrix/client".extraConfig = mkWellKnown {
"m.homeserver".base_url = "https://web.${matrixHostname}:443";
};
"/.well-known/acme-challenge" = {
root = "/var/lib/acme/acme-challenge/";
extraConfig = "auth_basic off;";
};
};
};
};
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";
};
};
# lemmyContainer = {
# enable = config.instance.hostname == lemmyHost;
# hostname = lemmyHostname;
# site-name = "Fudo Lemmy";
# smtp.host = "mail.fudo.org:587";
# # admin-password-file = hostSecrets.lemmyAdminPasswd.target-file;
# server-package = pkgs.pkgsUnstable.lemmy-server;
# };
};
fudo = {
secrets.host-secrets."${hostname}" = {
lemmyAdminPasswd = {
source-file =
pkgs.lib.passwd.stablerandom-passwd-file "lemmy-admin.passwd"
config.instance.build-seed;
target-file = "/run/lemmy/admin.passwd";
};
};
zones = {
"fudo.org".aliases = {
cloud = "germany.fudo.org.";
pics = "germany.fudo.org.";
webmail = "germany.fudo.org.";
};
"selby.ca".aliases.webmail = "germany.fudo.org.";
};
webmail = {
enable = hostname == webmailHost;
sites = {
"webmail.fudo.org" = {
title = "Fudo Webmail";
favicon = "${static}/fudo.org/favicon.ico";
mail-server = "mail.fudo.org";
domain = "fudo.org";
edit-mode = "Plain";
};
"webmail.fudo.link" = {
title = "Fudo Link Webmail";
favicon = "${static}/fudo.link/favicon.ico";
mail-server = "mail.fudo.org";
domain = "fudo.link";
edit-mode = "Plain";
layout-mode = "bottom";
};
"webmail.selby.ca" = {
title = "Selby Webmail";
favicon = "${static}/selby.ca/favicon.ico";
mail-server = "mail.fudo.org";
domain = "selby.ca";
};
};
};
services = {
# TEMPORARY
# DON'T enable, we're using mail-container instead
mail-server.enable = false;
jabber = {
@ -127,6 +236,25 @@ in {
};
};
lemmy = {
enable = hostname == lemmyHost;
hostname = "fudo.social";
site-name = "Fudo Lemmy";
smtp.host = "mail.fudo.org";
};
gitea-container = let siteName = config.fudo.hosts."${giteaHost}".site;
in {
enable = hostname == giteaHost;
site-name = "Fudo Git";
hostname = giteaHostname;
trusted-networks = config.instance.local-networks;
networking.ipv4 = {
address = giteaIpv4Address;
prefixLength = getSiteV4PrefixLength siteName;
};
};
authoritative-dns = {
enable = hostname == primaryNameserver;
@ -167,23 +295,56 @@ in {
mkDomain = domain: extraConfig:
{
default-host = defaultDeets;
ksk =
config.fudo.secrets.files.dns.key-signing-keys."${domain}";
} // extraConfig;
getDeets = hostname: description: {
inherit (config.fudo.zones."fudo.org".hosts."${hostname}")
ipv4-address ipv6-address sshfp-records;
};
in {
"fudo.org" = mkDomain "fudo.org" {
reverse-zones = [ "208.81.1.128/28" "208.81.3.112/28" ];
mail = fudoMailservers;
default-host = defaultDeets;
};
"test.fudo.org" = mkDomain "test.fudo.org" { };
"selby.ca" = mkDomain "selby.ca" { mail = fudoMailservers; };
"fudo.ca" = mkDomain "fudo.ca" { mail = fudoMailservers; };
"fudo.im" = mkDomain "fudo.im" { mail = fudoMailservers; };
"stewartsoundservices.ca" =
mkDomain "stewartsoundservices.ca" { mail = fudoMailservers; };
"fudo.live" = mkDomain "fudo.live" { mail = fudoMailservers; };
"fudo.social" = mkDomain "fudo.social" { mail = fudoMailservers; };
"selby.ca" = mkDomain "selby.ca" {
mail = fudoMailservers;
default-host = defaultDeets;
};
"fudo.ca" = mkDomain "fudo.ca" {
mail = fudoMailservers;
default-host = defaultDeets;
};
"fudo.im" = mkDomain "fudo.im" {
mail = fudoMailservers;
default-host = getDeets matrixHost "fudo.im primary server";
};
"stewartsoundservices.ca" = mkDomain "stewartsoundservices.ca" {
mail = fudoMailservers;
default-host = defaultDeets;
};
"fudo.live" = mkDomain "fudo.live" {
mail = fudoMailservers;
default-host = getDeets mastodonHost "fudo.live primary server";
};
"fudo.social" = mkDomain "fudo.social" {
mail = fudoMailservers;
default-host = getDeets lemmyHost "fudo.social primary server";
};
"fudo.dev" = mkDomain "fudo.dev" {
mail = fudoMailservers;
default-host = {
ipv4-address = giteaIpv4Address;
description = "fudo.dev";
};
};
"fudo.cloud" = mkDomain "fudo.cloud" {
mail = fudoMailservers;
default-host = getDeets cloudHost "fudo.dev primary server";
};
};
};
};

View File

@ -22,39 +22,48 @@ in {
# };
fudo = {
zones."${primaryDomain}" = let
mailserverDomain = config.fudo.hosts."${primaryMailserver}".domain;
mailserverIps = {
ipv4-address = getHostIpv4 primaryMailserver;
ipv6-address = getHostIpv6 primaryMailserver;
};
srvRecord = host: port: [{ inherit host port; }];
zones = let
mailserverIp = getHostIpv4 primaryMailserver;
spfRecords = [
''@ IN TXT "v=spf1 mx ip4:${mailserverIp}/32 -all"''
''@ IN SPF "v=spf1 mx ip4:${mailserverIp}/32 -all"''
];
in {
srv-records = {
tcp = {
imap = srvRecord "imap.${primaryDomain}" 143;
imaps = srvRecord "imap.${primaryDomain}" 993;
smtp = srvRecord "smtp.${primaryDomain}" 25;
submission = srvRecord "smtp.${primaryDomain}" 587;
submissions = srvRecord "smtp.${primaryDomain}" 465;
"${primaryDomain}" = let
mailserverDomain = config.fudo.hosts."${primaryMailserver}".domain;
mailserverIps = {
ipv4-address = getHostIpv4 primaryMailserver;
ipv6-address = getHostIpv6 primaryMailserver;
};
udp = {
smtp = srvRecord "smtp.${primaryDomain}" 25;
submission = srvRecord "smtp.${primaryDomain}" 587;
srvRecord = host: port: [{ inherit host port; }];
in {
srv-records = {
tcp = {
imap = srvRecord "mail.${primaryDomain}" 143;
imaps = srvRecord "mail.${primaryDomain}" 993;
smtp = srvRecord "mail.${primaryDomain}" 25;
submission = srvRecord "mail.${primaryDomain}" 587;
submissions = srvRecord "mail.${primaryDomain}" 465;
};
udp = {
smtp = srvRecord "mail.${primaryDomain}" 25;
submission = srvRecord "mail.${primaryDomain}" 587;
};
};
};
metric-records = genAttrs [ "dovecot" "postfix" "rspamd" ]
(_: srvRecord "mail-stats.${primaryDomain}" 443);
metric-records = genAttrs [ "dovecot" "postfix" "rspamd" ]
(_: srvRecord "mail-stats.${primaryDomain}" 443);
hosts = {
imap = mailserverIps;
smtp = mailserverIps;
mail = mailserverIps;
mail-stats = mailserverIps;
hosts = {
imap = mailserverIps;
smtp = mailserverIps;
mail = mailserverIps;
mail-stats = mailserverIps;
};
verbatim-dns-records = [ dkimRecord ] ++ spfRecords;
};
verbatim-dns-records = [ dkimRecord ];
};
} // (genAttrs (filter (dom: dom != primaryDomain) servedDomains)
(domain: { verbatim-dns-records = [ dkimRecord ] ++ spfRecords; }));
metrics.prometheus.service-discovery-dns =
(genAttrs [ "dovecot" "postfix" "rspamd" ]
@ -68,14 +77,14 @@ in {
sasl-domain = saslDomain;
trusted-networks = config.instance.local-networks;
smtp = {
hostname = "smtp.${primaryDomain}";
hostname = "mail.${primaryDomain}";
ssl-directory =
config.security.acme.certs."smtp.${primaryDomain}".directory;
config.security.acme.certs."mail.${primaryDomain}".directory;
};
imap = {
hostname = "imap.${primaryDomain}";
hostname = "mail.${primaryDomain}";
ssl-directory =
config.security.acme.certs."imap.${primaryDomain}".directory;
config.security.acme.certs."mail.${primaryDomain}".directory;
};
ldap = {
authentik-host = "https://${authentikServer}";
@ -112,7 +121,7 @@ in {
"imap.${primaryDomain}" = {
enableACME = true;
forceSSL = true;
locations."/".return = "301 https://webmail.${primaryDomain}";
locations."/".return = "403 Forbidden";
};
"mail.${primaryDomain}" = {
enableACME = true;
@ -122,7 +131,7 @@ in {
"smtp.${primaryDomain}" = {
enableACME = true;
forceSSL = true;
locations."/".return = "301 https://webmail.${primaryDomain}";
locations."/".return = "403 Forbidden";
};
};
};

View File

@ -7,50 +7,46 @@ with lib;
let
hostname = config.instance.hostname;
isMastodon = hostname == mastodonHost;
mkEnvFile = vars:
pkgs.writeText "mastodon.env"
(concatStringsSep "\n" (mapAttrsToList (k: v: ''${k}="${v}"'') vars));
in {
config = {
fudo.secrets.host-secrets."${hostname}".mastodonEnv = {
source-file = mkEnvFile {
OIDC_ENABLED = "true";
OIDC_DISPLAY_NAME = "fudo auth";
OIDC_DISCOVERY = "true";
OIDC_ISSUER = "https://authentik.fudo.org/application/o/mastodon/";
OIDC_AUTH_ENDPOINT =
"https://authentik.fudo.org/application/o/authorize/";
OIDC_SCOPE = "openid,profile,email";
OIDC_UID_FIELD = "sub";
OIDC_CLIENT_ID = readFile mastodonOidcClientId;
OIDC_CLIENT_SECRET = readFile mastodonOidcClientSecret;
OIDC_REDIRECT_URI =
"https://fudo.live/auth/auth/openid_connect/callback";
OIDC_SECURITY_ASSUME_EMAIL_IS_VERIFIED = "true";
OMNIAUTH_ONLY = "true";
ONE_CLICK_SSO_LOGIN = "true";
};
target-file = "/run/mastodon/env";
};
services = {
mastodonContainer = mkIf isMastodon {
enable = true;
hostname = mastodonWebDomain;
web-domain = mastodonHostname;
version = "v4.1.6";
state-directory = "/state/services/mastodon";
smtp.server = "mail.fudo.org";
environment = {
OIDC_ENABLED = "true";
OIDC_DISPLAY_NAME = "fudo auth";
OIDC_DISCOVERY = "true";
OIDC_ISSUER = "https://authentik.fudo.org/application/o/mastodon/";
OIDC_AUTH_ENDPOINT =
"https://authentik.fudo.org/application/o/authorize/";
OIDC_SCOPE = "openid,profile,email";
OIDC_UID_FIELD = "sub";
OIDC_CLIENT_ID = readFile mastodonOidcClientId;
OIDC_CLIENT_SECRET = readFile mastodonOidcClientSecret;
OIDC_REDIRECT_URI =
"https://mastodon.fudo.org/auth/auth/openid_connect/callback";
OIDC_SECURITY_ASSUME_EMAIL_IS_VERIFIED = "true";
};
};
nginx = mkIf isMastodon {
enable = true;
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedProxySettings = true;
virtualHosts = {
"${mastodonHostname}" = {
enableACME = true;
forceSSL = true;
locations."/" = {
proxyPass = "http://localhost:${
toString config.services.mastodonContainer.port
}";
proxyWebsockets = true;
};
};
hostname = mastodonHostname;
domain = mastodonWebDomain;
environment-files = [
config.fudo.secrets.host-secrets."${hostname}".mastodonEnv.target-file
];
smtp = {
host = "mail.fudo.org";
port = 25;
};
allow-registrations = false;
};
};
};

View File

@ -40,6 +40,10 @@ in {
};
extraConfig = ''
client_body_buffer_size 1024m;
client_max_body_size 4096m;
fastcgi_read_timeout 120s;
proxy_max_temp_file_size 4096m;
proxy_buffering off;
'';
};
};

View File

@ -5,6 +5,8 @@ let
hostname = config.instance.hostname;
hostSecrets = config.fudo.secrets.host-secrets."${hostname}";
domainName = "sea.fudo.org";
frigateExternalHost = "sea-cam.fudo.link";
frigateHost = "zbox";
frigateDirectory = frigateCfg.state-directory;
@ -12,9 +14,15 @@ let
pkgs.lib.passwd.stablerandom-passwd-file "frigate-mqtt-passwd"
config.instance.build-seed;
immichHost = "toothless";
in {
config = {
fudo.zones."sea.fudo.org".aliases = { "frigate" = "zbox"; };
fudo.zones."sea.fudo.org".aliases = {
chat = "nostromo";
frigate = "zbox";
immich = immichHost;
};
fudo = {
services = {
metrics = {
@ -37,8 +45,33 @@ in {
};
services = {
frigateContainer = {
enable = config.instance.hostname == frigateHost;
immichContainer = mkIf (hostname == immichHost) {
enable = true;
images = let immichVersion = "v1.94.1";
in {
immich = "ghcr.io/immich-app/immich-server:${immichVersion}";
immich-ml =
"ghcr.io/immich-app/immich-machine-learning:${immichVersion}";
redis = "redis:6.2-alpine";
postgresql = "tensorchord/pgvecto-rs:pg14-v0.1.11";
};
};
nginx = mkIf (hostname == immichHost) {
enable = true;
recommendedOptimisation = true;
recommendedGzipSettings = true;
recommendedProxySettings = true;
virtualHosts."immich.${domainName}".locations."/" = {
proxyPass = "http://${immichHost}.${domainName}:${
toString config.services.immichContainer.port
}/";
recommendedProxySettings = true;
};
};
frigateContainer = mkIf (config.instance.hostname == frigateHost) {
enable = true;
log-level = "info";
images.frigate = "ghcr.io/blakeblackshear/frigate:0.13.0-beta5";
cameras =

View File

@ -1,5 +1,6 @@
{ config, lib, pkgs, ... }:
with lib;
let generateMac = pkgs.lib.network.generate-mac-address;
in {
@ -22,6 +23,8 @@ in {
extraModulePackages = [ ];
kernelPackages = pkgs.linuxPackages_latest;
supportedFilesystems = [ "bcachefs" ];
loader.grub = {
enable = true;
devices = [
@ -85,11 +88,45 @@ in {
fsType = "btrfs";
options = [ "subvol=@container-data" "noatime" "compress=zstd" "noexec" ];
};
## BROKEN!
# "/store" = {
# device = lib.concatStringsSep ":" [
# "/dev/disk/by-id/ata-Crucial_CT525MX300SSD1_171516B3CB40"
# "/dev/disk/by-id/ata-ST8000DM004-2U9188_ZR153N5H"
# "/dev/disk/by-id/ata-ST8000DM004-2U9188_ZR153CDK"
# ];
# fsType = "bcachefs";
# options = [ "noexec" "compression=zstd" ];
# };
};
systemd.services.mount-bcachefs-store = let
mountpoint = "/store";
deviceString = concatStringsSep ":" [
"/dev/disk/by-id/ata-Crucial_CT525MX300SSD1_171516B3CB40"
"/dev/disk/by-id/ata-ST8000DM004-2U9188_ZR153N5H"
"/dev/disk/by-id/ata-ST8000DM004-2U9188_ZR153CDK"
];
options = concatStringsSep "," [ "noexec" "compression=zstd" ];
in {
description =
"Mount ${mountpoint} filesystem (can't use fileSystems with multiple devices).";
wantedBy = [ "local-fs.target" ];
script = ''
[ -d ${mountpoint} ] || mkdir ${mountpoint}
if ${pkgs.util-linux}/bin/findmnt ${mountpoint}; then
echo "already mounted: ${mountpoint}"
else
echo "mounting filesystem: ${mountpoint}"
${pkgs.bcachefs-tools}/bin/mount.bcachefs ${deviceString} -o ${options} ${mountpoint}
fi
'';
};
swapDevices = [{ device = "/dev/disk/by-label/germany-swap"; }];
nix.settings.max-jobs = lib.mkDefault 24;
nix.settings.max-jobs = mkDefault 24;
hardware.bluetooth.enable = false;

View File

@ -248,6 +248,16 @@ in {
(trustedNetworkClauses ++ [ "deny all;" ]);
};
};
"pics.fudo.link" = {
enableACME = true;
forceSSL = true;
locations."/" = {
proxyPass = "http://immich.sea.fudo.org/";
proxyWebsockets = true;
recommendedProxySettings = true;
};
};
};
};

View File

@ -31,7 +31,7 @@ in {
};
firewall = {
enable = false;
interfaces."podman+".allowedUDPPorts = [ 53 ];
interfaces."podman[0-9]+".allowedUDPPorts = [ 53 ];
};
};
@ -60,6 +60,11 @@ in {
'';
};
};
webmail-init = {
after = [ "fudo-secrets.target" ];
requires = [ "fudo-secrets.target" ];
};
};
timers.fudo-mail-sync = {
@ -79,13 +84,42 @@ in {
enable = true;
autoPrune.enable = true;
dockerSocket.enable = true;
defaultNetwork.settings.dns_enabled = true;
dockerCompat = true;
defaultNetwork.settings = {
dns_enabled = true;
network_dns_servers = [ "1.1.1.1" "8.8.4.4" ];
};
};
oci-containers.backend = "podman";
arion.backend = "podman-socket";
};
services.lemmyDocker.state-directory = "/state/services/lemmy";
services = {
lemmyContainer.state-directory = "/state/services/lemmy-container";
mastodonContainer.streaming-processes = 6;
nextcloudContainer = {
state-directory = "/state/services/nextcloud";
store-directory = "/store/nextcloud";
};
immichContainer = {
state-directory = "/state/services/immich";
store-directory = "/store/immich";
};
nginx = {
enable = true;
commonHttpConfig = ''
log_format with_response_time '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$request_time" "$upstream_response_time"';
access_log /var/log/nginx/access.log with_response_time;
'';
recommendedTlsSettings = true;
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedProxySettings = true;
};
};
fudo = {
client.dns = {
@ -105,12 +139,18 @@ in {
state-directory = "/state/services/postgresql";
};
webmail.state-directory = "/state/services/webmail";
services = {
auth = {
kerberos.state-directory = "/state/services/kerberos";
ldap.state-directory = "/state/services/ldap";
};
authoritative-dns.state-directory = "/state/services/dns";
gitea-container = {
networking.interface = "enp5s0f0";
state-directory = "/state/services/gitea-container";
};
jabber.state-directory = "/state/services/jabber";
logging.loki.state-directory = "/state/services/loki";
mail-server.state-directory = "/state/services/mail";
@ -118,6 +158,7 @@ in {
prometheus.state-directory = "/state/services/prometheus";
grafana.state-directory = "/state/services/grafana";
};
nexus.dns-server.listen-addresses = [ primary-ip ];
postgresql = {
state-directory = "/state/services/postgresql";
keytab = extractFudoKeytab {

View File

@ -125,22 +125,6 @@ in {
local-networks = config.instance.local-networks;
state-directory = "/state/services/postgresql";
};
services.gitea-container = {
enable = true;
site-name = "Seattle Fudo Git";
hostname = "git.fudo.org";
state-directory = "/state/services/gitea";
trusted-networks = config.instance.local-networks;
openid-urls = [ "https://authentik.fudo.org/" ];
networking = {
interface = "eno2";
ipv4 = {
address = "10.0.0.15";
prefixLength = 24;
};
};
};
};
virtualisation = {

View File

@ -14,7 +14,7 @@ let
host-secrets = config.fudo.secrets.host-secrets.${hostname};
postgresql-user = config.systemd.services.postgresql.serviceConfig.User;
# postgresql-user = config.systemd.services.postgresql.serviceConfig.User;
files = config.fudo.secrets.files;
@ -48,10 +48,10 @@ in {
"L /etc/adjtime - - - - /state/etc/adjtime"
"d /state/services 0555 - - - -"
];
services.grafana = {
bindsTo = [ "postgresql.service" ];
requires = [ "postgresql.service" ];
};
# services.grafana = {
# bindsTo = [ "postgresql.service" ];
# requires = [ "postgresql.service" ];
# };
};
environment = { systemPackages = local-packages; };
@ -69,11 +69,11 @@ in {
# part-of = [ config.fudo.auth.ldap-server.systemd-target ];
# };
postgresql = {
user = postgresql-user;
dependent-services = [ "postgresql.service" ];
part-of = [ config.fudo.postgresql.systemd-target ];
};
# postgresql = {
# user = postgresql-user;
# dependent-services = [ "postgresql.service" ];
# part-of = [ config.fudo.postgresql.systemd-target ];
# };
};
};
@ -99,13 +99,13 @@ in {
};
};
postgresql = {
state-directory = "/state/services/postgresql";
keytab = extractFudoKeytab {
realm = domain.gssapi-realm;
principals = [ "postgres/${host-fqdn}" ];
};
};
# postgresql = {
# state-directory = "/state/services/postgresql";
# keytab = extractFudoKeytab {
# realm = domain.gssapi-realm;
# principals = [ "postgres/${host-fqdn}" ];
# };
# };
metrics = {
prometheus.state-directory = "/state/services/prometheus";

View File

@ -28,21 +28,14 @@ in {
Defaults lecture = never
'';
services = {
immichContainer = {
state-directory = "/state/immich/state";
store-directory = "/state/immich/store";
};
};
fudo = {
# minecraft-server = {
# enable = true;
# data-dir = "/state/services/minecraft";
# world-name = "TLS";
# motd = "Welcome to Jasper's TLS minecraft server.";
# game-mode = "survival";
# difficulty = 1;
# allow-cheats = true;
# allocated-memory = 16;
# port = 25555;
# query-port = 25556;
# rcon-port = 25557;
# world-seed = 2090763904884813452;
# };
minecraft-clj = {
enable = true;
state-directory = "/state/services/minecraft-clj";
@ -86,6 +79,21 @@ in {
};
};
virtualisation = {
podman = {
enable = true;
autoPrune.enable = true;
dockerSocket.enable = true;
dockerCompat = true;
defaultNetwork.settings = {
dns_enabled = true;
network_dns_servers = [ "1.1.1.1" "8.8.4.4" ];
};
};
oci-containers.backend = "podman";
arion.backend = "podman-socket";
};
systemd.targets = {
sleep.enable = false;
suspend.enable = false;

View File

@ -34,9 +34,9 @@ let
isReadOnly = false;
};
} // (mapAttrs' (zoneName: _:
let zoneKeyName = zoneKeySecret zoneName;
in nameValuePair "/run/nsd/keys/${zoneKeyName}" {
hostPath = hostSecrets."${zoneKeyName}".target-file;
nameValuePair "/run/nsd/keys/${zoneName}" {
hostPath =
dirOf hostSecrets."${zoneKeySecret zoneName}".target-file;
}) securedZones);
config = let
nameserverHost = cfg.container.hostname;
@ -82,7 +82,10 @@ let
domains = mapAttrs' (zoneName: zoneCfg:
nameValuePair zoneCfg.domain {
ksk.key-file = "/run/nsd/keys/${zoneKeySecret zoneName}";
ksk.key-file = "/run/nsd/keys/${zoneName}/${
baseNameOf
hostSecrets."${zoneKeySecret zoneName}".target-file
}";
reverse-zones = zoneCfg.reverse-zones;
notify = mkIf cfg.enable-notifications {
ipv4 = concatMap
@ -280,11 +283,21 @@ in {
};
fudo = {
secrets.host-secrets."${hostname}" = mapAttrs' (zone: zoneCfg:
nameValuePair (zoneKeySecret zone) {
secrets.host-secrets."${hostname}" = concatMapAttrs (zone: zoneCfg: {
"${zoneKeySecret zone}" = {
source-file = zoneCfg.ksk.private-key;
target-file = "/run/nsd/${baseNameOf zoneCfg.ksk.private-key}";
}) (filterAttrs (_: zoneCfg: zoneCfg.ksk != null) cfg.zones);
target-file =
"/run/nsd/${zone}/${baseNameOf zoneCfg.ksk.private-key}";
};
"${zone}-ds" = {
source-file = zoneCfg.ksk.ds;
target-file = "/run/nsd/${zone}/${baseNameOf zoneCfg.ksk.ds}";
};
"${zone}-pubkey" = {
source-file = zoneCfg.ksk.public-key;
target-file = "/run/nsd/${zone}/${baseNameOf zoneCfg.ksk.public-key}";
};
}) (filterAttrs (_: zoneCfg: zoneCfg.ksk != null) cfg.zones);
zones = mapAttrs (zone-name: zoneCfg:
let

View File

@ -1,7 +1,20 @@
{ config, lib, pkgs, ... }:
with lib;
let cfg = config.fudo.services.gitea-container;
let
cfg = config.fudo.services.gitea-container;
hostname = config.instance.hostname;
domainName = config.fudo.hosts."${hostname}".domain;
zoneName = config.fudo.domains."${domainName}".zone;
siteName = config.fudo.hosts."${hostname}".site;
getSiteGatewayV4 = pkgs.lib.getSiteGatewayV4;
keyPaths = {
ed25519 = "/state/ssh/ed25519.key";
ecdsa = "/state/ssh/ecdsa.key";
};
in {
options.fudo.services.gitea-container = with types; {
@ -29,11 +42,6 @@ in {
default = [ ];
};
openid-urls = mkOption {
type = listOf str;
description = "List of authorized OpenID providers.";
};
networking = {
interface = mkOption {
type = str;
@ -75,7 +83,10 @@ in {
};
config = mkIf cfg.enable {
systemd.tmpfiles.rules = [ "d ${cfg.state-directory} 700 root root - -" ];
systemd.tmpfiles.rules = [
"d ${cfg.state-directory}/gitea 755 root root - -"
"d ${cfg.state-directory}/acme 755 root root - -"
];
containers.gitea = {
autoStart = true;
@ -83,18 +94,63 @@ in {
macvlans = [ cfg.networking.interface ];
bindMounts = {
"/state" = {
hostPath = cfg.state-directory;
hostPath = "${cfg.state-directory}/gitea";
isReadOnly = false;
};
"/var/lib/acme" = {
hostPath = "${cfg.state-directory}/acme";
isReadOnly = false;
};
};
config = {
nixpkgs.pkgs = pkgs;
systemd = { tmpfiles.rules = [ "d /state 0755 root root - -" ]; };
systemd = {
tmpfiles.rules = [ "d /state 0755 root root - -" ];
services = {
gitea-chown = {
requiredBy = [ "gitea.service" ];
before = [ "gitea.service" ];
serviceConfig.Type = "oneshot";
script = "chown -R gitea:gitea /state";
};
gitea-keygen = {
requiredBy = [ "gitea.service" ];
before = [ "gitea.service" ];
serviceConfig.Type = "oneshot";
script = let
keygenScripts = mapAttrsToList (type: path:
let dir = dirOf path;
in ''
if [ ! -f ${path} ]; then
mkdir -p ${dir}
${pkgs.openssh}/bin/ssh-keygen -q -N "" -t ${type} -f ${path}
chown -R gitea:gitea ${dir}
chmod 0750 ${dir}
chmod 0440 ${path}
fi
'') keyPaths;
in concatStringsSep "\n" keygenScripts;
};
};
};
environment.systemPackages = let
giteaCli = pkgs.writeShellApplication {
name = "gitea-cli";
runtimeInputs = with pkgs; [ gitea ];
text = ''gitea --config /state/gitea/custom/conf/app.ini "$@"'';
};
in [ giteaCli ];
networking = {
defaultGateway = config.networking.defaultGateway;
defaultGateway = {
address = getSiteGatewayV4 siteName;
interface = "mv-${cfg.networking.interface}";
};
enableIPv6 = !isNull cfg.networking.ipv6;
nameservers = config.networking.nameservers;
firewall = {
enable = true;
allowedTCPPorts = [ 22 80 443 ];
@ -111,6 +167,11 @@ in {
};
};
security.acme = {
acceptTerms = true;
defaults.email = "admin@${cfg.hostname}";
};
services = {
gitea = {
enable = true;
@ -122,7 +183,10 @@ in {
repositoryRoot = "/state/repositories";
stateDir = "/state/gitea";
settings = {
service.DISABLE_REGISTRATION = true;
service = {
#DISABLE_REGISTRATION = true;
ALLOW_ONLY_EXTERNAL_REGISTRATION = true;
};
security = {
INSTALL_LOCK = true;
LOGIN_REMEMBER_DAYS = 30;
@ -133,26 +197,23 @@ in {
# Host & port to display in the clone URL
SSH_DOMAIN = cfg.hostname;
# SSH_LISTEN_HOST = "0.0.0.0";
SSH_PORT = 22;
SSH_LISTEN_PORT = 2222;
SSH_LISTEN_HOST = "0.0.0.0";
DOMAIN = cfg.hostname;
ROOT_URL = "https://${cfg.hostname}";
SSH_SERVER_HOST_KEYS =
concatStringsSep "," (attrValues keyPaths);
HTTP_ADDR = "127.0.0.1";
HTTP_PORT = 8080;
};
openid = {
ENABLE_OPENID_SIGNIN = true;
WHITELISTED_URIS = concatStringsSep "," cfg.openid-urls;
};
oauth2_client = {
REGISTER_EMAIL_CONFIRM = false;
OPENID_CONNECT_SCOPES =
concatStringsSep "," [ "email" "profile" ];
ENABLE_AUTO_REGISTRATION = true;
#ENABLE_AUTO_REGISTRATION = true;
USERNAME = "email";
UPDATE_AVATAR = true;
ACCOUNT_LINKING = "login";
@ -164,8 +225,8 @@ in {
enable = true;
services = [{
name = "ssh";
# port = 22;
# protocol = "tcp";
port = 22;
protocol = "tcp";
extraConfig = ''
redirect = localhost 2222
wait = no
@ -185,9 +246,13 @@ in {
recommendedTlsSettings = true;
recommendedGzipSettings = true;
virtualHosts."${cfg.hostname}" = {
# enableACME = true;
# forceSSL = true;
locations."/".proxyPass = "http://127.0.0.1:8080";
enableACME = true;
forceSSL = true;
locations."/" = {
proxyPass = "http://127.0.0.1:8080";
proxyWebsockets = true;
recommendedProxySettings = true;
};
locations."/metrics" = mkIf (cfg.trusted-networks != [ ]) {
proxyPass = "http://127.0.0.1:8080/metrics";
extraConfig = let

View File

@ -2,20 +2,12 @@
with lib;
let
lemmyDbPasswd = pkgs.lib.passwd.stablerandom-passwd-file "lemmy-server-passwd"
"lemmy-server-${config.instance.build-seed}";
cfg = config.fudo.services.lemmy;
hostname = config.instance.hostname;
domainName = config.fudo.hosts."${hostname}".domain;
postgresqlServer = config.fudo.domains."${domainName}".postgresql-server;
postgresqlFqdn = pkgs.lib.getHostFqdn postgresqlServer;
isPostgresServer = hostname == postgresqlServer;
hostSecrets = config.fudo.secrets.host-secrets."${hostname}";
in {
@ -27,38 +19,55 @@ in {
description = "Hostname at which this server will be reachable.";
};
port = mkOption {
type = port;
description = "Port on which to listen for requests";
default = 8536;
site-name = mkOption {
type = str;
description = "Site Name";
};
listen-ip = mkOption {
type = str;
description = "IP on which to listen for incoming requests.";
default = "0.0.0.0";
smtp = {
host = mkOption {
type = str;
description = "SMTP server to relay Lemmy emails.";
};
port = mkOption {
type = port;
description = "Port to which to send outgoing messages.";
default = 25;
};
};
};
config = mkIf cfg.enable {
fudo = {
secrets.host-secrets."${hostname}" = {
dbLemmyPasswd = mkIf isPostgresServer {
source-file = lemmyDbPasswd;
secrets.host-secrets."${hostname}" = let
lemmyDbPasswdFile =
pkgs.lib.passwd.stablerandom-passwd-file "lemmy-server-passwd"
"lemmy-server-${config.instance.build-seed}";
lemmyDbPasswd = readFile lemmyDbPasswdFile;
in {
lemmyDbUrl = {
source-file = let
url =
"postgres:///lemmy?user=lemmy&password=${lemmyDbPasswd}&host=/var/run/postgresql";
in pkgs.writeText "lemmy-db.url" url;
target-file = "/run/lemmy/db.url";
};
dbLemmyPasswd = {
source-file = lemmyDbPasswdFile;
target-file = "/run/postgres/lemmy.passwd";
user = config.systemd.services.postgresql.serviceConfig.User;
};
lemmyEnv = mkIf cfg.enable {
source-file = pkgs.writeText "lemmy.env" ''
LEMMY_DATABASE_URL=postgres:///lemmy:${
readFile lemmyDbPasswd
}@${postgresqlFqdn}:5432/lemmy
'';
target-file = "/run/lemmy/env";
lemmyAdminPasswdFile = {
source-file =
pkgs.lib.passwd.stablerandom-passwd-file "lemmy-admin.passwd"
config.instance.build-seed;
target-file = "/run/lemmy/admin.passwd";
};
};
postgresql = mkIf isPostgresServer {
postgresql = {
enable = true;
databases.lemmy.users = config.instance.local-admins;
users.lemmy = {
password-file = hostSecrets.dbLemmyPasswd.target-file;
@ -74,35 +83,36 @@ in {
};
systemd.services.lemmy = {
requires = [ "fudo-secret-lemmyEnv.service" ];
after = [ "fudo-secret-lemmyEnv.service" ];
environment.LEMMY_DATABASE_URL = mkForce null;
serviceConfig = mkIf cfg.enable {
LoadCredential = [ "env:${hostSecrets.lemmyEnv.target-file}" ];
EnvironmentFile = "$$CREDENTIALS_DIRECTORY/env";
};
requires = [ "fudo-secret-lemmyDbUrl.service" "postgresql.service" ];
after = [ "fudo-secret-lemmyDbUrl.service" "postgresql.service" ];
};
services.lemmy = mkIf cfg.enable {
services.nginx.virtualHosts."${cfg.hostname}" = {
enableACME = true;
forceSSL = true;
};
services.lemmy = {
enable = true;
nginx.enable = true;
adminPasswordFile = hostSecrets.lemmyAdminPasswdFile.target-file;
database.uriFile = hostSecrets.lemmyDbUrl.target-file;
ui.port = 50395;
settings = {
hostname = cfg.hostname;
federation.enabled = true;
host = cfg.hostname;
captcha.enabled = true;
database = {
user = "lemmy";
host = pkgs.lib.getHostFqdn postgresqlServer;
database = "lemmy";
password = readFile lemmyDbPasswd;
email = {
smtp_server = "${cfg.smtp.host}:${toString cfg.smtp.port}";
smtp_from_address = "noreply@${cfg.hostname}";
tls_type = "starttls";
};
admin_username = "admin";
setup = {
site_name = cfg.site-name;
admin_username = "admin";
};
bind = cfg.listen-ip;
port = cfg.port;
};
};
networking.firewall = {
allowedTCPPorts = [ cfg.port ];
allowedUDPPorts = [ cfg.port ];
};
};
}

View File

@ -103,22 +103,6 @@ in {
};
};
zones = {
${mailserver-domain.zone} = let
server-ipv4 = pkgs.lib.network.host-ipv4 config mailserver-host;
server-ipv6 = pkgs.lib.network.host-ipv6 config mailserver-host;
srv-record = host: port: [{ inherit host port; }];
in {
aliases = mkIf metricsEnabled { mail-stats = "${mailserver-fqdn}."; };
metric-records = mkIf metricsEnabled
(genAttrs [ "dovecot" "postfix" "rspamd" ]
(_: srv-record "mail-stats" 443));
};
};
metrics.prometheus.service-discovery-dns = mkIf metricsEnabled
(genAttrs [ "dovecot" "postfix" "rspamd" ]
(mtype: [ "${mtype}._metrics._tcp.${mailserver-domain-name}" ]));

View File

@ -56,7 +56,7 @@ in {
};
zones."${zone-name}".aliases.postgresql =
pkgs.lib.getHostFqdn domain.postgresql-server;
"${pkgs.lib.getHostFqdn domain.postgresql-server}.";
postgresql = mkIf isPostgresHost (let
ssl-config = optionalAttrs publicNetwork (let

1520
flake.lock

File diff suppressed because it is too large Load Diff

View File

@ -98,6 +98,14 @@
};
};
lemmy-container = {
url = "git+https://git.fudo.org/fudo-public/lemmy-container.git";
inputs = {
nixpkgs.follows = "nixpkgs";
arion.follows = "arion";
};
};
authentik-container = {
url = "git+https://git.fudo.org/fudo-nix/authentik-container.git";
inputs = {
@ -121,7 +129,18 @@
mail-server = {
url = "git+https://git.fudo.org/fudo-public/mail-server.git";
inputs.nixpkgs.follows = "nixpkgs";
inputs = {
arion.follows = "arion";
nixpkgs.follows = "nixpkgs";
};
};
immich-container = {
url = "git+https://git.fudo.org/fudo-public/immich-container.git";
inputs = {
arion.follows = "arion";
nixpkgs.follows = "nixpkgs";
};
};
authoritative-dns = {
@ -150,7 +169,8 @@
, objectifier, nexus, suanni, snooper, tattler, lemmy-docker
, tesla-mate-container, mastodon-container, authentik-container
, nextcloud-container, textfiles, matrix-module, mail-server
, authoritative-dns, frigate-container, grafana-module, ... }@inputs:
, authoritative-dns, frigate-container, grafana-module, lemmy-container
, immich-container, ... }@inputs:
with nixpkgs.lib;
let
fudo-nixos-hosts = filterAttrs (hostname: hostOpts: hostOpts.nixos-system)
@ -232,6 +252,8 @@
authoritative-dns.nixosModules.default
frigate-container.nixosModules.default
grafana-module.nixosModules.default
lemmy-container.nixosModules.default
immich-container.nixosModules.default
nexus.nixosModules.nexus-client
nexus.nixosModules.nexus-server