From 1862821f8f9134870571e61d2168473e8ea404e9 Mon Sep 17 00:00:00 2001 From: randogoth Date: Thu, 5 Feb 2026 17:57:02 +0200 Subject: [PATCH] Initial clean commit --- .gitignore | 10 + .sops.yaml | 3 + agents.md | 151 +++++++ flake.lock | 167 +++++++ flake.nix | 52 +++ hosts/bucur.nix | 16 + modules/services/caddy.nix | 64 +++ modules/services/firewall.nix | 104 +++++ modules/services/openssh.nix | 13 + modules/services/podman.nix | 39 ++ modules/services/static-sites/default.nix | 160 +++++++ .../static-sites/scopesessions-gemset.nix | 419 ++++++++++++++++++ modules/services/tailscale.nix | 5 + modules/users/tobias.nix | 20 + secrets/bucur.yaml | 17 + 15 files changed, 1240 insertions(+) create mode 100644 .gitignore create mode 100644 .sops.yaml create mode 100644 agents.md create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 hosts/bucur.nix create mode 100644 modules/services/caddy.nix create mode 100644 modules/services/firewall.nix create mode 100644 modules/services/openssh.nix create mode 100644 modules/services/podman.nix create mode 100644 modules/services/static-sites/default.nix create mode 100644 modules/services/static-sites/scopesessions-gemset.nix create mode 100644 modules/services/tailscale.nix create mode 100644 modules/users/tobias.nix create mode 100644 secrets/bucur.yaml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a699ab3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +/.envrc +/.gitconfig-nix +/.ssh-nix-config +/.direnv/ +/secrets/age/keys.txt +/secrets/ssh/codeberg_id_ed25519 +/result +/result/ +/*.qcow2 +/server.md \ No newline at end of file diff --git a/.sops.yaml b/.sops.yaml new file mode 100644 index 0000000..ab43cbf --- /dev/null +++ b/.sops.yaml @@ -0,0 +1,3 @@ +creation_rules: + - path_regex: secrets/.*\.ya?ml + age: age1647c5f46njylggj33h26t6twhq57n5qeaza04l845uy0fksv0ucsq82c3d diff --git a/agents.md b/agents.md new file mode 100644 index 0000000..a52266b --- /dev/null +++ b/agents.md @@ -0,0 +1,151 @@ +# NixOS Migration and Configuration Agent + +## Directive + +Investigate server tobias@bucur for full reproducibility with Nix. + +- Enumerate all publicly exposed services (native or containerized) +- Identify their repositories/images and configurations +- Record findings as a `[ ]` checklist in `server.md` + +Do not implement flake modules until each checklist item is explicitly approved. + +When implementing, produce or modify **Nix code only**. +No explanations unless explicitly requested. +If information is missing or unclear, stop and ask. Do not infer. + +--- + +## Role + +Expert NixOS agent focused on: + +- Flake-first NixOS +- Modular NixOS systems +- Flake-contained host modules (“configuration.nix-style”) +- Deterministic, reproducible configurations + +--- + +## Authority + +- `flake.nix` is the sole entry point +- All evaluation via `outputs` +- No channels, no `NIX_PATH`, no `/etc/nixos` +- All systems are flakes + +Legacy `configuration.nix` **must not** be an entry point. +Files resembling it are allowed **only** as flake-contained host modules. + +--- + +## Workflow (Strict) + +### Before any changes +- Present a plan +- Bullet points only +- Exact file paths +- Intent per file +- No code, no prose + +Only approved files may be modified. + +### Permission Gates + +Explicit approval required **each time** before: +- Builds, tests, or evaluations +- Commits +- Pushing to remotes + +--- + +## Modules + +### Host Modules +- Path: `hosts/*.nix` +- Composition only +- Small, declarative +- No reusable logic + +Allowed: +- `imports` +- Host-specific values (hostname, locale, timezone, `system.stateVersion`) +- Small, truly host-unique overrides + +Forbidden: +- Reusable features +- Large logic blocks +- Inline user definitions +- Services usable by multiple hosts +- Monolithic system configs + +**Rule:** +> Host modules compose. Feature modules implement. + +### Feature Modules +- Path: `modules/**` +- Implementation only +- Reusable +- Upstream NixOS options only +- No custom option namespaces + +--- + +## Home Manager + +- No home-manager +- No `home-manager.users.*` +- `modules/users/*` manages accounts and user settings + +--- + +## Hardware + +- Hardware modules allowed +- All hardware changes must be listed in the plan +- No unapproved disk, boot, or kernel changes + +--- + +## Overlays + +- Allowed but discouraged +- Never introduce unless explicitly requested +- Prefer: + - flake inputs + - `callPackage` + - direct package references + +--- + +## Code Style + +### Nix +- Pure Nix +- Explicit attribute paths +- Prefer `lib.mkIf`, `lib.mkMerge`, `lib.optionals` +- Avoid `with pkgs;`, implicit imports, inline shell hacks + +### Formatting +- `nixfmt-rfc-style` +- Do not reformat unrelated files + +--- + +## Scripting + +- Scripts live in `./scripts/` +- Deterministic, non-interactive +- POSIX only +- Minimal +- Never inline scripts in Nix + +--- + +## Layout + +```text +flake.nix # authority +hosts/ # composition +modules/ # behavior +scripts/ \ No newline at end of file diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..905f7d5 --- /dev/null +++ b/flake.lock @@ -0,0 +1,167 @@ +{ + "nodes": { + "flux_vision": { + "flake": false, + "locked": { + "lastModified": 1766774843, + "narHash": "sha256-/bikoewxigIU4SJUhq3CwPA0fqPAhi53lXdH8QcfN98=", + "ref": "refs/heads/main", + "rev": "ff83815c4a781ff84de4c29ee656e078ca879fef", + "revCount": 17, + "type": "git", + "url": "https://codeberg.org/randogoth/flux.vision.git" + }, + "original": { + "type": "git", + "url": "https://codeberg.org/randogoth/flux.vision.git" + } + }, + "geoblog_plugin": { + "flake": false, + "locked": { + "lastModified": 1683036417, + "narHash": "sha256-0kGJfd72WLlAZ3X2tQ7Vwodsu/qKAW0cOcSpeRdPCnM=", + "ref": "refs/heads/main", + "rev": "840d907235d1a81b8ebfa0345f5e848452d69d60", + "revCount": 2, + "type": "git", + "url": "https://codeberg.org/randogoth/geoblog-plugin.git" + }, + "original": { + "type": "git", + "url": "https://codeberg.org/randogoth/geoblog-plugin.git" + } + }, + "nfc_web": { + "flake": false, + "locked": { + "lastModified": 1766145802, + "narHash": "sha256-Ptq4ySrE0muiAlhkt6QT2x+u0Ux1wLJQ9Rqlq2YUmHw=", + "ref": "refs/heads/main", + "rev": "6bd590bcd113b6159edcdf8beaf66629ea7aa8dc", + "revCount": 71, + "type": "git", + "url": "https://codeberg.org/randogoth/nfc-web.git" + }, + "original": { + "type": "git", + "url": "https://codeberg.org/randogoth/nfc-web.git" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1770136044, + "narHash": "sha256-tlFqNG/uzz2++aAmn4v8J0vAkV3z7XngeIIB3rM3650=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e576e3c9cf9bad747afcddd9e34f51d18c855b4e", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-25.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "praxis": { + "flake": false, + "locked": { + "lastModified": 1766389293, + "narHash": "sha256-noQDF8WKsGDR1lght9xaWXg0O8W8wPAhSoX2jwGIbRg=", + "ref": "refs/heads/master", + "rev": "dda2c101079b7d7e6563aa40edc1057ada710a9f", + "revCount": 1, + "type": "git", + "url": "https://codeberg.org/randogoth/praxis.git" + }, + "original": { + "type": "git", + "url": "https://codeberg.org/randogoth/praxis.git" + } + }, + "root": { + "inputs": { + "flux_vision": "flux_vision", + "geoblog_plugin": "geoblog_plugin", + "nfc_web": "nfc_web", + "nixpkgs": "nixpkgs", + "praxis": "praxis", + "scopesessions": "scopesessions", + "sops-nix": "sops-nix", + "sublunar": "sublunar", + "sublunar_almanac": "sublunar_almanac" + } + }, + "scopesessions": { + "flake": false, + "locked": { + "lastModified": 1766407123, + "narHash": "sha256-f1D1pEHGAhZ96Mt7R9vxWsi3dH+THeflSroRlUIgMxU=", + "ref": "refs/heads/main", + "rev": "36bfce14b41942eda24bd763b8f6613141a55a1f", + "revCount": 227, + "type": "git", + "url": "https://codeberg.org/randogoth/scopesessions.org.git" + }, + "original": { + "type": "git", + "url": "https://codeberg.org/randogoth/scopesessions.org.git" + } + }, + "sops-nix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1770145881, + "narHash": "sha256-ktjWTq+D5MTXQcL9N6cDZXUf9kX8JBLLBLT0ZyOTSYY=", + "owner": "Mic92", + "repo": "sops-nix", + "rev": "17eea6f3816ba6568b8c81db8a4e6ca438b30b7c", + "type": "github" + }, + "original": { + "owner": "Mic92", + "repo": "sops-nix", + "type": "github" + } + }, + "sublunar": { + "flake": false, + "locked": { + "lastModified": 1766145247, + "narHash": "sha256-XFAM+eD+GUDR3G+daOcPn2nLj5CZp+m/IwpSVmEYDrU=", + "ref": "refs/heads/main", + "rev": "4920396e8e9a5de9d93cb01f107823c9295f5bc2", + "revCount": 435, + "type": "git", + "url": "https://codeberg.org/randogoth/sublunar.git" + }, + "original": { + "type": "git", + "url": "https://codeberg.org/randogoth/sublunar.git" + } + }, + "sublunar_almanac": { + "flake": false, + "locked": { + "lastModified": 1766409110, + "narHash": "sha256-+xlqzuTsV5fUqmDWlPFrEcmThUCq9Yxh6j65DQtINkM=", + "ref": "refs/heads/main", + "rev": "c10e0a0bf27a685b8c00c6ed986f0616b7b7ba3d", + "revCount": 84, + "type": "git", + "url": "https://codeberg.org/randogoth/sublunar.almanac.git" + }, + "original": { + "type": "git", + "url": "https://codeberg.org/randogoth/sublunar.almanac.git" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..d528c1c --- /dev/null +++ b/flake.nix @@ -0,0 +1,52 @@ +{ + description = "Bucur NixOS configuration"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11"; + sops-nix.url = "github:Mic92/sops-nix"; + sops-nix.inputs.nixpkgs.follows = "nixpkgs"; + + sublunar.url = "git+https://codeberg.org/randogoth/sublunar.git"; + sublunar.flake = false; + + flux_vision.url = "git+https://codeberg.org/randogoth/flux.vision.git"; + flux_vision.flake = false; + + nfc_web.url = "git+https://codeberg.org/randogoth/nfc-web.git"; + nfc_web.flake = false; + + scopesessions.url = "git+https://codeberg.org/randogoth/scopesessions.org.git"; + scopesessions.flake = false; + + sublunar_almanac.url = "git+https://codeberg.org/randogoth/sublunar.almanac.git"; + sublunar_almanac.flake = false; + + praxis.url = "git+https://codeberg.org/randogoth/praxis.git"; + praxis.flake = false; + + geoblog_plugin.url = "git+https://codeberg.org/randogoth/geoblog-plugin.git"; + geoblog_plugin.flake = false; + }; + + outputs = { self, nixpkgs, sops-nix, ... }@inputs: + let + system = "x86_64-linux"; + in + { + nixosConfigurations.bucur = nixpkgs.lib.nixosSystem { + inherit system; + specialArgs = { inherit inputs; }; + modules = [ + sops-nix.nixosModules.sops + ./hosts/bucur.nix + ./modules/services/caddy.nix + ./modules/services/openssh.nix + ./modules/services/firewall.nix + ./modules/services/tailscale.nix + ./modules/services/podman.nix + ./modules/services/static-sites + ./modules/users/tobias.nix + ]; + }; + }; +} diff --git a/hosts/bucur.nix b/hosts/bucur.nix new file mode 100644 index 0000000..beaa7c9 --- /dev/null +++ b/hosts/bucur.nix @@ -0,0 +1,16 @@ +{ lib, ... }: +{ + networking.hostName = "bucur"; + time.timeZone = "UTC"; + i18n.defaultLocale = "en_US.UTF-8"; + system.stateVersion = "25.11"; + + virtualisation.vmVariant = { + users.mutableUsers = false; + users.users.tobias.password = "admin"; + users.users.tobias.openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILXTPk7gb4VDb+jORGw2sKp2SRTzoibXew6DqJJ0A3Zs randogoth@mrht" + ]; + services.firewalld.enable = lib.mkForce false; + }; +} diff --git a/modules/services/caddy.nix b/modules/services/caddy.nix new file mode 100644 index 0000000..ea27959 --- /dev/null +++ b/modules/services/caddy.nix @@ -0,0 +1,64 @@ +{ pkgs, ... }: +{ + services.caddy.enable = true; + services.caddy.configFile = pkgs.writeText "Caddyfile" '' +http:// { + root * /usr/share/caddy + file_server +} + +privatpraxis-last-heidelberg.de, www.privatpraxis-last-heidelberg.de { + root * /var/www/privatpraxis-last-heidelberg.de/public + encode zstd gzip + file_server +} + +raayoni-last.com, www.raayoni-last.com, flux.vision, www.flux.vision { + redir https://tobias.raayoni-last.com +} + +tobias.raayoni-last.com { + root * /var/www/raayoni-last.com/tobias/public + encode zstd gzip + file_server +} + +randogoth.com, www.randogoth.com { + root * /var/www/raayoni-last.com/tobias/public + encode zstd gzip + file_server +} + +sublunar.space, www.sublunar.space { + root * /var/www/sublunar.space/public + encode zstd gzip + file_server +} + +almanac.sublunar.space { + root * /var/www/sublunar.space/almanac/public + encode zstd gzip + + @wasm { + path /js/*.wasm + } + header @wasm Content-Type application/wasm + + file_server +} + +scopesessions.org, www.scopesessions.org { + root * /var/www/scopesessions.org/public + encode zstd gzip + file_server +} + +nmns.place, www.nmns.place { + root * /var/www/nmns.place/public + encode zstd gzip + file_server +} + +import Caddyfile.d/*.caddyfile +''; +} diff --git a/modules/services/firewall.nix b/modules/services/firewall.nix new file mode 100644 index 0000000..8bac1ec --- /dev/null +++ b/modules/services/firewall.nix @@ -0,0 +1,104 @@ +{ ... }: +{ + networking.firewall.enable = true; + networking.firewall.backend = "firewalld"; + networking.nftables.enable = true; + + services.firewalld.enable = true; + services.firewalld.settings.DefaultZone = "FedoraServer"; + + services.firewalld.zones.FedoraServer = { + target = "%%REJECT%%"; + interfaces = [ "ens3" ]; + forward = true; + services = [ "http" "https" "ssh" ]; + ports = [ + { + port = 8443; + protocol = "tcp"; + } + ]; + rules = [ + { + rule = { + "@family" = "ipv4"; + source = { "@address" = "80.94.92.177"; }; + port = { "@port" = "ssh"; "@protocol" = "tcp"; }; + reject = { "@type" = "icmp-port-unreachable"; }; + }; + } + { + rule = { + "@family" = "ipv4"; + source = { "@address" = "45.148.10.240"; }; + port = { "@port" = "ssh"; "@protocol" = "tcp"; }; + reject = { "@type" = "icmp-port-unreachable"; }; + }; + } + { + rule = { + "@family" = "ipv4"; + source = { "@address" = "193.242.125.233"; }; + port = { "@port" = "ssh"; "@protocol" = "tcp"; }; + reject = { "@type" = "icmp-port-unreachable"; }; + }; + } + { + rule = { + "@family" = "ipv4"; + source = { "@address" = "45.78.198.204"; }; + port = { "@port" = "ssh"; "@protocol" = "tcp"; }; + reject = { "@type" = "icmp-port-unreachable"; }; + }; + } + { + rule = { + "@family" = "ipv4"; + source = { "@address" = "176.120.22.47"; }; + port = { "@port" = "ssh"; "@protocol" = "tcp"; }; + reject = { "@type" = "icmp-port-unreachable"; }; + }; + } + { + rule = { + "@family" = "ipv4"; + source = { "@address" = "91.202.233.33"; }; + port = { "@port" = "ssh"; "@protocol" = "tcp"; }; + reject = { "@type" = "icmp-port-unreachable"; }; + }; + } + { + rule = { + "@family" = "ipv4"; + source = { "@address" = "188.166.24.102"; }; + port = { "@port" = "ssh"; "@protocol" = "tcp"; }; + reject = { "@type" = "icmp-port-unreachable"; }; + }; + } + { + rule = { + "@family" = "ipv4"; + source = { "@address" = "128.1.47.28"; }; + port = { "@port" = "ssh"; "@protocol" = "tcp"; }; + reject = { "@type" = "icmp-port-unreachable"; }; + }; + } + { + rule = { + "@family" = "ipv4"; + source = { "@address" = "188.166.11.218"; }; + port = { "@port" = "ssh"; "@protocol" = "tcp"; }; + reject = { "@type" = "icmp-port-unreachable"; }; + }; + } + { + rule = { + "@family" = "ipv4"; + source = { "@address" = "104.248.91.222"; }; + port = { "@port" = "ssh"; "@protocol" = "tcp"; }; + reject = { "@type" = "icmp-port-unreachable"; }; + }; + } + ]; + }; +} diff --git a/modules/services/openssh.nix b/modules/services/openssh.nix new file mode 100644 index 0000000..1dcd62b --- /dev/null +++ b/modules/services/openssh.nix @@ -0,0 +1,13 @@ +{ ... }: +{ + services.openssh.enable = true; + services.openssh.settings = { + PermitRootLogin = "no"; + PasswordAuthentication = false; + KbdInteractiveAuthentication = false; + AllowTcpForwarding = "no"; + X11Forwarding = false; + UseDns = false; + MaxAuthTries = 3; + }; +} diff --git a/modules/services/podman.nix b/modules/services/podman.nix new file mode 100644 index 0000000..c884261 --- /dev/null +++ b/modules/services/podman.nix @@ -0,0 +1,39 @@ +{ config, ... }: +{ + environment.etc."sops/age/keys.txt".source = ../../secrets/age/keys.txt; + sops.defaultSopsFile = ../../secrets/bucur.yaml; + sops.age.keyFile = "/etc/sops/age/keys.txt"; + + sops.secrets.mtproto_secret = {}; + + sops.templates."mtproto-proxy.env".content = '' +SECRET=${config.sops.placeholder."mtproto_secret"} +''; + + virtualisation.podman.enable = true; + virtualisation.oci-containers.backend = "podman"; + + virtualisation.oci-containers.containers = { + portainer = { + image = "docker.io/portainer/portainer-ce:lts"; + autoStart = true; + ports = [ + "100.124.109.92:8000:8000" + "100.124.109.92:9443:9443" + ]; + volumes = [ + "portainer_data:/data" + "/run/podman/podman.sock:/var/run/docker.sock" + ]; + extraOptions = [ "--privileged" ]; + }; + + mtproto-proxy = { + image = "docker.io/telegrammessenger/proxy:latest"; + autoStart = true; + ports = [ "0.0.0.0:8443:443" ]; + volumes = [ "mtproxy-data:/data" ]; + environmentFiles = [ config.sops.templates."mtproto-proxy.env".path ]; + }; + }; +} diff --git a/modules/services/static-sites/default.nix b/modules/services/static-sites/default.nix new file mode 100644 index 0000000..e56ea6d --- /dev/null +++ b/modules/services/static-sites/default.nix @@ -0,0 +1,160 @@ +{ inputs, pkgs, ... }: +let + buildPelicanSite = { name, src, subdir ? "", pluginSources ? [ ] }: + let + workdir = if subdir == "" then "." else subdir; + pythonEnv = pkgs.python3.withPackages (ps: [ + ps.pelican + ps.markdown + ps.pygments + ]); + copyPlugins = pkgs.lib.concatStringsSep "\n" (map (plugin: '' + mkdir -p "${workdir}/${plugin.dest}" + cp -a "${plugin.src}${if plugin ? subdir then "/${plugin.subdir}" else ""}/." "${workdir}/${plugin.dest}/" + '') pluginSources); + in + pkgs.stdenvNoCC.mkDerivation { + pname = name; + version = "git"; + src = src; + nativeBuildInputs = [ pythonEnv ]; + buildPhase = '' + runHook preBuild + cd ${workdir} + ${copyPlugins} + ${pythonEnv}/bin/pelican content -o "$out" + runHook postBuild + ''; + installPhase = "true"; + }; + + buildJekyllSite = { name, src, gemset }: + let + bundlerEnv = pkgs.bundlerEnv { + name = "${name}-bundler-env"; + gemdir = src; + gemset = gemset; + }; + in + pkgs.stdenvNoCC.mkDerivation { + pname = name; + version = "git"; + src = src; + nativeBuildInputs = [ bundlerEnv ]; + buildPhase = '' + runHook preBuild + JEKYLL_ENV=production bundle exec jekyll build -s . -d "$out" + runHook postBuild + ''; + installPhase = "true"; + }; + + buildStaticSite = { name, src, subdir ? "" }: + let + srcPath = if subdir == "" then src else "${src}/${subdir}"; + in + pkgs.stdenvNoCC.mkDerivation { + pname = name; + version = "git"; + src = src; + dontUnpack = true; + installPhase = '' + runHook preInstall + mkdir -p "$out" + cp -a ${srcPath}/. "$out/" + runHook postInstall + ''; + }; + + mkDeployService = { name, src, dest }: + { + description = "Deploy ${name} site"; + path = [ pkgs.coreutils pkgs.rsync ]; + serviceConfig = { + Type = "oneshot"; + }; + script = '' + install -d -m 755 ${dest} + rsync -a --delete ${src}/ ${dest}/ + ''; + }; + + sublunarSite = buildPelicanSite { + name = "sublunar"; + src = inputs.sublunar; + }; + + tobiasRaayoniLastSite = buildPelicanSite { + name = "tobias-raayoni-last"; + src = inputs.flux_vision; + subdir = "web"; + }; + + nmnsSite = buildPelicanSite { + name = "nmns"; + src = inputs.nfc_web; + subdir = "web"; + }; + + scopesessionsSite = buildJekyllSite { + name = "scopesessions"; + src = inputs.scopesessions; + gemset = ./scopesessions-gemset.nix; + }; + + almanacSite = buildStaticSite { + name = "sublunar-almanac"; + src = inputs.sublunar_almanac; + }; + + praxisSite = buildStaticSite { + name = "praxis"; + src = inputs.praxis; + }; + + isNixBuild = builtins.getEnv "IN_NIX_BUILD" == "1"; +in +{ + sops.secrets.codeberg_id_ed25519 = { + owner = "root"; + group = "root"; + mode = "0400"; + path = "/etc/ssh/codeberg_id_ed25519"; + }; + + systemd.services."deploy-sublunar" = mkDeployService { + name = "sublunar"; + src = sublunarSite; + dest = "/var/www/sublunar.space/public"; + }; + + systemd.services."deploy-tobias-raayoni-last" = mkDeployService { + name = "tobias-raayoni-last"; + src = tobiasRaayoniLastSite; + dest = "/var/www/raayoni-last.com/tobias/public"; + }; + + systemd.services."deploy-nmns" = mkDeployService { + name = "nmns"; + src = nmnsSite; + dest = "/var/www/nmns.place/public"; + }; + + systemd.services."deploy-scopesessions" = mkDeployService { + name = "scopesessions"; + src = scopesessionsSite; + dest = "/var/www/scopesessions.org/public"; + }; + + systemd.services."deploy-almanac" = mkDeployService { + name = "almanac"; + src = almanacSite; + dest = "/var/www/sublunar.space/almanac/public"; + }; + + systemd.services."deploy-privatpraxis" = mkDeployService { + name = "privatpraxis"; + src = praxisSite; + dest = "/var/www/privatpraxis-last-heidelberg.de/public"; + }; +} diff --git a/modules/services/static-sites/scopesessions-gemset.nix b/modules/services/static-sites/scopesessions-gemset.nix new file mode 100644 index 0000000..d00227d --- /dev/null +++ b/modules/services/static-sites/scopesessions-gemset.nix @@ -0,0 +1,419 @@ +{ + addressable = { + dependencies = ["public_suffix"]; + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0mxhjgihzsx45l9wh2n0ywl9w0c6k70igm5r0d63dxkcagwvh4vw"; + type = "gem"; + }; + version = "2.8.8"; + }; + base64 = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0yx9yn47a8lkfcjmigk79fykxvr80r4m1i35q82sxzynpbm7lcr7"; + type = "gem"; + }; + version = "0.3.0"; + }; + bigdecimal = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "19y406nx17arzsbc515mjmr6k5p59afprspa1k423yd9cp8d61wb"; + type = "gem"; + }; + version = "4.0.1"; + }; + colorator = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0f7wvpam948cglrciyqd798gdc6z3cfijciavd0dfixgaypmvy72"; + type = "gem"; + }; + version = "1.1.0"; + }; + concurrent-ruby = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1aymcakhzl83k77g2f2krz07bg1cbafbcd2ghvwr4lky3rz86mkb"; + type = "gem"; + }; + version = "1.3.6"; + }; + csv = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0gz7r2kazwwwyrwi95hbnhy54kwkfac5swh2gy5p5vw36fn38lbf"; + type = "gem"; + }; + version = "3.3.5"; + }; + em-websocket = { + dependencies = ["eventmachine" "http_parser.rb"]; + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1a66b0kjk6jx7pai9gc7i27zd0a128gy73nmas98gjz6wjyr4spm"; + type = "gem"; + }; + version = "0.5.3"; + }; + eventmachine = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0wh9aqb0skz80fhfn66lbpr4f86ya2z5rx6gm5xlfhd05bj1ch4r"; + type = "gem"; + }; + version = "1.2.7"; + }; + faraday = { + dependencies = ["faraday-net_http" "json" "logger"]; + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1ka175ci0q9ylpcy651pjj580diplkaskycn4n7jcmbyv7jwz6c6"; + type = "gem"; + }; + version = "2.14.0"; + }; + faraday-net_http = { + dependencies = ["net-http"]; + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0v4hfmc7d4lrqqj2wl366rm9551gd08zkv2ppwwnjlnkc217aizi"; + type = "gem"; + }; + version = "3.4.2"; + }; + ffi = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "19kdyjg3kv7x0ad4xsd4swy5izsbb1vl1rpb6qqcqisr5s23awi9"; + type = "gem"; + }; + version = "1.17.2"; + }; + forwardable-extended = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "15zcqfxfvsnprwm8agia85x64vjzr2w0xn9vxfnxzgcv8s699v0v"; + type = "gem"; + }; + version = "2.6.0"; + }; + google-protobuf = { + dependencies = ["bigdecimal" "rake"]; + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0583agdf2jvnq78scf8008bddrmbybn27ylyydg6bza2qvb510bl"; + type = "gem"; + }; + version = "4.33.2"; + }; + "http_parser.rb" = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1gj4fmls0mf52dlr928gaq0c0cb0m3aqa9kaa6l0ikl2zbqk42as"; + type = "gem"; + }; + version = "0.8.0"; + }; + i18n = { + dependencies = ["concurrent-ruby"]; + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1994i044vdmzzkyr76g8rpl1fq1532wf0sb21xg5r1ilj5iphmr8"; + type = "gem"; + }; + version = "1.14.8"; + }; + jekyll = { + dependencies = ["addressable" "base64" "colorator" "csv" "em-websocket" "i18n" "jekyll-sass-converter" "jekyll-watch" "json" "kramdown" "kramdown-parser-gfm" "liquid" "mercenary" "pathutil" "rouge" "safe_yaml" "terminal-table" "webrick"]; + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1h8qpki1zcw4srnzmbba2gwajycm50w53kxq8l6vicm5azc484ac"; + type = "gem"; + }; + version = "4.4.1"; + }; + jekyll-sass-converter = { + dependencies = ["sass-embedded"]; + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0hr4hsir8lm8aw3yj9zi7hx2xs4k00xn9inh24642d6iy625v4l3"; + type = "gem"; + }; + version = "3.1.0"; + }; + jekyll-watch = { + dependencies = ["listen"]; + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1qd7hy1kl87fl7l0frw5qbn22x7ayfzlv9a5ca1m59g0ym1ysi5w"; + type = "gem"; + }; + version = "2.2.1"; + }; + json = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "01fmiz052cvnxgdnhb3qwcy88xbv7l3liz0fkvs5qgqqwjp0c1di"; + type = "gem"; + }; + version = "2.18.0"; + }; + kramdown = { + dependencies = ["rexml"]; + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "131nwypz8b4pq1hxs6gsz3k00i9b75y3cgpkq57vxknkv6mvdfw7"; + type = "gem"; + }; + version = "2.5.1"; + }; + kramdown-parser-gfm = { + dependencies = ["kramdown"]; + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0a8pb3v951f4x7h968rqfsa19c8arz21zw1vaj42jza22rap8fgv"; + type = "gem"; + }; + version = "1.1.0"; + }; + liquid = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1czxv2i1gv3k7hxnrgfjb0z8khz74l4pmfwd70c7kr25l2qypksg"; + type = "gem"; + }; + version = "4.0.4"; + }; + listen = { + dependencies = ["rb-fsevent" "rb-inotify"]; + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0rwwsmvq79qwzl6324yc53py02kbrcww35si720490z5w0j497nv"; + type = "gem"; + }; + version = "3.9.0"; + }; + logger = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "00q2zznygpbls8asz5knjvvj2brr3ghmqxgr83xnrdj4rk3xwvhr"; + type = "gem"; + }; + version = "1.7.0"; + }; + mercenary = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0f2i827w4lmsizrxixsrv2ssa3gk1b7lmqh8brk8ijmdb551wnmj"; + type = "gem"; + }; + version = "0.4.0"; + }; + mini_magick = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1nfxjpmka12ihbwd87d5k2hh7d2pv3aq95x0l2lh8gca1s72bmki"; + type = "gem"; + }; + version = "4.13.2"; + }; + net-http = { + dependencies = ["uri"]; + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "15k96fj6qwbaiv6g52l538ass95ds1qwgynqdridz29yqrkhpfi5"; + type = "gem"; + }; + version = "0.9.1"; + }; + pathutil = { + dependencies = ["forwardable-extended"]; + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "12fm93ljw9fbxmv2krki5k5wkvr7560qy8p4spvb9jiiaqv78fz4"; + type = "gem"; + }; + version = "0.16.2"; + }; + public_suffix = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "15dhl6k4gbax0xz8frfs4nsb6lg5zgax9vkr1pqzjmhfxddhn2gp"; + type = "gem"; + }; + version = "7.0.0"; + }; + rake = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "175iisqb211n0qbfyqd8jz2g01q6xj038zjf4q0nm8k6kz88k7lc"; + type = "gem"; + }; + version = "13.3.1"; + }; + rb-fsevent = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1zmf31rnpm8553lqwibvv3kkx0v7majm1f341xbxc0bk5sbhp423"; + type = "gem"; + }; + version = "0.11.2"; + }; + rb-inotify = { + dependencies = ["ffi"]; + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0vmy8xgahixcz6hzwy4zdcyn2y6d6ri8dqv5xccgzc1r292019x0"; + type = "gem"; + }; + version = "0.11.1"; + }; + rexml = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0hninnbvqd2pn40h863lbrn9p11gvdxp928izkag5ysx8b1s5q0r"; + type = "gem"; + }; + version = "3.4.4"; + }; + rouge = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1pkp5icgm7s10b2n6b2pzbdsfiv0l5sxqyizx55qdmlpaxnk8xah"; + type = "gem"; + }; + version = "4.6.1"; + }; + safe_yaml = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0j7qv63p0vqcd838i2iy2f76c3dgwzkiz1d1xkg7n0pbnxj2vb56"; + type = "gem"; + }; + version = "1.0.5"; + }; + sass-embedded = { + dependencies = ["google-protobuf" "rake"]; + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1nb8wy2v397qi7hn3vamya6yv7v4ix2zfdsrk3mairslb24yhbhi"; + type = "gem"; + }; + version = "1.97.1"; + }; + terminal-table = { + dependencies = ["unicode-display_width"]; + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "14dfmfjppmng5hwj7c5ka6qdapawm3h6k9lhn8zj001ybypvclgr"; + type = "gem"; + }; + version = "3.0.2"; + }; + unicode-display_width = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0nkz7fadlrdbkf37m0x7sw8bnz8r355q3vwcfb9f9md6pds9h9qj"; + type = "gem"; + }; + version = "2.6.0"; + }; + uri = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1ijpbj7mdrq7rhpq2kb51yykhrs2s54wfs6sm9z3icgz4y6sb7rp"; + type = "gem"; + }; + version = "1.1.1"; + }; + webrick = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0ca1hr2rxrfw7s613rp4r4bxb454i3ylzniv9b9gxpklqigs3d5y"; + type = "gem"; + }; + version = "1.9.2"; + }; +} diff --git a/modules/services/tailscale.nix b/modules/services/tailscale.nix new file mode 100644 index 0000000..ad2d89c --- /dev/null +++ b/modules/services/tailscale.nix @@ -0,0 +1,5 @@ +{ ... }: +{ + services.tailscale.enable = true; + services.tailscale.port = 41641; +} diff --git a/modules/users/tobias.nix b/modules/users/tobias.nix new file mode 100644 index 0000000..3bd7c1b --- /dev/null +++ b/modules/users/tobias.nix @@ -0,0 +1,20 @@ +{ pkgs, ... }: +{ + users.users.tobias = { + isNormalUser = true; + uid = 1000; + group = "tobias"; + extraGroups = [ "wheel" ]; + home = "/home/tobias"; + shell = pkgs.bashInteractive; + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBgC4+zkTKNLPCt1vcTLyA+iwKGG8hrmcN2XKUExAR8W randogoth@mrht" + ]; + }; + + users.groups.tobias = { + gid = 1000; + }; + + security.sudo.wheelNeedsPassword = false; +} diff --git a/secrets/bucur.yaml b/secrets/bucur.yaml new file mode 100644 index 0000000..e4b85eb --- /dev/null +++ b/secrets/bucur.yaml @@ -0,0 +1,17 @@ +mtproto_secret: ENC[AES256_GCM,data:MyzyUCH8cLOG+GMtmV03daJ9sqwOw/ozN2yi/14SMlY=,iv:LLf2LIvX+jNjRdMHclHpsmTZa7wmVM3gD6RbqeCGmik=,tag:i36lVESyKJafsn14kSzh3g==,type:str] +codeberg_id_ed25519: ENC[AES256_GCM,data:AZbFWfc80HVskenEVLYL9MOYrGhW7Cwzdqv8gS4+1JGfk+nC801SmMgElUdISo+3m/O54b8RbJtdVz2u99gL8WG6wgbK7xqf40q4HNvV5cFXp7L/ozUkT41uXjWsDIdnMwumOqL/vjXowmAay30kMOiD5M4DL0t6EmuOo1Rcdffe/HwCVd2Pz7ZpU+BSTQV/pDTK1X3taUCjCY3Ui0XrcSCY8G2tuX5pFQ6t+vLrdqy3UGhofYHQ+nZuoyEKQHCcvEhYvEgDPJtyy+gk96vZCDYyXb9am/5k0I+MoIsArpavp4P0r5dNDcTnuCHH+fVPTG4tOsG/Ztf1rFBCsqPiM0azNElI8FERSKLYipuDDD8GI46p43OalHw4pxmAHXNOs70PfIH25iFJ5AUb32v2A71LScJMNP/TFSSezuq6g5eTd/JrtpQnWwToH1eVrwcN/8YX3xflLZ2JO1q4fjCXrkYHyw004dV/HAq3u1XQDmfMviZiH80+hiVIgZLfMWv5IyzfuomqSnfOj6oJ6D+j,iv:37HiX60OnO/zZFs1v4VWQLxcaoC1byZ3N2ueYFh4BVQ=,tag:5+z2YlnA8+MEcQTTrYhPJA==,type:str] +sops: + age: + - recipient: age1647c5f46njylggj33h26t6twhq57n5qeaza04l845uy0fksv0ucsq82c3d + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBpZWtwNDdiRlA0K25tbkZP + VDBrSVFCTlU4NlpqU2NHZnk1NEw4OEhXTTBJCktSU3pBcEZwN2NVNUl2ekNQY1Vp + YUdKbVE2ZzhUTmJwVDdRcVBpbXQ1b0EKLS0tIFZINGt1enNwUHlDdmZ4YTV6K09T + U0x1ZmtzLytSL1Y3cVo1ZVJ2Ymtob1EKTpgjSymQx14wLSuUhh5Txq++3DrLS4Bs + x8vVtQgcXZgv1q0OMGup6DT4bkY6UiNbn9bAt4rHCaRPeb15x4ZKNw== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2026-02-05T14:18:42Z" + mac: ENC[AES256_GCM,data:sZTFVbWYhtYML6tZrivXYGm8ug+isUf7wi0VWwQ0Wx1Swany1RSkyQI7N0eFs58tVsY2KoizOShvLkC8UcpRvtog1M/OyZi0LypYkfMUD7Rth11AF2n3Tg4Q3VNH5DGcLWkzYleA4mj1mJnPyCQzKOykXSPocODAcKUyFYcP8uQ=,iv:ZxuNWYQesR6mtezi5yBRacPF4GC5NDsevaSlRJ+A6X4=,tag:htOCSco/V2/twoRRWeoBbA==,type:str] + unencrypted_suffix: _unencrypted + version: 3.11.0