diff options
author | tdback <tyler@tdback.net> | 2025-01-26 11:34:28 -0500 |
---|---|---|
committer | tdback <tyler@tdback.net> | 2025-01-26 11:34:28 -0500 |
commit | 99e940770b61db350379d692df7cf3831ef4bd92 (patch) | |
tree | d927d171b483b9ae07de4ab615f250edf25e535a | |
parent | bc7b54af5193f8ac7333ce3f27f414f9a69a80c0 (diff) |
services: major overhaul on service modules
-rw-r--r-- | modules/services/cgit/default.nix | 32 | ||||
-rw-r--r-- | modules/services/dns/default.nix | 62 | ||||
-rw-r--r-- | modules/services/fediverse/default.nix | 67 | ||||
-rw-r--r-- | modules/services/immich/default.nix | 63 | ||||
-rw-r--r-- | modules/services/llm/default.nix | 70 | ||||
-rw-r--r-- | modules/services/matrix/default.nix | 230 | ||||
-rw-r--r-- | modules/services/proxy/default.nix | 12 | ||||
-rw-r--r-- | modules/services/searx/default.nix | 71 | ||||
-rw-r--r-- | modules/services/sftpgo/default.nix | 67 | ||||
-rw-r--r-- | modules/services/web/default.nix | 35 | ||||
-rw-r--r-- | modules/services/website/default.nix | 63 |
11 files changed, 494 insertions, 278 deletions
diff --git a/modules/services/cgit/default.nix b/modules/services/cgit/default.nix deleted file mode 100644 index 7e2955a..0000000 --- a/modules/services/cgit/default.nix +++ /dev/null @@ -1,32 +0,0 @@ -{ - inputs, - pkgs, - ... -}: -let - scanPath = "/tank/git"; - domain = "git.tdback.net"; -in -{ - imports = [ "${inputs.self}/modules/customs/cgit" ]; - - services.cgit = { - enable = true; - package = pkgs.cgit; - scanPath = scanPath; - virtualHost = domain; - authorizedKeys = [ - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEzLpTEoej7P04KoNzokQ9IOnNZiKyi2+YQ8yU5WSKCb" - ]; - settings = { - root-title = domain; - root-desc = "tdback's git repositories"; - enable-index-links = 1; - enable-index-owner = 0; - enable-commit-graph = 1; - enable-log-filecount = 1; - enable-log-linecount = 1; - readme = ":README.md"; - }; - }; -} diff --git a/modules/services/dns/default.nix b/modules/services/dns/default.nix index e229da3..e25645e 100644 --- a/modules/services/dns/default.nix +++ b/modules/services/dns/default.nix @@ -1,26 +1,48 @@ -{ pkgs, ... }: { - services.unbound = { - enable = true; - package = pkgs.unbound-with-systemd; - enableRootTrustAnchor = true; - resolveLocalQueries = true; - settings.server = { - interface = [ "0.0.0.0" ]; - port = 53; - access-control = [ "10.44.0.0/16 allow" ]; - harden-glue = true; - harden-dnssec-stripped = true; - use-caps-for-id = false; - edns-buffer-size = 1232; - prefetch = true; - hide-identity = true; - hide-version = true; + config, + lib, + pkgs, + ... +}: +with lib; +let + cfg = config.modules.services.dns; +in +{ + options.modules.services.dns = { + enable = mkEnableOption "dns"; + port = mkOption { + default = 53; + type = types.int; + }; + subnet = mkOption { + default = "192.168.0.0/24"; + type = types.str; }; }; - networking.firewall = { - allowedTCPPorts = [ 53 ]; - allowedUDPPorts = [ 53 ]; + config = mkIf cfg.enable { + networking.firewall = { + allowedTCPPorts = [ cfg.port ]; + allowedUDPPorts = [ cfg.port ]; + }; + services.unbound = { + enable = true; + package = pkgs.unbound-with-systemd; + enableRootTrustAnchor = true; + resolveLocalQueries = true; + settings.server = { + interface = [ "0.0.0.0" ]; + port = cfg.port; + access-control = [ "${cfg.subnet} allow" ]; + harden-glue = true; + harden-dnssec-stripped = true; + use-caps-for-id = false; + edns-buffer-size = 1232; + prefetch = true; + hide-identity = true; + hide-version = true; + }; + }; }; } diff --git a/modules/services/fediverse/default.nix b/modules/services/fediverse/default.nix index 0c3c696..b67cdcc 100644 --- a/modules/services/fediverse/default.nix +++ b/modules/services/fediverse/default.nix @@ -1,26 +1,55 @@ -{ pkgs, ... }: +{ + config, + lib, + pkgs, + ... +}: +with lib; let - domain = "social.tdback.net"; - port = 8080; + cfg = config.modules.services.fediverse; in { - services.gotosocial = { - enable = true; - package = pkgs.unstable.gotosocial; - settings = { - application-name = "gotosocial"; - host = "${domain}"; - protocol = "https"; - bind-address = "localhost"; - port = port; - db-type = "sqlite"; - db-address = "/var/lib/gotosocial/database.sqlite"; - storage-local-base-path = "/var/lib/gotosocial/storage"; + options.modules.services.fediverse = { + enable = mkEnableOption "fediverse"; + package = mkPackageOption pkgs "gotosocial" { }; + port = mkOption { + default = 8080; + type = types.int; + }; + url = mkOption { + type = types.str; }; }; - services.caddy.virtualHosts.${domain}.extraConfig = '' - encode zstd gzip - reverse_proxy http://localhost:${builtins.toString port} - ''; + config = mkIf cfg.enable { + networking.firewall.allowedTCPPorts = [ + 80 + 443 + ]; + + services.caddy = { + enable = true; + virtualHosts = { + ${cfg.url}.extraConfig = '' + encode zstd gzip + reverse_proxy http://localhost:${builtins.toString cfg.port} + ''; + }; + }; + + services.gotosocial = { + enable = true; + package = cfg.package; + settings = { + application-name = "gotosocial"; + bind-address = "localhost"; + port = cfg.port; + host = cfg.url; + protocol = "https"; + db-type = "sqlite"; + db-address = "/var/lib/gotosocial/database.sqlite"; + storage-local-base-path = "/var/lib/gotosocial/storage"; + }; + }; + }; } diff --git a/modules/services/immich/default.nix b/modules/services/immich/default.nix index 7904423..95da536 100644 --- a/modules/services/immich/default.nix +++ b/modules/services/immich/default.nix @@ -1,18 +1,55 @@ -{ pkgs, ... }: { - services.immich = { - enable = true; - package = pkgs.immich; - host = "localhost"; - port = 2283; - mediaLocation = "/tank/immich"; - environment = { - IMMICH_LOG_LEVEL = "log"; + config, + lib, + pkgs, + ... +}: +with lib; +let + cfg = config.modules.services.immich; +in +{ + options.modules.services.immich = { + enable = mkEnableOption "immich"; + port = mkOption { + default = 2283; + type = types.int; + }; + url = mkOption { + default = null; + type = types.str; + }; + mediaDir = mkOption { + default = "/var/lib/immich"; + type = types.str; }; }; - services.caddy.virtualHosts."photographs.brownbread.net".extraConfig = '' - encode zstd gzip - reverse_proxy http://localhost:2283 - ''; + config = mkIf cfg.enable { + networking.firewall.allowedTCPPorts = mkIf (cfg.url != null) [ + 80 + 443 + ]; + + services.caddy = mkIf (cfg.url != null) { + enable = true; + virtualHosts = { + "photographs.brownbread.net".extraConfig = '' + encode zstd gzip + reverse_proxy http://localhost:${builtins.toString cfg.port} + ''; + }; + }; + + services.immich = { + enable = true; + package = pkgs.immich; + host = "localhost"; + port = cfg.port; + mediaLocation = cfg.mediaDir; + environment = { + IMMICH_LOG_LEVEL = "log"; + }; + }; + }; } diff --git a/modules/services/llm/default.nix b/modules/services/llm/default.nix new file mode 100644 index 0000000..0c97720 --- /dev/null +++ b/modules/services/llm/default.nix @@ -0,0 +1,70 @@ +{ + config, + lib, + ... +}: +with lib; +let + cfg = config.modules.services.llm; +in +{ + options.modules.services.llm = { + enable = mkEnableOption "llm"; + port = mkOption { + default = 8080; + type = types.int; + description = "Which port the Open-WebUI server listens to."; + }; + networkRange = mkOption { + default = null; + type = types.str; + description = "The network range allowed to acccess Open-WebUI and the ollama API"; + }; + nvidiaGpu = mkOption { + default = false; + type = types.bool; + description = "Use NVIDIA cuda for hardware acceleration."; + }; + models = mkOption { + default = [ ]; + type = types.listOf types.str; + description = "Automatically download these models."; + }; + }; + + config = mkIf cfg.enable { + services.ollama = { + enable = true; + acceleration = if cfg.nvidiaGpu then "cuda" else false; + loadModels = cfg.models; + }; + + services.open-webui = { + enable = true; + host = if cfg.networkRange == null then "127.0.0.1" else "0.0.0.0"; + port = cfg.port; + }; + + # Only expose Open-WebUI and ollama API to the local network, since this + # server might have a public IPv6 address. + networking.firewall.extraCommands = + with config.services; + let + api = builtins.toString ollama.port; + web = builtins.toString open-webui.port; + in + mkIf (cfg.networkRange != null) '' + iptables -A nixos-fw -p tcp --source ${cfg.networkRange} --dport ${api}:${api} -j nixos-fw-accept + iptables -A nixos-fw -p tcp --source ${cfg.networkRange} --dport ${web}:${web} -j nixos-fw-accept + ''; + + # Enable the proprietary NVIDIA drivers in a headless fashion. + hardware.graphics.enable = cfg.nvidiaGpu; + services.xserver.videoDrivers = mkIf cfg.nvidiaGpu [ "nvidia" ]; + hardware.nvidia = mkIf cfg.nvidiaGpu { + package = config.boot.kernelPackages.nvidiaPackages.stable; + open = false; + nvidiaPersistenced = true; + }; + }; +} diff --git a/modules/services/matrix/default.nix b/modules/services/matrix/default.nix index c6d8755..0cfa56b 100644 --- a/modules/services/matrix/default.nix +++ b/modules/services/matrix/default.nix @@ -1,130 +1,148 @@ { - inputs, config, lib, pkgs, ... }: +with lib; let - baseUrl = "https://${fqdn}"; - fqdn = "synapse.${config.networking.domain}"; - synPort = 8008; + cfg = config.modules.services.matrix; in { - age.secrets = { - coturnStaticAuth = { - file = "${inputs.self}/secrets/coturnStaticAuth.age"; - owner = "turnserver"; + options.modules.services.matrix = { + enable = mkEnableOption "matrix"; + port = mkOption { + default = 8008; + type = types.int; }; - synapseYaml = { - file = "${inputs.self}/secrets/synapseYaml.age"; - owner = "matrix-synapse"; + url = mkOption { + type = types.str; + }; + registrationSecret = mkOption { + type = types.str; + description = "Path to registration shared secret yaml file."; + }; + coturnStaticAuth = mkOption { + type = types.str; + description = "Path to static auth secret file."; }; }; - networking.domain = "tdback.net"; - networking.firewall = - let - coturnPorts = [ - 3478 - 5349 - ]; - range = - with config.services.coturn; - lib.singleton { - from = min-port; - to = max-port; - }; - in - { - allowedUDPPortRanges = range; - allowedUDPPorts = coturnPorts; - allowedTCPPortRanges = [ ]; - allowedTCPPorts = coturnPorts ++ [ - 80 - 443 - ]; + config = mkIf cfg.enable { + age.secrets = { + registrationSecret = { + file = cfg.registrationSecret; + owner = "matrix-synapse"; + }; + coturnStaticAuth = { + file = cfg.coturnStaticAuth; + owner = "turnserver"; + }; }; - services.postgresql = { - enable = true; - package = pkgs.postgresql_17; - initialScript = pkgs.writeText "synapse-init.sql" '' - CREATE ROLE "matrix-synapse"; - CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse" - TEMPLATE template0 - LC_COLLATE = "C" - LC_CTYPE = "C"; - ''; - }; + networking.firewall = + let + coturnPorts = [ + 3478 + 5349 + ]; + range = + with config.services.coturn; + lib.singleton { + from = min-port; + to = max-port; + }; + in + { + allowedUDPPortRanges = range; + allowedUDPPorts = coturnPorts; + allowedTCPPortRanges = [ ]; + allowedTCPPorts = coturnPorts ++ [ + 80 + 443 + ]; + }; - services.coturn = { - enable = true; - use-auth-secret = true; - static-auth-secret-file = config.age.secrets.coturnStaticAuth.path; - realm = "turn.${config.networking.domain}"; - no-tcp-relay = true; - no-tls = true; - no-dtls = true; - extraConfig = '' - user-quota=12 - total-quota=1200 - no-multicast-peers - denied-peer-ip=0.0.0.0-0.255.255.255 - denied-peer-ip=10.0.0.0-10.255.255.255 - denied-peer-ip=100.64.0.0-100.127.255.255 - denied-peer-ip=127.0.0.0-127.255.255.255 - denied-peer-ip=169.254.0.0-169.254.255.255 - denied-peer-ip=172.16.0.0-172.31.255.255 - denied-peer-ip=192.0.0.0-192.0.0.255 - denied-peer-ip=192.0.2.0-192.0.2.255 - denied-peer-ip=192.88.99.0-192.88.99.255 - denied-peer-ip=192.168.0.0-192.168.255.255 - denied-peer-ip=198.18.0.0-198.19.255.255 - denied-peer-ip=198.51.100.0-198.51.100.255 - denied-peer-ip=203.0.113.0-203.0.113.255 - denied-peer-ip=240.0.0.0-255.255.255.255 - ''; - }; + services.postgresql = { + enable = true; + package = pkgs.postgresql_17; + initialScript = pkgs.writeText "synapse-init.sql" '' + CREATE ROLE "matrix-synapse"; + CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse" + TEMPLATE template0 + LC_COLLATE = "C" + LC_CTYPE = "C"; + ''; + }; - services.caddy = { - enable = true; - virtualHosts = { - ${fqdn}.extraConfig = - let - localhost = "http://localhost:${builtins.toString synPort}"; - in - '' - reverse_proxy /_matrix/* ${localhost} - reverse_proxy /_synapse/client/* ${localhost} - ''; + services.coturn = { + enable = true; + use-auth-secret = true; + static-auth-secret-file = config.age.secrets.coturnStaticAuth.path; + realm = "turn.${cfg.url}"; + no-tcp-relay = true; + no-tls = true; + no-dtls = true; + extraConfig = '' + user-quota=12 + total-quota=1200 + no-multicast-peers + denied-peer-ip=0.0.0.0-0.255.255.255 + denied-peer-ip=10.0.0.0-10.255.255.255 + denied-peer-ip=100.64.0.0-100.127.255.255 + denied-peer-ip=127.0.0.0-127.255.255.255 + denied-peer-ip=169.254.0.0-169.254.255.255 + denied-peer-ip=172.16.0.0-172.31.255.255 + denied-peer-ip=192.0.0.0-192.0.0.255 + denied-peer-ip=192.0.2.0-192.0.2.255 + denied-peer-ip=192.88.99.0-192.88.99.255 + denied-peer-ip=192.168.0.0-192.168.255.255 + denied-peer-ip=198.18.0.0-198.19.255.255 + denied-peer-ip=198.51.100.0-198.51.100.255 + denied-peer-ip=203.0.113.0-203.0.113.255 + denied-peer-ip=240.0.0.0-255.255.255.255 + ''; + }; + + services.caddy = { + enable = true; + virtualHosts = { + "synapse.${cfg.url}".extraConfig = + let + localhost = "http://localhost:${builtins.toString cfg.port}"; + in + '' + reverse_proxy /_matrix/* ${localhost} + reverse_proxy /_synapse/client/* ${localhost} + ''; + }; }; - }; - services.matrix-synapse = { - enable = true; - extraConfigFiles = [ config.age.secrets.synapseYaml.path ]; - settings = { - server_name = config.networking.domain; - public_baseurl = baseUrl; - listeners = lib.singleton { - port = synPort; - bind_addresses = [ "::1" ]; - type = "http"; - tls = false; - x_forwarded = true; - resources = lib.singleton { - names = [ - "client" - "federation" - ]; - compress = true; + services.matrix-synapse = { + enable = true; + extraConfigFiles = [ config.age.secrets.registrationSecret.path ]; + settings = { + server_name = cfg.url; + public_baseurl = "https://synapse.${cfg.url}"; + listeners = lib.singleton { + port = cfg.port; + bind_addresses = [ "::1" ]; + type = "http"; + tls = false; + x_forwarded = true; + resources = lib.singleton { + names = [ + "client" + "federation" + ]; + compress = true; + }; }; + turn_uris = with config.services.coturn; [ + "turn:${realm}?transport=udp" + "turn:${realm}?transport=tcp" + ]; }; - turn_uris = with config.services.coturn; [ - "turn:${realm}?transport=udp" - "turn:${realm}?transport=tcp" - ]; }; }; } diff --git a/modules/services/proxy/default.nix b/modules/services/proxy/default.nix deleted file mode 100644 index c70bb54..0000000 --- a/modules/services/proxy/default.nix +++ /dev/null @@ -1,12 +0,0 @@ -{ pkgs, ... }: -{ - services.caddy = { - enable = true; - package = pkgs.caddy; - }; - - networking.firewall.allowedTCPPorts = [ - 80 - 443 - ]; -} diff --git a/modules/services/searx/default.nix b/modules/services/searx/default.nix index 2b4a9d8..f7c00fb 100644 --- a/modules/services/searx/default.nix +++ b/modules/services/searx/default.nix @@ -1,33 +1,52 @@ -{ pkgs, ... }: +{ + config, + lib, + pkgs, + ... +}: +with lib; let - port = 8888; + cfg = config.modules.services.searx; in { - services.searx = { - enable = true; - package = pkgs.searxng; - environmentFile = "/var/lib/searx/env"; - settings = { - general = { - debug = false; - instance_name = "searx"; - }; - search = { - safe_search = 1; - autocomplete = "duckduckgo"; - autocomplete_min = 4; - default_lang = "en-US"; - }; - server = { - port = port; - bind_address = "0.0.0.0"; - secret_key = "@SEARX_SECRET_KEY@"; - public_instance = false; - image_proxy = true; - }; - ui.static_use_hash = true; + options.modules.services.searx = { + enable = mkEnableOption "searx"; + port = mkOption { + default = 8888; + type = types.int; + }; + environmentFile = mkOption { + default = "/var/lib/searx/env"; + type = types.str; }; }; - networking.firewall.allowedTCPPorts = [ port ]; + config = mkIf cfg.enable { + networking.firewall.allowedTCPPorts = [ cfg.port ]; + services.searx = { + enable = true; + package = pkgs.searxng; + environmentFile = cfg.environmentFile; + settings = { + general = { + debug = false; + instance_name = "searx"; + }; + server = { + port = cfg.port; + bind_address = "0.0.0.0"; + secret_key = "@SEARX_SECRET_KEY@"; + public_instance = false; + image_proxy = true; + }; + search = { + safe_search = 1; + autocomplete = "duckduckgo"; + autocomplete_min = 4; + default_lang = "en-US"; + }; + ui.static_use_hash = true; + }; + }; + }; } diff --git a/modules/services/sftpgo/default.nix b/modules/services/sftpgo/default.nix index de8b5b1..ae0af24 100644 --- a/modules/services/sftpgo/default.nix +++ b/modules/services/sftpgo/default.nix @@ -4,23 +4,60 @@ pkgs, ... }: +with lib; +let + cfg = config.modules.services.sftpgo; +in { - services.sftpgo = { - enable = true; - package = pkgs.sftpgo; - settings = { - httpd.bindings = lib.singleton { - port = 8080; - address = "0.0.0.0"; - enable_web_client = true; - enable_web_admin = true; - }; + options.modules.services.sftpgo = { + enable = mkEnableOption "sftpgo"; + port = mkOption { + default = 8080; + type = types.int; + }; + url = mkOption { + default = null; + type = types.str; + }; + dataDir = mkOption { + default = "/var/lib/sftpgo"; + type = types.str; }; }; - services.caddy.virtualHosts."${config.networking.hostName}.brownbread.net".extraConfig = '' - root * /web/client - encode zstd gzip - reverse_proxy http://localhost:8080 - ''; + config = + let + caddy = cfg.url != null; + in + mkIf cfg.enable { + networking.firewall.allowedTCPPorts = mkIf caddy [ + 80 + 443 + ]; + + services.caddy = mkIf caddy { + enable = true; + virtualHosts = { + ${cfg.url}.extraConfig = '' + root * /web/client + encode zstd gzip + reverse_proxy http://localhost:${builtins.toString cfg.port} + ''; + }; + }; + + services.sftpgo = { + enable = true; + package = pkgs.sftpgo; + dataDir = cfg.dataDir; + settings = { + httpd.bindings = lib.singleton { + port = cfg.port; + address = "0.0.0.0"; + enable_web_client = true; + enable_web_admin = true; + }; + }; + }; + }; } diff --git a/modules/services/web/default.nix b/modules/services/web/default.nix deleted file mode 100644 index 0a7b392..0000000 --- a/modules/services/web/default.nix +++ /dev/null @@ -1,35 +0,0 @@ -{ config, ... }: -let - fqdn = "synapse.${config.networking.domain}"; - baseUrl = "https://${fqdn}"; -in -{ - networking.domain = "tdback.net"; - networking.firewall.allowedTCPPorts = [ - 80 - 443 - ]; - - services.caddy = { - enable = true; - virtualHosts = { - ${config.networking.domain}.extraConfig = '' - handle /.well-known/matrix/server { - header Content-Type application/json - header Access-Control-Allow-Origin * - respond `{"m.server": "${fqdn}:443"}` - } - - handle /.well-known/matrix/client { - header Content-Type application/json - header Access-Control-Allow-Origin * - respond `{"m.homeserver": {"base_url": "${baseUrl}"}}` - } - - root * /var/www/tdback.net/ - encode zstd gzip - file_server - ''; - }; - }; -} diff --git a/modules/services/website/default.nix b/modules/services/website/default.nix new file mode 100644 index 0000000..425b69c --- /dev/null +++ b/modules/services/website/default.nix @@ -0,0 +1,63 @@ +{ + config, + lib, + ... +}: +with lib; +let + cfg = config.modules.services.website; +in +{ + options.modules.services.website = { + enable = mkEnableOption "website"; + url = mkOption { + type = types.str; + }; + federating = mkOption { + default = false; + type = types.bool; + description = "Federating a matrix server on this domain."; + }; + }; + + config = mkIf cfg.enable { + networking.firewall.allowedTCPPorts = [ + 80 + 443 + ]; + + services.caddy = { + enable = true; + virtualHosts = { + ${cfg.url}.extraConfig = + let + synapseUrl = "synapse.${cfg.url}"; + synapseBaseUrl = "https://${synapseUrl}"; + in + ( + if cfg.federating then + '' + handle /.well-known/matrix/server { + header Content-Type application/json + header Access-Control-Allow-Origin * + respond `{"m.server": "${synapseUrl}:443"}` + } + + handle /.well-known/matrix/client { + header Content-Type application/json + header Access-Control-Allow-Origin * + respond `{"m.homeserver": {"base_url": "${synapseBaseUrl}"}}` + } + '' + else + "" + ) + + '' + root * /var/www/${cfg.url}/ + encode zstd gzip + file_server + ''; + }; + }; + }; +} |