diff --git a/README.md b/README.md index 2ec089f..3544565 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,9 @@ nix build .#nixosConfigurations.installIso.config.system.build.images.iso sudo mount -o loop result/iso/nixos-*.iso mnt ls mnt umount mnt + +# Manipulate sops-nix secrets +nix-shell -p sops --run "sops secrets/example.yaml" ``` ## Design Goals diff --git a/flake.lock b/flake.lock index a50ca1f..9064650 100644 --- a/flake.lock +++ b/flake.lock @@ -72,6 +72,24 @@ "type": "github" } }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, "gitignore": { "inputs": { "nixpkgs": [ @@ -140,6 +158,28 @@ "type": "github" } }, + "microvm": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": [ + "nixpkgs" + ], + "spectrum": "spectrum" + }, + "locked": { + "lastModified": 1750358184, + "narHash": "sha256-17EYMeY5v8KRk9HW6Z4dExY8Wg4y/zM2eM2wbbx+vMs=", + "owner": "astro", + "repo": "microvm.nix", + "rev": "fd9f5dba1ffee5ad6f29394b2a9e4c66c1ce77dc", + "type": "github" + }, + "original": { + "owner": "astro", + "repo": "microvm.nix", + "type": "github" + } + }, "nixos-hardware": { "locked": { "lastModified": 1749195551, @@ -219,6 +259,7 @@ "disko": "disko", "home-manager": "home-manager", "lanzaboote": "lanzaboote", + "microvm": "microvm", "nixos-hardware": "nixos-hardware", "nixpkgs": "nixpkgs", "sops-nix": "sops-nix" @@ -264,6 +305,37 @@ "repo": "sops-nix", "type": "github" } + }, + "spectrum": { + "flake": false, + "locked": { + "lastModified": 1746869549, + "narHash": "sha256-BKZ/yZO/qeLKh9YqVkKB6wJiDQJAZNN5rk5NsMImsWs=", + "ref": "refs/heads/main", + "rev": "d927e78530892ec8ed389e8fae5f38abee00ad87", + "revCount": 862, + "type": "git", + "url": "https://spectrum-os.org/git/spectrum" + }, + "original": { + "type": "git", + "url": "https://spectrum-os.org/git/spectrum" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index b4a67f8..d6b35f8 100644 --- a/flake.nix +++ b/flake.nix @@ -11,9 +11,11 @@ sops-nix.inputs.nixpkgs.follows = "nixpkgs"; disko.url = "github:nix-community/disko"; disko.inputs.nixpkgs.follows = "nixpkgs"; + microvm.url = "github:astro/microvm.nix"; + microvm.inputs.nixpkgs.follows = "nixpkgs"; }; # https://nix.dev/tutorials/nix-language.html#named-attribute-set-argument - outputs = inputs@{self, nixpkgs, nixos-hardware, home-manager, sops-nix, lanzaboote, disko, ...}: + outputs = inputs@{self, nixpkgs, nixos-hardware, home-manager, sops-nix, lanzaboote, disko, microvm, ...}: let mkSystem = (import ./lib { inherit nixpkgs home-manager inputs; @@ -30,6 +32,7 @@ lithium = mkSystem { hostname = "lithium"; # extraModules = [ inputs.sops-nix.nixosModules.sops ]; + extraModules = [ microvm.nixosModules.host ]; users = [ "jml" "breakglass" diff --git a/hosts/lithium/configuration.nix b/hosts/lithium/configuration.nix index 5023ef1..80cd057 100644 --- a/hosts/lithium/configuration.nix +++ b/hosts/lithium/configuration.nix @@ -1,8 +1,8 @@ -{ config, pkgs, ... }: +{ config, pkgs, lib, ... }: { sops.defaultSopsFile = ./secrets/common.yaml; networking.hostName = "lithium"; - networking.domain = config.vars.domain; + networking.domain = lib.mkForce config.vars.domain; environment.systemPackages = with pkgs; [ zfs ]; diff --git a/hosts/lithium/default.nix b/hosts/lithium/default.nix index 4a02b76..8834b37 100644 --- a/hosts/lithium/default.nix +++ b/hosts/lithium/default.nix @@ -1,8 +1,18 @@ { inputs, ... }: +#let + #secretsPath = builtins.toString inputs.nixos-secrets; +#in { + #sops = { + #defaultSopsFile = "${secretsPath}/${config.hostname}/secrets.yaml"; + #defaultSopsFile = "${secretsPath}/global/secrets.yaml"; + #}; + imports = [ ../../modules/nixos/base.nix - inputs.sops-nix.nixosModules.sops + #inputs.sops-nix.nixosModules.sops + #import ./sops.nix ( {inherit inputs;} ) + ./sops.nix ./hardware.nix ./configuration.nix ./semi-secret-vars.nix @@ -12,5 +22,19 @@ ./services/jellyfin.nix ./services/uptime-kuma.nix ./services/file-shares.nix + ./services/miniflux + ./services/forgejo.nix + + # Monitoring + ./services/monitoring + + # Game Servers + ./services/palworld + + + # Services running in virtual machines + #./microvms + #./microvms/palworld ]; + } diff --git a/hosts/lithium/secrets/miniflux_admin_credentials.env b/hosts/lithium/secrets/miniflux_admin_credentials.env new file mode 100644 index 0000000..669e8fc --- /dev/null +++ b/hosts/lithium/secrets/miniflux_admin_credentials.env @@ -0,0 +1,10 @@ +ADMIN_USERNAME=ENC[AES256_GCM,data:1b9RG0hCr3mV+Q==,iv:+P9LxMk7gLvCvVgrzRgHhk7s3kMnMNkWyT8cyBe0msI=,tag:2TVfhdVToEsz4mF/UrrP9w==,type:str] +ADMIN_PASSWORD=ENC[AES256_GCM,data:3HUEKnmGJ9vRSA==,iv:UpY8iFBIT01QUFINo3Cn7dT6q0uDbbDNuU2K7hjfaRY=,tag:LizvS3rkk7PHQVTLRtmbqw==,type:str] +sops_age__list_0__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB0TWxwa21pNmxJczd1Y3l2\nZjIzYWJ2TEk0VlZGTXN2a3lvaGR3Q2cwNXlBClN5dXJyMmxFWnA5UytVUjErZ1Ju\nZHY5emdBd2plM1dvRWNwaE5ydW9IbGcKLS0tIEFtUFZnUkllajhDVTU4ejlTN09n\nN0VTWi9lb1UxQm1OTGwzU2dkc25XR1EKlsqqZCJ6YTseRoxaoQRcnnqg0Q6zDezP\ni8lVt4WCK/mIXiqASNf0EaunujxftSg4g5s1PoUzdh2RWRXjjUk6Rw==\n-----END AGE ENCRYPTED FILE-----\n +sops_age__list_0__map_recipient=age1mv8xtvkuuw3hphq5ytaekz7p8a4kht79uajyhy534uy9e5472fhqj5zpxu +sops_age__list_1__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBCY1pnNWdpUGNmTXQ5VHY4\nazJaSUVnMEd4cTVIa3p1NWJBWHAyMEhuMXprCjk3MENuUDJ3OE13bUhJKzNxV1Yr\nZmMwMUtyZldodDRBRkRIUnN5cCswVHcKLS0tIE43RmFHQU0zMitrcmtKaGRMTXZZ\nZWdCOHNVaXp2WjNWUUtTNmVjQTdQMkUK7dbXoDOAxppQi3nmp0S7q130BBvxtdo/\nuaC5FuUXijp0U+Xrdkq3Qukv/u4b7E17mw3zMgHIaxf8w0W/XmTcXQ==\n-----END AGE ENCRYPTED FILE-----\n +sops_age__list_1__map_recipient=age148yre4vaxp6lm59rft24te46szawqyguf8znkrtpq7ud8tpteauqxkwyjl +sops_lastmodified=2025-07-22T01:07:11Z +sops_mac=ENC[AES256_GCM,data:I17CIK+OqttRpVc9U3Xdefnb95PFcFpCykLSxoVvO74NCvYcHYaB09Wnbt5X46u3TtX1ZmDr85WNzWocu+rM1kdJFXnGI/N9UiCgnam66QCwIlIckCldDGsnPbHpkeB7SFgCJ+1GOz19poPu2RJ41b28NRxNdV4+9HB15Xz6OcM=,iv:7u28+i8HA6wv9SuTSjCGr5o0Wak6zmUvSj3z3CzxT6U=,tag:GXEbSyBGkPSveD0zREBEyQ==,type:str] +sops_unencrypted_suffix=_unencrypted +sops_version=3.10.2 diff --git a/hosts/lithium/services/calibre-web.nix b/hosts/lithium/services/calibre-web.nix new file mode 100644 index 0000000..44f8baf --- /dev/null +++ b/hosts/lithium/services/calibre-web.nix @@ -0,0 +1,44 @@ +{ inputs, config, pkgs, lib, ... }: +let + homelabDomain = inputs.nixos-secrets.homelabDomain; + certDir = config.security.acme.certs."${homelabDomain}".directory; + svcDomain = "books.${homelabDomain}"; + svcHttpPort = config.services.calibre-web.listen.port; + web_data_dir = "calibre-web"; + library_path = "/tank/media/library/books"; +in +{ + # TODO: This isn't the right place for this, but we need to guarantee that a + # media group exists. + users.users.calibre-web.extraGroups = [ "media" ]; + users.groups.media = {}; + + services.caddy.virtualHosts."${svcDomain}".extraConfig = '' + reverse_proxy :${toString svcHttpPort} + encode { + zstd + gzip + minimum_length 1024 + } + ''; + + services.calibre-web = { + enable = true; + listen.port = 8083; + # NOTE: Don't need to open calibre-web port, it's served by reverse_proxy + openFirewall = false; + + user = "calibre-web"; + group = "calibre-web"; + + # Either absolute path or directory name under "/var/lib" + # /tank/media/library/books + dataDir = web_data_dir; + + options = { + enableBookUploading = true; + enableBookConversion = true; + calibreLibrary = library_path; + }; + }; +} diff --git a/hosts/lithium/services/forgejo.nix b/hosts/lithium/services/forgejo.nix new file mode 100644 index 0000000..3cec1fa --- /dev/null +++ b/hosts/lithium/services/forgejo.nix @@ -0,0 +1,141 @@ +{ config, pkgs, lib, ... }: +let + homelabDomain = config.networking.domain; + svcDomain = "git.${homelabDomain}"; + theme = pkgs.fetchzip { + url = "https://github.com/catppuccin/gitea/releases/download/v1.0.2/catppuccin-gitea.tar.gz"; + hash = "sha256-rZHLORwLUfIFcB6K9yhrzr+UwdPNQVSadsw6rg8Q7gs="; + stripRoot = false; + }; + svcHttpPort = config.services.forgejo.settings.server.HTTP_PORT; + assetsDir = "${config.services.forgejo.stateDir}/custom/public/assets"; +in +{ + # NOTE: Periodically come update the catpuccin theme. + # `-auto` will automatically switch between latte and mocha modes. + services.forgejo.settings.ui = { + DEFAULT_THEME = "catpuccin-teal-auto"; + THEMES = builtins.concatStringsSep "," ( + [ "auto" ] + ++ (map (name: lib.removePrefix "theme-" (lib.removeSuffix ".css" name)) ( + builtins.attrNames (builtins.readDir theme) + )) + ); + }; + + # TODO: Setup a PostgreSQL Server. + # Inspiration here: https://github.com/nyawox/arcanum/blob/4629dfba1bc6d4dd2f4cf45724df81289230b61a/nixos/servers/forgejo.nix#L64 + #sops-secrets.postgres-forgejo = { + #sopsFile = ../secrets/forgejo.yaml; + #}; + + services.caddy.virtualHosts."${svcDomain}".extraConfig = '' + reverse_proxy :${toString svcHttpPort} + ''; + + services.forgejo = { + enable = true; + # database.type = "postgres"; + settings = { + default.APP_NAME = "GitGarage"; + server = { + DOMAIN = svcDomain; + ROOT_URL = "https://${svcDomain}"; + }; + # NOTE: Actions support is based on: https://github.com/nektos/act + #actions = { + #ENABLED = true; + #DEFAULT_ACTIONS_URL = "github"; + #}; + actions.ENABLED = false; + # NOTE: Registration is handled with kanidm. + service = { + REGISTER_EMAIL_CONFIRM = false; + DISABLE_REGISTRATION = false; + ALLOW_ONLY_EXTERNAL_REGISTRATION = true; + SHOW_REGISTRATION_BUTTON = false; + REQUIRE_SIGNIN_VIEW = false; + # TODO: Consider setting up emails. + ENABLE_NOTIFY_MAIL = false; + }; + openid = { + ENABLE_OPENID_SIGNIN = true; + ENABLE_OPENID_SIGNUP = true; + WHITELISTED_URIS = "id.${homelabDomain}"; + }; + # TODO: Literally review all server settings, and link the forgejo documentation. + # Also perhaps include every setting here explicitly. + oauth2_client = { + REGISTER_EMAIL_CONFIRM = false; + ENABLE_AUTO_REGISTRATION = true; + ACCOUNT_LINKING = "login"; + USERNAME = "nickname"; + UPDATE_AVATAR = true; + OPENID_CONNECT_SCOPES = "openid email profile"; + }; + repository = { + DEFAULT_PRIVATE = "private"; + DEFAULT_BRANCH = "main"; + ENABLE_PUSH_CREATE_USER = true; + ENABLE_PUSH_CREATE_ORG = true; + }; + mailer.ENABLED = false; + }; + }; + + # TODO: Finish Configuring the kandim oauth for forgejo.... + services.kanidm.provision.systems.oauth2.forgejo = { + displayName = "forgejo"; + # TODO: Get this from Forgejo + originUrl = "https://git.${homelabDomain}/user/oauth2/${homelabDomain}/callback"; + originLanding = "https://git.${homelabDomain}/"; + #basicSecretFile = "TODO!SETME"; + scopeMaps."git.users" = [ + "openid" + "email" + "profile" + ]; + # WARNING: PKCE is currently not supported by gitea/forgejo, + # see https://github.com/go-gitea/gitea/issues/21376 + allowInsecureClientDisablePkce = true; + preferShortUsername = true; + claimMaps.groups = { + joinType = "array"; + valuesByGroup."git.admins" = [ "admin" ]; + }; + }; + + systemd.services.forgejo = { + preStart = + lib.mkAfter # bash + '' + echo "Installing Catppuccin Assets" + rm -rf ${assetsDir} + mkdir -p ${assetsDir} + ln -sf ${theme} ${assetsDir}/css + ''; + }; + + + #sops.secrets.forgejo-runner-token = {}; + #services.gitea-actions-runner = { + #package = pkgs.forgejo-runner; + #instances.default = { + #enable = true; + #name = "monolith"; + #url = "https://${serviceDomain}"; + #tokenFile = config.sops.secrets.forgejo-runner-token.path; + # NOTE: I don't want huge images if it can be avoided. + # https://nektosact.com/usage/runners.html + #labels = [ + #"ubuntu-latest:docker://node:16-bullseye-slim" + #"ubuntu-22.04:docker://node:16-bullseye-slim" + #]; + #}; + #}; + + # TODO: Consider automatically creating admin account and password... + # https://wiki.nixos.org/wiki/Forgejo#Ensure_users + # Might be necessary to generate a token for kanidm + #sops.secrets.forgejo-admin-password.owner = "forgejo"; +} diff --git a/hosts/lithium/services/grafana.nix b/hosts/lithium/services/grafana.nix new file mode 100644 index 0000000..0dddf2b --- /dev/null +++ b/hosts/lithium/services/grafana.nix @@ -0,0 +1,24 @@ +{ config, pkgs, ... }: +let + svcDomain = "grafana.${config.networking.domain}"; + svcPort = config.services.grafana.settings.server.http_port; +in +{ + services.caddy.virtualHosts."${svcDomain}".extraConfig = '' + reverse_proxy :${svcPort} + ''; + + services.grafana = { + enable = true; + settings = { + server = { + http_addr = "127.0.0.1"; + http_port = 3000; + enforce_domain = true; + enable_gzip = true; + domain = svcDomain; + }; + analytics.reporting_enabled = false; # NOTE: Disable Telemetry + }; + }; +} diff --git a/hosts/lithium/services/immich.nix b/hosts/lithium/services/immich.nix new file mode 100644 index 0000000..1c71665 --- /dev/null +++ b/hosts/lithium/services/immich.nix @@ -0,0 +1,84 @@ +{ inputs, config, pkgs, lib, ... }: +let + homelabDomain = inputs.nixos-secrets.homelabDomain; + svcDomain = "photos.${homelabDomain}"; + photoStorageDir = "/tank/shares/photos"; + svcPort = config.services.immich.port; +in +{ + + # NOTE: The following repo contains a highly mature immich setup on nixos. + # https://github.com/xinyangli/nixos-config/blob/a8b5bea68caea573801ccfdb8ceacb7a8f2b0190/machines/agate/services/immich.nix + services.caddy.virtualHosts."${svcDomain}".extraConfig = '' + reverse_proxy :${svcPort} + ''; + + # NOTE: Primarily to contain DB_PASSWORD to make it possible to backup and restore the DB. + sops.secrets.immich_env = { + sopsFile = ../../secrets/immich.env; + format = "dotenv"; + mode = "0440"; + owner = "immich"; + group = "immich"; + restartUnits = [ "immich.service" ]; + }; + sops.secrets."immich/oauth2_client_secret" = { + owner = "immich"; + group = "kanidm"; + mode = "0440"; + restartUnits = [ "immich.service" "kanidm.service" ]; + }; + + users.users.immich = { + isSystemUser = true; + }; + users.groups.immich = {}; + systemd.tmpfiles.rules = [ + "d ${photoStorageDir} 0770 immich immich -" + ]; + + # TODO: Setup mTLS for external / non-tailscale VPN immich access. + # https://github.com/alangrainger/immich-public-proxy/blob/main/docs/securing-immich-with-mtls.md + # TODO: Consider immich-public-proxy for generating "share" links + # https://github.com/alangrainger/immich-public-proxy + services.immich = { + enable = true; + openFirewall = true; + port = 2283; # default + secretsFile = config.sops.secrets."immich_secrets.env".path; + + # TODO: Build this directory with permissions for the immich user. + mediaLocation = "/tank/shares/photos"; + + # https://docs.immich.app/install/config-file/ + settings = { + # TODO: Setup OAuth with Kanidm + oauth = { + enabled = true; + issuerUrl = "https://"; # TODO: the kanidm url? + clientId = "immich"; + clientSecret = config.sops.placeholder."immich/oauth2_client_secret"; + scope = "openid email profile"; + signingAlgorithm = "ES256"; + storageLabelClaim = "email"; + buttonText = "Login with Kanidm"; + autoLaunch = true; + mobileOverrideEnabled = true; + mobileRedirectUri = "https://${svcDomain}/api/oauth/mobile-redirect/"; + }; + }; + }; + + services.kanidm.provision.systems.oauth2.immich = { + displayName = "immich"; + originUrl = "https://${svcDomain}/oauth2/oidc/callback"; + originLanding = "https://${svcDomain}/"; + basicSecretFile = config.sops.secrets."immich/oauth2_client_secret".path; + scopeMaps."immich.users" = [ + "openid" + "email" + "profile" + ]; + preferShortUsername = true; + }; +} diff --git a/hosts/lithium/services/miniflux/default.nix b/hosts/lithium/services/miniflux/default.nix new file mode 100644 index 0000000..a109874 --- /dev/null +++ b/hosts/lithium/services/miniflux/default.nix @@ -0,0 +1,53 @@ +{ config, pkgs, ... }: +let + svcDomain = "feeds.${config.networking.domain}"; + svcPort = "8080"; +in +{ + services.caddy.virtualHosts."${svcDomain}".extraConfig = '' + reverse_proxy :${svcPort} + ''; + # NOTE: Ensure the user exists ahead of trying to give secret permissions to that user. + users.users.miniflux = { + isSystemUser = true; + group = "miniflux"; + createHome = false; + }; + users.groups.miniflux = {}; + sops.secrets.miniflux_env = { + sopsFile = ../../secrets/miniflux_admin_credentials.env; + format = "dotenv"; + mode = "0440"; + owner = "miniflux"; + group = "miniflux"; + restartUnits = [ "miniflux.service" ]; + }; + services.kanidm.provision = { + groups = {}; + systems.oauth2.miniflux = { + displayName = "Miniflux Feed Reader"; + originUrl = "https://${fqdn}/callback"; + public = true; # enforces PKCE + preferShortUsername = true; + scopeMaps.pages_users = ["openid" "email" "profile"]; + claimMaps."${permissionsMap}".valuesByGroup.pages_admin = ["admin"]; + }; + }; + # NOTE: Currently requires some web-interface configuration + services.miniflux = { + enable = true; + adminCredentialsFile = config.sops.secrets.miniflux_env.path; + config = { + BASE_URL = "https://${svcDomain}"; + CREATE_ADMIN = 0; + DISABLE_LOCAL_AUTH = 1; + OAUTH2_PROVIDER = "oidc"; + OAUTH2_OIDC_PROVIDER_NAME = "Kanidm"; + OAUTH2_OIDC_DISCOVERY_ENDPOINT = "https://id.${config.networking.domain}"; + OAUTH2_REDIRECT_URL = "https://${svcDomain}/oauth2/oidc/callback"; + OAUTH2_USER_CREATION = 1; + CLEANUP_FREQUENCY = 48; + LISTEN_ADDR = "localhost:${svcPort}"; + }; + }; +} diff --git a/hosts/lithium/services/monitoring/default.nix b/hosts/lithium/services/monitoring/default.nix new file mode 100644 index 0000000..1e37aea --- /dev/null +++ b/hosts/lithium/services/monitoring/default.nix @@ -0,0 +1,6 @@ +{ ... }: { + imports = [ + ./grafana.nix + ./prometheus.nix + ]; +} diff --git a/hosts/lithium/services/monitoring/grafana.nix b/hosts/lithium/services/monitoring/grafana.nix new file mode 100644 index 0000000..7ba0206 --- /dev/null +++ b/hosts/lithium/services/monitoring/grafana.nix @@ -0,0 +1,24 @@ +{ config, pkgs, ... }: +let + svcDomain = "grafana.${config.networking.domain}"; + svcPort = config.services.grafana.settings.server.http_port; +in +{ + services.caddy.virtualHosts."${svcDomain}".extraConfig = '' + reverse_proxy :${toString svcPort} + ''; + + services.grafana = { + enable = true; + settings = { + server = { + http_addr = "127.0.0.1"; + http_port = 3001; + enforce_domain = true; + enable_gzip = true; + domain = svcDomain; + }; + analytics.reporting_enabled = false; # NOTE: Disable Telemetry + }; + }; +} diff --git a/hosts/lithium/services/monitoring/prometheus.nix b/hosts/lithium/services/monitoring/prometheus.nix new file mode 100644 index 0000000..51be2ea --- /dev/null +++ b/hosts/lithium/services/monitoring/prometheus.nix @@ -0,0 +1,29 @@ +{ config, pkgs, ... }: +#let + #svcDomain = "status.${config.networking.domain}"; + #svcPort = config.services.prometheus.exporters.node.port; +#in +{ + #services.caddy.virtualHosts."${svcDomain}".extraConfig = '' + #reverse_proxy :${svcPort} + #''; + + services.prometheus = { + enable = true; + #globalConfig.scrape_interval = "10s"; # "1m" + #scrapeConfigs = [ + #{ + #job_name = "node"; + #static_configs = [{ + # targets = [ "localhost:${toString svcPort}" ]; + #}]; + #} + #]; + }; + + #services.prometheus.exporters.node = { + #enable = true; + #port = 9000; + #enabledCollectors = [ "systemd" ]; + #}; +} diff --git a/hosts/lithium/services/palworld/PalWorldSettings.ini b/hosts/lithium/services/palworld/PalWorldSettings.ini new file mode 100755 index 0000000..d589452 --- /dev/null +++ b/hosts/lithium/services/palworld/PalWorldSettings.ini @@ -0,0 +1,2 @@ +[/Script/Pal.PalGameWorldSettings] +OptionSettings=(Difficulty=None,RandomizerType=None,RandomizerSeed="",bIsRandomizerPalLevelRandom=False,DayTimeSpeedRate=1.000000,NightTimeSpeedRate=1.000000,ExpRate=1.000000,PalCaptureRate=1.100000,PalSpawnNumRate=1.100000,PalDamageRateAttack=1.000000,PalDamageRateDefense=1.000000,PlayerDamageRateAttack=1.000000,PlayerDamageRateDefense=1.000000,PlayerStomachDecreaceRate=0.800000,PlayerStaminaDecreaceRate=0.900000,PlayerAutoHPRegeneRate=1.100000,PlayerAutoHpRegeneRateInSleep=1.200000,PalStomachDecreaceRate=0.900000,PalStaminaDecreaceRate=1.000000,PalAutoHPRegeneRate=1.000000,PalAutoHpRegeneRateInSleep=1.000000,BuildObjectHpRate=1.000000,BuildObjectDamageRate=1.000000,BuildObjectDeteriorationDamageRate=1.000000,CollectionDropRate=1.000000,CollectionObjectHpRate=1.000000,CollectionObjectRespawnSpeedRate=1.000000,EnemyDropItemRate=1.000000,DeathPenalty=1,bEnablePlayerToPlayerDamage=False,bEnableFriendlyFire=False,bEnableInvaderEnemy=True,bActiveUNKO=False,bEnableAimAssistPad=True,bEnableAimAssistKeyboard=True,DropItemMaxNum=3000,DropItemMaxNum_UNKO=100,BaseCampMaxNum=128,BaseCampWorkerMaxNum=15,DropItemAliveMaxHours=1.000000,bAutoResetGuildNoOnlinePlayers=False,AutoResetGuildTimeNoOnlinePlayers=72.000000,GuildPlayerMaxNum=20,BaseCampMaxNumInGuild=4,PalEggDefaultHatchingTime=4.500000,WorkSpeedRate=1.100000,AutoSaveSpan=30.000000,bIsMultiplay=False,bIsPvP=False,bHardcore=False,bPalLost=False,bCharacterRecreateInHardcore=False,bCanPickupOtherGuildDeathPenaltyDrop=False,bEnableNonLoginPenalty=True,bEnableFastTravel=True,bIsStartLocationSelectByMap=True,bExistPlayerAfterLogout=False,bEnableDefenseOtherGuildPlayer=False,bInvisibleOtherGuildBaseCampAreaFX=False,bBuildAreaLimit=False,ItemWeightRate=1.000000,CoopPlayerMaxNum=4,ServerPlayerMaxNum=32,ServerName="GameNight Pals",ServerDescription="",AdminPassword="PenQueen",ServerPassword="penking",PublicPort=8211,PublicIP="",RCONEnabled=False,RCONPort=25575,Region="",bUseAuth=True,BanListURL="https://api.palworldgame.com/api/banlist.txt",RESTAPIEnabled=False,RESTAPIPort=8212,bShowPlayerList=False,ChatPostLimitPerMinute=30,CrossplayPlatforms=(Steam,Xbox,PS5,Mac),bIsUseBackupSaveData=True,LogFormatType=Text,SupplyDropSpan=90,EnablePredatorBossPal=True,MaxBuildingLimitNum=0,ServerReplicatePawnCullDistance=15000.000000,bAllowGlobalPalboxExport=True,bAllowGlobalPalboxImport=False,EquipmentDurabilityDamageRate=1.000000,ItemContainerForceMarkDirtyInterval=1.000000) diff --git a/hosts/lithium/services/palworld/default.nix b/hosts/lithium/services/palworld/default.nix new file mode 100644 index 0000000..e36823d --- /dev/null +++ b/hosts/lithium/services/palworld/default.nix @@ -0,0 +1,51 @@ +{ config, pkgs, lib, ... }: +let + palworldSettings = builtins.readFile ./PalWorldSettings.ini; +in +{ + # NOTE: Partly inspired by: https://github.com/pocketpairjp/palworld-dedicated-server-docker + networking.firewall.allowedUDPPorts = [ 8211 ]; + + users.users.palworld = { + isSystemUser = true; + createHome = true; + home = "/home/palworld"; + homeMode = "750"; + group = "palworld"; + extraGroups = [ "steamcmd" ]; + }; + users.groups.palworld = {}; + + systemd.services.palworld = { + enable = true; + description = "PalWorld Dedicated Server"; + #after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + ExecStartPre = '' + ${pkgs.steamcmd}/bin/steamcmd +login anonymous \ + +app_update 2394010 validate +quit + ''; + ExecStart = '' + ${pkgs.steam-run}/bin/steam-run \ + .steam/steam/Steamapps/common/PalServer/PalServer.sh -publiclobby \ + -useperfthreads -NoAsyncLoadingThread -UseMultithreadForDS + ''; + WorkingDirectory = "/home/palworld"; + Restart = "always"; + RuntimeMaxSec = "1d"; + User = "palworld"; + }; + }; + + # NOTE: Config is stashed at the following directory. + # /home/palworld/.steam/steam/Steamapps/common/PalServer/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini + environment.etc."palworld/PalWorldSettings.ini" = { + target = "/home/palworld/.steam/steam/Steamapps/common/PalServer/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini"; + text = palworldSettings; + mode = "0644"; + user = "palworld"; + group = "palworld"; + }; +} diff --git a/hosts/lithium/services/smartd.nix b/hosts/lithium/services/smartd.nix new file mode 100644 index 0000000..40bb159 --- /dev/null +++ b/hosts/lithium/services/smartd.nix @@ -0,0 +1,32 @@ +{ }: +{ + services.smartd = { + enable = true; + devices = [ + { + device = "ata-CT500MX500SSD1_2206E607D6AA"; + } + { + device = "ata-CT500MX500SSD1_2206E607D728"; + } + { + device = "ata-ST16000NM001G-2KK103_ZL2B73HT"; + } + { + device = "ata-ST16000NM001G-2KK103_ZL2PSELL"; + } + { + device = "ata-ST16000NM001G-2KK103_ZL2B4RSM"; + } + { + device = "ata-ST16000NM001G-2KK103_ZL23XYMM"; + } + { + device = "nvme-Samsung_SSD_960_EVO_500GB_S3X4NB0K244331X"; + } + { + device = "nvme-Samsung_SSD_960_EVO_500GB_S3X4NB0K244303V"; + } + ]; + }; +} diff --git a/hosts/lithium/sops.nix b/hosts/lithium/sops.nix new file mode 100644 index 0000000..23bee33 --- /dev/null +++ b/hosts/lithium/sops.nix @@ -0,0 +1,13 @@ +{ inputs, config, ... }: +let + secretsPath = builtins.toString inputs.nixos-secrets; +in +{ + imports = [ + inputs.sops-nix.nixosModules.sops + ]; + + sops = { + defaultSopsFile = "${secretsPath}/${config.hostname}/secrets.yaml"; + }; +} diff --git a/hosts/titanium/configuration.nix b/hosts/titanium/configuration.nix index ea4519f..c791efd 100644 --- a/hosts/titanium/configuration.nix +++ b/hosts/titanium/configuration.nix @@ -10,6 +10,9 @@ signal-desktop obs-studio ]; + services.udev.extraRules = '' + SUBSYSTEM=="usb", ATTRS{idVendor}=="14ed", ATTRS{idProduct}=="1012", MODE="0666", GROUP="audio" + ''; # Hardware Specific programs... #programs.ryzen-monitor-ng.enable = true; #programs.rog-control-center.enable = true;