about summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
authorgaykitty <126119280+gaykitty@users.noreply.github.com>2023-04-16 19:24:06 -0400
committerAnderson Torres <torres.anderson.85@protonmail.com>2023-04-24 21:52:19 -0300
commitc251c021fe168479f811d1496d5c4571592d8dfa (patch)
tree7e294e7a1a2842621b53682ec515744648e7a97e /nixos
parent6fd6ce10946f2d390cf3222ba7db60b1988e791c (diff)
nixos/stargazer: init
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/release-notes/rl-2305.section.md2
-rw-r--r--nixos/modules/module-list.nix1
-rw-r--r--nixos/modules/services/web-servers/stargazer.nix198
-rw-r--r--nixos/tests/all-tests.nix1
-rw-r--r--nixos/tests/web-servers/stargazer.nix30
5 files changed, 232 insertions, 0 deletions
diff --git a/nixos/doc/manual/release-notes/rl-2305.section.md b/nixos/doc/manual/release-notes/rl-2305.section.md
index a89c46152cab4..c411ecb6dcb67 100644
--- a/nixos/doc/manual/release-notes/rl-2305.section.md
+++ b/nixos/doc/manual/release-notes/rl-2305.section.md
@@ -95,6 +95,8 @@ In addition to numerous new and upgraded packages, this release has the followin
 
 - [jellyseerr](https://github.com/Fallenbagel/jellyseerr), a web-based requests manager for Jellyfin, forked from Overseerr. Available as [services.jellyseerr](#opt-services.jellyseerr.enable).
 
+- [stargazer](https://sr.ht/~zethra/stargazer/), a fast and easy to use Gemini server. Available as [services.stargazer](#opt-services.stargazer.enable).
+
 - [photoprism](https://photoprism.app/), a AI-Powered Photos App for the Decentralized Web. Available as [services.photoprism](options.html#opt-services.photoprism.enable).
 
 - [peroxide](https://github.com/ljanyst/peroxide), a fork of the official [ProtonMail bridge](https://github.com/ProtonMail/proton-bridge) that aims to be similar to [Hydroxide](https://github.com/emersion/hydroxide). Available as [services.peroxide](#opt-services.peroxide.enable).
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index f1c459f755708..bbbe8682fd072 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -1243,6 +1243,7 @@
   ./services/web-servers/nginx/gitweb.nix
   ./services/web-servers/phpfpm/default.nix
   ./services/web-servers/pomerium.nix
+  ./services/web-servers/stargazer.nix
   ./services/web-servers/tomcat.nix
   ./services/web-servers/traefik.nix
   ./services/web-servers/trafficserver/default.nix
diff --git a/nixos/modules/services/web-servers/stargazer.nix b/nixos/modules/services/web-servers/stargazer.nix
new file mode 100644
index 0000000000000..85783a500d6fe
--- /dev/null
+++ b/nixos/modules/services/web-servers/stargazer.nix
@@ -0,0 +1,198 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.stargazer;
+  routesFormat = pkgs.formats.ini { };
+  globalFile = pkgs.writeText "global.ini" ''
+    listen = ${concatStringsSep " " cfg.listen}
+    connection-logging = ${boolToString cfg.connectionLogging}
+    log-ip = ${boolToString cfg.ipLog}
+    log-ip-partial = ${boolToString cfg.ipLogPartial}
+    request-timeout = ${toString cfg.requestTimeout}
+    response-timeout = ${toString cfg.responseTimeout}
+
+    [:tls]
+    store = ${toString cfg.store}
+    organization = ${cfg.certOrg}
+    gen-certs = ${boolToString cfg.genCerts}
+    regen-certs = ${boolToString cfg.regenCerts}
+    ${optionalString (cfg.certLifetime != "") "cert-lifetime = ${cfg.certLifetime}"}
+
+  '';
+  routesFile = routesFormat.generate "router.ini" cfg.routes;
+  configFile = pkgs.runCommand "config.ini" { } ''
+    cat ${globalFile} ${routesFile} > $out
+  '';
+in
+{
+  options.services.stargazer = {
+    enable = mkEnableOption (lib.mdDoc "Stargazer Gemini server");
+
+    listen = lib.mkOption {
+      type = types.listOf types.str;
+      default = [ "0.0.0.0" ] ++ optional config.networking.enableIPv6 "[::0]";
+      defaultText = literalExpression ''[ "0.0.0.0" ] ++ lib.optional config.networking.enableIPv6 "[::0]"'';
+      example = literalExpression ''[ "10.0.0.12" "[2002:a00:1::]" ]'';
+      description = lib.mdDoc ''
+        Address and port to listen on.
+      '';
+    };
+
+    connectionLogging = lib.mkOption {
+      type = types.bool;
+      default = true;
+      description = lib.mdDoc "Whether or not to log connections to stdout.";
+    };
+
+    ipLog = lib.mkOption {
+      type = types.bool;
+      default = false;
+      description = lib.mdDoc "Log client IP addresses in the connection log.";
+    };
+
+    ipLogPartial = lib.mkOption {
+      type = types.bool;
+      default = false;
+      description = lib.mdDoc "Log partial client IP addresses in the connection log.";
+    };
+
+    requestTimeout = lib.mkOption {
+      type = types.int;
+      default = 5;
+      description = lib.mdDoc ''
+        Number of seconds to wait for the client to send a complete
+        request. Set to 0 to disable.
+      '';
+    };
+
+    responseTimeout = lib.mkOption {
+      type = types.int;
+      default = 0;
+      description = lib.mdDoc ''
+        Number of seconds to wait for the client to send a complete
+        request and for stargazer to finish sending the response.
+        Set to 0 to disable.
+      '';
+    };
+
+    store = lib.mkOption {
+      type = types.path;
+      default = /var/lib/gemini/certs;
+      description = lib.mdDoc ''
+        Path to the certificate store on disk. This should be a
+        persistent directory writable by Stargazer.
+      '';
+    };
+
+    certOrg = lib.mkOption {
+      type = types.str;
+      default = "stargazer";
+      description = lib.mdDoc ''
+        The name of the organization responsible for the X.509
+        certificate's /O name.
+      '';
+    };
+
+    genCerts = lib.mkOption {
+      type = types.bool;
+      default = true;
+      description = lib.mdDoc ''
+        Set to false to disable automatic certificate generation.
+        Use if you want to provide your own certs.
+      '';
+    };
+
+    regenCerts = lib.mkOption {
+      type = types.bool;
+      default = true;
+      description = lib.mdDoc ''
+        Set to false to turn off automatic regeneration of expired certificates.
+        Use if you want to provide your own certs.
+      '';
+    };
+
+    certLifetime = lib.mkOption {
+      type = types.str;
+      default = "";
+      description = lib.mdDoc ''
+        How long certs generated by Stargazer should live for.
+        Certs live forever by default.
+      '';
+      example = literalExpression "\"1y\"";
+    };
+
+    routes = lib.mkOption {
+      type = routesFormat.type;
+      default = { };
+      description = lib.mdDoc ''
+        Routes that Stargazer should server.
+
+        [Refer to upstream docs](https://git.sr.ht/~zethra/stargazer/tree/main/item/doc/stargazer.ini.5.txt)
+      '';
+      example = literalExpression ''
+        {
+          "example.com" = {
+            root = "/srv/gemini/example.com";
+          };
+          "example.com:/man" = {
+            root = "/cgi-bin";
+            cgi = true;
+          };
+          "other.org~(.*)" = {
+            redirect = "gemini://example.com";
+            rewrite = "\1";
+          };
+        }
+      '';
+    };
+
+    user = mkOption {
+      type = types.str;
+      default = "stargazer";
+      description = lib.mdDoc "User account under which stargazer runs.";
+    };
+
+    group = mkOption {
+      type = types.str;
+      default = "stargazer";
+      description = lib.mdDoc "Group account under which stargazer runs.";
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.stargazer = {
+      description = "Stargazer gemini server";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        ExecStart = "${pkgs.stargazer}/bin/stargazer ${configFile}";
+        Restart = "always";
+        # User and group
+        User = cfg.user;
+        Group = cfg.group;
+      };
+    };
+
+    # Create default cert store
+    system.activationScripts.makeStargazerCertDir =
+      optionalAttrs (cfg.store == /var/lib/gemini/certs) ''
+        mkdir -p /var/lib/gemini/certs
+        chown -R ${cfg.user}:${cfg.group} /var/lib/gemini/certs
+      '';
+
+    users.users = optionalAttrs (cfg.user == "stargazer") {
+      stargazer = {
+        group = cfg.group;
+        isSystemUser = true;
+      };
+    };
+
+    users.groups = optionalAttrs (cfg.group == "stargazer") {
+      stargazer = { };
+    };
+  };
+
+  meta.maintainers = with lib.maintainers; [ gaykitty ];
+}
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index 715fe7e51e0f2..dace17d76706e 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -645,6 +645,7 @@ in {
   sslh = handleTest ./sslh.nix {};
   sssd = handleTestOn ["x86_64-linux"] ./sssd.nix {};
   sssd-ldap = handleTestOn ["x86_64-linux"] ./sssd-ldap.nix {};
+  stargazer = runTest ./web-servers/stargazer.nix;
   starship = handleTest ./starship.nix {};
   step-ca = handleTestOn ["x86_64-linux"] ./step-ca.nix {};
   stratis = handleTest ./stratis {};
diff --git a/nixos/tests/web-servers/stargazer.nix b/nixos/tests/web-servers/stargazer.nix
new file mode 100644
index 0000000000000..6e720b120d1ab
--- /dev/null
+++ b/nixos/tests/web-servers/stargazer.nix
@@ -0,0 +1,30 @@
+{ pkgs, lib, ... }:
+{
+  name = "stargazer";
+  meta = with lib.maintainers; { maintainers = [ gaykitty ]; };
+
+  nodes = {
+    geminiserver = { pkgs, ... }: {
+      services.stargazer = {
+        enable = true;
+        routes = {
+          "localhost" = {
+            root = toString (pkgs.writeTextDir "index.gmi" ''
+              # Hello NixOS!
+            '');
+          };
+        };
+      };
+    };
+  };
+
+  testScript = { nodes, ... }: ''
+    geminiserver.wait_for_unit("stargazer")
+    geminiserver.wait_for_open_port(1965)
+
+    with subtest("check is serving over gemini"):
+      response = geminiserver.succeed("${pkgs.gmni}/bin/gmni -j once -i -N gemini://localhost:1965")
+      print(response)
+      assert "Hello NixOS!" in response
+  '';
+}