commit eabcf2de48b808cc4be44918f083552685fd363b Author: Jake Hamilton Date: Sat May 4 14:20:45 2024 -0700 chore: initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..726d2d6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +result +.direnv diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..276a8da --- /dev/null +++ b/flake.lock @@ -0,0 +1,247 @@ +{ + "nodes": { + "auxolotl-website": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "snowfall-lib": "snowfall-lib", + "unstable": "unstable" + }, + "locked": { + "lastModified": 1714714468, + "narHash": "sha256-wvEj39Fz22d6OG6BueNAATKALj69jS0nrTGDoDFsw/c=", + "owner": "auxolotl", + "repo": "website", + "rev": "204955138787e77bfba4e08ff9b7270ce9e025ca", + "type": "github" + }, + "original": { + "owner": "auxolotl", + "repo": "website", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1650374568, + "narHash": "sha256-Z+s0J8/r907g149rllvwhb4pKi8Wam5ij0st8PwAh+E=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "b4a34015c698c7793d592d66adbab377907a2be8", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_2": { + "flake": false, + "locked": { + "lastModified": 1650374568, + "narHash": "sha256-Z+s0J8/r907g149rllvwhb4pKi8Wam5ij0st8PwAh+E=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "b4a34015c698c7793d592d66adbab377907a2be8", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1694529238, + "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils-plus": { + "inputs": { + "flake-utils": "flake-utils" + }, + "locked": { + "lastModified": 1696331477, + "narHash": "sha256-YkbRa/1wQWdWkVJ01JvV+75KIdM37UErqKgTf0L54Fk=", + "owner": "gytis-ivaskevicius", + "repo": "flake-utils-plus", + "rev": "bfc53579db89de750b25b0c5e7af299e0c06d7d3", + "type": "github" + }, + "original": { + "owner": "gytis-ivaskevicius", + "repo": "flake-utils-plus", + "type": "github" + } + }, + "flake-utils-plus_2": { + "inputs": { + "flake-utils": "flake-utils_2" + }, + "locked": { + "lastModified": 1696331477, + "narHash": "sha256-YkbRa/1wQWdWkVJ01JvV+75KIdM37UErqKgTf0L54Fk=", + "owner": "gytis-ivaskevicius", + "repo": "flake-utils-plus", + "rev": "bfc53579db89de750b25b0c5e7af299e0c06d7d3", + "type": "github" + }, + "original": { + "owner": "gytis-ivaskevicius", + "repo": "flake-utils-plus", + "type": "github" + } + }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1694529238, + "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1714746430, + "narHash": "sha256-CzlNTvi5IwOQnE1mnOYrIojEMObXaAqV+16rJykFYIM=", + "owner": "auxolotl", + "repo": "nixpkgs", + "rev": "f8182123fedb08e5423c964952041e9666ba484c", + "type": "github" + }, + "original": { + "owner": "auxolotl", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "auxolotl-website": "auxolotl-website", + "nixpkgs": "nixpkgs", + "snowfall-lib": "snowfall-lib_2" + } + }, + "snowfall-lib": { + "inputs": { + "flake-compat": "flake-compat", + "flake-utils-plus": "flake-utils-plus", + "nixpkgs": [ + "auxolotl-website", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1696432959, + "narHash": "sha256-oJQZv2MYyJaVyVJY5IeevzqpGvMGKu5pZcCCJvb+xjc=", + "owner": "snowfallorg", + "repo": "lib", + "rev": "92803a029b5314d4436a8d9311d8707b71d9f0b6", + "type": "github" + }, + "original": { + "owner": "snowfallorg", + "repo": "lib", + "type": "github" + } + }, + "snowfall-lib_2": { + "inputs": { + "flake-compat": "flake-compat_2", + "flake-utils-plus": "flake-utils-plus_2", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1713814392, + "narHash": "sha256-IanrgtpgDqxGfzNczstspPljAHKaY0e4DGvYgdAwC1Y=", + "owner": "snowfallorg", + "repo": "lib", + "rev": "91ab40c2e01cc1bade8092604370964ee86e9317", + "type": "github" + }, + "original": { + "owner": "snowfallorg", + "ref": "dev", + "repo": "lib", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "unstable": { + "locked": { + "lastModified": 1714253743, + "narHash": "sha256-mdTQw2XlariysyScCv2tTE45QSU9v/ezLcHJ22f0Nxc=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "58a1abdbae3217ca6b702f03d3b35125d88a2994", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..f8485ed --- /dev/null +++ b/flake.nix @@ -0,0 +1,28 @@ +{ + description = "Auxolotl infrastructure."; + + inputs = { + nixpkgs.url = "github:auxolotl/nixpkgs/nixos-unstable"; + + snowfall-lib = { + url = "github:snowfallorg/lib/dev"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + auxolotl-website = { + url = "github:auxolotl/website"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = inputs: + inputs.snowfall-lib.mkFlake { + inherit inputs; + + src = ./.; + + overlays = with inputs; [ + auxolotl-website.overlays.default + ]; + }; +} diff --git a/modules/nixos/auxolotl/nix/default.nix b/modules/nixos/auxolotl/nix/default.nix new file mode 100644 index 0000000..e00a6f4 --- /dev/null +++ b/modules/nixos/auxolotl/nix/default.nix @@ -0,0 +1,94 @@ +{ + options, + config, + pkgs, + lib, + inputs, + ... +}: let + cfg = config.axolotl.nix; + + substituters-submodule = lib.types.submodule ({name, ...}: { + options = { + key = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + description = "The trusted public key for this substituter."; + }; + }; + }); +in { + options.axolotl.nix = { + enable = lib.mkEnableOption "Nix configuration"; + package = lib.mkOption { + type = lib.types.package; + default = pkgs.nixUnstable; + defaultText = "pkgs.nixUnstable"; + description = "Which Nix package to use."; + }; + + default-substituter = { + url = lib.mkOption { + type = lib.types.str; + default = "https://cache.nixos.org"; + description = "The url for the substituter."; + }; + key = lib.mkOption { + type = lib.types.str; + default = "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="; + description = "The trusted public key for the substituter."; + }; + }; + + extra-substituters = lib.mkOption { + type = lib.types.attrsOf substituters-submodule; + default = {}; + description = "Extra substituters to configure."; + }; + }; + + config = lib.mkIf cfg.enable { + assertions = + lib.mapAttrsToList + (name: value: { + assertion = value.key != null; + message = "axolotl.nix.extra-substituters.${name}.key must be set"; + }) + cfg.extra-substituters; + + nix = let + users = ["root"]; + in { + package = cfg.package; + + settings = { + experimental-features = "nix-command flakes"; + http-connections = 50; + log-lines = 50; + auto-optimise-store = true; + + trusted-users = users; + allowed-users = users; + + substituters = + [cfg.default-substituter.url] + ++ (lib.mapAttrsToList (name: value: name) cfg.extra-substituters); + + trusted-public-keys = + [cfg.default-substituter.key] + ++ (lib.mapAttrsToList (name: value: value.key) cfg.extra-substituters); + }; + + gc = { + automatic = true; + dates = "weekly"; + options = "--delete-older-than 30d"; + }; + + # flake-utils-plus + generateRegistryFromInputs = true; + generateNixPathFromInputs = true; + linkInputs = true; + }; + }; +} diff --git a/modules/nixos/auxolotl/security/acme.nix b/modules/nixos/auxolotl/security/acme.nix new file mode 100644 index 0000000..7410f80 --- /dev/null +++ b/modules/nixos/auxolotl/security/acme.nix @@ -0,0 +1,39 @@ +{ + lib, + config, + ... +}: let + cfg = config.auxolotl.security.acme; +in { + options.auxolotl.security.acme = { + enable = lib.mkEnableOption "Acme defaults"; + + email = lib.mkOption { + type = lib.types.string; + default = ""; + description = "Email address to use for Let's Encrypt registration."; + }; + + staging = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Use the Let's Encrypt staging server."; + }; + }; + + config = lib.mkIf cfg.enable { + security.acme = { + acceptTerms = true; + + defaults = { + inherit (cfg) email; + + group = lib.mkIf config.services.nginx.enable "nginx"; + server = lib.mkIf cfg.staging "https://acme-staging-v02.api.letsencrypt.org/directory"; + + # Reload nginx when certs change. + reloadServices = lib.optional config.services.nginx.enable "nginx.service"; + }; + }; + }; +} diff --git a/modules/nixos/auxolotl/services/chat/default.nix b/modules/nixos/auxolotl/services/chat/default.nix new file mode 100644 index 0000000..8ae2f19 --- /dev/null +++ b/modules/nixos/auxolotl/services/chat/default.nix @@ -0,0 +1,76 @@ +{ + lib, + pkgs, + config, + ... +}: let + cfg = config.auxolotl.services.chat; + + matrix-config = { + "m.server" = "matrix.${cfg.domain}:443"; + }; + + matrix-config-json = pkgs.writeText "matrix-config.json" (builtins.toJSON matrix-config); +in { + options.auxolotl.services.chat = { + enable = lib.mkEnableOption "Matrix chat"; + + domain = lib.mkOption { + type = lib.types.str; + default = "auxolotl.org"; + description = "The domain name for the website."; + }; + }; + + config = lib.mkIf cfg.enable { + services.matrix-conduit = { + enable = true; + + settings = { + global = { + server_name = cfg.domain; + }; + }; + }; + + services.nginx = { + enable = true; + + virtualHosts = { + "${cfg.domain}" = { + locations = { + "/.well-known/matrix/server" = { + tryFiles = "${matrix-config-json} =404"; + + extraConfig = '' + add_header Access-Control-Allow-Origin *; + ''; + }; + }; + }; + + "chat.${cfg.domain}" = { + forceSSL = true; + enableACME = true; + + locations = { + "/" = { + root = pkgs.cinny; + }; + }; + }; + + "matrix.${cfg.domain}" = { + forceSSL = true; + enableACME = true; + locations = { + "/" = { + proxyPass = "http://localhost:${config.services.matrix-conduit.settings.global.port}"; + proxyWebsockets = true; + }; + }; + }; + }; + }; + }; +} diff --git a/modules/nixos/auxolotl/services/website/default.nix b/modules/nixos/auxolotl/services/website/default.nix new file mode 100644 index 0000000..49fe7d9 --- /dev/null +++ b/modules/nixos/auxolotl/services/website/default.nix @@ -0,0 +1,42 @@ +{ + lib, + pkgs, + config, + ... +}: let + cfg = config.auxolotl.services.website; +in { + options.auxolotl.services.website = { + enable = lib.mkEnableOption "Auxolotl website"; + + domain = lib.mkOption { + type = lib.types.str; + default = "auxolotl.org"; + description = "The domain name for the website."; + }; + + package = lib.mkOption { + type = lib.types.package; + default = pkgs.aux.website; + defaultText = "pkgs.aux.website"; + description = "The website files to serve."; + }; + }; + + config = lib.mkIf cfg.enable { + services.nginx = { + enable = true; + + virtualHosts."${cfg.domain}" = { + forceSSL = true; + enableACME = true; + + locations = { + "/" = { + root = cfg.package; + }; + }; + }; + }; + }; +} diff --git a/modules/nixos/auxolotl/users/infra.nix b/modules/nixos/auxolotl/users/infra.nix new file mode 100644 index 0000000..ea11826 --- /dev/null +++ b/modules/nixos/auxolotl/users/infra.nix @@ -0,0 +1,33 @@ +{ + lib, + config, + ... +}: let + cfg = config.auxolotl.users.infra; +in { + options.auxolotl.users.infra = { + enable = lib.mkEnableOption "Infra user"; + }; + + config = lib.mkIf cfg.enable { + users.users.infra = { + isNormalUser = true; + description = "Infra user"; + + home = "/home/infra"; + createHome = true; + + extraGroups = ["wheel"]; + + openssh.authorizedKeys.keys = [ + # jakehamilton + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCwaaCUq3Ooq1BaHbg5IwVxWj/xmNJY2dDthHKPZefrHXv/ksM/IREgm38J0CdoMpVS0Zp1C/vFrwGfaYZ2lCF5hBVdV3gf+mvj8Yb8Xpm6aM4L5ig+oBMp/3cz1+g/I4aLMJfCKCtdD6Q2o4vtkTpid6X+kL3UGZbX0HFn3pxoDinzOXQnVGSGw+pQhLASvQeVXWTJjVfIWhj9L2NRJau42cBRRlAH9kE3HUbcgLgyPUZ28aGXLLmiQ6CUjiIlce5ee16WNLHQHOzVfPJfF1e1F0HwGMMBe39ey3IEQz6ab1YqlIzjRx9fQ9hQK6Du+Duupby8JmBlbUAxhh8KJFCJB2cXW/K5Et4R8GHMS6MyIoKQwFUXGyrszVfiuNTGZIkPAYx9zlCq9M/J+x1xUZLHymL85WLPyxhlhN4ysM9ILYiyiJ3gYrPIn5FIZrW7MCQX4h8k0bEjWUwH5kF3dZpEvIT2ssyIu12fGzXkYaNQcJEb5D9gT1mNyi2dxQ62NPZ5orfYyIZ7fn22d1P/jegG+7LQeXPiy5NLE6b7MP5Rq2dL8Y9Oi8pOBtoY9BpLh7saSBbNFXTBtH/8OfAQacxDsZD/zTFtCzZjtTK6yiAaXCZTvMIOuoYGZvEk6zWXrjVsU8FlqF+4JOTfePqr/SSUXNJyKnrvQJ1BfHQiYsrckw==" + ]; + }; + + nix.settings = { + trusted-users = ["infra"]; + allowed-users = ["infra"]; + }; + }; +} diff --git a/systems/x86_64-linux/axol/default.nix b/systems/x86_64-linux/axol/default.nix new file mode 100644 index 0000000..f05e001 --- /dev/null +++ b/systems/x86_64-linux/axol/default.nix @@ -0,0 +1,42 @@ +{ + pkgs, + modulesPath, + ... +}: { + imports = [ + (modulesPath + "/virtualisation/digital-ocean-config.nix") + ]; + + boot.loader.grub.enable = true; + + virtualisation.digitalOcean.rebuildFromUserData = false; + + networking.firewall.allowedTCPPorts = [ + 80 + 443 + ]; + + environment.systemPackages = with pkgs; [ + neovim + ]; + + auxolotl = { + nix.enable = true; + + users.infra.enable = true; + + security = { + acme = { + enable = true; + email = "jake.hamilton@hey.com"; + staging = true; + }; + }; + + services = { + website.enable = true; + }; + }; + + system.stateVersion = "23.11"; +}