diff options
author | sterni <sternenseemann@systemli.org> | 2022-06-06T10·37+0200 |
---|---|---|
committer | sterni <sternenseemann@systemli.org> | 2022-11-26T15·51+0000 |
commit | 2490ce968c73181d383b297c2e473605d8ac96c3 (patch) | |
tree | 500dc5aab9316ddfa305780b347428a5065bb428 | |
parent | 7b4a545699f62faecc3b0223a761e1ca456f8cd9 (diff) |
feat(sterni/machines): add edwin r/5336
This adds edwin, the machine running sterni.lv, as well as my idiosyncratic deployment solution. It is based on instantiating the system configuration locally (where you'd work on the configuration), copying the derivation files to the remote machine where the system derivation is realised and deployed. Unfortunately, the first step tends to be quite slow (despite gzip compression), so this may not be the definite way despite its advantages. Change-Id: I30f597692338df3981e01a1b7eee9cdad48f94cb Reviewed-on: https://cl.tvl.fyi/c/depot/+/7293 Reviewed-by: sterni <sternenseemann@systemli.org> Tested-by: BuildkiteCI
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 |