diff --git a/hosts/server/hikari/hako/default.nix b/hosts/server/hikari/hako/default.nix index a0c4771..97ea8f4 100644 --- a/hosts/server/hikari/hako/default.nix +++ b/hosts/server/hikari/hako/default.nix @@ -13,6 +13,7 @@ nixpkgs.lib.nixosSystem { ./services/forgejo.nix ./services/immich.nix ./services/attic.nix + ./services/helium-services.nix ./services/api.nix ./services/caddy.nix ./services/postgresql.nix diff --git a/hosts/server/hikari/hako/services/attic.nix b/hosts/server/hikari/hako/services/attic.nix index 4ae3d7e..eb6568e 100644 --- a/hosts/server/hikari/hako/services/attic.nix +++ b/hosts/server/hikari/hako/services/attic.nix @@ -10,7 +10,7 @@ jwt = { }; - database.url = "postgresql:///attic"; + database.url = "postgresql:///attic?user=atticd"; storage = { type = "local"; diff --git a/hosts/server/hikari/hako/services/helium-services.nix b/hosts/server/hikari/hako/services/helium-services.nix new file mode 100644 index 0000000..e2c9ffb --- /dev/null +++ b/hosts/server/hikari/hako/services/helium-services.nix @@ -0,0 +1,221 @@ +{ + lib, + pkgs, + ... +}: + +let + hostname = "helium-services.imnya.ng"; + source = pkgs.fetchFromGitHub { + owner = "imputnet"; + repo = "helium-services"; + rev = "01c0515a27948a34dd0d4fd67c6014020fb52d0a"; + hash = "sha256-OSG92YpI7jLxvtBqsK1lfGrWRFREXGVyw+Q9C92FjEI="; + }; + + dictionaries = pkgs.stdenvNoCC.mkDerivation { + pname = "helium-services-dictionaries"; + version = "2026-08-26"; + src = pkgs.fetchurl { + url = "https://chromium.googlesource.com/chromium/deps/hunspell_dictionaries/+archive/cccf64a8acc951afe3f47fee023908e55699bc58.tar.gz"; + hash = "sha256-KMVNa0XsR9BXJzW6d7/D6AzAGErRVRGPU9CjjTIvyv0="; + }; + + dontUnpack = true; + installPhase = '' + mkdir -p "$out" + tar --extract --gzip --file "$src" --directory "$out" + ''; + }; + + serviceUser = "helium-services"; + stateDirectory = "/var/lib/helium-services"; + hmacSecretFile = "${stateDirectory}/extension-proxy.env"; + deno = "${pkgs.deno}/bin/deno"; + + initializeSecret = pkgs.writeShellApplication { + name = "initialize-helium-services-secret"; + runtimeInputs = [ pkgs.coreutils pkgs.openssl ]; + text = '' + set -eu + + install -d -o ${serviceUser} -g ${serviceUser} -m 0750 ${stateDirectory} + + if [ ! -s ${hmacSecretFile} ]; then + secret_file="$(mktemp ${stateDirectory}/.extension-proxy.env.XXXXXX)" + trap 'rm -f "$secret_file"' EXIT + umask 077 + printf 'HMAC_SECRET=%s\n' "$(openssl rand -hex 32)" > "$secret_file" + chown ${serviceUser}:${serviceUser} "$secret_file" + chmod 0400 "$secret_file" + mv "$secret_file" ${hmacSecretFile} + trap - EXIT + fi + ''; + }; + + mkDenoService = + { + description, + port, + configFile, + mainFile, + allowEnv, + environment, + cacheDirectory, + parallel ? false, + environmentFile ? null, + requiresSecret ? false, + }: + { + description = description; + wantedBy = [ "multi-user.target" ]; + wants = [ "network-online.target" ]; + after = [ "network-online.target" ] ++ lib.optional requiresSecret "helium-services-secret.service"; + requires = lib.optional requiresSecret "helium-services-secret.service"; + + environment = environment // { + DENO_DIR = "/var/cache/${cacheDirectory}"; + DENO_NO_UPDATE_CHECK = "1"; + }; + + serviceConfig = { + User = serviceUser; + Group = serviceUser; + WorkingDirectory = stateDirectory; + + StateDirectory = "helium-services"; + StateDirectoryMode = "0750"; + CacheDirectory = cacheDirectory; + CacheDirectoryMode = "0750"; + + ExecStartPre = [ "${deno} cache --config=${configFile} --frozen ${mainFile}" ]; + ExecStart = + "${deno} serve --config=${configFile} --frozen --cached-only --host=127.0.0.1 " + + "--port=${toString port} --allow-net --allow-env=${allowEnv} " + + lib.optionalString parallel "--parallel " + + mainFile; + + EnvironmentFile = lib.optional (environmentFile != null) environmentFile; + Restart = "always"; + RestartSec = 5; + TimeoutStopSec = 15; + UMask = "0077"; + + NoNewPrivileges = true; + PrivateDevices = true; + PrivateTmp = true; + ProtectHome = true; + ProtectSystem = "strict"; + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + "AF_UNIX" + ]; + }; + }; +in +{ + users.groups.${serviceUser} = { }; + users.users.${serviceUser} = { + isSystemUser = true; + group = serviceUser; + }; + + systemd.services.helium-services-secret = { + description = "Initialize the Helium Services extension signing secret"; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${initializeSecret}/bin/initialize-helium-services-secret"; + RemainAfterExit = true; + }; + }; + + systemd.services.helium-extension-proxy = mkDenoService { + description = "Helium Services extension proxy"; + port = 18080; + configFile = "${source}/svc/extension-proxy/deno.json"; + mainFile = "${source}/svc/extension-proxy/main.ts"; + allowEnv = "HMAC_SECRET,PROXY_BASE_URL"; + environment = { + PROXY_BASE_URL = "https://${hostname}/ext/"; + }; + cacheDirectory = "helium-services-ext"; + environmentFile = hmacSecretFile; + parallel = true; + requiresSecret = true; + }; + + systemd.services.helium-extension-proxy-backup = mkDenoService { + description = "Helium Services backup extension proxy"; + port = 18081; + configFile = "${source}/svc/extension-proxy/deno.json"; + mainFile = "${source}/svc/extension-proxy/main.ts"; + allowEnv = "HMAC_SECRET,PROXY_BASE_URL"; + environment = { + PROXY_BASE_URL = "https://${hostname}/ext/"; + }; + cacheDirectory = "helium-services-ext-backup"; + environmentFile = hmacSecretFile; + parallel = true; + requiresSecret = true; + }; + + systemd.services.helium-ubo = mkDenoService { + description = "Helium Services uBlock Origin proxy"; + port = 18082; + configFile = "${source}/svc/ubo/deno.json"; + mainFile = "${source}/svc/ubo/main.ts"; + allowEnv = "UBO_*"; + environment = { + UBO_PROXY_BASE_URL = "https://${hostname}/ubo/"; + }; + cacheDirectory = "helium-services-ubo"; + }; + + services.caddy.virtualHosts."${hostname}".extraConfig = '' + @root path / + redir @root https://helium.computer 302 + + @robots path /robots.txt + header @robots Content-Type "text/plain; charset=utf-8" + respond @robots "User-agent: *\nDisallow: /" 200 + + @connectivity path /connectivitycheck + respond @connectivity 204 + + @bangs path /bangs.json + handle @bangs { + root * ${source}/svc/bangs + header { + Access-Control-Allow-Origin "*" + Cache-Control "public, max-age=86400, stale-if-error=604800" + } + file_server + } + + @dictionaries path /dict /dict/* + handle @dictionaries { + root * ${dictionaries} + file_server browse + } + + handle_path /ext/* { + reverse_proxy 127.0.0.1:18080 127.0.0.1:18081 { + lb_policy first + } + } + + @com path /com /com/* + handle @com { + reverse_proxy 127.0.0.1:18080 127.0.0.1:18081 { + lb_policy first + } + } + + handle_path /ubo/* { + reverse_proxy 127.0.0.1:18082 + } + ''; +} diff --git a/wow b/wow new file mode 100644 index 0000000..e69de29