about summary refs log tree commit diff
path: root/users/sterni
diff options
context:
space:
mode:
Diffstat (limited to 'users/sterni')
-rw-r--r--users/sterni/machines/.skip-subtree1
-rw-r--r--users/sterni/machines/default.nix77
-rw-r--r--users/sterni/machines/edwin/default.nix77
-rw-r--r--users/sterni/machines/edwin/gopher.nix19
-rw-r--r--users/sterni/machines/edwin/hardware.nix64
-rw-r--r--users/sterni/machines/edwin/http/code.sterni.lv.nix120
-rw-r--r--users/sterni/machines/edwin/http/fcgiwrap.nix15
-rw-r--r--users/sterni/machines/edwin/http/flipdot.openlab-augsburg.de.nix36
-rw-r--r--users/sterni/machines/edwin/http/likely-music.sterni.lv.nix23
-rw-r--r--users/sterni/machines/edwin/http/nginx.nix28
-rw-r--r--users/sterni/machines/edwin/http/sterni.lv.nix16
-rw-r--r--users/sterni/machines/edwin/minecraft.nix118
-rw-r--r--users/sterni/machines/edwin/network.nix62
-rw-r--r--users/sterni/secrets/default.nix3
-rw-r--r--users/sterni/secrets/minecraft-rcon.age9
-rw-r--r--users/sterni/secrets/secrets.nix15
-rw-r--r--users/sterni/secrets/warteraum-salt.agebin0 -> 530 bytes
-rw-r--r--users/sterni/secrets/warteraum-tokens.age10
18 files changed, 693 insertions, 0 deletions
diff --git a/users/sterni/machines/.skip-subtree b/users/sterni/machines/.skip-subtree
new file mode 100644
index 000000000000..a79762853edd
--- /dev/null
+++ b/users/sterni/machines/.skip-subtree
@@ -0,0 +1 @@
+Subdirectories are manually reexposed by default.nix as the contain NixOS modules
diff --git a/users/sterni/machines/default.nix b/users/sterni/machines/default.nix
new file mode 100644
index 000000000000..4a859a337a22
--- /dev/null
+++ b/users/sterni/machines/default.nix
@@ -0,0 +1,77 @@
+{ depot, lib, pkgs, ... }:
+
+let
+  bins = depot.nix.getBins pkgs.nq [ "fq" "nq" ];
+
+  machines = lib.mapAttrs
+    (name: _:
+      depot.ops.nixos.nixosFor (import (./. + ("/" + name)))
+    )
+    (lib.filterAttrs (_: type: type == "directory") (builtins.readDir ./.));
+
+  # TODO(sterni): share code with rebuild-system
+  localDeployScriptFor = { system, ... }:
+    pkgs.writeShellScript "local-deploy-${system.name}" ''
+      set -eu
+      nix-env -p /nix/var/nix/profiles/system --set "${system}"
+      "${system}/bin/switch-to-configuration" switch
+    '';
+
+  # Builds the system on the remote machine
+  deployScriptFor = { system, ... }@machine:
+    pkgs.writeShellScript "remote-deploy-${system.name}" ''
+      set -eu
+
+      if [ $# != 1 ]; then
+        printf 'usage: %s [USER@]HOST' "$0"
+        exit 100
+      fi
+
+      readonly TARGET_HOST="$1"
+      readonly DEPLOY_DRV="${
+        builtins.unsafeDiscardOutputDependency (
+          # Wrapper script around localDeployScriptFor that merely starts the
+          # local deploy script using and nq and then waits using fq. This means
+          # we can't Ctrl-C the deploy and it won't be terminated by a lost
+          # connection.
+          pkgs.writeShellScript "queue-deploy-${system.name}" ''
+            readonly STATE_DIR="''${XDG_STATE_HOME:-$HOME/.local/state}/sterni-deploy"
+            mkdir -p "$STATE_DIR"
+
+            export NQDIR="$STATE_DIR"
+
+            "${bins.nq}" "${localDeployScriptFor machine}"
+            "${bins.fq}"
+          ''
+        ).drvPath
+      }"
+
+      nix-copy-closure -s --gzip --to "$TARGET_HOST" "$DEPLOY_DRV"
+
+      readonly DEPLOY_OUT="$(ssh "$TARGET_HOST" "nix-store -r '$DEPLOY_DRV'")"
+
+      ssh "$TARGET_HOST" "$DEPLOY_OUT"
+    '';
+
+in
+
+depot.nix.readTree.drvTargets (
+  # this somehow becomes necessarily ugly with nixpkgs-fmt
+  machines // { inherit deployScriptFor; } //
+
+  lib.mapAttrs'
+    (name: _: {
+      name = "${name}System";
+      value = machines.${name}.system;
+    })
+    machines
+
+    //
+
+  lib.mapAttrs'
+    (name: _: {
+      name = "${name}Deploy";
+      value = deployScriptFor machines.${name};
+    })
+    machines
+)
diff --git a/users/sterni/machines/edwin/default.nix b/users/sterni/machines/edwin/default.nix
new file mode 100644
index 000000000000..40700ea1e91b
--- /dev/null
+++ b/users/sterni/machines/edwin/default.nix
@@ -0,0 +1,77 @@
+{ config, lib, pkgs, depot, ... }:
+
+{
+  imports = [
+    # Third party modules we use
+    "${depot.third_party.agenix.src}/modules/age.nix"
+    # These modules touch things related to booting (filesystems, initrd network…)
+    ./hardware.nix
+    ./network.nix
+    # These modules configure services, websites etc.
+    ./minecraft.nix
+    ./gopher.nix
+    ./http/sterni.lv.nix
+    ./http/code.sterni.lv.nix
+    ./http/flipdot.openlab-augsburg.de.nix
+    ./http/likely-music.sterni.lv.nix
+  ];
+
+  config = {
+    time.timeZone = "Europe/Berlin";
+
+    nixpkgs.config.allowUnfreeRedistributable = true;
+    nix.package = pkgs.nix_2_3;
+    tvl.cache.enable = true;
+
+    services = {
+      journald.extraConfig = ''
+        SystemMaxUse=1024M
+      '';
+
+      openssh.enable = true;
+    };
+
+    security.acme = {
+      defaults.email = builtins.getAttr "email" (
+        builtins.head (
+          builtins.filter (attrs: attrs.username == "sterni") depot.ops.users
+        )
+      );
+      acceptTerms = true;
+    };
+
+    programs = {
+      fish.enable = true;
+      mosh.enable = true;
+      tmux.enable = true;
+    };
+
+    environment.systemPackages = [
+      pkgs.weechat
+      pkgs.wget
+      pkgs.git
+      pkgs.stow
+      pkgs.htop
+      pkgs.foot.terminfo
+      pkgs.vim
+    ];
+
+    users = {
+      users = {
+        root.openssh.authorizedKeys.keys = depot.users.sterni.keys.all;
+        lukas = {
+          isNormalUser = true;
+          extraGroups = [ "wheel" "http" ];
+          openssh.authorizedKeys.keys = depot.users.sterni.keys.all;
+          shell = "${pkgs.fish}/bin/fish";
+        };
+      };
+    };
+
+    nix.settings.trusted-users = [
+      "lukas"
+    ];
+
+    system.stateVersion = "20.09";
+  };
+}
diff --git a/users/sterni/machines/edwin/gopher.nix b/users/sterni/machines/edwin/gopher.nix
new file mode 100644
index 000000000000..57275e13a55a
--- /dev/null
+++ b/users/sterni/machines/edwin/gopher.nix
@@ -0,0 +1,19 @@
+{ depot, ... }:
+
+{
+  config = {
+    services.spacecookie = {
+      enable = true;
+      openFirewall = true;
+      settings = {
+        hostname = "sterni.lv";
+        root = depot.users.sterni.lv.gopher;
+        log = {
+          enable = true;
+          hide-ips = true;
+          hide-time = true;
+        };
+      };
+    };
+  };
+}
diff --git a/users/sterni/machines/edwin/hardware.nix b/users/sterni/machines/edwin/hardware.nix
new file mode 100644
index 000000000000..258410894a80
--- /dev/null
+++ b/users/sterni/machines/edwin/hardware.nix
@@ -0,0 +1,64 @@
+{ config, lib, pkgs, depot, ... }:
+
+{
+  config = {
+    boot = {
+      loader.grub = {
+        enable = true;
+        version = 2;
+        # TODO(sterni): use /dev/disk/by-id ?
+        devices = [
+          "/dev/sda"
+          "/dev/sdb"
+        ];
+      };
+
+      kernelModules = [
+        "kvm-intel"
+      ];
+
+      initrd.availableKernelModules = [
+        "ahci"
+        "sd_mod"
+        "btrfs"
+        "realtek"
+        "r8169"
+      ];
+    };
+
+    boot.initrd.luks.devices = {
+      "crypt1".device = "/dev/disk/by-uuid/02ac34ee-be10-401b-90c2-1c6aa54c4d5f";
+      "crypt2".device = "/dev/disk/by-uuid/7ce07191-e704-4aed-a60f-dfa3ce386b26";
+      "crypt-swap1".device = "/dev/disk/by-uuid/fec7155c-6a65-4f25-b271-43763e4c31eb";
+      "crypt-swap2".device = "/dev/disk/by-uuid/7b0a03fc-51de-4578-9811-94b00df09d88";
+    };
+
+    fileSystems = {
+      "/" = {
+        device = "/dev/disk/by-label/root";
+        fsType = "btrfs";
+      };
+
+      "/boot" = {
+        device = "/dev/disk/by-label/boot";
+        fsType = "btrfs";
+      };
+    };
+
+    swapDevices = [
+      { device = "/dev/disk/by-label/swap1"; }
+      { device = "/dev/disk/by-label/swap2"; }
+    ];
+
+    powerManagement.cpuFreqGovernor = "performance";
+    hardware = {
+      enableRedistributableFirmware = true;
+      cpu.intel.updateMicrocode = true;
+    };
+
+    nix.settings = {
+      max-jobs = 2;
+      cores = 4;
+    };
+  };
+}
diff --git a/users/sterni/machines/edwin/http/code.sterni.lv.nix b/users/sterni/machines/edwin/http/code.sterni.lv.nix
new file mode 100644
index 000000000000..6c7e73cbc24e
--- /dev/null
+++ b/users/sterni/machines/edwin/http/code.sterni.lv.nix
@@ -0,0 +1,120 @@
+{ depot, pkgs, lib, config, ... }:
+
+# TODO(sterni): automatically sync repositories with upstream if needed
+let
+  virtualHost = "code.sterni.lv";
+
+  repos = {
+    spacecookie = {
+      description = "gopher server (and library for Haskell)";
+    };
+    gopher-proxy = {
+      description = "Gopher over HTTP proxy";
+    };
+    emoji-generic = {
+      description = "generic emoji library for Haskell (wip)";
+    };
+    grav2ty = {
+      description = "“realistic” 2d space game";
+    };
+    likely-music = {
+      description = "experimental application for probabilistic music composition";
+    };
+    logbook = {
+      description = "file format for keeping a personal log";
+    };
+    sternenblog = {
+      description = "file based cgi blog software";
+    };
+    haskell-dot-time = {
+      description = "UTC-centric time library for haskell with dot time support";
+      defaultBranch = "main";
+    };
+    buchstabensuppe = {
+      description = "toy font rendering for low pixelcount, high contrast displays";
+      defaultBranch = "main";
+    };
+  };
+
+  cgitRepoEntry = name: repo:
+    let
+      repoName = repos.name or name;
+      path = repo.path or "${repoName}.git";
+    in
+    lib.concatStringsSep "\n" (
+      [
+        "repo.url=${repoName}"
+        "repo.path=/srv/git/${path}"
+      ]
+      ++ lib.optional (repo ? description) "repo.desc=${repo.description}"
+      ++ lib.optional (repo ? defaultBranch) "repo.defbranch=${repo.defaultBranch}"
+    );
+
+  cgitHead = pkgs.writeText "cgit-head.html" ''
+    <style>
+    #summary {
+      max-width: 80em;
+    }
+
+    #summary * {
+      max-width: 100%;
+    }
+    </style>
+  '';
+
+  cgitConfig = pkgs.writeText "cgitrc" ''
+    virtual-root=/
+
+    enable-http-clone=1
+    clone-url=https://${virtualHost}/$CGIT_REPO_URL
+
+    enable-blame=1
+    enable-log-filecount=1
+    enable-log-linecount=1
+    enable-index-owner=0
+    enable-blame=1
+    enable-commit-graph=1
+
+    root-title=code
+    root-desc=sterni's git repositories
+    css=/cgit.css
+    head-include=${cgitHead}
+
+    mimetype-file=${pkgs.mime-types}/etc/mime.types
+
+    about-filter=${depot.tools.cheddar.about-filter}/bin/cheddar-about
+    source-filter=${depot.tools.cheddar}/bin/cheddar
+    readme=:README.md
+    readme=:readme.md
+
+    ${builtins.concatStringsSep "\n\n" (lib.mapAttrsToList cgitRepoEntry repos)}
+  '';
+in
+
+{
+  imports = [
+    ./nginx.nix
+    ./fcgiwrap.nix
+  ];
+
+  config = {
+    services.nginx.virtualHosts."${virtualHost}" = {
+      enableACME = true;
+      forceSSL = true;
+      root = "${pkgs.cgit-pink}/cgit/";
+      extraConfig = ''
+        try_files $uri @cgit;
+
+        location @cgit {
+          include ${pkgs.nginx}/conf/fastcgi_params;
+          fastcgi_param    SCRIPT_FILENAME ${pkgs.cgit-pink}/cgit/cgit.cgi;
+          fastcgi_param    PATH_INFO       $uri;
+          fastcgi_param    QUERY_STRING    $args;
+          fastcgi_param    HTTP_HOST       $server_name;
+          fastcgi_param    CGIT_CONFIG     ${cgitConfig};
+          fastcgi_pass     unix:${toString config.services.fcgiwrap.socketAddress};
+        }
+      '';
+    };
+  };
+}
diff --git a/users/sterni/machines/edwin/http/fcgiwrap.nix b/users/sterni/machines/edwin/http/fcgiwrap.nix
new file mode 100644
index 000000000000..19696d85d413
--- /dev/null
+++ b/users/sterni/machines/edwin/http/fcgiwrap.nix
@@ -0,0 +1,15 @@
+{ ... }:
+
+{
+  imports = [
+    ./nginx.nix
+  ];
+
+  config.services.fcgiwrap = {
+    enable = true;
+    socketType = "unix";
+    socketAddress = "/run/fcgiwrap.sock";
+    user = "http";
+    group = "http";
+  };
+}
diff --git a/users/sterni/machines/edwin/http/flipdot.openlab-augsburg.de.nix b/users/sterni/machines/edwin/http/flipdot.openlab-augsburg.de.nix
new file mode 100644
index 000000000000..c86956a0a473
--- /dev/null
+++ b/users/sterni/machines/edwin/http/flipdot.openlab-augsburg.de.nix
@@ -0,0 +1,36 @@
+{ depot, lib, config, ... }:
+
+let
+  inherit (depot.users.sterni.external.flipdot-gschichtler)
+    bahnhofshalle
+    warteraum
+    nixosModule
+    ;
+in
+
+{
+  imports = [
+    nixosModule
+    ./nginx.nix
+  ];
+
+  config = {
+    age.secrets = lib.genAttrs [
+      "warteraum-salt"
+      "warteraum-tokens"
+    ]
+      (name: {
+        file = depot.users.sterni.secrets."${name}.age";
+      });
+
+    services.flipdot-gschichtler = {
+      enable = true;
+      virtualHost = "flipdot.openlab-augsburg.de";
+      packages = {
+        inherit bahnhofshalle warteraum;
+      };
+      saltFile = config.age.secretsDir + "/warteraum-salt";
+      tokensFile = config.age.secretsDir + "/warteraum-tokens";
+    };
+  };
+}
diff --git a/users/sterni/machines/edwin/http/likely-music.sterni.lv.nix b/users/sterni/machines/edwin/http/likely-music.sterni.lv.nix
new file mode 100644
index 000000000000..8da03ac5e6ec
--- /dev/null
+++ b/users/sterni/machines/edwin/http/likely-music.sterni.lv.nix
@@ -0,0 +1,23 @@
+{ depot, ... }:
+
+let
+  inherit (depot.users.sterni.external.likely-music)
+    nixosModule
+    likely-music
+    ;
+in
+
+{
+  imports = [
+    ./nginx.nix
+    nixosModule
+  ];
+
+  config = {
+    services.likely-music = {
+      enable = true;
+      virtualHost = "likely-music.sterni.lv";
+      package = likely-music;
+    };
+  };
+}
diff --git a/users/sterni/machines/edwin/http/nginx.nix b/users/sterni/machines/edwin/http/nginx.nix
new file mode 100644
index 000000000000..7c99cdd150e0
--- /dev/null
+++ b/users/sterni/machines/edwin/http/nginx.nix
@@ -0,0 +1,28 @@
+{ ... }:
+
+{
+  config = {
+    users = {
+      users.http = {
+        isSystemUser = true;
+        group = "http";
+      };
+
+      groups.http = { };
+    };
+
+    services.nginx = {
+      enable = true;
+      recommendedTlsSettings = true;
+      recommendedGzipSettings = true;
+      recommendedProxySettings = true;
+
+      user = "http";
+      group = "http";
+
+      appendHttpConfig = ''
+        charset utf-8;
+      '';
+    };
+  };
+}
diff --git a/users/sterni/machines/edwin/http/sterni.lv.nix b/users/sterni/machines/edwin/http/sterni.lv.nix
new file mode 100644
index 000000000000..44306c75bf64
--- /dev/null
+++ b/users/sterni/machines/edwin/http/sterni.lv.nix
@@ -0,0 +1,16 @@
+{ ... }:
+
+{
+  imports = [
+    ./nginx.nix
+  ];
+
+  config = {
+    services.nginx.virtualHosts."sterni.lv" = {
+      enableACME = true;
+      forceSSL = true;
+      # TODO(sterni): take website from store, replace /tmp with a simple LRU thing
+      root = toString /srv/http;
+    };
+  };
+}
diff --git a/users/sterni/machines/edwin/minecraft.nix b/users/sterni/machines/edwin/minecraft.nix
new file mode 100644
index 000000000000..6014a3d5795a
--- /dev/null
+++ b/users/sterni/machines/edwin/minecraft.nix
@@ -0,0 +1,118 @@
+{ pkgs, depot, config, ... }:
+
+let
+  carpet = pkgs.fetchurl {
+    url = "https://github.com/gnembon/fabric-carpet/releases/download/1.4.44/fabric-carpet-1.16.5-1.4.44+v210714.jar";
+    sha256 = "099nwspgxv7h2k3mwwmgcykmwfcb7yg1azb38fd4ravv97z4l3j8";
+  };
+
+  carpet-extra = pkgs.fetchurl {
+    url = "https://github.com/gnembon/carpet-extra/releases/download/1.4.43/carpet-extra-1.16.5-1.4.43.jar";
+    sha256 = "0w3gng1xyiqybm1qv4gbbsyqry3dr2ndvynx14qb59wxlw0dv5za";
+  };
+
+  userGroup = "minecraft";
+
+  makeJvmOpts = megs: [
+    "-Xms${toString megs}M"
+    "-Xmx${toString megs}M"
+  ];
+
+  whitelist = {
+    spreadwasser = "242a66eb-2df2-4585-9a28-ac763ad0d0f9";
+    sternenseemann = "d8e48069-1905-4886-a5da-a4ee917ee254";
+  };
+
+  rconPasswordFile = config.age.secretsDir + "/minecraft-rcon";
+
+  baseProperties = {
+    white-list = true;
+    allow-flight = true;
+    difficulty = "hard";
+    function-permission-level = 4;
+    snooper-enabled = false;
+    view-distance = 12;
+    sync-chunk-writes = "false"; # the single biggest performance fix
+    max-tick-time = 6000000; # TODO(sterni): disable watchdog via carpet
+  };
+in
+
+{
+  imports = [
+    ../../modules/minecraft-fabric.nix
+  ];
+
+  config = {
+    environment.systemPackages = [
+      pkgs.mcrcon
+      pkgs.jre
+    ];
+
+    users = {
+      users."${userGroup}" = {
+        isNormalUser = true;
+        openssh.authorizedKeys.keys = depot.users.sterni.keys.all;
+        shell = "${pkgs.fish}/bin/fish";
+      };
+
+      groups."${userGroup}" = { };
+    };
+
+    age.secrets = {
+      minecraft-rcon.file = depot.users.sterni.secrets."minecraft-rcon.age";
+    };
+
+    services.minecraft-fabric-server = {
+      creative = {
+        enable = true;
+        version = "1.16.5";
+        mods = [
+          carpet
+          carpet-extra
+        ];
+        world = config.users.users.${userGroup}.home + "/worlds/creative";
+
+        jvmOpts = makeJvmOpts 2048;
+        user = userGroup;
+        group = userGroup;
+
+        inherit whitelist rconPasswordFile;
+        ops = whitelist;
+
+        serverProperties = baseProperties // {
+          server-port = 25566;
+          "rcon.port" = 25576;
+          gamemode = "creative";
+          enable-command-block = true;
+          motd = "storage design server";
+          spawn-protection = 2;
+        };
+      };
+
+      carpet = {
+        enable = true;
+        version = "1.16.5";
+        mods = [
+          carpet
+          carpet-extra
+        ];
+        world = config.users.users.${userGroup}.home + "/worlds/carpet";
+
+        jvmOpts = makeJvmOpts 4096;
+        user = userGroup;
+        group = userGroup;
+
+        inherit whitelist rconPasswordFile;
+        ops = whitelist;
+
+        serverProperties = baseProperties // {
+          server-port = 25565;
+          "rcon.port" = 25575;
+          motd = "ich tu fleissig hustlen nenn mich bob der baumeister";
+
+          level-seed = 7240251176989694927; # for posterity
+        };
+      };
+    };
+  };
+}
diff --git a/users/sterni/machines/edwin/network.nix b/users/sterni/machines/edwin/network.nix
new file mode 100644
index 000000000000..1e3d4e76f078
--- /dev/null
+++ b/users/sterni/machines/edwin/network.nix
@@ -0,0 +1,62 @@
+{ config, pkgs, lib, depot, ... }:
+
+let
+  ipv6 = "2a01:4f8:151:54d0::/64";
+
+  ipv4 = "176.9.107.207";
+  gatewayv4 = "176.9.107.193";
+  netmaskv4 = "255.255.255.224";
+in
+
+{
+  config = {
+    boot = {
+      kernelParams = [
+        "ip=${ipv4}::${gatewayv4}:${netmaskv4}::eth0:none"
+      ];
+
+      initrd.network = {
+        enable = true;
+        ssh = {
+          enable = true;
+          authorizedKeys = depot.users.sterni.keys.all;
+          hostKeys = [
+            "/etc/nixos/unlock_rsa_key_openssh"
+            "/etc/nixos/unlock_ed25519_key_openssh"
+          ];
+        };
+        postCommands = ''
+          echo 'cryptsetup-askpass' >> /root/.profile
+        '';
+      };
+    };
+
+    networking = {
+      usePredictableInterfaceNames = false;
+      useDHCP = false;
+      interfaces."eth0".useDHCP = false;
+
+      hostName = "edwin";
+
+      firewall = {
+        enable = true;
+        allowPing = true;
+        allowedTCPPorts = [ 22 80 443 ];
+      };
+    };
+
+    systemd.network = {
+      enable = true;
+      networks."eth0".extraConfig = ''
+        [Match]
+        Name = eth0
+
+        [Network]
+        Address = ${ipv6}
+        Gateway = fe80::1
+        Address = ${ipv4}/27
+        Gateway = ${gatewayv4}
+      '';
+    };
+  };
+}
diff --git a/users/sterni/secrets/default.nix b/users/sterni/secrets/default.nix
new file mode 100644
index 000000000000..5550103c5a66
--- /dev/null
+++ b/users/sterni/secrets/default.nix
@@ -0,0 +1,3 @@
+{ depot, ... }:
+
+depot.ops.secrets.mkSecrets ./. (import ./secrets.nix)
diff --git a/users/sterni/secrets/minecraft-rcon.age b/users/sterni/secrets/minecraft-rcon.age
new file mode 100644
index 000000000000..7c896861b9d8
--- /dev/null
+++ b/users/sterni/secrets/minecraft-rcon.age
@@ -0,0 +1,9 @@
+age-encryption.org/v1
+-> ssh-ed25519 aXKGcg VELHhE9AlsAUspZj8M9zzOcjaml3/KSuNAae73TOOEk
+0vpPVz2TFMK2MLxHzMVO3a9QvnU9MfYcNO+JpMRRhN8
+-> ssh-ed25519 34g70A 28ldud+S2mz83kcIkEGv5XWWOdXUN/vetsqho7kiCh4
+/P+hJqj9r3KEi0VD15yg0MHyy0XgYUU5/zpMRrLaysM
+-> .-grease }}M
+ennsvHEhRup8I8R23GPWlILkCIMZmAuMT2F22SQPdjU
+--- e6u1rsLXltysnQqp3x73HfHLhqzTfkIV3mXaCtW1cxE
+!NiAO4P&Ԏ	FFRrz
\ No newline at end of file
diff --git a/users/sterni/secrets/secrets.nix b/users/sterni/secrets/secrets.nix
new file mode 100644
index 000000000000..d2f4860ff241
--- /dev/null
+++ b/users/sterni/secrets/secrets.nix
@@ -0,0 +1,15 @@
+let
+  nonremote = [
+    "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJk+KvgvI2oJTppMASNUfMcMkA2G5ZNt+HnWDzaXKLlo"
+  ];
+
+  edwin = [
+    "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB+OZ8f++cnvd4E2kFyn9jEoVpxi7LfjRvyQwzE8a5Ll"
+  ];
+in
+
+{
+  "warteraum-salt.age".publicKeys = nonremote ++ edwin;
+  "warteraum-tokens.age".publicKeys = nonremote ++ edwin;
+  "minecraft-rcon.age".publicKeys = nonremote ++ edwin;
+}
diff --git a/users/sterni/secrets/warteraum-salt.age b/users/sterni/secrets/warteraum-salt.age
new file mode 100644
index 000000000000..f932a881cd43
--- /dev/null
+++ b/users/sterni/secrets/warteraum-salt.age
Binary files differdiff --git a/users/sterni/secrets/warteraum-tokens.age b/users/sterni/secrets/warteraum-tokens.age
new file mode 100644
index 000000000000..37ab46981ecb
--- /dev/null
+++ b/users/sterni/secrets/warteraum-tokens.age
@@ -0,0 +1,10 @@
+age-encryption.org/v1
+-> ssh-ed25519 aXKGcg yHE1bla5BN1Kgows1tdeswamJQHfzGpv8fL3qZs04k0
+rR1O25EIQXctnyVsQCZO47bM44KFhmOZ7ePiecKrZ40
+-> ssh-ed25519 34g70A voVJDU9DIrT0z6X/mAi0tQqXthRZAyrzsPXOTIIzKUw
+yEiIaD9jblO44/RaoiPA0mjvRToNc4Ur9GcwfG9TSVo
+-> =UOH^-Z4-grease Do<;So
+l0F72v4UD8r5kbpNIT2i1IUT6ttXZhuPE91H2tucMc5TKRvGDvpdJNpQ+P+XmX2M
+661iYooyust5TGZsXJFHVYg
+--- To85A7ohH2Sjfy8js2+JzV0c86dmDO2JCH8TK7OtVtM
+Vq%n!M#`3;1wFCH'Y]-Q1m
\ No newline at end of file