From 3ae51fa545a218a8d4b156085571ae153350e7c6 Mon Sep 17 00:00:00 2001
From: Valentin Gagarin <valentin.gagarin@tweag.io>
Date: Thu, 14 Nov 2024 13:41:19 +0100
Subject: [PATCH] deploy website from the repo (#1)

- move the impure single-node deploy helper here

  it's not used anywhere else

- reuse the pins from the website

  this needs to be cleaned up later

- don't copy the config to the server

  it's impure (can't even build that without jumping through hoops), and useless when building via SSH

Reviewed-on: https://git.fediversity.eu/Fediversity/Fediversity/pulls/1
---
 .gitignore               |   3 ++
 server/README.md         |  15 ++++++
 server/configuration.nix | 105 ++++++++++++++++++---------------------
 server/default.nix       |  46 +++++++++++++++++
 server/shell.nix         |   1 +
 services/README.md       |  10 ----
 services/deploy.nix      |  13 -----
 services/flake.nix       |   6 ---
 8 files changed, 114 insertions(+), 85 deletions(-)
 create mode 100644 .gitignore
 create mode 100644 server/README.md
 create mode 100644 server/default.nix
 create mode 100644 server/shell.nix
 delete mode 100644 services/deploy.nix

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..fbfad60
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+.envrc
+.direnv
+result
diff --git a/server/README.md b/server/README.md
new file mode 100644
index 0000000..8b54414
--- /dev/null
+++ b/server/README.md
@@ -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
+```
diff --git a/server/configuration.nix b/server/configuration.nix
index a6b4f06..1717d55 100644
--- a/server/configuration.nix
+++ b/server/configuration.nix
@@ -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,7 +222,7 @@
     isNormalUser = true;
     extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user.
     openssh.authorizedKeys.keys = [
-    "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJg5TlS1NGCRZwMjDgBkXeFUXqooqRlM8fJdBAQ4buPg"
+      "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJg5TlS1NGCRZwMjDgBkXeFUXqooqRlM8fJdBAQ4buPg"
     ];
     packages = with pkgs; [
     ];
@@ -245,24 +246,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 +266,3 @@
   system.stateVersion = "23.11"; # Did you read the comment?
 
 }
-
diff --git a/server/default.nix b/server/default.nix
new file mode 100644
index 0000000..cfdae5b
--- /dev/null
+++ b/server/default.nix
@@ -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;
+    };
+  };
+}
diff --git a/server/shell.nix b/server/shell.nix
new file mode 100644
index 0000000..a6bdf20
--- /dev/null
+++ b/server/shell.nix
@@ -0,0 +1 @@
+(import ./. { }).shell
diff --git a/services/README.md b/services/README.md
index 66114e7..6ef0b93 100644
--- a/services/README.md
+++ b/services/README.md
@@ -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)
diff --git a/services/deploy.nix b/services/deploy.nix
deleted file mode 100644
index 232b7e3..0000000
--- a/services/deploy.nix
+++ /dev/null
@@ -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
-  '';
-}
diff --git a/services/flake.nix b/services/flake.nix
index 7836171..aec006b 100644
--- a/services/flake.nix
+++ b/services/flake.nix
@@ -114,12 +114,6 @@
       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; };