diff --git a/flake.nix b/flake.nix index 858c618..6de07d3 100644 --- a/flake.nix +++ b/flake.nix @@ -93,6 +93,8 @@ ./systems/fettuccine ./systems/pappardelle ./systems/focaccia + ./systems/brioche + ./systems/deploy.nix ]; flake = { @@ -134,7 +136,9 @@ nixd nixfmt deploy-rs + sops ]; + env.SOPS_AGE_KEY_CMD = "${./age_from_1password.nu}"; }; }; }; diff --git a/systems/NAMING.md b/systems/NAMING.md new file mode 100644 index 0000000..85cf7a7 --- /dev/null +++ b/systems/NAMING.md @@ -0,0 +1,32 @@ +# Naming systems + +In accordance with fun hacker tradition, all of my machines are given fun and +memorable names with an identifiable pattern. Here's all of them (as of time +of writing anyways): + +- Linux personal computers, named after pastas + - ~~`tagliatelle`~~: My custom-built mATX workstation in China. Decommissioned. + - `fettuccine`: An ASUS ROG Zephyrus M16 2021 (GU603H) who served as my main + laptop from 2021 to early 2025. Dormant. + - **`pappardelle`**: A Lenovo XiaoXin Pro / IdeaPad Pro 5 14-inch 2025 (14IAH10). + Current main laptop (and PC in general really). + +- Mobile phones, named after cheeses + - `ricotta`: A Chinese iPhone 12. Mostly used as a hotspot machine and for + quarantining questionable Chinese apps. + - **`roquefort`**: A European iPhone 15. My main phone. + - As an exception to the pattern, `fromage` was my 2018 Intel MacBook Pro. + It still works, but not very well, for obvious reasons. + +- Servers, named after breads + - **`focaccia`**: A CX22 box from Hetzner that runs everything between + proxies, a Tangled knot, an ATProto PDS, even my Ente instance, and + my main reverse proxy tying them all together. + + - `brioche`: A CX23 box from Hetzner. I don't really know what to do + with it yet. + +- Miscellaneous + - `marmelade`: S3-compatible Hetzner Object Storage containing all my + Ente photos. Yes, I should consider getting some backups. Maybe I'll + name them after another jam/jelly/however you call it. diff --git a/systems/brioche/configuration.nix b/systems/brioche/configuration.nix new file mode 100644 index 0000000..a9a8f30 --- /dev/null +++ b/systems/brioche/configuration.nix @@ -0,0 +1,32 @@ +{ + ... +}: { + imports = [ + ../common.nix + ./hardware-configuration.nix + ./networking.nix + ]; + + networking = { + hostName = "brioche"; + domain = "pluie.me"; + firewall = { + allowedTCPPorts = [ + 80 + 443 + ]; + }; + }; + + services.openssh = { + enable = true; + # ports = [ 42069 ]; + settings.PermitRootLogin = "prohibit-password"; + }; + + boot.tmp.cleanOnBoot = true; + zramSwap.enable = true; + users.users.root.openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKbsavGX9rGRx5R+7ovLn+r7D/w3zkbqCik4bS31moSz" + ]; +} diff --git a/systems/brioche/default.nix b/systems/brioche/default.nix new file mode 100644 index 0000000..24aef70 --- /dev/null +++ b/systems/brioche/default.nix @@ -0,0 +1,11 @@ +{ + inputs, + lib, + ... +}: +{ + flake.nixosConfigurations.brioche = lib.nixosSystem { + modules = [ ./configuration.nix ]; + specialArgs = { inherit inputs; }; + }; +} diff --git a/systems/brioche/hardware-configuration.nix b/systems/brioche/hardware-configuration.nix new file mode 100644 index 0000000..8e6f21c --- /dev/null +++ b/systems/brioche/hardware-configuration.nix @@ -0,0 +1,18 @@ +{ modulesPath, ... }: +{ + imports = [ (modulesPath + "/profiles/qemu-guest.nix") ]; + boot.loader.grub.device = "/dev/sda"; + boot.initrd.availableKernelModules = [ + "ata_piix" + "uhci_hcd" + "xen_blkfront" + "vmw_pvscsi" + ]; + boot.initrd.kernelModules = [ "nvme" ]; + fileSystems."/" = { + device = "/dev/sda1"; + fsType = "ext4"; + }; + + nixpkgs.hostPlatform = "x86_64-linux"; +} diff --git a/systems/brioche/networking.nix b/systems/brioche/networking.nix new file mode 100644 index 0000000..a4a2113 --- /dev/null +++ b/systems/brioche/networking.nix @@ -0,0 +1,33 @@ +{ lib, ... }: { + # This file was populated at runtime with the networking + # details gathered from the active system. + networking = { + nameservers = [ "8.8.8.8" + ]; + defaultGateway = "172.31.1.1"; + defaultGateway6 = { + address = "fe80::1"; + interface = "eth0"; + }; + dhcpcd.enable = false; + usePredictableInterfaceNames = lib.mkForce false; + interfaces = { + eth0 = { + ipv4.addresses = [ + { address="91.99.202.138"; prefixLength=32; } + ]; + ipv6.addresses = [ + { address="2a01:4f8:c2c:cb4e::1"; prefixLength=64; } +{ address="fe80::9000:7ff:fe49:d963"; prefixLength=64; } + ]; + ipv4.routes = [ { address = "172.31.1.1"; prefixLength = 32; } ]; + ipv6.routes = [ { address = "fe80::1"; prefixLength = 128; } ]; + }; + + }; + }; + services.udev.extraRules = '' + ATTR{address}=="92:00:07:49:d9:63", NAME="eth0" + + ''; +} diff --git a/systems/deploy.nix b/systems/deploy.nix new file mode 100644 index 0000000..b2ebae0 --- /dev/null +++ b/systems/deploy.nix @@ -0,0 +1,38 @@ +{ + self, + inputs, + ... +}: +{ + flake.deploy.nodes = { + focaccia = { + sshOpts = [ + "-p" + "42069" + ]; + hostname = "focaccia.pluie.me"; + profiles = { + system = { + path = inputs.deploy-rs.lib.x86_64-linux.activate.nixos self.nixosConfigurations.focaccia; + user = "root"; + sshUser = "root"; + }; + }; + }; + + brioche = { + # sshOpts = [ + # "-p" + # "22" + # ]; + hostname = "brioche.pluie.me"; + profiles = { + system = { + path = inputs.deploy-rs.lib.x86_64-linux.activate.nixos self.nixosConfigurations.brioche; + user = "root"; + sshUser = "root"; + }; + }; + }; + }; +} diff --git a/systems/focaccia/configuration.nix b/systems/focaccia/configuration.nix index 71b9cf1..1e69475 100644 --- a/systems/focaccia/configuration.nix +++ b/systems/focaccia/configuration.nix @@ -13,6 +13,7 @@ ./services/hysteria.nix ./services/knot.nix ./services/pds.nix + ./services/ente.nix ]; sops = { @@ -28,7 +29,15 @@ 80 443 ]; + allowedUDPPorts = [ + 443 + ]; + # Allow Tailscale users to connect to port 22 directly + extraInputRules = '' + iifname "tailscale0" tcp dport 22 accept + ''; }; + nftables.enable = true; }; users.users.leah = { @@ -47,7 +56,10 @@ services.openssh = { enable = true; - ports = [ 42069 ]; + ports = [ + 22 + 42069 + ]; settings.PermitRootLogin = "prohibit-password"; }; @@ -60,4 +72,6 @@ enable = true; email = "srv@acc.pluie.me"; }; - } + + services.tailscale.enable = true; +} diff --git a/systems/focaccia/default.nix b/systems/focaccia/default.nix index d2ca40a..9121a3a 100644 --- a/systems/focaccia/default.nix +++ b/systems/focaccia/default.nix @@ -1,5 +1,4 @@ { - self, inputs, lib, ... @@ -9,19 +8,4 @@ modules = [ ./configuration.nix ]; specialArgs = { inherit inputs; }; }; - - flake.deploy.nodes.focaccia = { - sshOpts = [ - "-p" - "42069" - ]; - hostname = "focaccia.pluie.me"; - profiles = { - system = { - path = inputs.deploy-rs.lib.x86_64-linux.activate.nixos self.nixosConfigurations.focaccia; - user = "root"; - sshUser = "root"; - }; - }; - }; } diff --git a/systems/focaccia/secrets/ente.yaml b/systems/focaccia/secrets/ente.yaml new file mode 100644 index 0000000..d2aa4dd --- /dev/null +++ b/systems/focaccia/secrets/ente.yaml @@ -0,0 +1,36 @@ +s3: + b2-eu-cen: + key: ENC[AES256_GCM,data:+u8cUMH4UKmObQHDfXoGk/UY8FM=,iv:FqsD0fmYoUhbHI6Ozqfk19fN6B5Ju20ZeB2SEo4uVxM=,tag:HBsWCaJgCw/TaMn1NOof8w==,type:str] + secret: ENC[AES256_GCM,data:uzwfBiZ2vasW7KWFYLFvunV0CpdDefawxb+3yXUTACHT3xgXkdt4ug==,iv:oAW2L7lmh9xXjxfO3LJ2ePDLBX+MkojlKnQEv+Jsdfc=,tag:FFwqK5WlAypZ6Jpn9StHxA==,type:str] +key: + encryption: ENC[AES256_GCM,data:SOUgVR+SN8r8JFiAYs3rhSrJ6YvLrGuLZPq285BsRKf6QKxTLk7LS7k1zHQ=,iv:2BJWKuS3bgyNiDAH8KvpqFRFhNX19g/I0/g0lXhh1co=,tag:GjbVWE2Q/fGuu9Re6aTf2Q==,type:str] + hash: ENC[AES256_GCM,data:5LF8v1o8ZmChkuIfyhBuo/uTMwLDmezXH5Ajh4wgWWeb5Mk/I8TNKNeosOil7aOvXnbSAJRr43ATDX7hvBQtIJy20Nzjhri01bTQbwBKIGw6fFPug8vhdg==,iv:+OUxhWdIpyGzMYHPyu9FmhyWCnmjRD7DuRhrYMbgjC8=,tag:bSavxsF38tfHjphBp2vjBA==,type:str] +jwt: + secret: ENC[AES256_GCM,data:v59Duv9kJOW74Caeitvp3Lys+6dkkDarraMWmmGTRZwo+cH0RVB/Aijiyzw=,iv:Zm3Q66KFmc+cvvAyxi91dAqhEeWACMp1EUm499+FtXc=,tag:jiiA2P+f/5I/spX5K662yQ==,type:str] +internal: + admins: + - ENC[AES256_GCM,data:sj1ATdVgPti/IAUGM8dYVw==,iv:vP45TCr+c4yPIV3y3mzcRvcPYpWo+2Kg3bmQt7kOCBM=,tag:IPGDydcXzzITknY0OBOvhw==,type:int] +sops: + age: + - recipient: age1lh4sn2s9gxj2s3naqdl4wpmz3uhpd3p8l0jfy6k5hu6cu34uyygsdwadd5 + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1SGlOU2pPNkRtZ0VlME5V + NVFyZllGT25YSURxUnQ2N3VTdFN5bFYvNnhrCm5xUlZBeHFHWS9FbWw0R1lXMUpm + OVVIOVhvM0pGQVErUHYveVEyMVYzMVEKLS0tIHVCZTRNSTRSTmNhVlVPcXRCam11 + dm95SFY4eHpaYkc3R1pURmFCalVrbFkK89/h3FUcVQIrbOr6GiYORtHBjw6TTpHs + uzx5cFaTtS2oweYTkTcuWzJzjG+pzuKBKrw3NCxbOW6EcSIvg6H5MQ== + -----END AGE ENCRYPTED FILE----- + - recipient: age1wtr58sze4sxjjzq9jmsq7ztkvkjakvnfzuqzn025p92htz7zsdesjpc2c8 + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBUa2czYURoeGhXWU9sOW9M + cmxETG9pdVdzWURpZUdoZUp2T0Mwak5aT2prCmhnOEJERG53ZEtCRS9UZmtDRlFx + Q1docCsrN2F2cGdZUUtNS3cyMXVYYzAKLS0tIEZzNXFXeWU5RVA4QzcwM0pMT2NU + Y3FpS01jaDBHZTNSbXhuRDRyb2xHZk0K7cOxejnHR4Wm81dO18+r3PVY2nxlKqXf + Ldrht8GxVR7kdACdlr34B4QO97O86WuUcjndt60+Lu2aGUOVVjaZ3w== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2026-02-27T14:59:06Z" + mac: ENC[AES256_GCM,data:tZHHz5wLTOvMsGFA+WEnejV1PKK9Rbqxx0oil+cjE8X5qWQ7UW+PFVtfwnsTPG3LFDg2oa0Cy0Nzwd5de+yRJo/7sb+2MNbdrQaSUEZv8t8PAeBxaY2c2BBVTO7Z4tQBVllWs7UstPLLCgz7QMkvTeObvFCtPrBNXctsTieesYU=,iv:JeubVhKbvtO1Hzymp+zNg10Ico/NTSUnGBnflBf3JH4=,tag:PTWcseQ/23J1u0kJnQ69LQ==,type:str] + unencrypted_suffix: _unencrypted + version: 3.11.0 diff --git a/systems/focaccia/services/ente.nix b/systems/focaccia/services/ente.nix new file mode 100644 index 0000000..cf46a9b --- /dev/null +++ b/systems/focaccia/services/ente.nix @@ -0,0 +1,100 @@ +{ + config, + lib, + ... +}: +let + baseDomain = "ente.pluie.me"; + domainFor = n: "${n}.${baseDomain}"; + + webPackage = + enteApp: + let + cfgWeb = config.services.ente.web; + in + cfgWeb.package.override { + inherit enteApp; + enteMainUrl = "https://${cfgWeb.domains.photos}"; + extraBuildEnv = { + NEXT_PUBLIC_ENTE_ENDPOINT = "https://${cfgWeb.domains.api}"; + NEXT_PUBLIC_ENTE_ALBUMS_ENDPOINT = "https://${cfgWeb.domains.albums}"; + NEXT_TELEMETRY_DISABLED = "1"; + }; + }; + + apps = rec { + photos = webPackage "photos"; + albums = photos; + accounts = webPackage "accounts"; + cast = webPackage "cast"; + }; + subdomains = lib.mapAttrs (n: _: domainFor n) apps; +in +{ + sops.secrets.ente = { + # Needs an explicit file extension + name = "ente.yaml"; + sopsFile = ../secrets/ente.yaml; + format = "yaml"; + key = ""; # Use the entire file + + # Allow the service user to access the secret + owner = config.services.ente.api.user; + }; + + services.ente = { + web = { + enable = true; + domains = { + api = domainFor "api"; + inherit (subdomains) + photos + cast + albums + accounts + ; + }; + }; + + api = { + enable = true; + enableLocalDB = true; + nginx.enable = false; + + domain = domainFor "api"; + settings = { + credentials-file = config.sops.secrets.ente.path; + s3 = { + are_local_buckets = false; + b2-eu-cen = { + endpoint = "nbg1.your-objectstorage.com"; + region = "eu-central"; + bucket = "marmelade"; + }; + }; + }; + }; + }; + + # FIXME: For some arcane reason the ente module keeps + # trying to enable nginx despite me explicitly disabling it. + # PR a fix to upstream soon. + services.nginx.enable = lib.mkForce false; + + services.postgresql.authentication = "local all all trust"; + + services.caddy.virtualHosts = + (lib.mapAttrs' (name: app: { + name = domainFor name; + value.extraConfig = '' + root * ${app} + file_server + try_files {path} {path}.html /index.html + ''; + }) apps) + // { + "api.${baseDomain}" = { + extraConfig = "reverse_proxy :8080"; + }; + }; +} diff --git a/systems/focaccia/services/hysteria.nix b/systems/focaccia/services/hysteria.nix index 6832bd8..27e9165 100644 --- a/systems/focaccia/services/hysteria.nix +++ b/systems/focaccia/services/hysteria.nix @@ -6,7 +6,6 @@ sops.secrets.hysteria = { }; networking.firewall.allowedUDPPorts = [ 53 ]; - services.hysteria = { enable = true; settings = { diff --git a/systems/laptop.nix b/systems/laptop.nix index ae3bdc3..4765019 100644 --- a/systems/laptop.nix +++ b/systems/laptop.nix @@ -15,7 +15,7 @@ nix.settings.extra-platforms = [ "aarch64-linux" ]; boot = { - kernelPackages = pkgs.linuxPackages_xanmod; + kernelPackages = pkgs.linuxPackages_xanmod_latest; loader = { limine = { diff --git a/systems/pappardelle/configuration.nix b/systems/pappardelle/configuration.nix index edbbbdf..445da2e 100644 --- a/systems/pappardelle/configuration.nix +++ b/systems/pappardelle/configuration.nix @@ -12,4 +12,9 @@ hardware.bluetooth.enable = true; networking.hostName = "pappardelle"; users.users.leah.enable = true; + + boot.kernelParams = [ "intel_idle.max_cstate=9" ]; + services.fwupd.enable = true; + + services.tailscale.enable = true; }