2023-04-16 23:24:06 +00:00
|
|
|
{ config, lib, pkgs, ... }:
|
|
|
|
|
|
|
|
let
|
|
|
|
cfg = config.services.stargazer;
|
2023-04-30 00:54:24 +00:00
|
|
|
globalSection = ''
|
|
|
|
listen = ${lib.concatStringsSep " " cfg.listen}
|
|
|
|
connection-logging = ${lib.boolToString cfg.connectionLogging}
|
|
|
|
log-ip = ${lib.boolToString cfg.ipLog}
|
|
|
|
log-ip-partial = ${lib.boolToString cfg.ipLogPartial}
|
2023-04-16 23:24:06 +00:00
|
|
|
request-timeout = ${toString cfg.requestTimeout}
|
|
|
|
response-timeout = ${toString cfg.responseTimeout}
|
|
|
|
|
|
|
|
[:tls]
|
|
|
|
store = ${toString cfg.store}
|
|
|
|
organization = ${cfg.certOrg}
|
2023-04-30 01:02:44 +00:00
|
|
|
gen-certs = ${lib.boolToString cfg.genCerts}
|
|
|
|
regen-certs = ${lib.boolToString cfg.regenCerts}
|
|
|
|
${lib.optionalString (cfg.certLifetime != "") "cert-lifetime = ${cfg.certLifetime}"}
|
2023-04-16 23:24:06 +00:00
|
|
|
|
|
|
|
'';
|
2023-04-30 00:54:24 +00:00
|
|
|
genINI = lib.generators.toINI { };
|
|
|
|
configFile = pkgs.writeText "config.ini" (lib.strings.concatStrings (
|
|
|
|
[ globalSection ] ++ (lib.lists.forEach cfg.routes (section:
|
|
|
|
let
|
|
|
|
name = section.route;
|
|
|
|
params = builtins.removeAttrs section [ "route" ];
|
|
|
|
in
|
|
|
|
genINI
|
|
|
|
{
|
|
|
|
"${name}" = params;
|
|
|
|
} + "\n"
|
|
|
|
))
|
|
|
|
));
|
2023-04-16 23:24:06 +00:00
|
|
|
in
|
|
|
|
{
|
|
|
|
options.services.stargazer = {
|
2023-04-30 01:02:44 +00:00
|
|
|
enable = lib.mkEnableOption (lib.mdDoc "Stargazer Gemini server");
|
2023-04-16 23:24:06 +00:00
|
|
|
|
|
|
|
listen = lib.mkOption {
|
2023-04-30 01:02:44 +00:00
|
|
|
type = lib.types.listOf lib.types.str;
|
|
|
|
default = [ "0.0.0.0" ] ++ lib.optional config.networking.enableIPv6 "[::0]";
|
|
|
|
defaultText = lib.literalExpression ''[ "0.0.0.0" ] ++ lib.optional config.networking.enableIPv6 "[::0]"'';
|
|
|
|
example = lib.literalExpression ''[ "10.0.0.12" "[2002:a00:1::]" ]'';
|
2023-04-16 23:24:06 +00:00
|
|
|
description = lib.mdDoc ''
|
|
|
|
Address and port to listen on.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
connectionLogging = lib.mkOption {
|
2023-04-30 01:02:44 +00:00
|
|
|
type = lib.types.bool;
|
2023-04-16 23:24:06 +00:00
|
|
|
default = true;
|
|
|
|
description = lib.mdDoc "Whether or not to log connections to stdout.";
|
|
|
|
};
|
|
|
|
|
|
|
|
ipLog = lib.mkOption {
|
2023-04-30 01:02:44 +00:00
|
|
|
type = lib.types.bool;
|
2023-04-16 23:24:06 +00:00
|
|
|
default = false;
|
|
|
|
description = lib.mdDoc "Log client IP addresses in the connection log.";
|
|
|
|
};
|
|
|
|
|
|
|
|
ipLogPartial = lib.mkOption {
|
2023-04-30 01:02:44 +00:00
|
|
|
type = lib.types.bool;
|
2023-04-16 23:24:06 +00:00
|
|
|
default = false;
|
|
|
|
description = lib.mdDoc "Log partial client IP addresses in the connection log.";
|
|
|
|
};
|
|
|
|
|
|
|
|
requestTimeout = lib.mkOption {
|
2023-04-30 01:02:44 +00:00
|
|
|
type = lib.types.int;
|
2023-04-16 23:24:06 +00:00
|
|
|
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 {
|
2023-04-30 01:02:44 +00:00
|
|
|
type = lib.types.int;
|
2023-04-16 23:24:06 +00:00
|
|
|
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 {
|
2023-04-30 01:02:44 +00:00
|
|
|
type = lib.types.path;
|
2023-04-16 23:24:06 +00:00
|
|
|
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 {
|
2023-04-30 01:02:44 +00:00
|
|
|
type = lib.types.str;
|
2023-04-16 23:24:06 +00:00
|
|
|
default = "stargazer";
|
|
|
|
description = lib.mdDoc ''
|
|
|
|
The name of the organization responsible for the X.509
|
|
|
|
certificate's /O name.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
genCerts = lib.mkOption {
|
2023-04-30 01:02:44 +00:00
|
|
|
type = lib.types.bool;
|
2023-04-16 23:24:06 +00:00
|
|
|
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 {
|
2023-04-30 01:02:44 +00:00
|
|
|
type = lib.types.bool;
|
2023-04-16 23:24:06 +00:00
|
|
|
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 {
|
2023-04-30 01:02:44 +00:00
|
|
|
type = lib.types.str;
|
2023-04-16 23:24:06 +00:00
|
|
|
default = "";
|
|
|
|
description = lib.mdDoc ''
|
|
|
|
How long certs generated by Stargazer should live for.
|
|
|
|
Certs live forever by default.
|
|
|
|
'';
|
2023-04-30 01:02:44 +00:00
|
|
|
example = lib.literalExpression "\"1y\"";
|
2023-04-16 23:24:06 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
routes = lib.mkOption {
|
2023-04-30 00:54:24 +00:00
|
|
|
type = lib.types.listOf
|
|
|
|
(lib.types.submodule {
|
|
|
|
freeformType = with lib.types; attrsOf (nullOr
|
|
|
|
(oneOf [
|
|
|
|
bool
|
|
|
|
int
|
|
|
|
float
|
|
|
|
str
|
|
|
|
]) // {
|
|
|
|
description = "INI atom (null, bool, int, float or string)";
|
|
|
|
});
|
|
|
|
options.route = lib.mkOption {
|
|
|
|
type = lib.types.str;
|
|
|
|
description = lib.mdDoc "Route section name";
|
|
|
|
};
|
|
|
|
});
|
|
|
|
default = [ ];
|
2023-04-16 23:24:06 +00:00
|
|
|
description = lib.mdDoc ''
|
|
|
|
Routes that Stargazer should server.
|
|
|
|
|
2023-04-30 00:54:24 +00:00
|
|
|
Expressed as a list of attribute sets. Each set must have a key `route`
|
|
|
|
that becomes the section name for that route in the stargazer ini cofig.
|
2023-05-20 02:11:38 +00:00
|
|
|
The remaining keys and values become the parameters for that route.
|
2023-04-30 00:54:24 +00:00
|
|
|
|
|
|
|
[Refer to upstream docs for other params](https://git.sr.ht/~zethra/stargazer/tree/main/item/doc/stargazer.ini.5.txt)
|
2023-04-16 23:24:06 +00:00
|
|
|
'';
|
2023-04-30 00:54:24 +00:00
|
|
|
example = lib.literalExpression ''
|
|
|
|
[
|
|
|
|
{
|
|
|
|
route = "example.com";
|
|
|
|
root = "/srv/gemini/example.com"
|
|
|
|
}
|
|
|
|
{
|
|
|
|
route = "example.com:/man";
|
2023-04-16 23:24:06 +00:00
|
|
|
root = "/cgi-bin";
|
|
|
|
cgi = true;
|
2023-04-30 00:54:24 +00:00
|
|
|
}
|
|
|
|
{
|
|
|
|
route = "other.org~(.*)";
|
2023-04-16 23:24:06 +00:00
|
|
|
redirect = "gemini://example.com";
|
|
|
|
rewrite = "\1";
|
2023-04-30 00:54:24 +00:00
|
|
|
}
|
|
|
|
]
|
2023-04-16 23:24:06 +00:00
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2023-04-30 01:02:44 +00:00
|
|
|
user = lib.mkOption {
|
|
|
|
type = lib.types.str;
|
2023-04-16 23:24:06 +00:00
|
|
|
default = "stargazer";
|
|
|
|
description = lib.mdDoc "User account under which stargazer runs.";
|
|
|
|
};
|
|
|
|
|
2023-04-30 01:02:44 +00:00
|
|
|
group = lib.mkOption {
|
|
|
|
type = lib.types.str;
|
2023-04-16 23:24:06 +00:00
|
|
|
default = "stargazer";
|
|
|
|
description = lib.mdDoc "Group account under which stargazer runs.";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2023-04-30 01:02:44 +00:00
|
|
|
config = lib.mkIf cfg.enable {
|
2023-04-16 23:24:06 +00:00
|
|
|
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 =
|
2023-04-30 01:02:44 +00:00
|
|
|
lib.optionalAttrs (cfg.store == /var/lib/gemini/certs) ''
|
2023-04-16 23:24:06 +00:00
|
|
|
mkdir -p /var/lib/gemini/certs
|
|
|
|
chown -R ${cfg.user}:${cfg.group} /var/lib/gemini/certs
|
|
|
|
'';
|
|
|
|
|
2023-04-30 01:02:44 +00:00
|
|
|
users.users = lib.optionalAttrs (cfg.user == "stargazer") {
|
2023-04-16 23:24:06 +00:00
|
|
|
stargazer = {
|
|
|
|
group = cfg.group;
|
|
|
|
isSystemUser = true;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2023-04-30 01:02:44 +00:00
|
|
|
users.groups = lib.optionalAttrs (cfg.group == "stargazer") {
|
2023-04-16 23:24:06 +00:00
|
|
|
stargazer = { };
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
meta.maintainers = with lib.maintainers; [ gaykitty ];
|
|
|
|
}
|