diff --git a/config/endpoints.nix b/config/endpoints.nix index 3160f56..082f336 100644 --- a/config/endpoints.nix +++ b/config/endpoints.nix @@ -3,6 +3,5 @@ let web = import ./endpoints/web.nix; matrix = import ./endpoints/matrix.nix; vikunja = import ./endpoints/vikunja.nix; - git = import ./endpoints/git.nix; in -local ++ web ++ matrix ++ vikunja ++ git ++ [] \ No newline at end of file +local ++ web ++ matrix ++ vikunja ++ [] \ No newline at end of file diff --git a/config/endpoints/git.nix b/config/endpoints/git.nix deleted file mode 100644 index 6202d25..0000000 --- a/config/endpoints/git.nix +++ /dev/null @@ -1,18 +0,0 @@ -let - net = import ../network.nix; -in -[ - { - type = "proxy"; - domain = "git.${net.devices.remote_proxy.domain}"; - endpoint = "/"; - force_ssl = true; - port = 443; - content = { - type = "service"; - ip = net.devices.tuserver.ip; - port = 3000; - proxyWebsockets = false; - }; - } -] \ No newline at end of file diff --git a/config/endpoints/matrix.nix b/config/endpoints/matrix.nix index 8ea90ed..fa6ffc6 100644 --- a/config/endpoints/matrix.nix +++ b/config/endpoints/matrix.nix @@ -29,19 +29,6 @@ in proxyWebsockets = true; }; } - # { - # type = "proxy"; - # domain = net.devices.remote_proxy.domain; - # endpoint = "/.well-known/matrix/"; - # force_ssl = true; - # port = 443; - # content = { - # type = "service"; - # ip = net.devices.pi.ip; - # port = services.continuwuity.port; - # proxyWebsockets = true; - # }; - # } { type = "inline"; domain = net.devices.remote_proxy.domain; @@ -50,11 +37,6 @@ in port = 443; content = { contentType = "application/json"; - headers = { - Access-Control-Allow-Origin = "*"; - Access-Control-Allow-Methods = "GET, POST, PUT, DELETE, OPTIONS"; - Access-Control-Allow-Headers = "X-Requested-With, Content-Type, Authorization"; - }; status = 200; body = ''{"m.server":"${net.devices.remote_proxy.domain}:443"}''; }; @@ -67,13 +49,8 @@ in port = 443; content = { contentType = "application/json"; - headers = { - Access-Control-Allow-Origin = "*"; - Access-Control-Allow-Methods = "GET, POST, PUT, DELETE, OPTIONS"; - Access-Control-Allow-Headers = "X-Requested-With, Content-Type, Authorization"; - }; status = 200; - body = ''{"m.homeserver": {"base_url": "https://${net.devices.remote_proxy.domain}"},"org.matrix.msc3575.proxy":{"url":"https://nudelerde.de/"},"org.matrix.msc4143.rtc_foci": [{"type": "livekit","livekit_service_url": "https://livekit.${net.devices.remote_proxy.domain}"}]}''; + body = ''{"m.homeserver":{"base_url":"https://${net.devices.remote_proxy.domain}"}}''; }; } ] \ No newline at end of file diff --git a/config/endpoints/vikunja.nix b/config/endpoints/vikunja.nix index ec801ba..0212f71 100644 --- a/config/endpoints/vikunja.nix +++ b/config/endpoints/vikunja.nix @@ -16,15 +16,4 @@ in proxyWebsockets = true; }; } - { - type = "redirect"; - domain = "wekan.${net.devices.remote_proxy.domain}"; - endpoint = "/"; - force_ssl = true; - port = 443; - content = { - target = "https://vikunja.${net.devices.remote_proxy.domain}/"; - status = 301; - }; - } ] \ No newline at end of file diff --git a/config/network.nix b/config/network.nix index 0bad294..74688d2 100644 --- a/config/network.nix +++ b/config/network.nix @@ -33,18 +33,9 @@ rec { auto_ssh = { enable = true; sshPort = 22; - sshUser = "autossh-incoming"; + sshUser = "root"; key = secrets.byName.autossh_remote_proxy_key.path; known_hosts = secrets.byName.autossh_remote_proxy_known_hosts.path; - portOffset = 10000; - }; - }; - "tuserver" = { - type = "local"; - ip = "192.168.2.102"; - reservation = { - hw_address = "00:23:24:f9:43:e6"; - hostname = "tuserver"; }; }; }; diff --git a/config/services.nix b/config/services.nix index c0ab036..d037e6b 100644 --- a/config/services.nix +++ b/config/services.nix @@ -5,16 +5,6 @@ in rec { continuwuity = { port = 6167; - server_name = "nudelerde.de"; - trusted_servers = [ "matrix.org" ]; - memory_max = "512M"; - livekit_url = "https://livekit.nudelerde.de"; - - package = { - version = "0.5.6"; - sourceHash = "sha256-p6dL1wL9n+1ivUItdlZuLxTneDBjCHEdNr0ukau2rHI="; - cargoHash = "sha256-lLbnFA2WS96er84G2e9bGrYhhqe2zL3Npn1SXB3De2w="; - }; }; qbittorrent = { @@ -35,6 +25,10 @@ rec { ]; }; + matrix = { + trusted_servers = [ "matrix.org" ]; + }; + vikunja = { port = 8081; }; diff --git a/configuration.nix b/configuration.nix index e312cc9..adc645f 100644 --- a/configuration.nix +++ b/configuration.nix @@ -9,7 +9,6 @@ timeZone = "Europe/Berlin"; defaultLocale = "en_US.UTF-8"; - storageConfig = import ./config/storage.nix; storageModel = import ./intermediate/storage.nix; in { imports = [ @@ -22,13 +21,6 @@ in { fileSystems = storageModel.fileSystems; - swapDevices = [ - { - device = "${storageConfig.ssd.path}/swapfile"; - size = 8192; - } - ]; - networking.hostName = "raspberry"; environment.systemPackages = with pkgs; [ diff --git a/intermediate/nginx.nix b/intermediate/nginx.nix index 85a8f6f..e44f4da 100644 --- a/intermediate/nginx.nix +++ b/intermediate/nginx.nix @@ -205,25 +205,6 @@ let proxyWebsockets = route.content.proxyWebsockets; }; } - else if route.type == "redirect" then - let - redirectTarget = - if builtins.isString route.content then - route.content - else - route.content.target; - redirectStatus = - if builtins.isAttrs route.content && route.content ? status then - route.content.status - else - 301; - in - { - name = "= ${route.endpoint}"; - value = { - return = "${toString redirectStatus} ${redirectTarget}"; - }; - } else if route.type == "inline" then let inlineBody = @@ -241,14 +222,6 @@ let route.content.contentType else "text/plain; charset=utf-8"; - inlineHeaders = - if builtins.isAttrs route.content && route.content ? headers then - route.content.headers - else - {}; - inlineHeaderLines = lib.concatStringsSep "\n" ( - lib.mapAttrsToList (name: value: " add_header ${name} ${builtins.toJSON value} always;") inlineHeaders - ); in { name = "= ${route.endpoint}"; @@ -256,7 +229,6 @@ let return = "${toString inlineStatus} ${builtins.toJSON inlineBody}"; extraConfig = '' default_type ${inlineContentType}; -${lib.optionalString (inlineHeaderLines != "") inlineHeaderLines} ''; }; } diff --git a/intermediate/remote.nix b/intermediate/remote.nix index 251cfb8..4cbd677 100644 --- a/intermediate/remote.nix +++ b/intermediate/remote.nix @@ -19,31 +19,22 @@ let getRemotePortMap = device: autoSshValidation.getRemotePortMap device; - getPortOffset = device: - autoSshValidation.getPortOffset device; - - ensurePortRange = context: port: - if builtins.isInt port && port >= 1 && port <= 65535 then - port - else - throw "${context} must be in range 1..65535."; - - resolveRemotePort = remotePortMap: portOffset: endpoint: + resolveRemotePort = remotePortMap: endpoint: let localPort = if endpoint ? port then - ensurePortRange "Endpoint port '${toString endpoint.port}'" endpoint.port + endpoint.port else throw "Endpoint is missing required field: port."; overrides = lib.filter (entry: entry.localPort == localPort) remotePortMap; in if overrides != [] then - ensurePortRange "remotePortMap remotePort '${toString (builtins.head overrides).remotePort}'" (builtins.head overrides).remotePort + (builtins.head overrides).remotePort else - ensurePortRange "Computed remote port (local ${toString localPort} + offset ${toString portOffset})" (localPort + portOffset); + localPort; - mapEndpointToForward = remotePortMap: portOffset: endpoint: { - remote = resolveRemotePort remotePortMap portOffset endpoint; + mapEndpointToForward = remotePortMap: endpoint: { + remote = resolveRemotePort remotePortMap endpoint; localAddress = "localhost"; localPort = endpoint.port; }; @@ -59,7 +50,6 @@ let else throw "Auto SSH device is missing required field: domain."; remotePortMap = getRemotePortMap device; - portOffset = getPortOffset device; matchedEndpoints = lib.filter (endpoint: if endpoint.force_ssl && endpoint.port == 80 then @@ -71,8 +61,8 @@ let ) endpoints; forwards = lib.concatMap (endpoint: let - baseForward = mapEndpointToForward remotePortMap portOffset endpoint; - httpRedirectForward = mapEndpointToForward remotePortMap portOffset (endpointForHttpRedirect endpoint); + baseForward = mapEndpointToForward remotePortMap endpoint; + httpRedirectForward = mapEndpointToForward remotePortMap (endpointForHttpRedirect endpoint); in if endpoint.force_ssl then [ baseForward httpRedirectForward ] diff --git a/secrets/autossh/remote_proxy_known_hosts b/secrets/autossh/remote_proxy_known_hosts index 101fc4e..d27b3bc 100644 --- a/secrets/autossh/remote_proxy_known_hosts +++ b/secrets/autossh/remote_proxy_known_hosts @@ -1,5 +1,5 @@ { - "data": "ENC[AES256_GCM,data:2O2/4FIDmmuwG0eRGmPUAm8Ji5lIly4dGT/ll+HZDvlC/sS6cbb3SEyplpVvqjMJNZACZtI9U87WJqKtoj9778Asxu0CFkwrsZK5bOf7XM27ZIN44/KWzbO6xezdcQ==,iv:XdgphFl56RNyjIIr9JQTUbh36j7UB8yjT0jgtCpMXDk=,tag:6OklZR86/gudejOFd9UneQ==,type:str]", + "data": "ENC[AES256_GCM,data:1ZzjJFqw28vXu6cw9efESy11132ntsaZwBmNqupqWju+y2iT2qq1wE+meGVH/e59YMC0ptNpsm+RbcfvC81vFvTFu46FUXPw2fXPb5UQmyDZxN7q+AM8SuOCqSy6,iv:FguIXmdsNUvhoqME97e5OIY+LMy5uuNd+d295U4lTuE=,tag:QlKokl5sOAtgwu06pnuRgA==,type:str]", "sops": { "age": [ { @@ -11,9 +11,8 @@ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBiSVhGUHVJNVZVRXhxZzhx\ncEVSNWZBQW8vQXlYdnFUQTg4Q2VlY0lZckRnCkRKNnF5R3ZlUElWN0FOL1hrNHAr\nT2JPaDJ3bzVhZzZONHBkRHBueW16eVEKLS0tIEFxU2pWMVRqaC9BeGRsaWppT1lO\nMzI4UmkybmROL3dKK0xEaWpCM1VPQzQKWsLEb0Z7fbTVF8WQ8a1Lom8Bh7FQ2cPB\nIwIqWRM1L0oXNHyBoFkmHO434DZ8SXlyUYegBwrbVZGedRQFLQ4ibg==\n-----END AGE ENCRYPTED FILE-----\n" } ], - "lastmodified": "2026-04-04T19:45:45Z", - "mac": "ENC[AES256_GCM,data:EEAh4MsdWJa6GvI2CZ0dS19ERRNtYucvEVCENZnc4Yqyz1vyQbNYuBZKi15D/XL5A8WN0jweBFtJV8bNwbuwW1gJZW8x10uhGJ1WpZrT+/vlFQbEzmEvvjkiO46R4kkQ+yhzkmth+85S0m/nz6p3lgIzcTRBfHIMe9V+kVb2eZI=,iv:u3E9Ybjl9a91Z8ic1fjCUqLqedAVS1e6ZZ9PNE7Em7c=,tag:XOJJBCQBxShz4bC/2t/VXg==,type:str]", - "unencrypted_suffix": "_unencrypted", + "lastmodified": "2026-04-04T09:12:02Z", + "mac": "ENC[AES256_GCM,data:C6jOqg6lFy8A2UTIfZXjtNB/F+0UZJV8/F1sOm4aGgR5B4e2JT+3vL/A62m6pvrj1zSuoD1dH47y3OcpmO/FmsnYcCTdWW2MPEOA63NkHJMScaLJry8JDHpColG8WYmJfGb9QwLJ1O64vpUNXNscmUFs7PomBgJnMCmTyo3twKk=,iv:wiAJw8Vk70b/gnfcgPlT3exsnnp87mGoIXMtzqd5m88=,tag:oT9TPTNSDX9y0cJJCP/JkQ==,type:str]", "version": "3.12.1" } } diff --git a/services/continuwuity.nix b/services/continuwuity.nix index 3509ab8..2b07d7b 100644 --- a/services/continuwuity.nix +++ b/services/continuwuity.nix @@ -1,40 +1,21 @@ -{ config, pkgs, lib, ... }: +{ config, pkgs, ... }: let + net = import ../config/network.nix; serv = import ../config/services.nix; serviceValidation = import ../validation/service/continuwuity.nix; - continuwuity = serv.continuwuity; - serverName = serviceValidation.getServerName serv; + serverName = + if net ? devices && builtins.isAttrs net.devices && net.devices ? remote_proxy && net.devices.remote_proxy ? domain && builtins.isString net.devices.remote_proxy.domain then + net.devices.remote_proxy.domain + else + throw "config/network.nix must define devices.remote_proxy.domain as string for continuwuity."; trustedServers = serviceValidation.getTrustedServers serv; - memoryMax = serviceValidation.getMemoryMax serv; - - package = if continuwuity ? package then - pkgs.matrix-continuwuity.overrideAttrs (old: rec { - version = continuwuity.package.version; - pname = old.pname or "matrix-continuwuity"; - - src = pkgs.fetchFromGitea { - domain = "forgejo.ellis.link"; - owner = "continuwuation"; - repo = "continuwuity"; - tag = "v${version}"; - hash = continuwuity.package.sourceHash; - }; - - cargoDeps = pkgs.rustPlatform.fetchCargoVendor { - inherit src; - hash = continuwuity.package.cargoHash; - }; - }) - else - pkgs.matrix-continuwuity; in { services.matrix-continuwuity = { enable = true; - package = package; settings = { global = { server_name = serverName; @@ -43,17 +24,7 @@ in allow_federation = true; max_request_size = 20 * 1024 * 1024; # 20 MiB trusted_servers = trustedServers; - matrix_rtc = { - foci = [ - { type = "livekit"; livekit_service_url = continuwuity.livekit_url; } - ]; - }; }; }; }; - - systemd.services.matrix-continuwuity.serviceConfig = - lib.optionalAttrs (memoryMax != null) { - MemoryMax = memoryMax; - }; } diff --git a/validation/auto_ssh.nix b/validation/auto_ssh.nix index 14070ee..0035ce3 100644 --- a/validation/auto_ssh.nix +++ b/validation/auto_ssh.nix @@ -53,23 +53,9 @@ let else device.auto_ssh.remotePortMap; - getPortOffset = device: - if !(device ? auto_ssh) then - 0 - else if !builtins.isAttrs device.auto_ssh then - throw "Device auto_ssh must be an attrset when present." - else if !(device.auto_ssh ? portOffset) then - 0 - else if !builtins.isInt device.auto_ssh.portOffset then - throw "Device auto_ssh.portOffset must be an int." - else if device.auto_ssh.portOffset < 0 then - throw "Device auto_ssh.portOffset must be >= 0." - else - device.auto_ssh.portOffset; - isSafeName = name: builtins.match "^[a-z_][a-z0-9_-]*$" name != null; in { - inherit getDevices getAutoSshDevices getAutoSshDomains getAutoSshConfig getRemotePortMap getPortOffset isSafeName; + inherit getDevices getAutoSshDevices getAutoSshDomains getAutoSshConfig getRemotePortMap isSafeName; } diff --git a/validation/endpoints.nix b/validation/endpoints.nix index 410eba1..cf60b0f 100644 --- a/validation/endpoints.nix +++ b/validation/endpoints.nix @@ -5,8 +5,7 @@ let allowedProxyContentKeys = [ "type" "ip" "port" "proxyWebsockets" ]; allowedWebContentKeys = [ "type" "files" ]; allowedWebFileKeys = [ "path" "filePath" "contentType" "status" ]; - allowedInlineContentKeys = [ "body" "contentType" "headers" "status" ]; - allowedRedirectContentKeys = [ "target" "status" ]; + allowedInlineContentKeys = [ "body" "contentType" "status" ]; ensureNoUnknownKeys = context: obj: allowedKeys: let @@ -39,10 +38,10 @@ let else throw "Endpoint at index ${toString index} must define type as a string."; _type = - if lib.elem typeValue [ "proxy" "web" "inline" "redirect" ] then + if lib.elem typeValue [ "proxy" "web" "inline" ] then null else - throw "Endpoint at index ${toString index} type must be 'proxy', 'web', 'inline', or 'redirect'."; + throw "Endpoint at index ${toString index} type must be 'proxy', 'web', or 'inline'."; _domain = if endpoint ? domain && builtins.isString endpoint.domain && endpoint.domain != "" then null @@ -132,26 +131,6 @@ let ) filesValue; in null - else if typeValue == "redirect" then - if builtins.isString contentValue then - null - else if builtins.isAttrs contentValue then - let - ____ = ensureNoUnknownKeys "Redirect content at endpoint index ${toString index}" contentValue allowedRedirectContentKeys; - _____ = - if contentValue ? target && builtins.isString contentValue.target && contentValue.target != "" then - null - else - throw "Redirect endpoint at index ${toString index} must define content.target as a non-empty string when content is an attrset."; - ______ = - if !(contentValue ? status) || builtins.isInt contentValue.status then - null - else - throw "Redirect endpoint at index ${toString index} content.status must be an int when provided."; - in - null - else - throw "Redirect endpoint at index ${toString index} must define content as a string or an attrset." else if builtins.isString contentValue then null @@ -168,20 +147,6 @@ let null else throw "Inline endpoint at index ${toString index} content.contentType must be a non-empty string when provided."; - ________ = - if contentValue ? headers then - if builtins.isAttrs contentValue.headers then - let - headerValues = builtins.attrValues contentValue.headers; - in - if lib.all (value: builtins.isString value && value != "") headerValues then - null - else - throw "Inline endpoint at index ${toString index} content.headers values must be non-empty strings." - else - throw "Inline endpoint at index ${toString index} content.headers must be an attrset when provided." - else - null; _______ = if !(contentValue ? status) || builtins.isInt contentValue.status then null diff --git a/validation/service/continuwuity.nix b/validation/service/continuwuity.nix index d428002..4e9dc64 100644 --- a/validation/service/continuwuity.nix +++ b/validation/service/continuwuity.nix @@ -2,54 +2,19 @@ let common = import ./common.nix; in rec { - getServerName = serviceData: - let - continuwuity = - if serviceData ? continuwuity then - common.ensureAttrset "config/services.nix continuwuity" serviceData.continuwuity - else - throw "config/services.nix must define continuwuity attrset."; - - serverName = - if continuwuity ? server_name then - common.ensureString "config/services.nix continuwuity.server_name" continuwuity.server_name - else - throw "config/services.nix continuwuity.server_name must exist."; - in - if serverName != "" then - serverName - else - throw "config/services.nix continuwuity.server_name must be a non-empty string."; - getTrustedServers = serviceData: let - continuwuity = - if serviceData ? continuwuity then - common.ensureAttrset "config/services.nix continuwuity" serviceData.continuwuity + matrix = + if serviceData ? matrix then + common.ensureAttrset "config/services.nix matrix" serviceData.matrix else - throw "config/services.nix must define continuwuity attrset."; + throw "config/services.nix must define matrix attrset."; trustedServers = - if continuwuity ? trusted_servers then - common.ensureList "config/services.nix continuwuity.trusted_servers" continuwuity.trusted_servers + if matrix ? trusted_servers then + common.ensureList "config/services.nix matrix.trusted_servers" matrix.trusted_servers else - throw "config/services.nix continuwuity.trusted_servers must exist."; + throw "config/services.nix matrix.trusted_servers must exist."; in trustedServers; - - getMemoryMax = serviceData: - let - continuwuity = - if serviceData ? continuwuity then - common.ensureAttrset "config/services.nix continuwuity" serviceData.continuwuity - else - throw "config/services.nix must define continuwuity attrset."; - in - if !(continuwuity ? memory_max) then - null - else - let - value = common.ensureString "config/services.nix continuwuity.memory_max" continuwuity.memory_max; - in - if value != "" then value else throw "config/services.nix continuwuity.memory_max must be a non-empty string when provided."; } \ No newline at end of file