diff --git a/assets/wallpaper/wallpaper6.png b/assets/wallpaper/wallpaper6.png new file mode 100644 index 0000000..558a060 Binary files /dev/null and b/assets/wallpaper/wallpaper6.png differ diff --git a/flake.nix b/flake.nix index 91f85bf..9708821 100644 --- a/flake.nix +++ b/flake.nix @@ -83,7 +83,10 @@ url = "git+ssh://forgejo@mizuki.guru/imnyang/amia"; flake = false; }; - + api = { + url = "git+ssh://forgejo@mizuki.guru/imnyang/api.git"; + flake = false; + }; cfwithoutincident = { url = "git+https://git.mizuki.guru/imnyang/cfwithoutincident.git"; flake = false; diff --git a/hosts/machine/kanade/modules/homebrew/casks.nix b/hosts/machine/kanade/modules/homebrew/casks.nix index d936c74..837bfd6 100644 --- a/hosts/machine/kanade/modules/homebrew/casks.nix +++ b/hosts/machine/kanade/modules/homebrew/casks.nix @@ -13,6 +13,7 @@ "camo-studio" "proton-drive" "figma" + "adobe-creative-cloud" "notion" "firefox@developer-edition" @@ -28,9 +29,9 @@ "codex" "codex-app" "codexbar" + "metalterm" # Media and audio - "finetune" "spotify" # Gaming and remote access @@ -38,7 +39,6 @@ "steam" # macOS utilities - "alt-tab" "keka" "raycast" "thaw" diff --git a/hosts/machine/kanade/modules/homebrew/default.nix b/hosts/machine/kanade/modules/homebrew/default.nix index f616632..36467f6 100644 --- a/hosts/machine/kanade/modules/homebrew/default.nix +++ b/hosts/machine/kanade/modules/homebrew/default.nix @@ -12,6 +12,12 @@ upgrade = true; }; + taps = [ + { + name = "pioner92/tap"; + trusted = true; + } + ]; brews = import ./brews.nix; casks = import ./casks.nix; }; diff --git a/hosts/machine/kanade/modules/mac/dock.nix b/hosts/machine/kanade/modules/mac/dock.nix index 26924d6..a502203 100644 --- a/hosts/machine/kanade/modules/mac/dock.nix +++ b/hosts/machine/kanade/modules/mac/dock.nix @@ -16,15 +16,15 @@ "/Applications/KakaoTalk.app" "/Applications/Signal.app" "/Applications/Proton Mail.app" - # "/Applications/Proton Pass.app" - # "/System/Applications/Mail.app" "/Applications/1Password.app" + "/Applications/Utilities/Adobe Creative Cloud/ACC/Creative Cloud.app" "/Applications/Figma.app" "/Applications/Notion.app" - # "/Applications/Notion Calendar.app" "${pkgs.utm}/Applications/UTM.app" "/Applications/Spotify.app" - "${pkgs.ghostty-bin}/Applications/Ghostty.app" + "/Applications/Metalterm.app" + "/Applications/Burp Suite.app" + "/Applications/ChatGPT.app" "/Applications/Visual Studio Code - Insiders.app" "/Applications/Zed.app" "/System/Applications/System Settings.app" diff --git a/hosts/machine/kanade/modules/mac/wallpaper.nix b/hosts/machine/kanade/modules/mac/wallpaper.nix index c39fa0c..9cf7efb 100644 --- a/hosts/machine/kanade/modules/mac/wallpaper.nix +++ b/hosts/machine/kanade/modules/mac/wallpaper.nix @@ -4,7 +4,7 @@ ... }: let - wallpaper = "${inputs.self}/assets/wallpaper/wallpaper5.png"; + wallpaper = "${inputs.self}/assets/wallpaper/wallpaper6.png"; setWallpaperScript = pkgs.writeShellScriptBin "set-wallpaper-script" '' set -eu diff --git a/hosts/server/hikari/amia/configuration.nix b/hosts/server/hikari/amia/configuration.nix index 1715721..4fea465 100644 --- a/hosts/server/hikari/amia/configuration.nix +++ b/hosts/server/hikari/amia/configuration.nix @@ -60,6 +60,7 @@ in unitConfig.ConditionPathExists = "/home/imnyang/amia/config.toml"; path = [ pkgs.bind.dnsutils + pkgs.whois ]; serviceConfig = { diff --git a/hosts/server/hikari/hako/configuration.nix b/hosts/server/hikari/hako/configuration.nix index 8714a24..4158120 100644 --- a/hosts/server/hikari/hako/configuration.nix +++ b/hosts/server/hikari/hako/configuration.nix @@ -44,6 +44,16 @@ networking.firewall.enable = false; + # /dev/sdd1 (ext4, UUID efdf753d-282c-4b78-9549-a124b353c6a5) + fileSystems."/mnt/static" = { + device = "/dev/disk/by-uuid/efdf753d-282c-4b78-9549-a124b353c6a5"; + fsType = "ext4"; + }; + + systemd.tmpfiles.rules = [ + "L+ /var/static - - - - /mnt/static/static" + ]; + networking.hostName = "hako"; system.stateVersion = "26.05"; } diff --git a/hosts/server/hikari/hako/default.nix b/hosts/server/hikari/hako/default.nix index 4bbad34..97ea8f4 100644 --- a/hosts/server/hikari/hako/default.nix +++ b/hosts/server/hikari/hako/default.nix @@ -13,6 +13,8 @@ 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 ./services/nc.nix diff --git a/hosts/server/hikari/hako/services/api.nix b/hosts/server/hikari/hako/services/api.nix new file mode 100644 index 0000000..7e0fe85 --- /dev/null +++ b/hosts/server/hikari/hako/services/api.nix @@ -0,0 +1,87 @@ +{ inputs, pkgs, ... }: + +let + apiDependencies = pkgs.stdenv.mkDerivation { + pname = "imnyang-api-dependencies"; + version = "unstable"; + src = inputs.api; + + nativeBuildInputs = [ pkgs.bun ]; + + dontConfigure = true; + + buildPhase = '' + export HOME="$TMPDIR/home" + mkdir -p "$HOME" + bun install --frozen-lockfile --no-progress + ''; + + installPhase = '' + mkdir -p "$out" + cp -a node_modules "$out/node_modules" + ''; + + outputHashMode = "recursive"; + outputHash = "sha256-ke6cG/cBON6d6giFo1RAQ4gMfIbmagJfCI1FfZl1w/8="; + }; + + apiPackage = pkgs.stdenv.mkDerivation { + pname = "imnyang-api"; + version = "unstable"; + src = inputs.api; + + nativeBuildInputs = [ pkgs.bun ]; + + # Bun standalone executables contain the bundled application after the + # ELF sections; stripping them leaves only the Bun runtime. + dontStrip = true; + + dontConfigure = true; + + buildPhase = '' + cp -a ${apiDependencies}/node_modules ./node_modules + bun run build + ''; + + installPhase = '' + install -Dm755 server "$out/bin/server" + mkdir -p "$out/share/imnyang-api" + cp -r src/mitda "$out/share/imnyang-api/mitda" + ''; + }; +in +{ + systemd.services.api = { + description = "Elysia"; + wantedBy = [ "multi-user.target" ]; + wants = [ "network-online.target" ]; + after = [ "network-online.target" ]; + + path = [ pkgs.dnsutils ]; + + preStart = '' + if ! test -e /var/lib/imnyang-api/nadae.hrts; then + printf '0\n' > /var/lib/imnyang-api/nadae.hrts + fi + ''; + + serviceConfig = { + Type = "simple"; + User = "imnyang"; + WorkingDirectory = "/var/lib/imnyang-api"; + StateDirectory = "imnyang-api"; + StateDirectoryMode = "0750"; + ExecStart = "${apiPackage}/bin/server"; + Restart = "always"; + RestartSec = 5; + Environment = [ + "NODE_ENV=production" + "MITDA_ASSETS_DIR=${apiPackage}/share/imnyang-api/mitda" + ]; + NoNewPrivileges = true; + PrivateTmp = true; + ProtectHome = true; + ProtectSystem = "strict"; + }; + }; +} 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/caddy.nix b/hosts/server/hikari/hako/services/caddy.nix index e09e4a0..0cd8a82 100644 --- a/hosts/server/hikari/hako/services/caddy.nix +++ b/hosts/server/hikari/hako/services/caddy.nix @@ -27,7 +27,7 @@ let @serverError expression {http.error.status_code} in [500, 502, 504, 505] handle @serverError { - rewrite * /server.html + rewrite * /5xx.html root * /var/static/error file_server } @@ -118,6 +118,31 @@ let "twohearts.imnya.ng" "whs.imnya.ng" ]; + + cloudflareIpRanges = [ + "103.21.244.0/22" + "103.22.200.0/22" + "103.31.4.0/22" + "104.16.0.0/13" + "104.24.0.0/14" + "108.162.192.0/18" + "131.0.72.0/22" + "141.101.64.0/18" + "162.158.0.0/15" + "172.64.0.0/13" + "173.245.48.0/20" + "188.114.96.0/20" + "190.93.240.0/20" + "197.234.240.0/22" + "198.41.128.0/17" + "2400:cb00::/32" + "2606:4700::/32" + "2803:f800::/32" + "2405:b500::/32" + "2405:8100::/32" + "2a06:98c0::/29" + "2c0f:f248::/32" + ]; in { services.caddy = { @@ -126,6 +151,17 @@ in openFirewall = true; package = pkgs.caddy; + globalConfig = '' + admin unix//run/caddy/admin.socket + storage file_system /var/lib/caddy + servers { + trusted_proxies static ${builtins.concatStringsSep " " cloudflareIpRanges} + client_ip_headers Cf-Connecting-Ip + } + debug + ''; + + virtualHosts = builtins.listToAttrs ( map (host: { @@ -134,12 +170,23 @@ in }) staticHosts ) // { - "api.imnya.ng".extraConfig = reverseProxyWithHeaders "10.11.8.101:1108"; - "nou.imnya.ng".extraConfig = reverseProxyWithHeaders "10.11.8.101:6974"; + "api.imnya.ng".extraConfig = reverseProxyWithHeaders "127.0.0.1:10118"; "docs.imnya.ng".extraConfig = reverseProxy "100.70.1.1:3939"; "panel.imnya.ng".extraConfig = reverseProxy "127.0.0.1:32981"; "monitorss.imnya.ng".extraConfig = reverseProxy "127.0.0.1:3132"; + "ip.imnya.ng".extraConfig = '' + header Access-Control-Allow-Origin "*" + header Access-Control-Allow-Methods "GET, OPTIONS" + header Access-Control-Allow-Headers "*" + + @options method OPTIONS + respond @options 204 + + @ip path / + respond @ip "{http.request.header.Cf-Connecting-Ip}" + ''; + "imnya.ng".extraConfig = withErrors '' handle_path /.well-known/webfinger { root * /var/www/imnya.ng @@ -240,7 +287,6 @@ in reverse_proxy 10.20.30.101:6769 ''; - "t.hrts.kr".extraConfig = reverseProxy "10.11.8.101:4041"; "wakapi.hrts.kr".extraConfig = reverseProxy "127.0.0.1:13000"; "ziit.hrts.kr".extraConfig = reverseProxy "127.0.0.1:6030"; "hikari-panel.hrts.kr".extraConfig = reverseProxy "10.11.8.104:8080"; @@ -261,7 +307,6 @@ in "auth.hrts.kr".extraConfig = reverseProxy "10.11.8.32:1411"; "git.hrts.kr".extraConfig = reverseProxy "127.0.0.1:3000"; - "api-ftp.hrts.kr".extraConfig = reverseProxy "10.11.8.101:25716"; "panel.hrts.kr".extraConfig = reverseProxy "127.0.0.1:3929"; "pgadmin.hrts.kr".extraConfig = reverseProxy "127.0.0.1:5050"; "al-1s.hrts.kr".extraConfig = reverseProxy "127.0.0.1:9120"; @@ -322,4 +367,13 @@ in "demo.mizuki.guru".extraConfig = reverseProxy "10.20.30.103:3000"; }; }; + + systemd.services.caddy = { + requires = [ "mnt-static.mount" ]; + after = [ "mnt-static.mount" "systemd-tmpfiles-setup.service" ]; + serviceConfig = { + RuntimeDirectory = "caddy"; + RuntimeDirectoryMode = "0755"; + }; + }; } diff --git a/hosts/server/hikari/hako/services/forgejo.nix b/hosts/server/hikari/hako/services/forgejo.nix index bd43068..062f0e0 100644 --- a/hosts/server/hikari/hako/services/forgejo.nix +++ b/hosts/server/hikari/hako/services/forgejo.nix @@ -97,13 +97,8 @@ USER = "systemmail@mizuki.guru"; }; - oauth2 = { - ENABLED = true; - }; - - actions = { - ENABLED = false; - }; + oauth2.ENABLED = true; + actions.ENABLED = true; ui = { THEMES = "dark,light,auto,forgejo-auto,forgejo-light,forgejo-dark"; 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 + } + ''; +}