Compare commits
	
		
			94 commits
		
	
	
		
			17a6c48cf6
			...
			8c7ee15bcc
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 8c7ee15bcc | ||
| f67c012dfe | |||
| 0e7eef5ea2 | |||
| 89d25fa7a5 | |||
| 5134bab2d2 | |||
| 51c3ec754f | |||
| 7c88d47fb8 | |||
| f4f1ecdf71 | |||
| 5699ca8ba6 | |||
| 37aac118ce | |||
| 6ef263f53e | |||
| 6e260b3bdc | |||
| a8dcc9f298 | |||
| 22c7c3091f | |||
| 37590599ad | |||
| 80f38ff7bc | |||
| 746fddcbbb | |||
| 243ff8f070 | |||
| b04b3c457f | |||
| da25f9221a | |||
| 5bc7f954bd | |||
| e4c891b284 | |||
| 104827746a | |||
| 2beb64af83 | |||
| d2638845d0 | |||
| fca563a987 | |||
| 9f471327df | |||
| 0749bda96c | |||
| 9888ae0d07 | |||
| dbba09de45 | |||
| 17611b7e53 | |||
| dd56774f34 | |||
| 8a075bb837 | |||
| 7c8b26c07c | |||
| 40ae3db164 | |||
| 6d0c8caf57 | |||
| ba8c1d9d9c | |||
| 1e8174799b | |||
| 67eddccc40 | |||
| 4bef70a2ab | |||
| 6efe45a88b | |||
| 09764eeab9 | |||
| 6e7e0e5ef7 | |||
| 9c7b370447 | |||
| 60ec9aab2a | |||
| 18559dab54 | |||
| f56c00eb59 | |||
| fe6d68446b | |||
| c8d9b1c669 | |||
| 3bc484754f | |||
| da127445bc | |||
| 8ad1457763 | |||
| fe0c69f6d9 | |||
| aad7a984c2 | |||
| 62eea1bf8a | |||
| 2ffab40687 | |||
| 47bca471da | |||
| c2f820b85d | |||
| 771708c557 | |||
| f1c0d29df9 | |||
| 18b03924ad | |||
| d8320bc287 | |||
| e300ff517d | |||
| ae90b3e362 | |||
| f9f096cff8 | |||
| 69cad1592e | |||
| 40ec7e9c8c | |||
| 8a53b5242b | |||
| accb4d4c81 | |||
| fc29873949 | |||
| 2c5046ab0e | |||
| be057fb93b | |||
| bd478eb32b | |||
| 3765a7e049 | |||
| 94e5356886 | |||
| 74bf29bb75 | |||
| 56d125a5b0 | |||
| 95389bb615 | |||
| 1c614ff3b8 | |||
| 84ba26d187 | |||
| 07fa942989 | |||
| b78d341d95 | |||
| e61ff7c039 | |||
| 9803e69e3f | |||
| 435d9c861a | |||
| fc2acc13d8 | |||
| 9c08267fce | |||
| 81ae2df87b | |||
| 7ac8ec85cc | |||
| a888540580 | |||
| 4b77808f3f | |||
| e51fca5f0e | |||
| c323453234 | |||
| 3ae51fa545 | 
					 63 changed files with 1738 additions and 1443 deletions
				
			
		
							
								
								
									
										16
									
								
								.forgejo/workflows/ci.yaml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								.forgejo/workflows/ci.yaml
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,16 @@ | |||
| on: | ||||
|   pull_request: | ||||
|     types: | ||||
|       - opened | ||||
|       - synchronize | ||||
|       - reopened | ||||
|   push: | ||||
|     branches: | ||||
|       - main | ||||
| 
 | ||||
| jobs: | ||||
|   check-pre-commit: | ||||
|     runs-on: native | ||||
|     steps: | ||||
|       - uses: actions/checkout@v4 | ||||
|       - run: nix build .#checks.x86_64-linux.pre-commit -L | ||||
							
								
								
									
										12
									
								
								services/.gitignore → .gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								services/.gitignore → .gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -1,9 +1,15 @@ | |||
| .DS_Store | ||||
| .idea | ||||
| *.log | ||||
| tmp/ | ||||
| *.iso | ||||
| .proxmox | ||||
| /.pre-commit-config.yaml | ||||
| nixos.qcow2 | ||||
| result* | ||||
| .envrc | ||||
| .direnv | ||||
| result* | ||||
| .nixos-test-history | ||||
| *screenshot.png | ||||
| output | ||||
| todo | ||||
| 
 | ||||
| /.pre-commit-config.yaml | ||||
							
								
								
									
										29
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										29
									
								
								README.md
									
										
									
									
									
								
							|  | @ -1,2 +1,29 @@ | |||
| # Fediversity | ||||
| # The Fediversity project | ||||
| 
 | ||||
| This repository contains all the code and code-related files having to do with | ||||
| [the Fediversity project](https://fediversity.eu/), with the notable exception | ||||
| of [NixOps4 that is hosted on GitHub](https://github.com/nixops4/nixops4). | ||||
| 
 | ||||
| ## Content of this repository | ||||
| 
 | ||||
| Most of the directories in this repository have their own README going into more | ||||
| details as to what they are for. As an overview: | ||||
| 
 | ||||
| - [`deployment/`](./deployment) contains bits and pieces having to do with | ||||
|   auto-deployment of test VMs on a private Proxmox. | ||||
| 
 | ||||
| - [`infra/`](./infra) contains the configurations for the various VMs that are | ||||
|   in production for the project, for instance the Git instances or the Wiki. | ||||
| 
 | ||||
| - [`matrix/`](./matrix) contains everything having to do with setting up a | ||||
|   fully-featured Matrix server. | ||||
| 
 | ||||
| - [`server/`](./server) contains the configuration of the VM hosting the | ||||
|   website. This should be integrated into `infra/` shortly in the future, as | ||||
|   tracked in https://git.fediversity.eu/Fediversity/Fediversity/issues/31. | ||||
| 
 | ||||
| - [`services/`](./services) contains our effort to make Fediverse applications | ||||
|   work seemlessly together in our specific setting. | ||||
| 
 | ||||
| - [`website/`](./website) contains the framework and the content of [the | ||||
|   Fediversity website](https://fediversity.eu/) | ||||
|  |  | |||
							
								
								
									
										8
									
								
								deployment/.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								deployment/.gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -1,8 +0,0 @@ | |||
| .DS_Store | ||||
| .idea | ||||
| *.log | ||||
| tmp/ | ||||
| *.iso | ||||
| result | ||||
| .proxmox | ||||
| .pre-commit-config.yaml | ||||
							
								
								
									
										129
									
								
								deployment/flake-part.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								deployment/flake-part.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,129 @@ | |||
| { inputs, self, ... }: | ||||
| 
 | ||||
| let | ||||
|   allVmIds = # 100 -- 255 | ||||
|     let | ||||
|       allVmIdsFrom = x: if x > 255 then [ ] else [ x ] ++ allVmIdsFrom (x + 1); | ||||
|     in | ||||
|     allVmIdsFrom 100; | ||||
| 
 | ||||
|   makeInstaller = import ./makeInstaller.nix; | ||||
| 
 | ||||
| in | ||||
| { | ||||
|   flake.nixosConfigurations.provisioning = | ||||
|     let | ||||
|       inherit (builtins) map listToAttrs; | ||||
|       makeProvisioningConfiguration = | ||||
|         vmid: | ||||
|         inputs.nixpkgs.lib.nixosSystem { | ||||
|           modules = [ | ||||
|             { procolix.vmid = vmid; } | ||||
|             ./procolixVm.nix | ||||
|             inputs.disko.nixosModules.default | ||||
|           ]; | ||||
|         }; | ||||
|     in | ||||
|     listToAttrs ( | ||||
|       map (vmid: { | ||||
|         name = "fedi${toString vmid}"; | ||||
|         value = makeProvisioningConfiguration vmid; | ||||
|       }) allVmIds | ||||
|     ); | ||||
| 
 | ||||
|   flake.isoInstallers.provisioning = | ||||
|     let | ||||
|       inherit (builtins) mapAttrs; | ||||
|     in | ||||
|     mapAttrs ( | ||||
|       vmname: | ||||
|       makeInstaller { | ||||
|         inherit (inputs) nixpkgs; | ||||
|         hostKeys = { | ||||
|           rsa = { | ||||
|             private = ./hostKeys/${vmname}/ssh_host_rsa_key; | ||||
|             public = ./hostKeys/${vmname}/ssh_host_rsa_key.pub; | ||||
|           }; | ||||
|           ed25519 = { | ||||
|             private = ./hostKeys/${vmname}/ssh_host_ed25519_key; | ||||
|             public = ./hostKeys/${vmname}/ssh_host_ed25519_key.pub; | ||||
|           }; | ||||
|         }; | ||||
|       } | ||||
|     ) self.nixosConfigurations.provisioning; | ||||
| 
 | ||||
|   nixops4Deployments.feditest = | ||||
|     { providers, ... }: | ||||
| 
 | ||||
|     let | ||||
|       inherit (builtins) readFile; | ||||
| 
 | ||||
|       makeProcolixVmResource = vmid: vmconfig: { | ||||
|         type = providers.local.exec; | ||||
|         imports = [ inputs.nixops4-nixos.modules.nixops4Resource.nixos ]; | ||||
|         ssh.opts = ""; | ||||
|         ssh.host = "95.215.187.${toString vmid}"; | ||||
|         ssh.hostPublicKey = readFile ./hostKeys/fedi${toString vmid}/ssh_host_ed25519_key.pub; | ||||
| 
 | ||||
|         nixpkgs = inputs.nixpkgs; | ||||
|         nixos.module = { | ||||
|           imports = [ | ||||
|             vmconfig | ||||
|             { procolix.vmid = vmid; } | ||||
|             ./procolixVm.nix | ||||
|             inputs.snf.nixosModules.fediversity | ||||
|             inputs.disko.nixosModules.default | ||||
|           ]; | ||||
|         }; | ||||
|       }; | ||||
| 
 | ||||
|     in | ||||
|     { | ||||
|       providers.local = inputs.nixops4-nixos.modules.nixops4Provider.local; | ||||
| 
 | ||||
|       resources = { | ||||
|         fedi100 = makeProcolixVmResource 100 { }; | ||||
| 
 | ||||
|         fedi101 = makeProcolixVmResource 101 { | ||||
|           fediversity = { | ||||
|             enable = true; | ||||
|             domain = "fedi101.abundos.eu"; | ||||
|             pixelfed.enable = true; | ||||
|           }; | ||||
|         }; | ||||
| 
 | ||||
|         fedi102 = makeProcolixVmResource 102 { | ||||
|           fediversity = { | ||||
|             enable = true; | ||||
|             domain = "fedi102.abundos.eu"; | ||||
|             mastodon.enable = true; | ||||
| 
 | ||||
|             temp.cores = 1; # FIXME: should come from NixOps4 eventually | ||||
|           }; | ||||
|         }; | ||||
| 
 | ||||
|         fedi103 = makeProcolixVmResource 103 ( | ||||
|           { pkgs, ... }: | ||||
|           { | ||||
|             fediversity = { | ||||
|               enable = true; | ||||
|               domain = "fedi103.abundos.eu"; | ||||
|               peertube.enable = true; | ||||
| 
 | ||||
|               temp.peertubeSecretsFile = pkgs.writeText "secret" '' | ||||
|                 574e093907d1157ac0f8e760a6deb1035402003af5763135bae9cbd6abe32b24 | ||||
|               ''; | ||||
|             }; | ||||
|           } | ||||
|         ); | ||||
| 
 | ||||
|         fedi120 = makeProcolixVmResource 120 { | ||||
|           fediversity = { | ||||
|             enable = true; | ||||
|             domain = "fedi120.abundos.eu"; | ||||
|             pixelfed.enable = true; | ||||
|           }; | ||||
|         }; | ||||
|       }; | ||||
|     }; | ||||
| } | ||||
|  | @ -1,184 +0,0 @@ | |||
| { | ||||
|   inputs = { | ||||
|     nixpkgs.url = "github:nixos/nixpkgs/nixos-24.05"; | ||||
|     flake-parts.url = "github:hercules-ci/flake-parts"; | ||||
|     git-hooks.url = "github:cachix/git-hooks.nix"; | ||||
| 
 | ||||
|     # snf.url = "path:/home/niols/git/fediversity/simple-nixos-fediverse"; #dev | ||||
|     snf.url = "git+https://git.fediversity.eu/fediversity/simple-nixos-fediverse.git"; | ||||
|     disko.url = "github:nix-community/disko"; | ||||
| 
 | ||||
|     nixops4.url = "github:nixops4/nixops4"; | ||||
|     nixops4-nixos.url = "github:nixops4/nixops4/eval"; | ||||
|   }; | ||||
| 
 | ||||
|   outputs = | ||||
|     inputs@{ | ||||
|       self, | ||||
|       flake-parts, | ||||
|       nixpkgs, | ||||
|       snf, | ||||
|       ... | ||||
|     }: | ||||
|     flake-parts.lib.mkFlake { inherit inputs; } { | ||||
| 
 | ||||
|       imports = [ | ||||
|         inputs.nixops4-nixos.modules.flake.default | ||||
|         inputs.git-hooks.flakeModule | ||||
|       ]; | ||||
| 
 | ||||
|       systems = [ | ||||
|         "x86_64-linux" | ||||
|         "aarch64-linux" | ||||
|         "aarch64-darwin" | ||||
|         "x86_64-darwin" | ||||
|       ]; | ||||
| 
 | ||||
|       perSystem = | ||||
|         { | ||||
|           config, | ||||
|           inputs', | ||||
|           pkgs, | ||||
|           ... | ||||
|         }: | ||||
|         { | ||||
|           formatter = pkgs.nixfmt-rfc-style; | ||||
| 
 | ||||
|           pre-commit.settings.hooks = { | ||||
|             nixfmt-rfc-style.enable = true; | ||||
|             deadnix.enable = true; | ||||
|           }; | ||||
| 
 | ||||
|           devShells.default = pkgs.mkShell { | ||||
|             packages = [ inputs'.nixops4.packages.default ]; | ||||
|             shellHook = config.pre-commit.installationScript; | ||||
|           }; | ||||
|         }; | ||||
| 
 | ||||
|       flake.vmIdTo03d = | ||||
|         id: | ||||
|         let | ||||
|           sid = toString id; | ||||
|         in | ||||
|         if id >= 0 && id <= 9 then | ||||
|           "00${sid}" | ||||
|         else if id >= 10 && id <= 99 then | ||||
|           "0${sid}" | ||||
|         else | ||||
|           sid; | ||||
| 
 | ||||
|       flake.allVmIds = # 100 -- 255 | ||||
|         let | ||||
|           allVmIdsFrom = x: if x > 255 then [ ] else [ x ] ++ allVmIdsFrom (x + 1); | ||||
|         in | ||||
|         allVmIdsFrom 100; | ||||
| 
 | ||||
|       flake.nixosConfigurations.provisioning = | ||||
|         let | ||||
|           inherit (builtins) map listToAttrs; | ||||
|           makeProvisioningConfiguration = | ||||
|             vmid: | ||||
|             nixpkgs.lib.nixosSystem { | ||||
|               modules = [ | ||||
|                 { procolix.vmid = vmid; } | ||||
|                 ./procolixVm.nix | ||||
|                 inputs.disko.nixosModules.default | ||||
|               ]; | ||||
|             }; | ||||
|         in | ||||
|         listToAttrs ( | ||||
|           map (vmid: { | ||||
|             name = "fedi${self.vmIdTo03d vmid}"; | ||||
|             value = makeProvisioningConfiguration vmid; | ||||
|           }) self.allVmIds | ||||
|         ); | ||||
| 
 | ||||
|       flake.isoInstallers.provisioning = | ||||
|         let | ||||
|           inherit (builtins) mapAttrs; | ||||
|         in | ||||
|         mapAttrs ( | ||||
|           vmname: | ||||
|           snf.mkInstaller { | ||||
|             inherit nixpkgs; | ||||
|             hostKeys = { | ||||
|               rsa = { | ||||
|                 private = ./hostKeys/${vmname}/ssh_host_rsa_key; | ||||
|                 public = ./hostKeys/${vmname}/ssh_host_rsa_key.pub; | ||||
|               }; | ||||
|               ed25519 = { | ||||
|                 private = ./hostKeys/${vmname}/ssh_host_ed25519_key; | ||||
|                 public = ./hostKeys/${vmname}/ssh_host_ed25519_key.pub; | ||||
|               }; | ||||
|             }; | ||||
|           } | ||||
|         ) self.nixosConfigurations.provisioning; | ||||
| 
 | ||||
|       nixops4Deployments.default = | ||||
|         { providers, ... }: | ||||
| 
 | ||||
|         let | ||||
|           inherit (builtins) readFile; | ||||
| 
 | ||||
|           makeProcolixVmResource = vmid: vmconfig: { | ||||
|             type = providers.local.exec; | ||||
|             imports = [ inputs.nixops4-nixos.modules.nixops4Resource.nixos ]; | ||||
|             ssh.opts = ""; | ||||
|             ssh.host = "95.215.187.${self.vmIdTo03d vmid}"; | ||||
|             ssh.hostPublicKey = readFile ./hostKeys/fedi${self.vmIdTo03d vmid}/ssh_host_ed25519_key.pub; | ||||
| 
 | ||||
|             nixpkgs = inputs.nixpkgs; | ||||
|             nixos.module = { | ||||
|               imports = [ | ||||
|                 vmconfig | ||||
|                 { procolix.vmid = vmid; } | ||||
|                 ./procolixVm.nix | ||||
|                 inputs.snf.nixosModules.fediversity | ||||
|                 inputs.disko.nixosModules.default | ||||
|               ]; | ||||
|             }; | ||||
|           }; | ||||
| 
 | ||||
|         in | ||||
|         { | ||||
|           providers.local = inputs.nixops4-nixos.modules.nixops4Provider.local; | ||||
| 
 | ||||
|           resources = { | ||||
|             fedi100 = makeProcolixVmResource 100 { }; | ||||
| 
 | ||||
|             fedi101 = makeProcolixVmResource 101 { | ||||
|               fediversity = { | ||||
|                 enable = true; | ||||
|                 domain = "fedi101.abundos.eu"; | ||||
|                 pixelfed.enable = true; | ||||
|               }; | ||||
|             }; | ||||
| 
 | ||||
|             fedi102 = makeProcolixVmResource 102 { | ||||
|               fediversity = { | ||||
|                 enable = true; | ||||
|                 domain = "fedi102.abundos.eu"; | ||||
|                 mastodon.enable = true; | ||||
| 
 | ||||
|                 temp.cores = 1; # FIXME: should come from NixOps4 eventually | ||||
|               }; | ||||
|             }; | ||||
| 
 | ||||
|             fedi103 = makeProcolixVmResource 103 ( | ||||
|               { pkgs, ... }: | ||||
|               { | ||||
|                 fediversity = { | ||||
|                   enable = true; | ||||
|                   domain = "fedi103.abundos.eu"; | ||||
|                   peertube.enable = true; | ||||
| 
 | ||||
|                   temp.peertubeSecretsFile = pkgs.writeText "secret" '' | ||||
|                     574e093907d1157ac0f8e760a6deb1035402003af5763135bae9cbd6abe32b24 | ||||
|                   ''; | ||||
|                 }; | ||||
|               } | ||||
|             ); | ||||
|           }; | ||||
|         }; | ||||
|     }; | ||||
| } | ||||
|  | @ -42,9 +42,7 @@ let | |||
|       }; | ||||
|     in | ||||
|     { | ||||
|       imports = [ | ||||
|         "${nixpkgs}/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix" | ||||
|       ]; | ||||
|       imports = [ "${nixpkgs}/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix" ]; | ||||
|       nixpkgs.hostPlatform = "x86_64-linux"; | ||||
|       services.getty.autologinUser = lib.mkForce "root"; | ||||
|       programs.bash.loginShellInit = nixpkgs.lib.getExe bootstrap; | ||||
|  | @ -8,18 +8,6 @@ | |||
| let | ||||
|   inherit (lib) mkOption; | ||||
|   inherit (lib.types) types; | ||||
| 
 | ||||
|   vmIdTo03d = | ||||
|     id: | ||||
|     let | ||||
|       sid = toString id; | ||||
|     in | ||||
|     if id >= 0 && id <= 9 then | ||||
|       "00${sid}" | ||||
|     else if id >= 10 && id <= 99 then | ||||
|       "0${sid}" | ||||
|     else | ||||
|       sid; | ||||
| in | ||||
| 
 | ||||
| { | ||||
|  | @ -30,7 +18,7 @@ in | |||
|       vmid = mkOption { | ||||
|         type = types.int; | ||||
|         description = '' | ||||
|           Identifier of the machine. This is a number between 10 and 255. | ||||
|           Identifier of the machine. This is a number between 100 and 255. | ||||
|         ''; | ||||
|       }; | ||||
|     }; | ||||
|  | @ -43,7 +31,7 @@ in | |||
|     services.openssh.enable = true; | ||||
| 
 | ||||
|     networking = { | ||||
|       hostName = "fedi${vmIdTo03d config.procolix.vmid}"; | ||||
|       hostName = "fedi${toString config.procolix.vmid}"; | ||||
|       domain = "procolix.com"; | ||||
| 
 | ||||
|       interfaces = { | ||||
|  | @ -51,7 +39,7 @@ in | |||
|           ipv4 = { | ||||
|             addresses = [ | ||||
|               { | ||||
|                 address = "95.215.187.${vmIdTo03d config.procolix.vmid}"; | ||||
|                 address = "95.215.187.${toString config.procolix.vmid}"; | ||||
|                 prefixLength = 24; | ||||
|               } | ||||
|             ]; | ||||
|  | @ -59,7 +47,7 @@ in | |||
|           ipv6 = { | ||||
|             addresses = [ | ||||
|               { | ||||
|                 address = "2a00:51c0:13:1305::${vmIdTo03d config.procolix.vmid}"; | ||||
|                 address = "2a00:51c0:13:1305::${toString config.procolix.vmid}"; | ||||
|                 prefixLength = 64; | ||||
|               } | ||||
|             ]; | ||||
|  |  | |||
|  | @ -1,223 +0,0 @@ | |||
| #!/usr/bin/env sh | ||||
| set -euC | ||||
| 
 | ||||
| ## Proxmox API doc: https://pve.proxmox.com/pve-docs/api-viewer | ||||
| 
 | ||||
| ################################################################################ | ||||
| ## Parse arguments | ||||
| 
 | ||||
| username= | ||||
| password= | ||||
| iso=result/iso/installer.iso | ||||
| sockets=1 | ||||
| cores=1 | ||||
| memory=2048 | ||||
| vmid= | ||||
| 
 | ||||
| help () { | ||||
|   cat <<EOF | ||||
| Usage: $0 [OPTION...] | ||||
| 
 | ||||
| Required: | ||||
|   --username STR    Username, with provider (eg. niols@pve) | ||||
|   --password STR    Password | ||||
|   --vmid INT        Identifier of the VM | ||||
| 
 | ||||
|   If not provided via the command line, username and password will be looked for | ||||
|   in a `.proxmox` file in the current working directory, the username on the | ||||
|   first line, and the password on the second. | ||||
| 
 | ||||
| Optional: | ||||
|   --iso PATH        Installer ISO (default: $iso) | ||||
|   --sockets INT     Number of sockets (default: $sockets) | ||||
|   --cores INT       Number of cores (default: $cores) | ||||
|   --memory INT      Memory (default: $memory) | ||||
| 
 | ||||
| Others: | ||||
|   -h|-?|--help      Show this help and exit | ||||
| EOF | ||||
| } | ||||
| 
 | ||||
| die () { printf "$@"; printf '\n'; help; exit 2; } | ||||
| 
 | ||||
| while [ $# -gt 0 ]; do | ||||
|   argument=$1 | ||||
|   shift | ||||
|   case $argument in | ||||
|     --username) readonly username=$1; shift ;; | ||||
|     --password) readonly password=$1; shift ;; | ||||
|     --vmid) readonly vmid=$1; shift ;; | ||||
| 
 | ||||
|     --iso) iso=$1; shift ;; | ||||
|     --sockets) sockets=$1; shift ;; | ||||
|     --cores) cores=$1; shift ;; | ||||
|     --memory) memory=$1; shift ;; | ||||
| 
 | ||||
|     -h|-\?|--help) help; exit 0 ;; | ||||
|     *) die 'Unknown argument: `%s`.' "$argument" ;; | ||||
|   esac | ||||
| done | ||||
| 
 | ||||
| if [ -z "$username" ] || [ -z "$password" ]; then | ||||
|   if [ -f .proxmox ]; then | ||||
|     { read username; read password; } < .proxmox | ||||
|   else | ||||
|     die 'Required: `--username` and `--password`.\n' | ||||
|   fi | ||||
| fi | ||||
| 
 | ||||
| [ -z "$vmid" ] && die 'Required: `--vmid`.\n' | ||||
| 
 | ||||
| printf 'Configuration:\n' | ||||
| 
 | ||||
| printf '  username: %s\n' $username | ||||
| printf '  password: %s\n' $password | ||||
| printf '  vmid: %s\n' $vmid | ||||
| 
 | ||||
| readonly iso | ||||
| readonly sockets | ||||
| readonly cores | ||||
| readonly memory | ||||
| 
 | ||||
| printf '  iso: %s\n' $iso | ||||
| printf '  sockets: %d\n' $sockets | ||||
| printf '  cores: %d\n' $cores | ||||
| printf '  memory: %d\n' $memory | ||||
| 
 | ||||
| ################################################################################ | ||||
| ## Getting started | ||||
| 
 | ||||
| readonly apiurl=https://192.168.51.81:8006/api2/json | ||||
| 
 | ||||
| ## FIXME: There seems to be a problem with file upload where the task is | ||||
| ## registered to `node051` no matter what node we are actually uploading to? For | ||||
| ## now, let us just use `node051` everywhere. | ||||
| node=node051 | ||||
| 
 | ||||
| from_response () { echo "$response" | jq -r "$1"; } | ||||
| 
 | ||||
| printf 'Authenticating...' | ||||
| response=$( | ||||
|     http \ | ||||
|         --verify no \ | ||||
|         POST $apiurl/access/ticket \ | ||||
|         "username=$username" \ | ||||
|         "password=$password" | ||||
|     ) | ||||
| readonly csrfToken=$(from_response .data.CSRFPreventionToken) | ||||
| readonly ticket=$(from_response .data.ticket) | ||||
| printf ' done.\n' | ||||
| 
 | ||||
| http_ () { | ||||
|   response=$( | ||||
|     http \ | ||||
|       --verify no \ | ||||
|       "$@" \ | ||||
|       "Cookie:PVEAuthCookie=$ticket" \ | ||||
|       "CSRFPreventionToken:$csrfToken" | ||||
|   ) | ||||
| } | ||||
| 
 | ||||
| wait_ () { | ||||
|   upid=$1 | ||||
|   while :; do | ||||
|     http_ GET $apiurl/nodes/$node/tasks/$upid/status | ||||
|     status=$(from_response .data.status) | ||||
|     case $status in | ||||
|       running) printf '.'; sleep 1 ;; | ||||
|       stopped) break ;; | ||||
|       *) printf ' unexpected status: `%s`\n' "$status"; exit 2 ;; | ||||
|     esac | ||||
|   done | ||||
| } | ||||
| 
 | ||||
| ################################################################################ | ||||
| ## Upload ISO | ||||
| 
 | ||||
| if [ -z "$node" ]; then | ||||
|   printf 'Picking random node...' | ||||
|   http_ GET $apiurl/nodes | ||||
|   node=$(from_response .data[].node | sort -R | head -n 1) | ||||
|   printf ' done. Picked `%s`.\n' "$node" | ||||
| fi | ||||
| readonly node | ||||
| 
 | ||||
| absiso=$(cd "$(dirname "$iso")"; pwd)/$(basename "$iso") | ||||
| readonly isoname=installer-$vmid.iso | ||||
| 
 | ||||
| printf 'Uploading ISO...' | ||||
| ln -sf $absiso /tmp/$isoname | ||||
| http_ --form POST $apiurl/nodes/$node/storage/local/upload \ | ||||
|   filename@/tmp/$isoname \ | ||||
|   content==iso | ||||
| rm /tmp/$isoname | ||||
| wait_ $(from_response .data) | ||||
| printf ' done.\n' | ||||
| 
 | ||||
| ################################################################################ | ||||
| ## Create VM | ||||
| 
 | ||||
| printf 'Creating VM...' | ||||
| 
 | ||||
| http_ --form POST $apiurl/nodes/$node/qemu \ | ||||
|   \ | ||||
|   vmid==$vmid \ | ||||
|   name==$(printf 'fedi%03d' $vmid) \ | ||||
|   pool==Fediversity \ | ||||
|   \ | ||||
|   ide2=="local:iso/$isoname,media=cdrom" \ | ||||
|   ostype==l26 \ | ||||
|   \ | ||||
|   bios==ovmf \ | ||||
|   efidisk0=='linstor_storage:1,efitype=4m' \ | ||||
|   agent==1 \ | ||||
|   \ | ||||
|   scsihw==virtio-scsi-single \ | ||||
|   scsi0=='linstor_storage:32,discard=on,ssd=on,iothread=on' \ | ||||
|   \ | ||||
|   sockets==$sockets \ | ||||
|   cores==$cores \ | ||||
|   cpu==x86-64-v2-AES \ | ||||
|   numa==1 \ | ||||
|   \ | ||||
|   memory==$memory \ | ||||
|   \ | ||||
|   net0=='virtio,bridge=vnet1306' | ||||
| 
 | ||||
| wait_ $(from_response .data) | ||||
| printf ' done.\n' | ||||
| 
 | ||||
| ################################################################################ | ||||
| ## Install VM | ||||
| 
 | ||||
| printf 'Installing VM...' | ||||
| 
 | ||||
| http_ POST $apiurl/nodes/$node/qemu/$vmid/status/start | ||||
| wait_ $(from_response .data) | ||||
| 
 | ||||
| while :; do | ||||
|   http_ GET $apiurl/nodes/$node/qemu/$vmid/status/current | ||||
|   status=$(from_response .data.status) | ||||
|   case $status in | ||||
|     running) printf '.'; sleep 1 ;; | ||||
|     stopped) break ;; | ||||
|     *) printf ' unexpected status: `%s`\n' "$status"; exit 2 ;; | ||||
|   esac | ||||
| done | ||||
| 
 | ||||
| printf 'done.\n' | ||||
| 
 | ||||
| ################################################################################ | ||||
| ## Start VM | ||||
| 
 | ||||
| printf 'Starting VM...' | ||||
| 
 | ||||
| http_ --form POST $apiurl/nodes/$node/qemu/$vmid/config \ | ||||
|   ide2=='none,media=cdrom' \ | ||||
|   net0=='virtio,bridge=vnet1305' | ||||
| wait_ $(from_response .data) | ||||
| 
 | ||||
| http_ POST $apiurl/nodes/$node/qemu/$vmid/status/start | ||||
| wait_ $(from_response .data) | ||||
| 
 | ||||
| printf 'done.\n' | ||||
|  | @ -1,14 +1,22 @@ | |||
| #+title: Provisioning a Proxmox VM | ||||
| #+author: Kevin Muller, Hans van Zijst & Nicolas Jeannerod | ||||
| #+date: <2024-10-25 Fri> | ||||
| #+title: Provisioning VMs via Proxmox | ||||
| 
 | ||||
| * Fediversity Proxmox | ||||
| - http://192.168.51.81:8006/. | ||||
| - It is only accessible via Procolix's VPN; see with Kevin. | ||||
| - You will need identifiers. Also see with Kevin. Select “Promox VE authentication server”. | ||||
| - Ignore “You do not have a valid subscription” message. | ||||
| * Quick links | ||||
| - Proxmox API doc :: https://pve.proxmox.com/pve-docs/api-viewer | ||||
| - Fediversity Proxmox :: | ||||
|   - http://192.168.51.81:8006/. | ||||
|   - It is only accessible via Procolix's VPN; see with Kevin. | ||||
|   - You will need identifiers. Also see with Kevin. Select “Promox VE authentication server”. | ||||
|   - Ignore “You do not have a valid subscription” message. | ||||
| * Basic terminology | ||||
| - Node :: physical host | ||||
| * Automatically | ||||
| This directory contains scripts that can automatically provision or remove a | ||||
| Proxmox VM. For now, they are tied to one node in the Fediversity Proxmox, but | ||||
| it would not be difficult to make them more generic. Try: | ||||
| #+begin_src sh | ||||
| sh provision.sh --help | ||||
| sh remove.sh --help | ||||
| #+end_src | ||||
| * Preparing the machine configuration | ||||
| - It is nicer if the machine is a QEMU guest. On NixOS: | ||||
|   #+begin_src nix | ||||
|  | @ -23,46 +31,47 @@ | |||
|   ~2a00:51c0:13:1305::XXX~. | ||||
| - Name servers should be ~95.215.185.6~ and ~95.215.185.7~. | ||||
| - Check [[https://netbox.protagio.org][Netbox]] to see which addresses are free. | ||||
| * Upload your ISO | ||||
| * Manually via the GUI | ||||
| ** Upload your ISO | ||||
| - Go to Fediversity proxmox. | ||||
| - In the left view, expand under the node that you want and click on “local”. | ||||
| - Select “ISO Images”, then click “Upload”. | ||||
| - Note: You can also download from URL. | ||||
| - Note: You should click on “local” and not “local-zfs”. | ||||
| * Creating the VM | ||||
| ** Creating the VM | ||||
| - Click “Create VM” at the top right corner. | ||||
| ** General | ||||
| *** General | ||||
| - Node :: which node will host the VM; has to be the same | ||||
| - VM ID :: Has to be unique, probably best to use the "xxxx" in "vm0xxxx" (yet to be decided) | ||||
| - Name :: Usually "vm" + 5 digits, e.g. "vm02199" | ||||
| - Resource pool :: Fediversity | ||||
| ** OS | ||||
| *** OS | ||||
| - Use CD/DVD disc image file (iso) :: | ||||
|   - Storage :: local, means storage of the node. | ||||
|   - ISO image :: select the image previously uploaded | ||||
| No need to touch anything else | ||||
| ** System | ||||
| *** System | ||||
| - BIOS :: OVMF (UEFI) | ||||
| - EFI Storage ::  ~linstor_storage~; this is a storage shared by all of the Proxmox machines. | ||||
| - Pre-Enroll keys :: MUST be unchecked | ||||
| - Qemu Agent :: check | ||||
| ** Disks | ||||
| *** Disks | ||||
| - Tick “advanced” at the bottom. | ||||
| - Disk size (GiB) :: 40 (depending on requirements) | ||||
| - SSD emulation :: check (only visible if “Advanced” is checked) | ||||
| - Discard :: check, so that blocks of removed data are cleared | ||||
| ** CPU | ||||
| *** CPU | ||||
| - Sockets :: 1 (depending on requirements) | ||||
| - Cores :: 2 (depending on requirements) | ||||
| - Enable NUMA :: check | ||||
| ** Memory | ||||
| *** Memory | ||||
| - Memory (MiB) :: choose what you want | ||||
| - Ballooning Device :: leave checked (only visible if “Advanced” is checked) | ||||
| ** Network | ||||
| *** Network | ||||
| - Bridge :: ~vnet1306~. This is the provisioning bridge; we will change it later. | ||||
| - Firewall :: uncheck, we will handle the firewall on the VM itself | ||||
| ** Confirm | ||||
| * Install and start the VM | ||||
| *** Confirm | ||||
| ** Install and start the VM | ||||
| - Start the VM a first time. | ||||
|   - Select the VM in the left panel. You might have to expand the node on which it is hosted. | ||||
|   - Select “Console” and start the VM. | ||||
|  | @ -73,18 +82,18 @@ No need to touch anything else | |||
|   - Double click on the CD/DVD Drive line. Select “Do not use any media” and press OK. | ||||
|   - Double click on Network Device, and change the bridge to ~vnet1305~, the public bridge. | ||||
| - Start the VM again. | ||||
| * Remove the VM | ||||
| ** Remove the VM | ||||
| - [[Shutdown the VM]]. | ||||
| - On the top right corner, click “More”, then “Remove”. | ||||
| - Enter the ID of the machine. | ||||
| - Check “Purge from job configurations” | ||||
| - Check “Destroy unreferenced disks owned by guest” | ||||
| - Click “Remove”. | ||||
| * Move the VM to another node | ||||
| ** Move the VM to another node | ||||
| - Make sure there is no ISO plugged in. | ||||
| - Click on the VM. Click migrate. Choose target node. Go. | ||||
| - Since the storage is shared, it should go pretty fast (~1 minute). | ||||
| * Shutdown the VM | ||||
| ** Shutdown the VM | ||||
| - Find the VM in the left panel. | ||||
| - At the top right corner appears a “Shutdown” button with a submenu. | ||||
| - Clicking “Shutdown” sends a signal to shutdown the machine. This might not work if the machine is not listening for that signal. | ||||
							
								
								
									
										281
									
								
								deployment/proxmox/provision.sh
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										281
									
								
								deployment/proxmox/provision.sh
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,281 @@ | |||
| #!/usr/bin/env sh | ||||
| set -euC | ||||
| 
 | ||||
| ################################################################################ | ||||
| ## Constants | ||||
| 
 | ||||
| readonly apiurl=https://192.168.51.81:8006/api2/json | ||||
| 
 | ||||
| ## FIXME: There seems to be a problem with file upload where the task is | ||||
| ## registered to `node051` no matter what node we are actually uploading to? For | ||||
| ## now, let us just use `node051` everywhere. | ||||
| readonly node=node051 | ||||
| 
 | ||||
| readonly tmpdir=/tmp/proxmox-provision-$RANDOM$RANDOM | ||||
| mkdir $tmpdir | ||||
| 
 | ||||
| ################################################################################ | ||||
| ## Parse arguments | ||||
| 
 | ||||
| username= | ||||
| password= | ||||
| sockets=1 | ||||
| cores=1 | ||||
| memory=2048 | ||||
| vmids= | ||||
| 
 | ||||
| help () { | ||||
|   cat <<EOF | ||||
| Usage: $0 [OPTION...] [ID...] | ||||
| 
 | ||||
| Authentication options: | ||||
|   --username STR    Username, with provider (eg. niols@pve) | ||||
|   --password STR    Password | ||||
| 
 | ||||
|   If not provided via the command line, username and password will be looked for | ||||
|   in a '.proxmox' file in the current working directory, the username on the | ||||
|   first line, and the password on the second. | ||||
| 
 | ||||
| Other options: | ||||
|   --sockets INT     Number of sockets (default: $sockets) | ||||
|   --cores INT       Number of cores (default: $cores) | ||||
|   --memory INT      Memory (default: $memory) | ||||
| 
 | ||||
| Others: | ||||
|   -h|-?|--help      Show this help and exit | ||||
| EOF | ||||
| } | ||||
| 
 | ||||
| die () { printf '\033[31m'; printf "$@"; printf '\033[0m\n'; exit 2; } | ||||
| die_with_help () { printf '\033[31m'; printf "$@"; printf '\033[0m\n'; help; exit 2; } | ||||
| 
 | ||||
| while [ $# -gt 0 ]; do | ||||
|   argument=$1 | ||||
|   shift | ||||
|   case $argument in | ||||
|     --username) readonly username=$1; shift ;; | ||||
|     --password) readonly password=$1; shift ;; | ||||
| 
 | ||||
|     --sockets) sockets=$1; shift ;; | ||||
|     --cores) cores=$1; shift ;; | ||||
|     --memory) memory=$1; shift ;; | ||||
| 
 | ||||
|     -h|-\?|--help) help; exit 0 ;; | ||||
| 
 | ||||
|     -*) die_with_help 'Unknown argument: `%s`.' "$argument" ;; | ||||
| 
 | ||||
|     *) vmids="$vmids $argument" ;; | ||||
|   esac | ||||
| done | ||||
| 
 | ||||
| if [ -z "$username" ] || [ -z "$password" ]; then | ||||
|   if [ -f .proxmox ]; then | ||||
|     { read username; read password; } < .proxmox | ||||
|   else | ||||
|     die_with_help 'Required: `--username` and `--password`.\n' | ||||
|   fi | ||||
| fi | ||||
| 
 | ||||
| readonly sockets | ||||
| readonly cores | ||||
| readonly memory | ||||
| 
 | ||||
| ## FIXME: When we figure out how to use other nodes than node051. | ||||
| # if [ -z "$node" ]; then | ||||
| #   printf 'Picking random node...' | ||||
| #   proxmox GET $apiurl/nodes | ||||
| #   node=$(from_response .data[].node | sort -R | head -n 1) | ||||
| #   printf ' done. Picked `%s`.\n' "$node" | ||||
| # fi | ||||
| # readonly node | ||||
| 
 | ||||
| ################################################################################ | ||||
| ## Getting started | ||||
| 
 | ||||
| printf 'Authenticating...' | ||||
| response=$( | ||||
|     http \ | ||||
|         --verify no \ | ||||
|         POST $apiurl/access/ticket \ | ||||
|         "username=$username" \ | ||||
|         "password=$password" | ||||
|     ) | ||||
| readonly ticket=$(echo "$response" | jq -r .data.ticket) | ||||
| readonly csrfToken=$(echo "$response" | jq -r .data.CSRFPreventionToken) | ||||
| printf ' done.\n' | ||||
| 
 | ||||
| acquire_lock () { | ||||
|   until mkdir $tmpdir/lock-$1 2>/dev/null; do sleep 1; done | ||||
| } | ||||
| release_lock () { | ||||
|   rmdir $tmpdir/lock-$1 | ||||
| } | ||||
| 
 | ||||
| proxmox () { | ||||
|   acquire_lock proxmox | ||||
|   http \ | ||||
|     --form \ | ||||
|     --verify no \ | ||||
|     --ignore-stdin \ | ||||
|     "$@" \ | ||||
|     "Cookie:PVEAuthCookie=$ticket" \ | ||||
|     "CSRFPreventionToken:$csrfToken" | ||||
|   release_lock proxmox | ||||
| } | ||||
| 
 | ||||
| ## Synchronous variant for when the `proxmox` function would just respond an | ||||
| ## UPID in the `data` JSON field. | ||||
| proxmox_sync () ( | ||||
|   response=$(proxmox "$@") | ||||
|   upid=$(echo "$response" | jq -r .data) | ||||
| 
 | ||||
|   while :; do | ||||
|     response=$(proxmox GET $apiurl/nodes/$node/tasks/$upid/status) | ||||
|     status=$(echo "$response" | jq -r .data.status) | ||||
| 
 | ||||
|     case $status in | ||||
|       running) sleep 1 ;; | ||||
|       stopped) break ;; | ||||
|       *) die 'unexpected status: `%s`' "$status" ;; | ||||
|     esac | ||||
|   done | ||||
| ) | ||||
| 
 | ||||
| ################################################################################ | ||||
| ## Build ISO | ||||
| 
 | ||||
| build_iso () { | ||||
|   acquire_lock build | ||||
|   printf 'Building ISO for VM %d...\n' $1 | ||||
| 
 | ||||
|   nix build \ | ||||
|     .#isoInstallers.provisioning.fedi$1 \ | ||||
|     --log-format raw --quiet \ | ||||
|     --out-link $tmpdir/installer-fedi$1 | ||||
| 
 | ||||
|   ln -sf $tmpdir/installer-fedi$1/iso/installer.iso $tmpdir/installer-fedi$1.iso | ||||
| 
 | ||||
|   printf 'done building ISO for VM %d.\n' $1 | ||||
|   release_lock build | ||||
| } | ||||
| 
 | ||||
| ################################################################################ | ||||
| ## Upload ISO | ||||
| 
 | ||||
| upload_iso () { | ||||
|   acquire_lock upload | ||||
|   printf 'Uploading ISO for VM %d...\n' $1 | ||||
| 
 | ||||
|   proxmox_sync POST $apiurl/nodes/$node/storage/local/upload \ | ||||
|     filename@$tmpdir/installer-fedi$1.iso \ | ||||
|     content==iso | ||||
| 
 | ||||
|   printf 'done uploading ISO for VM %d.\n' $1 | ||||
|   release_lock upload | ||||
| } | ||||
| 
 | ||||
| ################################################################################ | ||||
| ## Remove ISO | ||||
| 
 | ||||
| remove_iso () { | ||||
|   printf 'Removing ISO for VM %d... unsupported for now. (FIXME)\n' $1 | ||||
| } | ||||
| 
 | ||||
| ################################################################################ | ||||
| ## Create VM | ||||
| 
 | ||||
| create_vm () { | ||||
|   printf 'Creating VM %d...\n' $1 | ||||
| 
 | ||||
|   proxmox_sync POST $apiurl/nodes/$node/qemu \ | ||||
|     \ | ||||
|     vmid==$1 \ | ||||
|     name=="fedi$1" \ | ||||
|     pool==Fediversity \ | ||||
|     \ | ||||
|     ide2=="local:iso/installer-fedi$1.iso,media=cdrom" \ | ||||
|     ostype==l26 \ | ||||
|     \ | ||||
|     bios==ovmf \ | ||||
|     efidisk0=='linstor_storage:1,efitype=4m' \ | ||||
|     agent==1 \ | ||||
|     \ | ||||
|     scsihw==virtio-scsi-single \ | ||||
|     scsi0=='linstor_storage:32,discard=on,ssd=on,iothread=on' \ | ||||
|     \ | ||||
|     sockets==$sockets \ | ||||
|     cores==$cores \ | ||||
|     cpu==x86-64-v2-AES \ | ||||
|     numa==1 \ | ||||
|     \ | ||||
|     memory==$memory \ | ||||
|     \ | ||||
|     net0=='virtio,bridge=vnet1306' | ||||
| 
 | ||||
|   printf 'done creating VM %d.\n' $1 | ||||
| } | ||||
| 
 | ||||
| ################################################################################ | ||||
| ## Install VM | ||||
| 
 | ||||
| install_vm () ( | ||||
|   printf 'Installing VM %d...\n' $1 | ||||
| 
 | ||||
|   proxmox_sync POST $apiurl/nodes/$node/qemu/$1/status/start | ||||
| 
 | ||||
|   while :; do | ||||
|     response=$(proxmox GET $apiurl/nodes/$node/qemu/$1/status/current) | ||||
|     status=$(echo "$response" | jq -r .data.status) | ||||
|     case $status in | ||||
|       running) sleep 1 ;; | ||||
|       stopped) break ;; | ||||
|       *) printf ' unexpected status: `%s`\n' "$status"; exit 2 ;; | ||||
|     esac | ||||
|   done | ||||
| 
 | ||||
|   printf 'done installing VM %d.\n' $1 | ||||
| ) | ||||
| 
 | ||||
| ################################################################################ | ||||
| ## Start VM | ||||
| 
 | ||||
| start_vm () { | ||||
|   printf 'Starting VM %d...\n' $1 | ||||
| 
 | ||||
|   proxmox_sync POST $apiurl/nodes/$node/qemu/$1/config \ | ||||
|     ide2=='none,media=cdrom' \ | ||||
|     net0=='virtio,bridge=vnet1305' | ||||
| 
 | ||||
|   proxmox_sync POST $apiurl/nodes/$node/qemu/$1/status/start | ||||
| 
 | ||||
|   printf 'done starting VM %d.\n' $1 | ||||
| } | ||||
| 
 | ||||
| ################################################################################ | ||||
| ## Main loop | ||||
| 
 | ||||
| printf 'Provisioning VMs%s with:\n' "$vmids" | ||||
| printf '  sockets: %d\n' $sockets | ||||
| printf '  cores: %d\n' $cores | ||||
| printf '  memory: %d\n' $memory | ||||
| 
 | ||||
| provision_vm () { | ||||
|   build_iso $1 | ||||
|   upload_iso $1 | ||||
|   create_vm $1 | ||||
|   install_vm $1 | ||||
|   start_vm $1 | ||||
|   remove_iso $1 | ||||
| } | ||||
| 
 | ||||
| for vmid in $vmids; do | ||||
|   provision_vm $vmid & | ||||
| done | ||||
| wait | ||||
| 
 | ||||
| printf 'done provisioning VMs%s.\n' "$vmids" | ||||
| 
 | ||||
| ################################################################################ | ||||
| ## Cleanup | ||||
| 
 | ||||
| rm -Rf $tmpdir | ||||
							
								
								
									
										163
									
								
								deployment/proxmox/remove.sh
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										163
									
								
								deployment/proxmox/remove.sh
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,163 @@ | |||
| #!/usr/bin/env sh | ||||
| set -euC | ||||
| 
 | ||||
| ################################################################################ | ||||
| ## Constants | ||||
| 
 | ||||
| readonly apiurl=https://192.168.51.81:8006/api2/json | ||||
| 
 | ||||
| ## FIXME: There seems to be a problem with file upload where the task is | ||||
| ## registered to `node051` no matter what node we are actually uploading to? For | ||||
| ## now, let us just use `node051` everywhere. | ||||
| readonly node=node051 | ||||
| 
 | ||||
| readonly tmpdir=/tmp/proxmox-provision-$RANDOM$RANDOM | ||||
| mkdir $tmpdir | ||||
| 
 | ||||
| ################################################################################ | ||||
| ## Parse arguments | ||||
| 
 | ||||
| username= | ||||
| password= | ||||
| vmids= | ||||
| 
 | ||||
| help () { | ||||
|   cat <<EOF | ||||
| Usage: $0 [OPTION...] [ID...] | ||||
| 
 | ||||
| Authentication options: | ||||
|   --username STR    Username, with provider (eg. niols@pve) | ||||
|   --password STR    Password | ||||
| 
 | ||||
|   If not provided via the command line, username and password will be looked for | ||||
|   in a '.proxmox' file in the current working directory, the username on the | ||||
|   first line, and the password on the second. | ||||
| 
 | ||||
| Others: | ||||
|   -h|-?|--help      Show this help and exit | ||||
| EOF | ||||
| } | ||||
| 
 | ||||
| die () { printf '\033[31m'; printf "$@"; printf '\033[0m\n'; exit 2; } | ||||
| die_with_help () { printf '\033[31m'; printf "$@"; printf '\033[0m\n'; help; exit 2; } | ||||
| 
 | ||||
| while [ $# -gt 0 ]; do | ||||
|   argument=$1 | ||||
|   shift | ||||
|   case $argument in | ||||
|     --username) readonly username=$1; shift ;; | ||||
|     --password) readonly password=$1; shift ;; | ||||
| 
 | ||||
|     -h|-\?|--help) help; exit 0 ;; | ||||
| 
 | ||||
|     -*) die_with_help 'Unknown argument: `%s`.' "$argument" ;; | ||||
| 
 | ||||
|     *) vmids="$vmids $argument" ;; | ||||
|   esac | ||||
| done | ||||
| 
 | ||||
| if [ -z "$username" ] || [ -z "$password" ]; then | ||||
|   if [ -f .proxmox ]; then | ||||
|     { read username; read password; } < .proxmox | ||||
|   else | ||||
|     die_with_help 'Required: `--username` and `--password`.\n' | ||||
|   fi | ||||
| fi | ||||
| 
 | ||||
| ################################################################################ | ||||
| ## Getting started | ||||
| 
 | ||||
| printf 'Authenticating...' | ||||
| response=$( | ||||
|     http \ | ||||
|         --verify no \ | ||||
|         POST $apiurl/access/ticket \ | ||||
|         "username=$username" \ | ||||
|         "password=$password" | ||||
|     ) | ||||
| readonly ticket=$(echo "$response" | jq -r .data.ticket) | ||||
| readonly csrfToken=$(echo "$response" | jq -r .data.CSRFPreventionToken) | ||||
| printf ' done.\n' | ||||
| 
 | ||||
| acquire_lock () { | ||||
|   until mkdir $tmpdir/lock-$1 2>/dev/null; do sleep 1; done | ||||
| } | ||||
| release_lock () { | ||||
|   rmdir $tmpdir/lock-$1 | ||||
| } | ||||
| 
 | ||||
| proxmox () { | ||||
|   acquire_lock proxmox | ||||
|   http \ | ||||
|     --verify no \ | ||||
|     --form \ | ||||
|     "$@" \ | ||||
|     "Cookie:PVEAuthCookie=$ticket" \ | ||||
|     "CSRFPreventionToken:$csrfToken" | ||||
|   release_lock proxmox | ||||
| } | ||||
| 
 | ||||
| ## Synchronous variant for when the `proxmox` function would just respond an | ||||
| ## UPID in the `data` JSON field. | ||||
| proxmox_sync () ( | ||||
|   response=$(proxmox "$@") | ||||
|   upid=$(echo "$response" | jq -r .data) | ||||
| 
 | ||||
|   while :; do | ||||
|     response=$(proxmox GET $apiurl/nodes/$node/tasks/$upid/status) | ||||
|     status=$(echo "$response" | jq -r .data.status) | ||||
| 
 | ||||
|     case $status in | ||||
|       running) sleep 1 ;; | ||||
|       stopped) break ;; | ||||
|       *) die 'unexpected status: `%s`' "$status" ;; | ||||
|     esac | ||||
|   done | ||||
| ) | ||||
| 
 | ||||
| ################################################################################ | ||||
| ## Stop VM | ||||
| 
 | ||||
| stop_vm () { | ||||
|   printf 'Stopping VM %d...\n' $1 | ||||
| 
 | ||||
|   proxmox_sync POST $apiurl/nodes/$node/qemu/$1/status/stop \ | ||||
|     'overrule-shutdown'==1 | ||||
| 
 | ||||
|   printf 'done stopping VM %d.\n' $1 | ||||
| } | ||||
| 
 | ||||
| ################################################################################ | ||||
| ## Delete VM | ||||
| 
 | ||||
| delete_vm () { | ||||
|   printf 'Deleting VM %d...\n' $1 | ||||
| 
 | ||||
|   proxmox_sync DELETE $apiurl/nodes/$node/qemu/$1 \ | ||||
|     'destroy-unreferenced-disks'==1 \ | ||||
|     'purge'==1 | ||||
| 
 | ||||
|   printf 'done deleting VM %d.\n' $1 | ||||
| } | ||||
| 
 | ||||
| ################################################################################ | ||||
| ## Main loop | ||||
| 
 | ||||
| printf 'Removing VMs%s...\n' "$vmids" | ||||
| 
 | ||||
| remove_vm () { | ||||
|   stop_vm $1 | ||||
|   delete_vm $1 | ||||
| } | ||||
| 
 | ||||
| for vmid in $vmids; do | ||||
|   remove_vm $vmid & | ||||
| done | ||||
| wait | ||||
| 
 | ||||
| printf 'done removing VMs%s.\n' "$vmids" | ||||
| 
 | ||||
| ################################################################################ | ||||
| ## Cleanup | ||||
| 
 | ||||
| rm -Rf $tmpdir | ||||
							
								
								
									
										126
									
								
								deployment/flake.lock → flake.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										126
									
								
								deployment/flake.lock → flake.lock
									
										
									
										generated
									
									
									
								
							|  | @ -39,29 +39,11 @@ | |||
|         "nixpkgs": "nixpkgs" | ||||
|       }, | ||||
|       "locked": { | ||||
|         "lastModified": 1727531434, | ||||
|         "narHash": "sha256-b+GBgCWd2N6pkiTkRZaMFOPztPO4IVTaclYPrQl2uLk=", | ||||
|         "lastModified": 1731274291, | ||||
|         "narHash": "sha256-cZ0QMpv5p2a6WEE+o9uu0a4ma6RzQDOQTbm7PbixWz8=", | ||||
|         "owner": "nix-community", | ||||
|         "repo": "disko", | ||||
|         "rev": "b709e1cc33fcde71c7db43850a55ebe6449d0959", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
|         "owner": "nix-community", | ||||
|         "repo": "disko", | ||||
|         "type": "github" | ||||
|       } | ||||
|     }, | ||||
|     "disko_2": { | ||||
|       "inputs": { | ||||
|         "nixpkgs": "nixpkgs_6" | ||||
|       }, | ||||
|       "locked": { | ||||
|         "lastModified": 1727347829, | ||||
|         "narHash": "sha256-y7cW6TjJKy+tu7efxeWI6lyg4VVx/9whx+OmrhmRShU=", | ||||
|         "owner": "nix-community", | ||||
|         "repo": "disko", | ||||
|         "rev": "1879e48907c14a70302ff5d0539c3b9b6f97feaa", | ||||
|         "rev": "486250f404f4a4f4f33f8f669d83ca5f6e6b7dfc", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
|  | @ -541,11 +523,11 @@ | |||
|     }, | ||||
|     "nixpkgs": { | ||||
|       "locked": { | ||||
|         "lastModified": 1725194671, | ||||
|         "narHash": "sha256-tLGCFEFTB5TaOKkpfw3iYT9dnk4awTP/q4w+ROpMfuw=", | ||||
|         "lastModified": 1730958623, | ||||
|         "narHash": "sha256-JwQZIGSYnRNOgDDoIgqKITrPVil+RMWHsZH1eE1VGN0=", | ||||
|         "owner": "NixOS", | ||||
|         "repo": "nixpkgs", | ||||
|         "rev": "b833ff01a0d694b910daca6e2ff4a3f26dee478c", | ||||
|         "rev": "85f7e662eda4fa3a995556527c87b2524b691933", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
|  | @ -587,21 +569,6 @@ | |||
|         "type": "github" | ||||
|       } | ||||
|     }, | ||||
|     "nixpkgs-latest": { | ||||
|       "locked": { | ||||
|         "lastModified": 1727220152, | ||||
|         "narHash": "sha256-6ezRTVBZT25lQkvaPrfJSxYLwqcbNWm6feD/vG1FO0o=", | ||||
|         "owner": "nixos", | ||||
|         "repo": "nixpkgs", | ||||
|         "rev": "24959f933187217890b206788a85bfa73ba75949", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
|         "owner": "nixos", | ||||
|         "repo": "nixpkgs", | ||||
|         "type": "github" | ||||
|       } | ||||
|     }, | ||||
|     "nixpkgs-lib": { | ||||
|       "locked": { | ||||
|         "lastModified": 1730504152, | ||||
|  | @ -736,48 +703,16 @@ | |||
|     }, | ||||
|     "nixpkgs_5": { | ||||
|       "locked": { | ||||
|         "lastModified": 1727672256, | ||||
|         "narHash": "sha256-9/79hjQc9+xyH+QxeMcRsA6hDyw6Z9Eo1/oxjvwirLk=", | ||||
|         "lastModified": 1732350895, | ||||
|         "narHash": "sha256-GcOQbOgmwlsRhpLGSwZJwLbo3pu9ochMETuRSS1xpz4=", | ||||
|         "owner": "nixos", | ||||
|         "repo": "nixpkgs", | ||||
|         "rev": "1719f27dd95fd4206afb9cec9f415b539978827e", | ||||
|         "rev": "0c582677378f2d9ffcb01490af2f2c678dcb29d3", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
|         "owner": "nixos", | ||||
|         "ref": "nixos-24.05", | ||||
|         "repo": "nixpkgs", | ||||
|         "type": "github" | ||||
|       } | ||||
|     }, | ||||
|     "nixpkgs_6": { | ||||
|       "locked": { | ||||
|         "lastModified": 1725194671, | ||||
|         "narHash": "sha256-tLGCFEFTB5TaOKkpfw3iYT9dnk4awTP/q4w+ROpMfuw=", | ||||
|         "owner": "NixOS", | ||||
|         "repo": "nixpkgs", | ||||
|         "rev": "b833ff01a0d694b910daca6e2ff4a3f26dee478c", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
|         "owner": "NixOS", | ||||
|         "ref": "nixpkgs-unstable", | ||||
|         "repo": "nixpkgs", | ||||
|         "type": "github" | ||||
|       } | ||||
|     }, | ||||
|     "nixpkgs_7": { | ||||
|       "locked": { | ||||
|         "lastModified": 1730137230, | ||||
|         "narHash": "sha256-0kW6v0alzWIc/Dc/DoVZ7A9qNScv77bj/zYTKI67HZM=", | ||||
|         "owner": "radvendii", | ||||
|         "repo": "nixpkgs", | ||||
|         "rev": "df815998652a1d00ce7c059a1e5ef7d7c0548c90", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
|         "owner": "radvendii", | ||||
|         "ref": "nixos_rebuild_tests", | ||||
|         "ref": "nixos-24.11", | ||||
|         "repo": "nixpkgs", | ||||
|         "type": "github" | ||||
|       } | ||||
|  | @ -826,23 +761,6 @@ | |||
|         "type": "github" | ||||
|       } | ||||
|     }, | ||||
|     "pixelfed": { | ||||
|       "flake": false, | ||||
|       "locked": { | ||||
|         "lastModified": 1719823820, | ||||
|         "narHash": "sha256-CKjqnxp7p2z/13zfp4HQ1OAmaoUtqBKS6HFm6TV8Jwg=", | ||||
|         "owner": "pixelfed", | ||||
|         "repo": "pixelfed", | ||||
|         "rev": "4c245cf429330d01fcb8ebeb9aa8c84a9574a645", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
|         "owner": "pixelfed", | ||||
|         "ref": "v0.12.3", | ||||
|         "repo": "pixelfed", | ||||
|         "type": "github" | ||||
|       } | ||||
|     }, | ||||
|     "pre-commit-hooks": { | ||||
|       "inputs": { | ||||
|         "flake-compat": [ | ||||
|  | @ -1003,8 +921,7 @@ | |||
|         "git-hooks": "git-hooks", | ||||
|         "nixops4": "nixops4", | ||||
|         "nixops4-nixos": "nixops4-nixos", | ||||
|         "nixpkgs": "nixpkgs_5", | ||||
|         "snf": "snf" | ||||
|         "nixpkgs": "nixpkgs_5" | ||||
|       } | ||||
|     }, | ||||
|     "rust-overlay": { | ||||
|  | @ -1087,27 +1004,6 @@ | |||
|         "type": "github" | ||||
|       } | ||||
|     }, | ||||
|     "snf": { | ||||
|       "inputs": { | ||||
|         "disko": "disko_2", | ||||
|         "nixpkgs": "nixpkgs_7", | ||||
|         "nixpkgs-latest": "nixpkgs-latest", | ||||
|         "pixelfed": "pixelfed" | ||||
|       }, | ||||
|       "locked": { | ||||
|         "lastModified": 1731341458, | ||||
|         "narHash": "sha256-n6OJFaUtqRgzu5pFsk3di2AadSpudWjF5QXIcUKgu4c=", | ||||
|         "ref": "refs/heads/main", | ||||
|         "rev": "49473c43c85e167e5ef0b1deccdfb40664774ec5", | ||||
|         "revCount": 104, | ||||
|         "type": "git", | ||||
|         "url": "https://git.fediversity.eu/fediversity/simple-nixos-fediverse.git" | ||||
|       }, | ||||
|       "original": { | ||||
|         "type": "git", | ||||
|         "url": "https://git.fediversity.eu/fediversity/simple-nixos-fediverse.git" | ||||
|       } | ||||
|     }, | ||||
|     "treefmt": { | ||||
|       "inputs": { | ||||
|         "nixpkgs": [ | ||||
							
								
								
									
										78
									
								
								flake.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								flake.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,78 @@ | |||
| { | ||||
|   inputs = { | ||||
|     nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11"; | ||||
|     flake-parts.url = "github:hercules-ci/flake-parts"; | ||||
|     git-hooks.url = "github:cachix/git-hooks.nix"; | ||||
| 
 | ||||
|     disko.url = "github:nix-community/disko"; | ||||
| 
 | ||||
|     nixops4.url = "github:nixops4/nixops4"; | ||||
|     nixops4-nixos.url = "github:nixops4/nixops4/eval"; | ||||
|   }; | ||||
| 
 | ||||
|   outputs = | ||||
|     inputs@{ flake-parts, ... }: | ||||
|     flake-parts.lib.mkFlake { inherit inputs; } { | ||||
|       systems = [ | ||||
|         "x86_64-linux" | ||||
|         "aarch64-linux" | ||||
|         "x86_64-darwin" | ||||
|         "aarch64-darwin" | ||||
|       ]; | ||||
| 
 | ||||
|       imports = [ | ||||
|         inputs.git-hooks.flakeModule | ||||
|         inputs.nixops4-nixos.modules.flake.default | ||||
| 
 | ||||
|         ./deployment/flake-part.nix | ||||
|         ./infra/flake-part.nix | ||||
|         ./services/flake-part.nix | ||||
|       ]; | ||||
| 
 | ||||
|       perSystem = | ||||
|         { | ||||
|           config, | ||||
|           pkgs, | ||||
|           inputs', | ||||
|           ... | ||||
|         }: | ||||
|         { | ||||
|           formatter = pkgs.nixfmt-rfc-style; | ||||
| 
 | ||||
|           pre-commit.settings.hooks = | ||||
|             ## Not everybody might want pre-commit hooks, so we make them | ||||
|             ## opt-in. Maybe one day we will decide to have them everywhere. | ||||
|             let | ||||
|               inherit (builtins) concatStringsSep; | ||||
|               optin = [ | ||||
|                 "deployment" | ||||
|                 "infra" | ||||
|                 "services" | ||||
|               ]; | ||||
|               files = "^((" + concatStringsSep "|" optin + ")/.*\\.nix|[^/]*\\.nix)$"; | ||||
|             in | ||||
|             { | ||||
|               nixfmt-rfc-style = { | ||||
|                 enable = true; | ||||
|                 inherit files; | ||||
|               }; | ||||
|               deadnix = { | ||||
|                 enable = true; | ||||
|                 inherit files; | ||||
|               }; | ||||
|               trim-trailing-whitespace = { | ||||
|                 enable = true; | ||||
|                 inherit files; | ||||
|               }; | ||||
|             }; | ||||
| 
 | ||||
|           devShells.default = pkgs.mkShell { | ||||
|             packages = [ | ||||
|               pkgs.nil | ||||
|               inputs'.nixops4.packages.default | ||||
|             ]; | ||||
|             shellHook = config.pre-commit.installationScript; | ||||
|           }; | ||||
|         }; | ||||
|     }; | ||||
| } | ||||
							
								
								
									
										33
									
								
								infra/README.org
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								infra/README.org
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,33 @@ | |||
| #+title: Infra | ||||
| 
 | ||||
| This directory contains the definition of the VMs that host our infrastructure. | ||||
| Their configuration can be updated via NixOps4. Run | ||||
| 
 | ||||
| #+begin_src sh | ||||
| nixops4 deployments list | ||||
| #+end_src | ||||
| 
 | ||||
| to see the available deployments. Given a deployment (eg. ~git~), run | ||||
| 
 | ||||
| #+begin_src sh | ||||
| nixops4 apply <deployment> | ||||
| #+end_src | ||||
| 
 | ||||
| * Deployments | ||||
| 
 | ||||
| - ~git~ :: Machines hosting our Git infrastructure, eg. Forgejo and its actions | ||||
|   runners | ||||
| - ~web~ :: Machines hosting our online content, eg. the website or the wiki | ||||
| 
 | ||||
| * Procolix machines | ||||
| 
 | ||||
| These machines are hosted on the Procolix Proxmox instance, to which | ||||
| non-Procolix members of the project do not have access. They host our stable | ||||
| infrastructure. | ||||
| 
 | ||||
| | Machine | Description            | Deployment | | ||||
| |---------+------------------------+------------| | ||||
| | vm02116 | Forgejo                | ~git~        | | ||||
| | vm02179 | Forgejo actions runner | ~git~        | | ||||
| | vm02186 | Forgejo actions runner | ~git~        | | ||||
| | vm02187 | Wiki                   | ~web~        | | ||||
							
								
								
									
										37
									
								
								infra/common/default.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								infra/common/default.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,37 @@ | |||
| { lib, pkgs, ... }: | ||||
| 
 | ||||
| let | ||||
|   inherit (lib) mkDefault; | ||||
| 
 | ||||
| in | ||||
| { | ||||
|   imports = [ | ||||
|     ./hardware.nix | ||||
|     ./networking.nix | ||||
|     ./users.nix | ||||
|   ]; | ||||
| 
 | ||||
|   time.timeZone = "Europe/Amsterdam"; | ||||
|   i18n.defaultLocale = "en_US.UTF-8"; | ||||
|   system.stateVersion = "24.05"; # do not change | ||||
|   nixpkgs.hostPlatform = mkDefault "x86_64-linux"; | ||||
| 
 | ||||
|   environment.systemPackages = with pkgs; [ | ||||
|     (pkgs.vim_configurable.customize { | ||||
|       name = "vim"; | ||||
|       vimrcConfig.packages.myplugins = with pkgs.vimPlugins; { | ||||
|         start = [ vim-nix ]; # load plugin on startup | ||||
|       }; | ||||
|       vimrcConfig.customRC = '' | ||||
|         " your custom vimrc | ||||
|         set nocompatible | ||||
|         set backspace=indent,eol,start | ||||
|         " Turn on syntax highlighting by default | ||||
|         syntax on | ||||
|         " ... | ||||
|       ''; | ||||
|     }) | ||||
|     wget | ||||
|     subversion | ||||
|   ]; | ||||
| } | ||||
							
								
								
									
										24
									
								
								infra/common/hardware.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								infra/common/hardware.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,24 @@ | |||
| { modulesPath, ... }: | ||||
| 
 | ||||
| { | ||||
|   imports = [ (modulesPath + "/profiles/qemu-guest.nix") ]; | ||||
| 
 | ||||
|   boot = { | ||||
|     loader = { | ||||
|       systemd-boot.enable = true; | ||||
|       efi.canTouchEfiVariables = true; | ||||
|     }; | ||||
| 
 | ||||
|     initrd = { | ||||
|       availableKernelModules = [ | ||||
|         "ata_piix" | ||||
|         "uhci_hcd" | ||||
|         "virtio_pci" | ||||
|         "virtio_scsi" | ||||
|         "sd_mod" | ||||
|         "sr_mod" | ||||
|       ]; | ||||
|       kernelModules = [ "dm-snapshot" ]; | ||||
|     }; | ||||
|   }; | ||||
| } | ||||
							
								
								
									
										73
									
								
								infra/common/networking.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								infra/common/networking.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,73 @@ | |||
| { config, lib, ... }: | ||||
| 
 | ||||
| let | ||||
|   inherit (lib) mkOption mkDefault; | ||||
| 
 | ||||
| in | ||||
| { | ||||
|   options = { | ||||
|     procolix.vm = { | ||||
|       name = mkOption { }; | ||||
|       ip4 = mkOption { }; | ||||
|       ip6 = mkOption { }; | ||||
|     }; | ||||
|   }; | ||||
| 
 | ||||
|   config = { | ||||
|     services.openssh = { | ||||
|       enable = true; | ||||
|       settings.PasswordAuthentication = false; | ||||
|     }; | ||||
| 
 | ||||
|     networking = { | ||||
|       hostName = config.procolix.vm.name; | ||||
|       domain = "procolix.com"; | ||||
| 
 | ||||
|       ## REVIEW: Do we actually need that, considering that we have static IPs? | ||||
|       useDHCP = mkDefault true; | ||||
| 
 | ||||
|       interfaces = { | ||||
|         eth0 = { | ||||
|           ipv4 = { | ||||
|             addresses = [ | ||||
|               { | ||||
|                 address = config.procolix.vm.ip4; | ||||
|                 prefixLength = 24; | ||||
|               } | ||||
|             ]; | ||||
|           }; | ||||
|           ipv6 = { | ||||
|             addresses = [ | ||||
|               { | ||||
|                 address = config.procolix.vm.ip6; | ||||
|                 prefixLength = 64; | ||||
|               } | ||||
|             ]; | ||||
|           }; | ||||
|         }; | ||||
|       }; | ||||
| 
 | ||||
|       defaultGateway = { | ||||
|         address = "185.206.232.1"; | ||||
|         interface = "eth0"; | ||||
|       }; | ||||
|       defaultGateway6 = { | ||||
|         address = "2a00:51c0:12:1201::1"; | ||||
|         interface = "eth0"; | ||||
|       }; | ||||
| 
 | ||||
|       nameservers = [ | ||||
|         "95.215.185.6" | ||||
|         "95.215.185.7" | ||||
|         "2a00:51c0::5fd7:b906" | ||||
|         "2a00:51c0::5fd7:b907" | ||||
|       ]; | ||||
| 
 | ||||
|       firewall.enable = false; | ||||
|       nftables = { | ||||
|         enable = true; | ||||
|         rulesetFile = ./nftables-ruleset.nft; | ||||
|       }; | ||||
|     }; | ||||
|   }; | ||||
| } | ||||
							
								
								
									
										70
									
								
								infra/common/nftables-ruleset.nft
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								infra/common/nftables-ruleset.nft
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,70 @@ | |||
| #!/usr/sbin/nft -f | ||||
| 
 | ||||
| flush ruleset | ||||
| 
 | ||||
| ########### define usefull variables here ##################### | ||||
| 
 | ||||
| define wan        = eth0 | ||||
| define ssh_allow  = { | ||||
|     83.161.147.127/32, # host801 ipv4 | ||||
|     95.215.185.92/32,  # host088 ipv4 | ||||
|     95.215.185.211/32, # host089 ipv4 | ||||
|     95.215.185.34/32,  # nagios2 ipv4 | ||||
|     95.215.185.235/32, # ansible-hq | ||||
| } | ||||
| define snmp_allow = { | ||||
|     95.215.185.31/32,  # cacti ipv4 | ||||
| } | ||||
| define nrpe_allow = { | ||||
|     95.215.185.34/32,  # nagios2 ipv4 | ||||
| } | ||||
| 
 | ||||
| ########### here starts the automated bit ##################### | ||||
| 
 | ||||
| table inet filter { | ||||
|     chain input { | ||||
|         type filter hook input priority 0; | ||||
|         policy drop; | ||||
| 
 | ||||
|         # established/related connections | ||||
|         ct state established,related accept | ||||
|         ct state invalid drop | ||||
| 
 | ||||
|         # Limit ping requests. | ||||
|         ip protocol icmp icmp type echo-request limit rate over 10/second burst 50 packets drop | ||||
|         ip6 nexthdr icmpv6 icmpv6 type echo-request limit rate over 10/second burst 50 packets drop | ||||
| 
 | ||||
|         # loopback interface | ||||
|         iifname lo accept | ||||
| 
 | ||||
|         # icmp | ||||
|         ip protocol icmp icmp type { destination-unreachable, echo-reply, echo-request, source-quench, time-exceeded } accept | ||||
|         # Without the nd-* ones ipv6 will not work. | ||||
|         ip6 nexthdr icmpv6 icmpv6 type { destination-unreachable, echo-reply, echo-request, nd-neighbor-solicit,  nd-router-advert, nd-neighbor-advert, packet-too-big, parameter-problem, time-exceeded } accept | ||||
| 
 | ||||
|         # open tcp ports: sshd (22) | ||||
|         tcp dport {ssh} accept | ||||
| 
 | ||||
|         # open tcp ports: snmp (161) | ||||
|         ip saddr $snmp_allow udp dport {snmp} accept | ||||
| 
 | ||||
|         # open tcp ports: nrpe (5666) | ||||
|         ip saddr $nrpe_allow tcp dport {nrpe} accept | ||||
| 
 | ||||
|         # open tcp ports: http (80,443) | ||||
|         tcp dport {http,https} accept | ||||
|     } | ||||
|     chain forward { | ||||
|         type filter hook forward priority 0; | ||||
|     } | ||||
|     chain output { | ||||
|         type filter hook output priority 0; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| table ip nat { | ||||
|     chain postrouting { | ||||
|     } | ||||
|     chain prerouting { | ||||
|     } | ||||
| } | ||||
							
								
								
									
										40
									
								
								infra/common/users.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								infra/common/users.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,40 @@ | |||
| { | ||||
|   users.users = { | ||||
|     procolix = { | ||||
|       isNormalUser = true; | ||||
|       extraGroups = [ "wheel" ]; | ||||
|       hashedPassword = "$y$j9T$UH8Dh/poTCCZ3PXk43au6/$iYen8VUEVvv7SIPqteNtTPKktLxny3TbqvjUwhvi.6B"; | ||||
|       openssh.authorizedKeys.keys = [ | ||||
|         "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAotfCIjLoDlHOe+++kVS1xiBPaS8mC5FypgrxDrDVst6SHxMTca2+IScMajzUZajenvNAoZOwIsyAPacT8OHeyFvV5Y7G874Qa+cZVqJxLht9gdXxr1GNabU3RfhhCh272dUeIKIqfgsRsM2HzdnZCMDavS1Yo+f+RhhHhnJIua+NdVFo21vPrpsz+Cd0M1NhojARLajrTHvEXW0KskUnkbfgxT0vL9jeRZxdgMS+a9ZoR5dbzOxQHWfbP8N04Xc+7CweMlvKwlWuAE/xDb5XLNHorfGWFvZuVhptJN8jPaaVS25wsmsF5IbaAuSZfzCtBdFQhIloUhy0L6ZisubHjQ== procolix@sshnode1" | ||||
|         "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAuT3C0f3nyQ7SwUvXcFmEYEgwL+crY6iK0Bhoi9yfn4soz3fhfMKyKSwc/0RIlRnrz3xnkyJiV0vFeU7AC1ixbGCS3T9uc0G1x0Yedd9n2yR8ZJmkdyfjZ5KE4YvqZ3f6UZn5Mtj+7tGmyp+ee+clLSHzsqeyDiX0FIgFmqiiAVJD6qeKPFAHeWz9b2MOXIBIw+fSLOpx0rosCgesOmPc8lgFvo+dMKpSlPkCuGLBPj2ObT4sLjc98NC5z8sNJMu3o5bMbiCDR9JWgx9nKj+NlALwk3Y/nzHSL/DNcnP5vz2zbX2CBKjx6ju0IXh6YKlJJVyMsH9QjwYkgDQVmy8amQ== procolix@sshnode2" | ||||
|       ]; | ||||
|     }; | ||||
| 
 | ||||
|     niols = { | ||||
|       isNormalUser = true; | ||||
|       extraGroups = [ "wheel" ]; | ||||
|       openssh.authorizedKeys.keys = [ | ||||
|         "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEElREJN0AC7lbp+5X204pQ5r030IbgCllsIxyU3iiKY" | ||||
|       ]; | ||||
|     }; | ||||
| 
 | ||||
|     valentin = { | ||||
|       isNormalUser = true; | ||||
|       extraGroups = [ "wheel" ]; | ||||
|       openssh.authorizedKeys.keys = [ | ||||
|         "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOJzgwAYAoMexc1fBJxU08YmsiU9T4Ua8QFeE4/kZNZ5" | ||||
|       ]; | ||||
|     }; | ||||
|   }; | ||||
| 
 | ||||
|   security.sudo.wheelNeedsPassword = false; | ||||
| 
 | ||||
|   nix.settings.trusted-users = [ "@wheel" ]; | ||||
| 
 | ||||
|   ## FIXME: Remove direct root authentication once NixOps4 supports users with | ||||
|   ## password-less sudo. | ||||
|   users.users.root.openssh.authorizedKeys.keys = [ | ||||
|     "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEElREJN0AC7lbp+5X204pQ5r030IbgCllsIxyU3iiKY" | ||||
|     "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJg5TlS1NGCRZwMjDgBkXeFUXqooqRlM8fJdBAQ4buPg" | ||||
|   ]; | ||||
| } | ||||
							
								
								
									
										75
									
								
								infra/flake-part.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								infra/flake-part.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,75 @@ | |||
| { inputs, ... }: | ||||
| 
 | ||||
| { | ||||
|   nixops4Deployments.git = | ||||
|     { providers, ... }: | ||||
|     { | ||||
|       providers.local = inputs.nixops4-nixos.modules.nixops4Provider.local; | ||||
| 
 | ||||
|       resources = { | ||||
|         vm02116 = { | ||||
|           type = providers.local.exec; | ||||
|           imports = [ inputs.nixops4-nixos.modules.nixops4Resource.nixos ]; | ||||
|           ssh = { | ||||
|             host = "185.206.232.34"; | ||||
|             opts = ""; | ||||
|             hostPublicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILriawl1za2jbxzelkL5v8KPmcvuj7xVBgwFxuM/zhYr"; | ||||
|           }; | ||||
|           nixpkgs = inputs.nixpkgs; | ||||
|           nixos.module = { | ||||
|             imports = [ ./vm02116 ]; | ||||
|           }; | ||||
|         }; | ||||
| 
 | ||||
|         vm02179 = { | ||||
|           type = providers.local.exec; | ||||
|           imports = [ inputs.nixops4-nixos.modules.nixops4Resource.nixos ]; | ||||
|           ssh = { | ||||
|             host = "185.206.232.179"; | ||||
|             opts = ""; | ||||
|             hostPublicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPAsOCOsJ0vNL9fGj0XC25ir8B+k2NlVJzsiVUx+0eWM"; | ||||
|           }; | ||||
|           nixpkgs = inputs.nixpkgs; | ||||
|           nixos.module = { | ||||
|             imports = [ ./vm02179 ]; | ||||
|           }; | ||||
|         }; | ||||
| 
 | ||||
|         vm02186 = { | ||||
|           type = providers.local.exec; | ||||
|           imports = [ inputs.nixops4-nixos.modules.nixops4Resource.nixos ]; | ||||
|           ssh = { | ||||
|             host = "185.206.232.186"; | ||||
|             opts = ""; | ||||
|             hostPublicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII6mnBgEeyYE4tzHeFNHVNBV6KR+hAqh3PYSqlh0QViW"; | ||||
|           }; | ||||
|           nixpkgs = inputs.nixpkgs; | ||||
|           nixos.module = { | ||||
|             imports = [ ./vm02186 ]; | ||||
|           }; | ||||
|         }; | ||||
|       }; | ||||
|     }; | ||||
| 
 | ||||
|   nixops4Deployments.web = | ||||
|     { providers, ... }: | ||||
|     { | ||||
|       providers.local = inputs.nixops4-nixos.modules.nixops4Provider.local; | ||||
| 
 | ||||
|       resources = { | ||||
|         vm02187 = { | ||||
|           type = providers.local.exec; | ||||
|           imports = [ inputs.nixops4-nixos.modules.nixops4Resource.nixos ]; | ||||
|           ssh = { | ||||
|             host = "185.206.232.187"; | ||||
|             opts = ""; | ||||
|             hostPublicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN24ZfdQNklKkIqfMg/+0vqENuDcy6fhT6SfAq01ae83"; | ||||
|           }; | ||||
|           nixpkgs = inputs.nixpkgs; | ||||
|           nixos.module = { | ||||
|             imports = [ ./vm02187 ]; | ||||
|           }; | ||||
|         }; | ||||
|       }; | ||||
|     }; | ||||
| } | ||||
|  | @ -1,24 +0,0 @@ | |||
| { | ||||
|   inputs = { | ||||
|     nixpkgs.url = "github:nixos/nixpkgs/nixos-24.05"; | ||||
|     snf.url = "git+https://git.fediversity.eu/fediversity/simple-nixos-fediverse.git"; | ||||
|   }; | ||||
| 
 | ||||
|   outputs = { self, nixpkgs, snf }: | ||||
|     let | ||||
|       vmName = "vm02186"; | ||||
| 
 | ||||
|     in { | ||||
|       nixosConfigurations.${vmName} = nixpkgs.lib.nixosSystem { | ||||
|         system = "x86_64-linux"; | ||||
| 
 | ||||
|         modules = [ | ||||
|           ./procolix-configuration.nix | ||||
|           ./hardware-configuration.nix | ||||
|           ./gitea-runner.nix | ||||
|         ]; | ||||
|       }; | ||||
| 
 | ||||
|       isoInstallers.${vmName} = snf.mkInstaller nixpkgs self.nixosConfigurations.${vmName}; | ||||
|     }; | ||||
| } | ||||
|  | @ -1,37 +0,0 @@ | |||
| # Do not modify this file!  It was generated by ‘nixos-generate-config’ | ||||
| # and may be overwritten by future invocations.  Please make changes | ||||
| # to /etc/nixos/configuration.nix instead. | ||||
| { config, lib, pkgs, modulesPath, ... }: | ||||
| 
 | ||||
| { | ||||
|   imports = | ||||
|     [ (modulesPath + "/profiles/qemu-guest.nix") | ||||
|     ]; | ||||
| 
 | ||||
|   boot.initrd.availableKernelModules = [ "ata_piix" "uhci_hcd" "virtio_pci" "virtio_scsi" "sd_mod" "sr_mod" ]; | ||||
|   boot.initrd.kernelModules = [ "dm-snapshot" ]; | ||||
|   boot.kernelModules = [ ]; | ||||
|   boot.extraModulePackages = [ ]; | ||||
| 
 | ||||
|   fileSystems."/" = | ||||
|     { device = "/dev/disk/by-uuid/833ac0f9-ad8c-45ae-a9bf-5844e378c44a"; | ||||
|       fsType = "ext4"; | ||||
|     }; | ||||
| 
 | ||||
|   fileSystems."/boot" = | ||||
|     { device = "/dev/disk/by-uuid/B4D5-3AF9"; | ||||
|       fsType = "vfat"; | ||||
|       options = [ "fmask=0022" "dmask=0022" ]; | ||||
|     }; | ||||
| 
 | ||||
|   swapDevices = [ ]; | ||||
| 
 | ||||
|   # Enables DHCP on each ethernet and wireless interface. In case of scripted networking | ||||
|   # (the default) this is the recommended approach. When using systemd-networkd it's | ||||
|   # still possible to use this option, but it's recommended to use it in conjunction | ||||
|   # with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`. | ||||
|   networking.useDHCP = lib.mkDefault true; | ||||
|   # networking.interfaces.ens18.useDHCP = lib.mkDefault true; | ||||
| 
 | ||||
|   nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; | ||||
| } | ||||
|  | @ -1,192 +0,0 @@ | |||
| { pkgs, ... }: | ||||
| 
 | ||||
| { | ||||
|   # Use the systemd-boot EFI boot loader. | ||||
|   boot.loader.systemd-boot.enable = true; | ||||
|   boot.loader.efi.canTouchEfiVariables = true; | ||||
| 
 | ||||
|   networking = { | ||||
|     hostName = "vm02186"; | ||||
|     domain = "procolix.com"; | ||||
|     interfaces = { | ||||
|       eth0 = { | ||||
|         ipv4 = { | ||||
|           addresses = [ | ||||
|             { | ||||
|               address = "185.206.232.186"; | ||||
|               prefixLength = 24; | ||||
|             } | ||||
|           ]; | ||||
|         }; | ||||
|         ipv6 = { | ||||
|           addresses = [ | ||||
|             { | ||||
|               address = "2a00:51c0:12:1201::186"; | ||||
|               prefixLength = 64; | ||||
|             } | ||||
|           ]; | ||||
|         }; | ||||
|       }; | ||||
|     }; | ||||
|     defaultGateway = { | ||||
|       address = "185.206.232.1"; | ||||
|       interface = "eth0"; | ||||
|     }; | ||||
|     defaultGateway6 = { | ||||
|       address = "2a00:51c0:12:1201::1"; | ||||
|       interface = "eth0"; | ||||
|     }; | ||||
|     nameservers = [ "95.215.185.6" "95.215.185.7" ]; | ||||
|     firewall.enable = false; | ||||
|     nftables = { | ||||
|       enable = true; | ||||
|       ruleset = '' | ||||
|         #!/usr/sbin/nft -f | ||||
| 
 | ||||
|         flush ruleset | ||||
| 
 | ||||
|         ########### define usefull variables here ##################### | ||||
|         define wan        = eth0 | ||||
|         define ssh_allow  = { | ||||
|                     83.161.147.127/32, # host801 ipv4 | ||||
|                     95.215.185.92/32,  # host088 ipv4 | ||||
|                     95.215.185.211/32, # host089 ipv4 | ||||
|                     95.215.185.34/32,  # nagios2 ipv4 | ||||
|                     95.215.185.181/32, # ansible.procolix.com | ||||
|                     95.215.185.235/32,    # ansible-hq | ||||
|                 } | ||||
|         define snmp_allow = { | ||||
|                     95.215.185.31/32,   # cacti ipv4 | ||||
|                 } | ||||
|         define nrpe_allow = { | ||||
|                     95.215.185.34/32,   # nagios2 ipv4 | ||||
|                 } | ||||
| 
 | ||||
|         ########### here starts the automated bit ##################### | ||||
|         table inet filter { | ||||
|             chain input { | ||||
|                 type filter hook input priority 0; | ||||
|                 policy drop; | ||||
| 
 | ||||
|                 # established/related connections | ||||
|                 ct state established,related accept | ||||
|                 ct state invalid drop | ||||
| 
 | ||||
|                 # Limit ping requests. | ||||
|                 ip protocol icmp icmp type echo-request limit rate over 10/second burst 50 packets drop | ||||
|                 ip6 nexthdr icmpv6 icmpv6 type echo-request limit rate over 10/second burst 50 packets drop | ||||
| 
 | ||||
|                 # loopback interface | ||||
|                 iifname lo accept | ||||
| 
 | ||||
|                 # icmp | ||||
|                 ip protocol icmp icmp type { destination-unreachable, echo-reply, echo-request, source-quench, time-exceeded } accept | ||||
|                 # Without the nd-* ones ipv6 will not work. | ||||
|                 ip6 nexthdr icmpv6 icmpv6 type { destination-unreachable, echo-reply, echo-request, nd-neighbor-solicit,  nd-router-advert, nd-neighbor-advert, packet-too-big, parameter-problem, time-exceeded } accept | ||||
| 
 | ||||
|                 # open tcp ports: sshd (22) | ||||
|                 tcp dport {ssh} accept | ||||
| 
 | ||||
|                 # open tcp ports: snmp (161) | ||||
|                 ip saddr $snmp_allow udp dport {snmp} accept | ||||
| 
 | ||||
|                 # open tcp ports: nrpe (5666) | ||||
|                 ip saddr $nrpe_allow tcp dport {nrpe} accept | ||||
| 
 | ||||
|                 # open tcp ports: http (80,443) | ||||
|                 tcp dport {http,https} accept | ||||
|             } | ||||
|             chain forward { | ||||
|                 type filter hook forward priority 0; | ||||
|             } | ||||
|             chain output { | ||||
|                 type filter hook output priority 0; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         table ip nat { | ||||
|             chain postrouting { | ||||
|             } | ||||
|             chain prerouting { | ||||
|             } | ||||
|         } | ||||
|       ''; | ||||
|     }; | ||||
|   }; | ||||
| 
 | ||||
| 
 | ||||
|   # Set your time zone. | ||||
|   time.timeZone = "Europe/Amsterdam"; | ||||
| 
 | ||||
|   # Select internationalisation properties. | ||||
|   i18n.defaultLocale = "en_US.UTF-8"; | ||||
| 
 | ||||
|   # Define a user account. Don't forget to set a password with ‘passwd’. | ||||
|   users.users.root.hashedPassword = "$y$j9T$WXvLAUqArJJusuC017FCW0$.rfMOeyx/BsClkJFi5hLcynrSk.njWmfiB6Uy.9th3A"; | ||||
| 
 | ||||
|   users.users.procolix = { | ||||
|     isNormalUser = true; | ||||
|     extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user. | ||||
|     hashedPassword = "$y$j9T$UH8Dh/poTCCZ3PXk43au6/$iYen8VUEVvv7SIPqteNtTPKktLxny3TbqvjUwhvi.6B"; | ||||
|     openssh.authorizedKeys.keys = [ | ||||
|     "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAotfCIjLoDlHOe+++kVS1xiBPaS8mC5FypgrxDrDVst6SHxMTca2+IScMajzUZajenvNAoZOwIsyAPacT8OHeyFvV5Y7G874Qa+cZVqJxLht9gdXxr1GNabU3RfhhCh272dUeIKIqfgsRsM2HzdnZCMDavS1Yo+f+RhhHhnJIua+NdVFo21vPrpsz+Cd0M1NhojARLajrTHvEXW0KskUnkbfgxT0vL9jeRZxdgMS+a9ZoR5dbzOxQHWfbP8N04Xc+7CweMlvKwlWuAE/xDb5XLNHorfGWFvZuVhptJN8jPaaVS25wsmsF5IbaAuSZfzCtBdFQhIloUhy0L6ZisubHjQ== procolix@sshnode1" | ||||
|     "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAuT3C0f3nyQ7SwUvXcFmEYEgwL+crY6iK0Bhoi9yfn4soz3fhfMKyKSwc/0RIlRnrz3xnkyJiV0vFeU7AC1ixbGCS3T9uc0G1x0Yedd9n2yR8ZJmkdyfjZ5KE4YvqZ3f6UZn5Mtj+7tGmyp+ee+clLSHzsqeyDiX0FIgFmqiiAVJD6qeKPFAHeWz9b2MOXIBIw+fSLOpx0rosCgesOmPc8lgFvo+dMKpSlPkCuGLBPj2ObT4sLjc98NC5z8sNJMu3o5bMbiCDR9JWgx9nKj+NlALwk3Y/nzHSL/DNcnP5vz2zbX2CBKjx6ju0IXh6YKlJJVyMsH9QjwYkgDQVmy8amQ== procolix@sshnode2" | ||||
|     ]; | ||||
|     packages = with pkgs; [ | ||||
|     ]; | ||||
|   }; | ||||
| 
 | ||||
|   users.users.niols = { | ||||
|     isNormalUser = true; | ||||
|     extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user. | ||||
|     openssh.authorizedKeys.keys = [ | ||||
|     "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEElREJN0AC7lbp+5X204pQ5r030IbgCllsIxyU3iiKY niols@wallace" | ||||
|     "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBkQXv/VRZLfV0wNN9PHedmKWyAIfpPUCdaznHZNIDkS niols@orianne/fediversity" | ||||
|     ]; | ||||
|     packages = with pkgs; [ | ||||
|     ]; | ||||
|   }; | ||||
| 
 | ||||
|   users.users.valentin = { | ||||
|     isNormalUser = true; | ||||
|     extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user. | ||||
|     openssh.authorizedKeys.keys = [ | ||||
|     "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOJzgwAYAoMexc1fBJxU08YmsiU9T4Ua8QFeE4/kZNZ5" | ||||
|     ]; | ||||
|     packages = with pkgs; [ | ||||
|     ]; | ||||
|   }; | ||||
| 
 | ||||
|   # List packages installed in system profile. To search, run: | ||||
|   # $ nix search wget | ||||
|   environment.systemPackages = with pkgs; [ | ||||
|     (pkgs.vim_configurable.customize { | ||||
|       name = "vim"; | ||||
|       vimrcConfig.packages.myplugins = with pkgs.vimPlugins; { | ||||
|         start = [ vim-nix ]; # load plugin on startup | ||||
|       }; | ||||
|       vimrcConfig.customRC = '' | ||||
|         " your custom vimrc | ||||
|         set nocompatible | ||||
|         set backspace=indent,eol,start | ||||
|         " Turn on syntax highlighting by default | ||||
|         syntax on | ||||
|         " ... | ||||
|       ''; | ||||
|     }) | ||||
|     wget | ||||
|   ]; | ||||
| 
 | ||||
|   # List services that you want to enable: | ||||
| 
 | ||||
|   # Enable the OpenSSH daemon. | ||||
|   services.openssh.enable = true; | ||||
| 
 | ||||
|   # This value determines the NixOS release from which the default | ||||
|   # settings for stateful data, like file locations and database versions | ||||
|   # on your system were taken. It‘s perfectly fine and recommended to leave | ||||
|   # this value at the release version of the first install of this system. | ||||
|   # Before changing this value read the documentation for this option | ||||
|   # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html). | ||||
|   system.stateVersion = "24.05"; # Did you read the comment? | ||||
| } | ||||
							
								
								
									
										28
									
								
								infra/vm02116/default.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								infra/vm02116/default.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,28 @@ | |||
| { | ||||
|   imports = [ | ||||
|     ../common | ||||
|     ./forgejo.nix | ||||
|   ]; | ||||
| 
 | ||||
|   procolix.vm = { | ||||
|     name = "vm02116"; | ||||
|     ip4 = "185.206.232.34"; | ||||
|     ip6 = "2a00:51c0:12:1201::20"; | ||||
|   }; | ||||
| 
 | ||||
|   ## vm02116 is running on old hardware based on a Xen VM environment, so it | ||||
|   ## needs these extra options. Once the VM gets moved to a newer node, these | ||||
|   ## two options can safely be removed. | ||||
|   boot.initrd.availableKernelModules = [ "xen_blkfront" ]; | ||||
|   services.xe-guest-utilities.enable = true; | ||||
| 
 | ||||
|   fileSystems."/" = { | ||||
|     device = "/dev/disk/by-uuid/3802a66d-e31a-4650-86f3-b51b11918853"; | ||||
|     fsType = "ext4"; | ||||
|   }; | ||||
| 
 | ||||
|   fileSystems."/boot" = { | ||||
|     device = "/dev/disk/by-uuid/2CE2-1173"; | ||||
|     fsType = "vfat"; | ||||
|   }; | ||||
| } | ||||
							
								
								
									
										98
									
								
								infra/vm02116/forgejo.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								infra/vm02116/forgejo.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,98 @@ | |||
| { pkgs, ... }: | ||||
| let | ||||
|   domain = "git.fediversity.eu"; | ||||
| in | ||||
| { | ||||
|   services.forgejo = { | ||||
|     enable = true; | ||||
|     lfs.enable = true; | ||||
|     settings = { | ||||
|       service = { | ||||
|         DISABLE_REGISTRATION = true; | ||||
|       }; | ||||
|       server = { | ||||
|         DOMAIN = "${domain}"; | ||||
|         ROOT_URL = "https://${domain}/"; | ||||
|         HTTP_ADDR = "127.0.0.1"; | ||||
|         LANDING_PAGE = "explore"; | ||||
|       }; | ||||
|     }; | ||||
| 
 | ||||
|     settings.service.ENABLE_NOTIFY_MAIL = true; | ||||
|     settings.mailer = { | ||||
|       ENABLED = true; | ||||
|       PROTOCOL = "smtp+starttls"; | ||||
|       SMTP_ADDR = "mail.protagio.nl"; | ||||
|       SMTP_PORT = "587"; | ||||
|       FROM = "git@fediversity.eu"; | ||||
|       USER = "git@fediversity.eu"; | ||||
|     }; | ||||
|     secrets.mailer.PASSWD = "/var/lib/forgejo/data/keys/forgejo-mailpw"; | ||||
| 
 | ||||
|     database = { | ||||
|       type = "mysql"; | ||||
|       socket = "/run/mysqld/mysqld.sock"; | ||||
|       passwordFile = "/var/lib/forgejo/data/keys/forgejo-dbpassword"; | ||||
|     }; | ||||
|   }; | ||||
| 
 | ||||
|   users.groups.keys.members = [ "forgejo" ]; | ||||
| 
 | ||||
|   services.mysql = { | ||||
|     enable = true; | ||||
|     package = pkgs.mariadb; | ||||
|     ensureDatabases = [ "forgejo" ]; | ||||
|     ensureUsers = [ | ||||
|       { | ||||
|         name = "forgejo"; | ||||
|         ensurePermissions = { | ||||
|           "forgejo.*" = "ALL PRIVILEGES"; | ||||
|         }; | ||||
|       } | ||||
|     ]; | ||||
|   }; | ||||
| 
 | ||||
|   security.acme = { | ||||
|     acceptTerms = true; | ||||
|     defaults.email = "beheer@procolix.com"; | ||||
|   }; | ||||
| 
 | ||||
|   services.nginx = { | ||||
|     enable = true; | ||||
|     recommendedTlsSettings = true; | ||||
|     recommendedOptimisation = true; | ||||
|     recommendedGzipSettings = true; | ||||
|     recommendedProxySettings = true; | ||||
|     clientMaxBodySize = "500m"; | ||||
|     appendHttpConfig = '' | ||||
| 
 | ||||
| 
 | ||||
|       map $uri $forgejo_access_log { | ||||
|         default 1; | ||||
|         /api/actions/runner.v1.RunnerService/FetchTask 0; | ||||
|       } | ||||
| 
 | ||||
|       # Add HSTS header with preloading to HTTPS requests. | ||||
|       # Adding this header to HTTP requests is discouraged | ||||
|       map $scheme $hsts_header { | ||||
|           https   "max-age=31536000; includeSubdomains; always"; | ||||
|       } | ||||
|       add_header Strict-Transport-Security $hsts_header; | ||||
|     ''; | ||||
|     virtualHosts.${domain} = { | ||||
|       listenAddresses = [ | ||||
|         "185.206.232.34" | ||||
|         "[2a00:51c0:12:1201::20]" | ||||
|       ]; | ||||
|       enableACME = true; | ||||
|       forceSSL = true; | ||||
|       locations."/" = { | ||||
|         proxyPass = "http://127.0.0.1:3000/"; | ||||
|         extraConfig = '' | ||||
|           proxy_set_header X-Real-IP $remote_addr; | ||||
|           #access_log /var/log/nginx/access.log info if=$forgejo_access_log; | ||||
|         ''; | ||||
|       }; | ||||
|     }; | ||||
|   }; | ||||
| } | ||||
							
								
								
									
										26
									
								
								infra/vm02179/default.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								infra/vm02179/default.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | |||
| { | ||||
|   imports = [ | ||||
|     ../common | ||||
|     ./gitea-runner.nix | ||||
|   ]; | ||||
| 
 | ||||
|   procolix.vm = { | ||||
|     name = "vm02179"; | ||||
|     ip4 = "185.206.232.179"; | ||||
|     ip6 = "2a00:51c0:12:1201::179"; | ||||
|   }; | ||||
| 
 | ||||
|   fileSystems."/" = { | ||||
|     device = "/dev/disk/by-uuid/119863f8-55cf-4e2f-ac17-27599a63f241"; | ||||
|     fsType = "ext4"; | ||||
|   }; | ||||
| 
 | ||||
|   fileSystems."/boot" = { | ||||
|     device = "/dev/disk/by-uuid/D9F4-9BF0"; | ||||
|     fsType = "vfat"; | ||||
|     options = [ | ||||
|       "fmask=0022" | ||||
|       "dmask=0022" | ||||
|     ]; | ||||
|   }; | ||||
| } | ||||
							
								
								
									
										43
									
								
								infra/vm02179/gitea-runner.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								infra/vm02179/gitea-runner.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,43 @@ | |||
| { pkgs, ... }: | ||||
| { | ||||
| 
 | ||||
|   virtualisation.docker.enable = true; | ||||
| 
 | ||||
|   services.gitea-actions-runner = { | ||||
|     package = pkgs.forgejo-actions-runner; | ||||
|     instances.default = { | ||||
|       enable = true; | ||||
|       name = "vm02179.procolix.com"; | ||||
|       url = "https://git.fediversity.eu"; | ||||
|       # Obtaining the path to the runner token file may differ | ||||
|       token = "MKmFPY4nxfR4zPYHIRLoiJdrrfkGmcRymj0GWOAk"; | ||||
|       labels = [ | ||||
|         "docker:docker://node:16-bullseye" | ||||
|         "native:host" | ||||
|       ]; | ||||
|       hostPackages = with pkgs; [ | ||||
|         bash | ||||
|         git | ||||
|         nix | ||||
|         nodejs | ||||
|       ]; | ||||
|       settings = { | ||||
|         log.level = "info"; | ||||
|         runner = { | ||||
|           file = ".runner"; | ||||
|           capacity = 8; | ||||
|           timeout = "3h"; | ||||
|           insecure = false; | ||||
|           fetch_timeout = "5s"; | ||||
|           fetch_interval = "2s"; | ||||
|         }; | ||||
|       }; | ||||
|     }; | ||||
|   }; | ||||
| 
 | ||||
|   ## The Nix configuration of the system influences the Nix configuration | ||||
|   ## in the workflow, and our workflows are often flake-based. | ||||
|   nix.extraOptions = '' | ||||
|     experimental-features = nix-command flakes | ||||
|   ''; | ||||
| } | ||||
							
								
								
									
										1
									
								
								infra/vm02179/token.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								infra/vm02179/token.txt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | |||
| MKmFPY4nxfR4zPYHIRLoiJdrrfkGmcRymj0GWOAk | ||||
							
								
								
									
										26
									
								
								infra/vm02186/default.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								infra/vm02186/default.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | |||
| { | ||||
|   imports = [ | ||||
|     ../common | ||||
|     ./gitea-runner.nix | ||||
|   ]; | ||||
| 
 | ||||
|   procolix.vm = { | ||||
|     name = "vm02186"; | ||||
|     ip4 = "185.206.232.186"; | ||||
|     ip6 = "2a00:51c0:12:1201::186"; | ||||
|   }; | ||||
| 
 | ||||
|   fileSystems."/" = { | ||||
|     device = "/dev/disk/by-uuid/833ac0f9-ad8c-45ae-a9bf-5844e378c44a"; | ||||
|     fsType = "ext4"; | ||||
|   }; | ||||
| 
 | ||||
|   fileSystems."/boot" = { | ||||
|     device = "/dev/disk/by-uuid/B4D5-3AF9"; | ||||
|     fsType = "vfat"; | ||||
|     options = [ | ||||
|       "fmask=0022" | ||||
|       "dmask=0022" | ||||
|     ]; | ||||
|   }; | ||||
| } | ||||
|  | @ -25,8 +25,16 @@ | |||
| 
 | ||||
|       ## This runner supports Docker (with a default Ubuntu image) and native | ||||
|       ## modes. In native mode, it contains a few default packages. | ||||
|       labels = ["docker:docker://node:16-bullseye" "native:host"]; | ||||
|       hostPackages = with pkgs; [ bash git nix nodejs ]; | ||||
|       labels = [ | ||||
|         "docker:docker://node:16-bullseye" | ||||
|         "native:host" | ||||
|       ]; | ||||
|       hostPackages = with pkgs; [ | ||||
|         bash | ||||
|         git | ||||
|         nix | ||||
|         nodejs | ||||
|       ]; | ||||
|     }; | ||||
|   }; | ||||
| 
 | ||||
							
								
								
									
										26
									
								
								infra/vm02187/default.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								infra/vm02187/default.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | |||
| { | ||||
|   imports = [ | ||||
|     ../common | ||||
|     ./wiki.nix | ||||
|   ]; | ||||
| 
 | ||||
|   procolix.vm = { | ||||
|     name = "vm02187"; | ||||
|     ip4 = "185.206.232.187"; | ||||
|     ip6 = "2a00:51c0:12:1201::187"; | ||||
|   }; | ||||
| 
 | ||||
|   fileSystems."/" = { | ||||
|     device = "/dev/disk/by-uuid/a46a9c46-e32b-4216-a4aa-8819b2cd0d49"; | ||||
|     fsType = "ext4"; | ||||
|   }; | ||||
| 
 | ||||
|   fileSystems."/boot" = { | ||||
|     device = "/dev/disk/by-uuid/6AB5-4FA8"; | ||||
|     fsType = "vfat"; | ||||
|     options = [ | ||||
|       "fmask=0022" | ||||
|       "dmask=0022" | ||||
|     ]; | ||||
|   }; | ||||
| } | ||||
							
								
								
									
										65
									
								
								infra/vm02187/wiki.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								infra/vm02187/wiki.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,65 @@ | |||
| { pkgs, ... }: | ||||
| 
 | ||||
| { | ||||
|   services.phpfpm.pools.mediawiki.phpOptions = '' | ||||
|     upload_max_filesize = 1024M; | ||||
|     post_max_size = 1024M; | ||||
|   ''; | ||||
| 
 | ||||
|   services.mediawiki = { | ||||
|     enable = true; | ||||
|     name = "Fediversity Wiki"; | ||||
|     webserver = "nginx"; | ||||
|     nginx.hostName = "wiki.fediversity.eu"; | ||||
|     passwordFile = pkgs.writeText "password" "eiM9etha8ohmo9Ohphahpesiux0ahda6"; | ||||
|     extraConfig = '' | ||||
|       # Disable anonymous editing | ||||
|       $wgGroupPermissions['*']['edit'] = false; | ||||
|       $wgEnableUploads  = true; | ||||
|       $wgFileExtensions = array('png', 'jpg', 'jpeg', 'svg', 'pdf', 'odt', 'ods', 'brd', 'sch', 'JPG', 'PNG', 'JPEG', 'SVG', 'json', 'mkv', 'mp4', 'gif'); | ||||
|       $wgUseImageMagick = true; | ||||
|       $wgMaxShellMemory = 524288; | ||||
|       $wgSVGMetadataCutoff = 1024*1024; | ||||
|       $wgAllowExternalImages = false; | ||||
| 
 | ||||
|       ## Permissions | ||||
|       $wgGroupPermissions['*']['edit'] = false; | ||||
|       $wgGroupPermissions['*']['createaccount'] = false; | ||||
|       $wgGroupPermissions['*']['autocreateaccount'] = true; | ||||
|       $wgGroupPermissions['user']['edit'] = true; | ||||
|       $wgGroupPermissions['user']['createaccount'] = true; | ||||
|       $wgGroupPermissions['user']['editmyprivateinfo'] = true; | ||||
|       $wgGroupPermissions['sysop']['interwiki'] = true; | ||||
|       $wgGroupPermissions['sysop']['editwidgets'] = true; | ||||
|       # 1 GB ought to be enough for everyone | ||||
|       $wgUploadSizeWarning = 1024*1024*512; | ||||
|       $wgMaxUploadSize = 1024*1024*1024; | ||||
| 
 | ||||
|       $wgHeadScriptCode = <<<'END' | ||||
|       <link rel=me href="https://mastodon.fediversity.eu/@fediversity"> | ||||
|       END; | ||||
|     ''; | ||||
| 
 | ||||
|     extensions = { | ||||
|       VisualEditor = null; | ||||
|     }; | ||||
|   }; | ||||
| 
 | ||||
|   services.nginx = { | ||||
|     enable = true; | ||||
|     virtualHosts."wiki.fediversity.eu" = { | ||||
|       basicAuth = { | ||||
|         fediv = "SecretSauce123!"; | ||||
|       }; | ||||
|       forceSSL = true; | ||||
|       enableACME = true; | ||||
|     }; | ||||
|   }; | ||||
| 
 | ||||
|   security.acme = { | ||||
|     acceptTerms = true; | ||||
|     defaults.email = "systeemmail@procolix.com"; | ||||
|   }; | ||||
| 
 | ||||
|   users.users.nginx.extraGroups = [ "acme" ]; | ||||
| } | ||||
							
								
								
									
										15
									
								
								server/README.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								server/README.md
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,15 @@ | |||
| # fediversity.eu webserver | ||||
| 
 | ||||
| This directory contains the configuration for the server hosting https://fediversity.eu | ||||
| 
 | ||||
| Build the configuration: | ||||
| 
 | ||||
| ```bash | ||||
| nix-build -A machine | ||||
| ``` | ||||
| 
 | ||||
| Deploy via SSH: | ||||
| 
 | ||||
| ```bash | ||||
| env SSH_OPTS="..." nix-shell --run deploy-webserver | ||||
| ``` | ||||
|  | @ -1,4 +1,3 @@ | |||
| 
 | ||||
| # Edit this configuration file to define what should be installed on | ||||
| # your system.  Help is available in the configuration.nix(5) man page | ||||
| # and in the NixOS manual (accessible by running ‘nixos-help’). | ||||
|  | @ -7,7 +6,8 @@ | |||
| 
 | ||||
| { | ||||
|   imports = | ||||
|     [ # Include the results of the hardware scan. | ||||
|     [ | ||||
|       # Include the results of the hardware scan. | ||||
|       ./hardware-configuration.nix | ||||
|     ]; | ||||
| 
 | ||||
|  | @ -32,44 +32,44 @@ | |||
|     forceSSL = true; | ||||
|     globalRedirect = "www.fediversity.eu"; | ||||
|     locations."/.well-known/matrix/client" = { | ||||
|        extraConfig = '' | ||||
| 	return 200 '{"m.homeserver": {"base_url": "https://matrix.fediversity.eu", "public_baseurl": "https://matrix.fediversity.eu"}}'; | ||||
| 	default_type application/json; | ||||
| 	add_header Access-Control-Allow-Origin "*"; | ||||
| 	add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"; | ||||
| 	add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, Authorization"; | ||||
|       extraConfig = '' | ||||
|         	return 200 '{"m.homeserver": {"base_url": "https://matrix.fediversity.eu", "public_baseurl": "https://matrix.fediversity.eu"}}'; | ||||
|         	default_type application/json; | ||||
|         	add_header Access-Control-Allow-Origin "*"; | ||||
|         	add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"; | ||||
|         	add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, Authorization"; | ||||
|       ''; | ||||
|     }; | ||||
|     locations."/.well-known/matrix/server" = { | ||||
|        extraConfig = '' | ||||
| 	return 200 '{"m.server": "matrix.fediversity.eu:443"}'; | ||||
| 	default_type application/json; | ||||
| 	add_header Access-Control-Allow-Origin "*"; | ||||
| 	add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"; | ||||
| 	add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, Authorization"; | ||||
|       extraConfig = '' | ||||
|         	return 200 '{"m.server": "matrix.fediversity.eu:443"}'; | ||||
|         	default_type application/json; | ||||
|         	add_header Access-Control-Allow-Origin "*"; | ||||
|         	add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"; | ||||
|         	add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, Authorization"; | ||||
|       ''; | ||||
|     }; | ||||
|   }; | ||||
|   services.nginx.virtualHosts."www.fediversity.eu" = { | ||||
|     enableACME = true; | ||||
|     forceSSL = true; | ||||
|     root = "/var/www/www.fediversity.eu/fediversity.eu/public"; | ||||
|     root = "${(import ../website { }).build}"; | ||||
|     locations."/.well-known/matrix/client" = { | ||||
|        extraConfig = '' | ||||
| 	return 200 '{"m.homeserver": {"base_url": "https://matrix.fediversity.eu", "public_baseurl": "https://matrix.fediversity.eu"}}'; | ||||
| 	default_type application/json; | ||||
| 	add_header Access-Control-Allow-Origin "*"; | ||||
| 	add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"; | ||||
| 	add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, Authorization"; | ||||
|       extraConfig = '' | ||||
|         	return 200 '{"m.homeserver": {"base_url": "https://matrix.fediversity.eu", "public_baseurl": "https://matrix.fediversity.eu"}}'; | ||||
|         	default_type application/json; | ||||
|         	add_header Access-Control-Allow-Origin "*"; | ||||
|         	add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"; | ||||
|         	add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, Authorization"; | ||||
|       ''; | ||||
|     }; | ||||
|     locations."/.well-known/matrix/server" = { | ||||
|        extraConfig = '' | ||||
| 	return 200 '{"m.server": "matrix.fediversity.eu:443"}'; | ||||
| 	default_type application/json; | ||||
| 	add_header Access-Control-Allow-Origin "*"; | ||||
| 	add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"; | ||||
| 	add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, Authorization"; | ||||
|       extraConfig = '' | ||||
|         	return 200 '{"m.server": "matrix.fediversity.eu:443"}'; | ||||
|         	default_type application/json; | ||||
|         	add_header Access-Control-Allow-Origin "*"; | ||||
|         	add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"; | ||||
|         	add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, Authorization"; | ||||
|       ''; | ||||
|     }; | ||||
|   }; | ||||
|  | @ -80,7 +80,7 @@ | |||
|     certs."oid.foundation".extraDomainNames = [ "www.oid.foundation" ]; | ||||
|   }; | ||||
| 
 | ||||
|   networking = {   | ||||
|   networking = { | ||||
|     hostName = "vm02117"; | ||||
|     domain = "procolix.com"; | ||||
|     interfaces = { | ||||
|  | @ -117,9 +117,9 @@ | |||
|       enable = true; | ||||
|       ruleset = '' | ||||
|         #!/usr/sbin/nft -f | ||||
|        | ||||
| 
 | ||||
|         flush ruleset | ||||
|        | ||||
| 
 | ||||
|         ########### define usefull variables here ##################### | ||||
|         define wan        = eth0 | ||||
|         define ssh_allow  = { | ||||
|  | @ -137,38 +137,38 @@ | |||
|         define nrpe_allow = { | ||||
|                     95.215.185.34/32,   # nagios2 ipv4 | ||||
|                 } | ||||
|        | ||||
| 
 | ||||
|         ########### here starts the automated bit ##################### | ||||
|         table inet filter { | ||||
|             chain input { | ||||
|                 type filter hook input priority 0;  | ||||
|                 type filter hook input priority 0; | ||||
|                 policy drop; | ||||
|        | ||||
| 
 | ||||
|                 # established/related connections | ||||
|                 ct state established,related accept | ||||
|                 ct state invalid drop | ||||
|        | ||||
| 
 | ||||
|                 # Limit ping requests. | ||||
|                 ip protocol icmp icmp type echo-request limit rate over 10/second burst 50 packets drop | ||||
|                 ip6 nexthdr icmpv6 icmpv6 type echo-request limit rate over 10/second burst 50 packets drop | ||||
|        | ||||
| 
 | ||||
|                 # loopback interface | ||||
|                 iifname lo accept | ||||
|                  | ||||
| 
 | ||||
|                 # icmp | ||||
|                 ip protocol icmp icmp type { destination-unreachable, echo-reply, echo-request, source-quench, time-exceeded } accept | ||||
|                 # Without the nd-* ones ipv6 will not work. | ||||
|                 ip6 nexthdr icmpv6 icmpv6 type { destination-unreachable, echo-reply, echo-request, nd-neighbor-solicit,  nd-router-advert, nd-neighbor-advert, packet-too-big, parameter-problem, time-exceeded } accept | ||||
|        | ||||
| 
 | ||||
|                 # open tcp ports: sshd (22) | ||||
|                 ip saddr $ssh_allow tcp dport {ssh} accept | ||||
|        | ||||
| 
 | ||||
|                 # open tcp ports: snmp (161) | ||||
|                 ip saddr $snmp_allow udp dport {snmp} accept | ||||
|        | ||||
| 
 | ||||
|                 # open tcp ports: nrpe (5666) | ||||
|                 ip saddr $nrpe_allow tcp dport {nrpe} accept | ||||
|        | ||||
| 
 | ||||
|                 # open tcp ports: http (80,443) | ||||
|                 tcp dport {http,https} accept | ||||
|             } | ||||
|  | @ -179,13 +179,13 @@ | |||
|                 type filter hook output priority 0; | ||||
|             } | ||||
|         } | ||||
|        | ||||
| 
 | ||||
|         table ip nat { | ||||
|             chain postrouting { | ||||
|             }    | ||||
|             } | ||||
|             chain prerouting { | ||||
|             } | ||||
|         }   | ||||
|         } | ||||
|       ''; | ||||
|     }; | ||||
|   }; | ||||
|  | @ -197,13 +197,14 @@ | |||
|   # Select internationalisation properties. | ||||
|   i18n.defaultLocale = "en_US.UTF-8"; | ||||
| 
 | ||||
|   security.sudo.wheelNeedsPassword = false; | ||||
|   # Define a user account. Don't forget to set a password with ‘passwd’. | ||||
|   users.users.procolix = { | ||||
|     isNormalUser = true; | ||||
|     extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user. | ||||
|     openssh.authorizedKeys.keys = [ | ||||
|     "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAotfCIjLoDlHOe+++kVS1xiBPaS8mC5FypgrxDrDVst6SHxMTca2+IScMajzUZajenvNAoZOwIsyAPacT8OHeyFvV5Y7G874Qa+cZVqJxLht9gdXxr1GNabU3RfhhCh272dUeIKIqfgsRsM2HzdnZCMDavS1Yo+f+RhhHhnJIua+NdVFo21vPrpsz+Cd0M1NhojARLajrTHvEXW0KskUnkbfgxT0vL9jeRZxdgMS+a9ZoR5dbzOxQHWfbP8N04Xc+7CweMlvKwlWuAE/xDb5XLNHorfGWFvZuVhptJN8jPaaVS25wsmsF5IbaAuSZfzCtBdFQhIloUhy0L6ZisubHjQ== procolix@sshnode1" | ||||
|     "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAuT3C0f3nyQ7SwUvXcFmEYEgwL+crY6iK0Bhoi9yfn4soz3fhfMKyKSwc/0RIlRnrz3xnkyJiV0vFeU7AC1ixbGCS3T9uc0G1x0Yedd9n2yR8ZJmkdyfjZ5KE4YvqZ3f6UZn5Mtj+7tGmyp+ee+clLSHzsqeyDiX0FIgFmqiiAVJD6qeKPFAHeWz9b2MOXIBIw+fSLOpx0rosCgesOmPc8lgFvo+dMKpSlPkCuGLBPj2ObT4sLjc98NC5z8sNJMu3o5bMbiCDR9JWgx9nKj+NlALwk3Y/nzHSL/DNcnP5vz2zbX2CBKjx6ju0IXh6YKlJJVyMsH9QjwYkgDQVmy8amQ== procolix@sshnode2" | ||||
|       "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAotfCIjLoDlHOe+++kVS1xiBPaS8mC5FypgrxDrDVst6SHxMTca2+IScMajzUZajenvNAoZOwIsyAPacT8OHeyFvV5Y7G874Qa+cZVqJxLht9gdXxr1GNabU3RfhhCh272dUeIKIqfgsRsM2HzdnZCMDavS1Yo+f+RhhHhnJIua+NdVFo21vPrpsz+Cd0M1NhojARLajrTHvEXW0KskUnkbfgxT0vL9jeRZxdgMS+a9ZoR5dbzOxQHWfbP8N04Xc+7CweMlvKwlWuAE/xDb5XLNHorfGWFvZuVhptJN8jPaaVS25wsmsF5IbaAuSZfzCtBdFQhIloUhy0L6ZisubHjQ== procolix@sshnode1" | ||||
|       "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAuT3C0f3nyQ7SwUvXcFmEYEgwL+crY6iK0Bhoi9yfn4soz3fhfMKyKSwc/0RIlRnrz3xnkyJiV0vFeU7AC1ixbGCS3T9uc0G1x0Yedd9n2yR8ZJmkdyfjZ5KE4YvqZ3f6UZn5Mtj+7tGmyp+ee+clLSHzsqeyDiX0FIgFmqiiAVJD6qeKPFAHeWz9b2MOXIBIw+fSLOpx0rosCgesOmPc8lgFvo+dMKpSlPkCuGLBPj2ObT4sLjc98NC5z8sNJMu3o5bMbiCDR9JWgx9nKj+NlALwk3Y/nzHSL/DNcnP5vz2zbX2CBKjx6ju0IXh6YKlJJVyMsH9QjwYkgDQVmy8amQ== procolix@sshnode2" | ||||
|     ]; | ||||
|     packages = with pkgs; [ | ||||
|     ]; | ||||
|  | @ -212,7 +213,7 @@ | |||
|     isNormalUser = true; | ||||
|     extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user. | ||||
|     openssh.authorizedKeys.keys = [ | ||||
|     "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBbK4ZB0Xnpf8yyK4QOI2HvjgQINI3GKi7/O2VEsYXUb laurenshof@Laurenss-MacBook-Air.local" | ||||
|       "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBbK4ZB0Xnpf8yyK4QOI2HvjgQINI3GKi7/O2VEsYXUb laurenshof@Laurenss-MacBook-Air.local" | ||||
|     ]; | ||||
|     packages = with pkgs; [ | ||||
|     ]; | ||||
|  | @ -221,11 +222,18 @@ | |||
|     isNormalUser = true; | ||||
|     extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user. | ||||
|     openssh.authorizedKeys.keys = [ | ||||
|     "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJg5TlS1NGCRZwMjDgBkXeFUXqooqRlM8fJdBAQ4buPg" | ||||
|       "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJg5TlS1NGCRZwMjDgBkXeFUXqooqRlM8fJdBAQ4buPg" | ||||
|     ]; | ||||
|     packages = with pkgs; [ | ||||
|     ]; | ||||
|   }; | ||||
|   users.users.niols = { | ||||
|     isNormalUser = true; | ||||
|     extraGroups = [ "wheel" ]; | ||||
|     openssh.authorizedKeys.keys = [ | ||||
|       "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEElREJN0AC7lbp+5X204pQ5r030IbgCllsIxyU3iiKY" | ||||
|     ]; | ||||
|   }; | ||||
|   # List packages installed in system profile. To search, run: | ||||
|   # $ nix search wget | ||||
|   environment.systemPackages = with pkgs; [ | ||||
|  | @ -245,24 +253,17 @@ | |||
|     }) | ||||
|     wget | ||||
|     git | ||||
|     hugo | ||||
|     go | ||||
|     nodejs | ||||
|   ]; | ||||
| 
 | ||||
|   # List services that you want to enable: | ||||
| 
 | ||||
|   # Enable the OpenSSH daemon. | ||||
|   services.openssh.enable = true; | ||||
|   services.openssh.settings.PasswordAuthentication = false; | ||||
| 
 | ||||
|   # Enable xe-guest-utilities | ||||
|   services.xe-guest-utilities.enable = true; | ||||
| 
 | ||||
|   # Copy the NixOS configuration file and link it from the resulting system | ||||
|   # (/run/current-system/configuration.nix). This is useful in case you | ||||
|   # accidentally delete configuration.nix. | ||||
|   system.copySystemConfiguration = true; | ||||
| 
 | ||||
|   # This value determines the NixOS release from which the default | ||||
|   # settings for stateful data, like file locations and database versions | ||||
|   # on your system were taken. It‘s perfectly fine and recommended to leave | ||||
|  | @ -272,4 +273,3 @@ | |||
|   system.stateVersion = "23.11"; # Did you read the comment? | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										46
									
								
								server/default.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								server/default.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,46 @@ | |||
| { sources ? import ../website/npins | ||||
| , system ? builtins.currentSystem | ||||
| , pkgs ? import sources.nixpkgs { | ||||
|     inherit system; | ||||
|     config = { }; | ||||
|     overlays = [ ]; | ||||
|   } | ||||
| , lib ? import "${sources.nixpkgs}/lib" | ||||
| }: | ||||
| let | ||||
|   # TODO: don't hard code target hosts; wire all of it up with NixOps4 | ||||
|   host = "vm02117.procolix.com"; | ||||
|   deploy = pkgs.writeShellApplication { | ||||
|     name = "deploy-webserver"; | ||||
|     text = '' | ||||
|       # HACK: decouple system evaluation from shell evaluation | ||||
|       # the structured way for using this hack is encoded in https://github.com/fricklerhandwerk/lazy-drv | ||||
|       result="$(nix-build ${toString ./.} -A machine --no-out-link --eval-store auto --store ssh-ng://${host})" | ||||
|       # shellcheck disable=SC2087 | ||||
|       ssh ${host} << EOF | ||||
|       sudo nix-env -p /nix/var/nix/profiles/system --set "$result" | ||||
|       sudo "$result"/bin/switch-to-configuration switch | ||||
|       EOF | ||||
|     ''; | ||||
|   }; | ||||
|   nixos-configuration = config: | ||||
|     import "${pkgs.path}/nixos/lib/eval-config.nix" { | ||||
|       modules = [ | ||||
|         config | ||||
|       ]; | ||||
|       system = null; | ||||
|     }; | ||||
| in | ||||
| rec { | ||||
|   nixos = nixos-configuration ./configuration.nix; | ||||
|   machine = nixos.config.system.build.toplevel; | ||||
|   shell = pkgs.mkShellNoCC { | ||||
|     packages = with pkgs; [ | ||||
|       deploy | ||||
|     ]; | ||||
|     env = { | ||||
|       # TODO: reusing other pins for now; wire up the whole repo to use the same dependencies | ||||
|       NPINS_DIRECTORY = toString ../website/npins; | ||||
|     }; | ||||
|   }; | ||||
| } | ||||
							
								
								
									
										1
									
								
								server/shell.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								server/shell.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | |||
| (import ./. { }).shell | ||||
|  | @ -1 +0,0 @@ | |||
| use flake | ||||
|  | @ -40,7 +40,7 @@ NOTE: it sometimes takes a while for the services to start up, and in the meanti | |||
|     ``` | ||||
|   - Creating other accounts has to be enabled via the admin interface. `Administration > Configuration > Basic > Enable Signup` or just add an account directly from `Administration > Create user`. But functionality can also be tested from the root account. | ||||
| 
 | ||||
| - Pixelfed: <http://pixelfed.localhost:8000> | ||||
| - Pixelfed: through the reverse proxy at <http://pixelfed.localhost:8080> | ||||
|   - Account creation via the web interface won't work until we figure out email | ||||
|   - For now, they can be created on the VM command line | ||||
|     ```bash | ||||
|  | @ -57,16 +57,6 @@ nix build .#installers.peertube | |||
| Upload the image in `./result` to Proxmox when creating a VM. | ||||
| Booting the image will format the disk and install NixOS with the desired configuration. | ||||
| 
 | ||||
| # Deploying an updated machine configuration | ||||
| 
 | ||||
| > TODO: There is currently no way to specify an actual target machine by name. | ||||
| 
 | ||||
| Assuming you have SSH configuration with access to the remote `root` user stored for a machine called e.g. `peertube`, deploy the configuration by the same name: | ||||
| 
 | ||||
| ```bash | ||||
| nix run .#deploy.peertube | ||||
| ``` | ||||
| 
 | ||||
| ## debugging notes | ||||
| 
 | ||||
| - it is sometimes useful to `cat result/bin/run-nixos-vm` to see what's really going on (e.g. which ports are getting forwarded) | ||||
|  |  | |||
|  | @ -1,13 +0,0 @@ | |||
| { writeShellApplication }: | ||||
| name: _config: | ||||
| writeShellApplication { | ||||
|   name = "deploy"; | ||||
|   text = '' | ||||
|     result="$(nix build --print-out-paths ${./.}#nixosConfigurations#${name} --eval-store auto --store ssh-ng://${name})" | ||||
|     # shellcheck disable=SC2087 | ||||
|     ssh ${name} << EOF | ||||
|     nix-env -p /nix/var/nix/profiles/system --set "$result" | ||||
|     "$result"/bin/switch-to-configuration switch | ||||
|     EOF | ||||
|   ''; | ||||
| } | ||||
|  | @ -1,36 +0,0 @@ | |||
| { ... }: | ||||
| { | ||||
|   disko.devices.disk.main = { | ||||
|     device = "/dev/sda"; | ||||
|     type = "disk"; | ||||
|     content = { | ||||
|       type = "gpt"; | ||||
|       partitions = { | ||||
|         MBR = { | ||||
|           priority = 0; | ||||
|           size = "1M"; | ||||
|           type = "EF02"; | ||||
|         }; | ||||
|         ESP = { | ||||
|           priority = 1; | ||||
|           size = "500M"; | ||||
|           type = "EF00"; | ||||
|           content = { | ||||
|             type = "filesystem"; | ||||
|             format = "vfat"; | ||||
|             mountpoint = "/boot"; | ||||
|           }; | ||||
|         }; | ||||
|         root = { | ||||
|           priority = 2; | ||||
|           size = "100%"; | ||||
|           content = { | ||||
|             type = "filesystem"; | ||||
|             format = "ext4"; | ||||
|             mountpoint = "/"; | ||||
|           }; | ||||
|         }; | ||||
|       }; | ||||
|     }; | ||||
|   }; | ||||
| } | ||||
|  | @ -141,12 +141,8 @@ in | |||
|           types.submodule { | ||||
|             # TODO: these should be managed as secrets, not in the nix store | ||||
|             options = { | ||||
|               id = mkOption { | ||||
|                 type = types.str; | ||||
|               }; | ||||
|               secret = mkOption { | ||||
|                 type = types.str; | ||||
|               }; | ||||
|               id = mkOption { type = types.str; }; | ||||
|               secret = mkOption { type = types.str; }; | ||||
|               # TODO: assert at least one of these is true | ||||
|               # NOTE: this currently needs to be done at the top level module | ||||
|               ensureAccess = mkOption { | ||||
|  | @ -184,9 +180,7 @@ in | |||
|       pkgs.awscli | ||||
|     ]; | ||||
| 
 | ||||
|     networking.firewall.allowedTCPPorts = [ | ||||
|       fedicfg.rpc.port | ||||
|     ]; | ||||
|     networking.firewall.allowedTCPPorts = [ fedicfg.rpc.port ]; | ||||
|     services.garage = { | ||||
|       enable = true; | ||||
|       package = pkgs.garage_0_9; | ||||
|  | @ -222,6 +216,10 @@ in | |||
|               proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | ||||
|               # Disable buffering to a temporary file. | ||||
|               proxy_max_temp_file_size 0; | ||||
| 
 | ||||
|               ## NOTE: This page suggests many more options for the object storage | ||||
|               ## proxy. We should take a look. | ||||
|               ## https://docs.joinmastodon.org/admin/optional/object-storage-proxy/ | ||||
|             ''; | ||||
|           }; | ||||
|         }; | ||||
|  |  | |||
|  | @ -5,11 +5,7 @@ let | |||
|   }; | ||||
| in | ||||
| 
 | ||||
| { | ||||
|   config, | ||||
|   lib, | ||||
|   ... | ||||
| }: | ||||
| { config, lib, ... }: | ||||
| 
 | ||||
| lib.mkIf (config.fediversity.enable && config.fediversity.mastodon.enable) { | ||||
|   #### garage setup | ||||
|  | @ -50,9 +46,7 @@ lib.mkIf (config.fediversity.enable && config.fediversity.mastodon.enable) { | |||
|       AWS_ACCESS_KEY_ID = snakeoil_key.id; | ||||
|       AWS_SECRET_ACCESS_KEY = snakeoil_key.secret; | ||||
|       S3_PROTOCOL = "http"; | ||||
|       S3_HOSTNAME = config.fediversity.internal.garage.web.rootDomain; | ||||
|       # by default it tries to use "<S3_HOSTNAME>/<S3_BUCKET>" | ||||
|       S3_ALIAS_HOST = "${S3_BUCKET}.${S3_HOSTNAME}"; | ||||
|       S3_ALIAS_HOST = "${S3_BUCKET}.${config.fediversity.internal.garage.web.rootDomain}"; | ||||
|       # SEE: the last section in https://docs.joinmastodon.org/admin/optional/object-storage/ | ||||
|       # TODO: can we set up ACLs with garage? | ||||
|       S3_PERMISSION = ""; | ||||
|  | @ -82,9 +76,6 @@ lib.mkIf (config.fediversity.enable && config.fediversity.mastodon.enable) { | |||
|       fromAddress = "noreply@${config.fediversity.internal.mastodon.domain}"; | ||||
|       createLocally = false; | ||||
|     }; | ||||
| 
 | ||||
|     # TODO: this is hardware-dependent. let's figure it out when we have hardware | ||||
|     # streamingProcesses = 1; | ||||
|   }; | ||||
| 
 | ||||
|   security.acme = { | ||||
|  |  | |||
|  | @ -5,11 +5,7 @@ let | |||
|   }; | ||||
| in | ||||
| 
 | ||||
| { | ||||
|   config, | ||||
|   lib, | ||||
|   ... | ||||
| }: | ||||
| { config, lib, ... }: | ||||
| 
 | ||||
| lib.mkIf (config.fediversity.enable && config.fediversity.peertube.enable) { | ||||
|   networking.firewall.allowedTCPPorts = [ | ||||
|  |  | |||
							
								
								
									
										14
									
								
								services/flake-part.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								services/flake-part.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | |||
| { self, ... }: | ||||
| 
 | ||||
| { | ||||
|   flake.nixosModules.fediversity = import ./fediversity; | ||||
| 
 | ||||
|   perSystem = | ||||
|     { pkgs, ... }: | ||||
|     { | ||||
|       checks = { | ||||
|         mastodon = import ./tests/mastodon.nix { inherit self pkgs; }; | ||||
|         pixelfed-garage = import ./tests/pixelfed-garage.nix { inherit self pkgs; }; | ||||
|       }; | ||||
|     }; | ||||
| } | ||||
							
								
								
									
										187
									
								
								services/flake.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										187
									
								
								services/flake.lock
									
										
									
										generated
									
									
									
								
							|  | @ -1,187 +0,0 @@ | |||
| { | ||||
|   "nodes": { | ||||
|     "disko": { | ||||
|       "inputs": { | ||||
|         "nixpkgs": "nixpkgs" | ||||
|       }, | ||||
|       "locked": { | ||||
|         "lastModified": 1727347829, | ||||
|         "narHash": "sha256-y7cW6TjJKy+tu7efxeWI6lyg4VVx/9whx+OmrhmRShU=", | ||||
|         "owner": "nix-community", | ||||
|         "repo": "disko", | ||||
|         "rev": "1879e48907c14a70302ff5d0539c3b9b6f97feaa", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
|         "owner": "nix-community", | ||||
|         "repo": "disko", | ||||
|         "type": "github" | ||||
|       } | ||||
|     }, | ||||
|     "flake-compat": { | ||||
|       "flake": false, | ||||
|       "locked": { | ||||
|         "lastModified": 1696426674, | ||||
|         "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", | ||||
|         "owner": "edolstra", | ||||
|         "repo": "flake-compat", | ||||
|         "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
|         "owner": "edolstra", | ||||
|         "repo": "flake-compat", | ||||
|         "type": "github" | ||||
|       } | ||||
|     }, | ||||
|     "git-hooks": { | ||||
|       "inputs": { | ||||
|         "flake-compat": "flake-compat", | ||||
|         "gitignore": "gitignore", | ||||
|         "nixpkgs": "nixpkgs_2", | ||||
|         "nixpkgs-stable": "nixpkgs-stable" | ||||
|       }, | ||||
|       "locked": { | ||||
|         "lastModified": 1730814269, | ||||
|         "narHash": "sha256-fWPHyhYE6xvMI1eGY3pwBTq85wcy1YXqdzTZF+06nOg=", | ||||
|         "owner": "cachix", | ||||
|         "repo": "git-hooks.nix", | ||||
|         "rev": "d70155fdc00df4628446352fc58adc640cd705c2", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
|         "owner": "cachix", | ||||
|         "repo": "git-hooks.nix", | ||||
|         "type": "github" | ||||
|       } | ||||
|     }, | ||||
|     "gitignore": { | ||||
|       "inputs": { | ||||
|         "nixpkgs": [ | ||||
|           "git-hooks", | ||||
|           "nixpkgs" | ||||
|         ] | ||||
|       }, | ||||
|       "locked": { | ||||
|         "lastModified": 1709087332, | ||||
|         "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", | ||||
|         "owner": "hercules-ci", | ||||
|         "repo": "gitignore.nix", | ||||
|         "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
|         "owner": "hercules-ci", | ||||
|         "repo": "gitignore.nix", | ||||
|         "type": "github" | ||||
|       } | ||||
|     }, | ||||
|     "nixpkgs": { | ||||
|       "locked": { | ||||
|         "lastModified": 1725194671, | ||||
|         "narHash": "sha256-tLGCFEFTB5TaOKkpfw3iYT9dnk4awTP/q4w+ROpMfuw=", | ||||
|         "owner": "NixOS", | ||||
|         "repo": "nixpkgs", | ||||
|         "rev": "b833ff01a0d694b910daca6e2ff4a3f26dee478c", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
|         "owner": "NixOS", | ||||
|         "ref": "nixpkgs-unstable", | ||||
|         "repo": "nixpkgs", | ||||
|         "type": "github" | ||||
|       } | ||||
|     }, | ||||
|     "nixpkgs-latest": { | ||||
|       "locked": { | ||||
|         "lastModified": 1727220152, | ||||
|         "narHash": "sha256-6ezRTVBZT25lQkvaPrfJSxYLwqcbNWm6feD/vG1FO0o=", | ||||
|         "owner": "nixos", | ||||
|         "repo": "nixpkgs", | ||||
|         "rev": "24959f933187217890b206788a85bfa73ba75949", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
|         "owner": "nixos", | ||||
|         "repo": "nixpkgs", | ||||
|         "type": "github" | ||||
|       } | ||||
|     }, | ||||
|     "nixpkgs-stable": { | ||||
|       "locked": { | ||||
|         "lastModified": 1730741070, | ||||
|         "narHash": "sha256-edm8WG19kWozJ/GqyYx2VjW99EdhjKwbY3ZwdlPAAlo=", | ||||
|         "owner": "NixOS", | ||||
|         "repo": "nixpkgs", | ||||
|         "rev": "d063c1dd113c91ab27959ba540c0d9753409edf3", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
|         "owner": "NixOS", | ||||
|         "ref": "nixos-24.05", | ||||
|         "repo": "nixpkgs", | ||||
|         "type": "github" | ||||
|       } | ||||
|     }, | ||||
|     "nixpkgs_2": { | ||||
|       "locked": { | ||||
|         "lastModified": 1730768919, | ||||
|         "narHash": "sha256-8AKquNnnSaJRXZxc5YmF/WfmxiHX6MMZZasRP6RRQkE=", | ||||
|         "owner": "NixOS", | ||||
|         "repo": "nixpkgs", | ||||
|         "rev": "a04d33c0c3f1a59a2c1cb0c6e34cd24500e5a1dc", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
|         "owner": "NixOS", | ||||
|         "ref": "nixpkgs-unstable", | ||||
|         "repo": "nixpkgs", | ||||
|         "type": "github" | ||||
|       } | ||||
|     }, | ||||
|     "nixpkgs_3": { | ||||
|       "locked": { | ||||
|         "lastModified": 1730137230, | ||||
|         "narHash": "sha256-0kW6v0alzWIc/Dc/DoVZ7A9qNScv77bj/zYTKI67HZM=", | ||||
|         "owner": "radvendii", | ||||
|         "repo": "nixpkgs", | ||||
|         "rev": "df815998652a1d00ce7c059a1e5ef7d7c0548c90", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
|         "owner": "radvendii", | ||||
|         "ref": "nixos_rebuild_tests", | ||||
|         "repo": "nixpkgs", | ||||
|         "type": "github" | ||||
|       } | ||||
|     }, | ||||
|     "pixelfed": { | ||||
|       "flake": false, | ||||
|       "locked": { | ||||
|         "lastModified": 1719823820, | ||||
|         "narHash": "sha256-CKjqnxp7p2z/13zfp4HQ1OAmaoUtqBKS6HFm6TV8Jwg=", | ||||
|         "owner": "pixelfed", | ||||
|         "repo": "pixelfed", | ||||
|         "rev": "4c245cf429330d01fcb8ebeb9aa8c84a9574a645", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
|         "owner": "pixelfed", | ||||
|         "ref": "v0.12.3", | ||||
|         "repo": "pixelfed", | ||||
|         "type": "github" | ||||
|       } | ||||
|     }, | ||||
|     "root": { | ||||
|       "inputs": { | ||||
|         "disko": "disko", | ||||
|         "git-hooks": "git-hooks", | ||||
|         "nixpkgs": "nixpkgs_3", | ||||
|         "nixpkgs-latest": "nixpkgs-latest", | ||||
|         "pixelfed": "pixelfed" | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "root": "root", | ||||
|   "version": 7 | ||||
| } | ||||
|  | @ -1,143 +0,0 @@ | |||
| { | ||||
|   inputs = { | ||||
|     nixpkgs.url = "github:radvendii/nixpkgs/nixos_rebuild_tests"; | ||||
|     nixpkgs-latest.url = "github:nixos/nixpkgs"; | ||||
|     git-hooks.url = "github:cachix/git-hooks.nix"; | ||||
| 
 | ||||
|     pixelfed = { | ||||
|       url = "github:pixelfed/pixelfed?ref=v0.12.3"; | ||||
|       flake = false; | ||||
|     }; | ||||
|     disko.url = "github:nix-community/disko"; | ||||
|   }; | ||||
| 
 | ||||
|   outputs = | ||||
|     { | ||||
|       self, | ||||
|       nixpkgs, | ||||
|       nixpkgs-latest, | ||||
|       git-hooks, | ||||
|       pixelfed, | ||||
|       disko, | ||||
|     }: | ||||
|     let | ||||
|       system = "x86_64-linux"; | ||||
|       lib = nixpkgs.lib; | ||||
|       pkgs = nixpkgs.legacyPackages.${system}; | ||||
|       pkgsLatest = nixpkgs-latest.legacyPackages.${system}; | ||||
|       bleedingFediverseOverlay = ( | ||||
|         _: _: { | ||||
|           pixelfed = pkgsLatest.pixelfed.overrideAttrs (old: { | ||||
|             src = pixelfed; | ||||
|             patches = (old.patches or [ ]) ++ [ ./fediversity/pixelfed-group-permissions.patch ]; | ||||
|           }); | ||||
|           ## TODO: give mastodon, peertube the same treatment | ||||
|         } | ||||
|       ); | ||||
|     in | ||||
|     { | ||||
|       nixosModules = { | ||||
|         ## Bleeding-edge fediverse packages | ||||
|         bleedingFediverse = { | ||||
|           nixpkgs.overlays = [ bleedingFediverseOverlay ]; | ||||
|         }; | ||||
|         ## Fediversity modules | ||||
|         fediversity = import ./fediversity; | ||||
| 
 | ||||
|         ## VM-specific modules | ||||
|         interactive-vm = import ./vm/interactive-vm.nix; | ||||
|         garage-vm = import ./vm/garage-vm.nix; | ||||
|         mastodon-vm = import ./vm/mastodon-vm.nix; | ||||
|         peertube-vm = import ./vm/peertube-vm.nix; | ||||
|         pixelfed-vm = import ./vm/pixelfed-vm.nix; | ||||
| 
 | ||||
|         disk-layout = import ./disk-layout.nix; | ||||
|       }; | ||||
| 
 | ||||
|       nixosConfigurations = { | ||||
|         mastodon = nixpkgs.lib.nixosSystem { | ||||
|           inherit system; | ||||
|           modules = with self.nixosModules; [ | ||||
|             disko.nixosModules.default | ||||
|             disk-layout | ||||
|             bleedingFediverse | ||||
|             fediversity | ||||
|             interactive-vm | ||||
|             garage-vm | ||||
|             mastodon-vm | ||||
|           ]; | ||||
|         }; | ||||
| 
 | ||||
|         peertube = nixpkgs.lib.nixosSystem { | ||||
|           inherit system; | ||||
|           modules = with self.nixosModules; [ | ||||
|             disko.nixosModules.default | ||||
|             disk-layout | ||||
|             bleedingFediverse | ||||
|             fediversity | ||||
|             interactive-vm | ||||
|             garage-vm | ||||
|             peertube-vm | ||||
|           ]; | ||||
|         }; | ||||
| 
 | ||||
|         pixelfed = nixpkgs.lib.nixosSystem { | ||||
|           inherit system; | ||||
|           modules = with self.nixosModules; [ | ||||
|             disko.nixosModules.default | ||||
|             disk-layout | ||||
|             bleedingFediverse | ||||
|             fediversity | ||||
|             interactive-vm | ||||
|             garage-vm | ||||
|             pixelfed-vm | ||||
|           ]; | ||||
|         }; | ||||
| 
 | ||||
|         all = nixpkgs.lib.nixosSystem { | ||||
|           inherit system; | ||||
|           modules = with self.nixosModules; [ | ||||
|             disko.nixosModules.default | ||||
|             disk-layout | ||||
|             bleedingFediverse | ||||
|             fediversity | ||||
|             interactive-vm | ||||
|             garage-vm | ||||
|             peertube-vm | ||||
|             pixelfed-vm | ||||
|             mastodon-vm | ||||
|           ]; | ||||
|         }; | ||||
|       }; | ||||
| 
 | ||||
|       ## Fully-feature ISO installer | ||||
|       mkInstaller = import ./installer.nix; | ||||
|       installers = lib.mapAttrs (_: config: self.mkInstaller nixpkgs config) self.nixosConfigurations; | ||||
| 
 | ||||
|       deploy = | ||||
|         let | ||||
|           deployCommand = (pkgs.callPackage ./deploy.nix { }); | ||||
|         in | ||||
|         lib.mapAttrs (name: config: deployCommand name config) self.nixosConfigurations; | ||||
| 
 | ||||
|       checks.${system} = { | ||||
|         mastodon-garage = import ./tests/mastodon-garage.nix { inherit pkgs self; }; | ||||
|         pixelfed-garage = import ./tests/pixelfed-garage.nix { inherit pkgs self; }; | ||||
| 
 | ||||
|         pre-commit = git-hooks.lib.${system}.run { | ||||
|           src = ./.; | ||||
|           hooks = { | ||||
|             nixfmt-rfc-style.enable = true; | ||||
|             deadnix.enable = true; | ||||
|           }; | ||||
|         }; | ||||
|       }; | ||||
| 
 | ||||
|       devShells.${system}.default = pkgs.mkShell { | ||||
|         inputs = with pkgs; [ | ||||
|           nil | ||||
|         ]; | ||||
|         shellHook = self.checks.${system}.pre-commit.shellHook; | ||||
|       }; | ||||
|     }; | ||||
| } | ||||
|  | @ -1,23 +1,28 @@ | |||
| ## This file is a basic test of Mastodon functionalities. | ||||
| ## | ||||
| ## NOTE: This test will fail for Mastodon < 4.3 because of | ||||
| ## https://github.com/mastodon/mastodon/issues/31145 | ||||
| 
 | ||||
| { pkgs, self }: | ||||
| 
 | ||||
| let | ||||
|   lib = pkgs.lib; | ||||
| 
 | ||||
|   ## FIXME: this binding was not used, but maybe we want a side-effect or something? | ||||
|   # rebuildableTest = import ./rebuildableTest.nix pkgs; | ||||
| 
 | ||||
|   testImage = pkgs.copyPathToStore ./green.png; | ||||
|   testImageColour = "#00FF00"; | ||||
| 
 | ||||
|   seleniumScript = | ||||
|     pkgs.writers.writePython3Bin "selenium-script" | ||||
|       { | ||||
|         libraries = with pkgs.python3Packages; [ selenium ]; | ||||
|       } | ||||
|       { libraries = with pkgs.python3Packages; [ selenium ]; } | ||||
|       '' | ||||
|         from selenium import webdriver | ||||
|         from selenium.webdriver.common.by import By | ||||
|         from selenium.webdriver.firefox.options import Options | ||||
|         from selenium.webdriver.support.ui import WebDriverWait | ||||
| 
 | ||||
|         print(1) | ||||
| 
 | ||||
|         options = Options() | ||||
|         options.add_argument("--headless") | ||||
|         # devtools don't show up in headless screenshots | ||||
|  | @ -25,7 +30,7 @@ let | |||
|         service = webdriver.FirefoxService(executable_path="${lib.getExe pkgs.geckodriver}")  # noqa: E501 | ||||
| 
 | ||||
|         driver = webdriver.Firefox(options=options, service=service) | ||||
|         driver.get("http://mastodon.localhost:55001/public/local") | ||||
|         driver.get("http://mastodon.localhost/public/local") | ||||
| 
 | ||||
|         # wait until the statuses load | ||||
|         WebDriverWait(driver, 90).until( | ||||
|  | @ -36,6 +41,7 @@ let | |||
|         driver.close() | ||||
|       ''; | ||||
| in | ||||
| 
 | ||||
| pkgs.nixosTest { | ||||
|   name = "test-mastodon-garage"; | ||||
| 
 | ||||
|  | @ -45,10 +51,10 @@ pkgs.nixosTest { | |||
|       { | ||||
|         virtualisation.memorySize = lib.mkVMOverride 4096; | ||||
|         imports = with self.nixosModules; [ | ||||
|           bleedingFediverse | ||||
|           fediversity | ||||
|           garage-vm | ||||
|           mastodon-vm | ||||
|           ../vm/garage-vm.nix | ||||
|           ../vm/mastodon-vm.nix | ||||
|           ../vm/interactive-vm.nix | ||||
|         ]; | ||||
|         # TODO: pair down | ||||
|         environment.systemPackages = with pkgs; [ | ||||
|  | @ -60,9 +66,9 @@ pkgs.nixosTest { | |||
|           seleniumScript | ||||
|           helix | ||||
|           imagemagick | ||||
|           expect | ||||
|         ]; | ||||
|         environment.variables = { | ||||
|           POST_MEDIA = ./green.png; | ||||
|           AWS_ACCESS_KEY_ID = config.services.garage.ensureKeys.mastodon.id; | ||||
|           AWS_SECRET_ACCESS_KEY = config.services.garage.ensureKeys.mastodon.secret; | ||||
|         }; | ||||
|  | @ -90,64 +96,67 @@ pkgs.nixosTest { | |||
|         if password_match is None: | ||||
|           raise Exception(f"account creation did not generate a password.\n{account_creation_output}") | ||||
|         password = password_match.group(1) | ||||
| 
 | ||||
|       with subtest("TTY Login"): | ||||
|         server.wait_until_tty_matches("1", "login: ") | ||||
|         server.send_chars("root\n"); | ||||
|         # print(f"Test user (test@test.com)'s password is: {password}") | ||||
| 
 | ||||
|       with subtest("Log in with toot"): | ||||
|         # toot doesn't provide a way to just specify our login details as arguments, so we have to pretend we're typing them in at the prompt | ||||
|         server.send_chars("toot login_cli --instance http://mastodon.localhost:55001 --email test@test.com\n") | ||||
|         server.wait_until_tty_matches("1", "Password: ") | ||||
|         server.send_chars(password + "\n") | ||||
|         server.wait_until_tty_matches("1", "Successfully logged in.") | ||||
|         # toot doesn't provide a way to just specify our login details as | ||||
|         # arguments, so we have to pretend we're typing them in at the prompt; | ||||
|         # we use 'expect' for this purpose. | ||||
|         server.succeed(f""" | ||||
|           expect -c ' | ||||
|             spawn toot login_cli --instance http://mastodon.localhost:55001 --email test@test.com | ||||
|             expect "Password: " | ||||
|             send "{password}\\n" | ||||
|             interact | ||||
|           ' >&2 | ||||
|         """) | ||||
| 
 | ||||
|       with subtest("post text"): | ||||
|       with subtest("Post a text"): | ||||
|         server.succeed("echo 'hello mastodon' | toot post") | ||||
| 
 | ||||
|       with subtest("post image"): | ||||
|         server.succeed("toot post --media $POST_MEDIA") | ||||
|       with subtest("Post an image"): | ||||
|         server.succeed("toot post --media ${testImage}") | ||||
| 
 | ||||
|       with subtest("access garage"): | ||||
|       with subtest("Access garage"): | ||||
|         server.succeed("mc alias set garage ${nodes.server.fediversity.internal.garage.api.url} --api s3v4 --path off $AWS_ACCESS_KEY_ID $AWS_SECRET_ACCESS_KEY") | ||||
|         server.succeed("mc ls garage/mastodon") | ||||
| 
 | ||||
|       with subtest("access image in garage"): | ||||
|       with subtest("Access image in garage"): | ||||
|         image = server.succeed("mc find garage --regex original") | ||||
|         image = image.rstrip() | ||||
|         if image == "": | ||||
|           raise Exception("image posted to mastodon did not get stored in garage") | ||||
|         server.succeed(f"mc cat {image} >/garage-image.webp") | ||||
|         garage_image_hash = server.succeed("identify -quiet -format '%#' /garage-image.webp") | ||||
|         image_hash = server.succeed("identify -quiet -format '%#' $POST_MEDIA") | ||||
|         image_hash = server.succeed("identify -quiet -format '%#' ${testImage}") | ||||
|         if garage_image_hash != image_hash: | ||||
|           raise Exception("image stored in garage did not match image uploaded") | ||||
| 
 | ||||
|       with subtest("Content security policy allows garage images"): | ||||
|       with subtest("Content-Security-Policy allows garage content"): | ||||
|         headers = server.succeed("xh -h http://mastodon.localhost:55001/public/local") | ||||
|         csp_match = None | ||||
|         # I can't figure out re.MULTILINE | ||||
|         for header in headers.split("\n"): | ||||
|           csp_match =  re.match('^Content-Security-Policy: (.*)$', header) | ||||
|           csp_match = re.match('^Content-Security-Policy: (.*)$', header) | ||||
|           if csp_match is not None: | ||||
|             break | ||||
|         if csp_match is None: | ||||
|           raise Exception("mastodon did not send a content security policy header") | ||||
|         csp = csp_match.group(1) | ||||
|         # the img-src content security policy should include the garage server | ||||
|         # the connect-src content security policy should include the garage server | ||||
|         ## TODO: use `nodes.server.fediversity.internal.garage.api.url` same as above, but beware of escaping the regex. Be careful with port 80 though. | ||||
|         garage_csp = re.match(".*; img-src[^;]*web\.garage\.localhost.*", csp) | ||||
|         if garage_csp is None: | ||||
|           raise Exception("Mastodon's content security policy does not include garage server. image will not be displayed properly on mastodon.") | ||||
|           raise Exception("Mastodon's Content-Security-Policy does not include Garage.") | ||||
| 
 | ||||
|       # this could in theory give a false positive if mastodon changes it's colorscheme to include pure green. | ||||
|       with subtest("image displays"): | ||||
|       # this could in theory give a false positive if mastodon changes it's colorscheme to include ${testImageColour}. | ||||
|       with subtest("Image displays"): | ||||
|         server.succeed("selenium-script") | ||||
|         server.copy_from_vm("/mastodon-screenshot.png", "") | ||||
|         displayed_colors = server.succeed("convert /mastodon-screenshot.png -define histogram:unique-colors=true -format %c histogram:info:") | ||||
|         # check that the green image displayed somewhere | ||||
|         green_check = re.match(".*#00FF00.*", displayed_colors, re.S) | ||||
|         if green_check is None: | ||||
|         # check that the image displayed somewhere | ||||
|         image_check = re.match(".*${testImageColour}.*", displayed_colors, re.S) | ||||
|         if image_check is None: | ||||
|           raise Exception("cannot detect the uploaded image on mastodon page.") | ||||
|     ''; | ||||
| } | ||||
|  | @ -54,9 +54,7 @@ let | |||
| 
 | ||||
|   seleniumScriptPostPicture = | ||||
|     pkgs.writers.writePython3Bin "selenium-script-post-picture" | ||||
|       { | ||||
|         libraries = with pkgs.python3Packages; [ selenium ]; | ||||
|       } | ||||
|       { libraries = with pkgs.python3Packages; [ selenium ]; } | ||||
|       '' | ||||
|         import os | ||||
|         import time | ||||
|  | @ -99,9 +97,7 @@ let | |||
| 
 | ||||
|   seleniumScriptGetSrc = | ||||
|     pkgs.writers.writePython3Bin "selenium-script-get-src" | ||||
|       { | ||||
|         libraries = with pkgs.python3Packages; [ selenium ]; | ||||
|       } | ||||
|       { libraries = with pkgs.python3Packages; [ selenium ]; } | ||||
|       '' | ||||
|         ${seleniumImports} | ||||
|         ${seleniumSetup} | ||||
|  | @ -147,10 +143,9 @@ pkgs.nixosTest { | |||
|           cores = 8; | ||||
|         }; | ||||
|         imports = with self.nixosModules; [ | ||||
|           bleedingFediverse | ||||
|           fediversity | ||||
|           garage-vm | ||||
|           pixelfed-vm | ||||
|           ../vm/garage-vm.nix | ||||
|           ../vm/pixelfed-vm.nix | ||||
|         ]; | ||||
|         # TODO: pair down | ||||
|         environment.systemPackages = with pkgs; [ | ||||
|  | @ -191,7 +186,7 @@ pkgs.nixosTest { | |||
|         server.succeed("pixelfed-manage user:create --name=test --username=test --email=${email} --password=${password} --confirm_email=1") | ||||
| 
 | ||||
|       # NOTE: This could in theory give a false positive if pixelfed changes it's | ||||
|       # colorscheme to include pure green. (see same problem in pixelfed-garage.nix). | ||||
|       # colorscheme to include pure green. (see same problem in mastodon-garage.nix). | ||||
|       # TODO: For instance: post a red image and check that the green pixel IS NOT | ||||
|       # there, then post a green image and check that the green pixel IS there. | ||||
| 
 | ||||
|  |  | |||
|  | @ -32,29 +32,8 @@ | |||
|     extra-experimental-features = nix-command flakes | ||||
|   ''; | ||||
| 
 | ||||
|   # no graphics. see nixos-shell | ||||
|   virtualisation = { | ||||
|     graphics = false; | ||||
|     qemu.consoles = [ | ||||
|       "tty0" | ||||
|       "hvc0" | ||||
|     ]; | ||||
|     qemu.options = [ | ||||
|       "-serial null" | ||||
|       "-device virtio-serial" | ||||
|       "-chardev stdio,mux=on,id=char0,signal=off" | ||||
|       "-mon chardev=char0,mode=readline" | ||||
|       "-device virtconsole,chardev=char0,nr=0" | ||||
|     ]; | ||||
|   }; | ||||
|   virtualisation.memorySize = 2048; | ||||
| 
 | ||||
|   # we can't forward port 80 or 443, so let's run nginx on a different port | ||||
|   networking.firewall.allowedTCPPorts = [ | ||||
|     8443 | ||||
|     8080 | ||||
|   ]; | ||||
|   services.nginx.defaultSSLListenPort = 8443; | ||||
|   services.nginx.defaultHTTPListenPort = 8080; | ||||
|   virtualisation.forwardPorts = [ | ||||
|     { | ||||
|       from = "host"; | ||||
|  | @ -64,12 +43,12 @@ | |||
|     { | ||||
|       from = "host"; | ||||
|       host.port = 8080; | ||||
|       guest.port = 8080; | ||||
|       guest.port = 80; | ||||
|     } | ||||
|     { | ||||
|       from = "host"; | ||||
|       host.port = 8443; | ||||
|       guest.port = 8443; | ||||
|       guest.port = 443; | ||||
|     } | ||||
|   ]; | ||||
| } | ||||
|  |  | |||
|  | @ -33,15 +33,6 @@ | |||
|           email = "none"; | ||||
|         }; | ||||
|       }; | ||||
| 
 | ||||
|       virtualisation.memorySize = 2048; | ||||
|       virtualisation.forwardPorts = [ | ||||
|         { | ||||
|           from = "host"; | ||||
|           host.port = 44443; | ||||
|           guest.port = 443; | ||||
|         } | ||||
|       ]; | ||||
|     } | ||||
| 
 | ||||
|     #### run mastodon as development environment | ||||
|  | @ -58,7 +49,6 @@ | |||
|           BIND = "0.0.0.0"; | ||||
|           # for letter_opener (still doesn't work though) | ||||
|           REMOTE_DEV = "true"; | ||||
|           LOCAL_DOMAIN = "${config.fediversity.internal.mastodon.domain}:8443"; | ||||
|         }; | ||||
|       }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,8 +1,4 @@ | |||
| { | ||||
|   lib, | ||||
|   modulesPath, | ||||
|   ... | ||||
| }: | ||||
| { lib, modulesPath, ... }: | ||||
| 
 | ||||
| let | ||||
|   inherit (lib) mkVMOverride; | ||||
|  | @ -27,13 +23,4 @@ in | |||
|       enableACME = mkVMOverride false; | ||||
|     }; | ||||
|   }; | ||||
| 
 | ||||
|   virtualisation.memorySize = 2048; | ||||
|   virtualisation.forwardPorts = [ | ||||
|     { | ||||
|       from = "host"; | ||||
|       host.port = 8000; | ||||
|       guest.port = 80; | ||||
|     } | ||||
|   ]; | ||||
| } | ||||
|  |  | |||
|  | @ -30,6 +30,26 @@ Structured content is managed through Nix expressions, and copy is written in [C | |||
| 
 | ||||
| - Edit any of the files, see [repository layout](#repository-layout) for guidance | ||||
| 
 | ||||
| # Testing | ||||
| 
 | ||||
| As a derivation, e.g. for CI: | ||||
| 
 | ||||
| ```bash | ||||
| nix-build -A tests | ||||
| ``` | ||||
| 
 | ||||
| In the development shell: | ||||
| 
 | ||||
| ```bash | ||||
| run-tests | ||||
| ``` | ||||
| 
 | ||||
| Running tests in a loop on source code changes: | ||||
| 
 | ||||
| ```bash | ||||
| test-loop | ||||
| ``` | ||||
| 
 | ||||
| # Repository layout | ||||
| 
 | ||||
| - [content](./content) | ||||
|  |  | |||
|  | @ -28,7 +28,6 @@ in | |||
|         ]; | ||||
|         body.content = | ||||
|           let | ||||
|             prev-content = prev.html.body.content; | ||||
|             to-section = { heading, body, attrs ? { } }: { | ||||
|               section = { | ||||
|                 heading.content = heading; | ||||
|  | @ -43,7 +42,7 @@ in | |||
|             }; | ||||
|           in | ||||
|           [ | ||||
|             (lib.head prev-content) # header | ||||
|             (lib.head prev.html.body.content) | ||||
|             { | ||||
|               section = { | ||||
|                 attrs = { }; | ||||
|  |  | |||
|  | @ -24,7 +24,7 @@ in | |||
|       { | ||||
|         link = { | ||||
|           label = "Contact"; | ||||
|           url = "mailto:mail@fediversity.eu"; | ||||
|           url = "mailto:contact@fediversity.eu"; | ||||
|         }; | ||||
|       } | ||||
|     ]; | ||||
|  |  | |||
|  | @ -14,16 +14,11 @@ let | |||
|     in | ||||
|     new // { types = prev.recursiveUpdate prev.types new.types; }; | ||||
|   lib'' = lib.extend lib'; | ||||
|   # TODO: update when the PR to expose `pkgs.devmode` is merged | ||||
|   #       https://github.com/NixOS/nixpkgs/pull/354556 | ||||
|   devmode = pkgs.callPackage "${sources.devmode-reusable}/pkgs/by-name/de/devmode/package.nix" { | ||||
|     buildArgs = "${toString ./.} -A build --show-trace"; | ||||
|     open = "/index.html"; | ||||
|   }; | ||||
| 
 | ||||
| in | ||||
| rec { | ||||
|   lib = import ./lib.nix { inherit lib; }; | ||||
|   result = lib''.evalModules { | ||||
|   lib = lib''; | ||||
|   result = lib.evalModules { | ||||
|     modules = [ | ||||
|       ./structure | ||||
|       ./content | ||||
|  | @ -38,11 +33,36 @@ rec { | |||
| 
 | ||||
|   inherit (result.config) build; | ||||
| 
 | ||||
|   shell = pkgs.mkShellNoCC { | ||||
|     packages = with pkgs; [ | ||||
|       cmark | ||||
|       npins | ||||
|       devmode | ||||
|     ]; | ||||
|   }; | ||||
|   shell = | ||||
|     let | ||||
|       run-tests = pkgs.writeShellApplication { | ||||
|         name = "run-tests"; | ||||
|         text = with pkgs; with lib; '' | ||||
|           ${getExe nix-unit} ${toString ./tests.nix} "$@" | ||||
|         ''; | ||||
|       }; | ||||
|       test-loop = pkgs.writeShellApplication { | ||||
|         name = "test-loop"; | ||||
|         text = with pkgs; with lib; '' | ||||
|           ${getExe watchexec} -w ${toString ./.} -- ${getExe nix-unit} ${toString ./tests.nix} | ||||
|         ''; | ||||
|       }; | ||||
|       devmode = pkgs.devmode.override { | ||||
|         buildArgs = "${toString ./.} -A build --show-trace"; | ||||
|         open = "/index.html"; | ||||
|       }; | ||||
|     in | ||||
|     pkgs.mkShellNoCC { | ||||
|       packages = [ | ||||
|         pkgs.npins | ||||
|         run-tests | ||||
|         test-loop | ||||
|         devmode | ||||
|       ]; | ||||
|     }; | ||||
| 
 | ||||
|   tests = with pkgs; with lib; runCommand "run-tests" { } '' | ||||
|     touch $out | ||||
|     ${getExe nix-unit} ${./tests.nix} "$@" | ||||
|   ''; | ||||
| } | ||||
|  |  | |||
|  | @ -99,20 +99,22 @@ rec { | |||
|   relativePath = path1': path2': | ||||
|     let | ||||
|       inherit (lib.path) subpath; | ||||
|       inherit (lib) lists; | ||||
|       inherit (lib) lists length take drop min max; | ||||
| 
 | ||||
|       path1 = subpath.components path1'; | ||||
|       prefix1 = with lib; take (length path1 - 1) path1; | ||||
|       prefix1 = take (length path1 - 1) path1; | ||||
|       path2 = subpath.components path2'; | ||||
|       prefix2 = with lib; take (length path1 - 1) path2; | ||||
|       prefix2 = take (length path2 - 1) path2; | ||||
| 
 | ||||
|       commonPrefixLength = with lists; | ||||
|         findFirstIndex (i: i.fst != i.snd) | ||||
|           (length prefix1) | ||||
|           (min (length prefix1) (length prefix2)) | ||||
|           (zipLists prefix1 prefix2); | ||||
| 
 | ||||
|       depth = max 0 (length prefix1 - commonPrefixLength); | ||||
| 
 | ||||
|       relativeComponents = with lists; | ||||
|         [ "." ] ++ (replicate (length prefix1 - commonPrefixLength) "..") ++ (drop commonPrefixLength path2); | ||||
|         [ "." ] ++ (replicate depth "..") ++ (drop commonPrefixLength path2); | ||||
|     in | ||||
|     join "/" relativeComponents; | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,22 +1,22 @@ | |||
| { | ||||
|   "pins": { | ||||
|     "devmode-reusable": { | ||||
|     "nix-unit": { | ||||
|       "type": "Git", | ||||
|       "repository": { | ||||
|         "type": "GitHub", | ||||
|         "owner": "fricklerhandwerk", | ||||
|         "repo": "nixpkgs" | ||||
|         "owner": "nix-community", | ||||
|         "repo": "nix-unit" | ||||
|       }, | ||||
|       "branch": "refactor-devmode", | ||||
|       "revision": "f0746a6690939987734d6519a2e3daf28ed36d87", | ||||
|       "url": "https://github.com/fricklerhandwerk/nixpkgs/archive/f0746a6690939987734d6519a2e3daf28ed36d87.tar.gz", | ||||
|       "hash": "011kg3c2mfy7y808llpmq3hf6vv6rlazx8m11w41pnym4kwr3ivz" | ||||
|       "branch": "main", | ||||
|       "revision": "2071bbb765681ac3d8194ec560c8b27ff2a3b541", | ||||
|       "url": "https://github.com/nix-community/nix-unit/archive/2071bbb765681ac3d8194ec560c8b27ff2a3b541.tar.gz", | ||||
|       "hash": "0blz1kcmn9vnr9q3iqp2mv13hv3pdccljmmc54f8j7ybf5v0wgmp" | ||||
|     }, | ||||
|     "nixpkgs": { | ||||
|       "type": "Channel", | ||||
|       "name": "nixpkgs-unstable", | ||||
|       "url": "https://releases.nixos.org/nixpkgs/nixpkgs-24.11pre691017.b69de56fac8c/nixexprs.tar.xz", | ||||
|       "hash": "0z32pj0lh5ng2a6cn0qfmka8cynnygckn5615mkaxq2aplkvgzx3" | ||||
|       "url": "https://releases.nixos.org/nixpkgs/nixpkgs-25.05pre711046.8edf06bea5bc/nixexprs.tar.xz", | ||||
|       "hash": "1mwsn0rvfm603svrq3pca4c51zlix5gkyr4gl6pxhhq3q6xs5s8y" | ||||
|     } | ||||
|   }, | ||||
|   "version": 3 | ||||
|  |  | |||
|  | @ -505,7 +505,6 @@ let | |||
|                   else baseType.merge loc (map (p: p.def // { value = p.processed; }) processed); | ||||
|               }; | ||||
|             in | ||||
|             # HACK: bail out for now | ||||
|             with-section-constraints | ||||
|               # TODO: find a reasonable cut-off for where to place raw content | ||||
|               (listOf (either str (attrTag categories.flow))); | ||||
|  |  | |||
|  | @ -127,8 +127,10 @@ header > nav > ul > li > details > nav ul li { | |||
|   padding: 0.25em 0; | ||||
| } | ||||
| 
 | ||||
| #menu-toggle { | ||||
| #menu-toggle, | ||||
| #menu-toggle + label { | ||||
|   display: none; | ||||
|   appearance: none; | ||||
| } | ||||
| 
 | ||||
| @media (max-width: 50em) { | ||||
|  | @ -136,14 +138,21 @@ header > nav > ul > li > details > nav ul li { | |||
|     display: block; | ||||
|   } | ||||
| 
 | ||||
|   #menu-toggle::before { | ||||
|     content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 20 20'%3E%3Cpath d='M0 3h20v2H0V3z m0 6h20v2H0V9z m0 6h20v2H0V0z'/%3E%3C/svg%3E"); | ||||
|   #menu-toggle ~ label { | ||||
|     position: absolute; | ||||
|     right: 0; | ||||
|     padding: 0.5em; | ||||
|     cursor: pointer; | ||||
|     display: block; | ||||
|   } | ||||
| 
 | ||||
|   #menu-toggle:checked::before { | ||||
|     content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 20 20'%3E%3Cpolygon points='11 9 22 9 22 11 11 11 11 22 9 22 9 11 -2 11 -2 9 9 9 9 -2 11 -2' transform='rotate(45 10 10)'/%3E%3C/svg%3E"); | ||||
|   .menu-close, | ||||
|   .menu-open { | ||||
|     cursor: pointer; | ||||
|   } | ||||
|   .menu-close { display: none; } | ||||
|   #menu-toggle:checked + label .menu-close { display: block; } | ||||
|   #menu-toggle:checked + label .menu-open { display: none; } | ||||
| 
 | ||||
|   header > nav { | ||||
|     margin-bottom: 1em; | ||||
|  | @ -210,14 +219,4 @@ header > nav > ul > li > details > nav ul li { | |||
|   header { | ||||
|     position: relative; | ||||
|   } | ||||
| 
 | ||||
|   /* for some reason this must be at the end to work */ | ||||
|   #menu-toggle { | ||||
|     display: block; | ||||
|     position: absolute; | ||||
|     right: 1em; | ||||
|     top: 0.5em; | ||||
|     appearance: none; | ||||
|     cursor: pointer; | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -63,7 +63,15 @@ in | |||
|       body.content = [ | ||||
|         '' | ||||
|           <header> | ||||
|             <input type="checkbox" id="menu-toggle"> | ||||
|             <input type="checkbox" id="menu-toggle" hidden> | ||||
|             <label for="menu-toggle" hidden> | ||||
|               <svg class="menu-open" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 20 20"> | ||||
|                <path d="M0 4 H20 M0 10 H20 M0 16 H20" stroke="currentColor" stroke-width="2"/> | ||||
|               </svg> | ||||
|               <svg class="menu-close" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 20 20"> | ||||
|                 <path d="M2 2L18 18M18 2L2 18" stroke="currentColor" stroke-width="2"/> | ||||
|               </svg> | ||||
|             </label> | ||||
|             ${lib.indent "  " (cfg.menus.main.outputs.html page)} | ||||
|           </header> | ||||
|         '' | ||||
|  |  | |||
							
								
								
									
										21
									
								
								website/tests.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								website/tests.nix
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | |||
| # tests written for running with `nix-unit` | ||||
| # https://github.com/nix-community/nix-unit | ||||
| let | ||||
|   inherit (import ./. { }) lib; | ||||
| in | ||||
| { | ||||
|   test-relativePath = with lib; | ||||
|     let | ||||
|       testData = [ | ||||
|         { from = "bar"; to = "baz"; expected = "./baz"; } | ||||
|         { from = "foo/bar"; to = "foo/baz"; expected = "./baz"; } | ||||
|         { from = "foo"; to = "bar/baz"; expected = "./bar/baz"; } | ||||
|         { from = "foo/bar"; to = "baz"; expected = "./../baz"; } | ||||
|         { from = "foo/bar/baz"; to = "foo"; expected = "./../../foo"; } | ||||
|       ]; | ||||
|     in | ||||
|     { | ||||
|       expr = map (case: relativePath case.from case.to) testData; | ||||
|       expected = map (case: case.expected) testData; | ||||
|     }; | ||||
| } | ||||
		Loading…
	
	Add table
		
		Reference in a new issue