nixos/preload: init
[NixPkgs.git] / nixos / modules / services / web-servers / agate.nix
bloba0c8a8c94ee5aba14fd753054ebbaad96e698137
1 { config, lib, pkgs, ... }:
3 with lib;
5 let
6   cfg = config.services.agate;
7 in
9   options = {
10     services.agate = {
11       enable = mkEnableOption (lib.mdDoc "Agate Server");
13       package = mkOption {
14         type = types.package;
15         default = pkgs.agate;
16         defaultText = literalExpression "pkgs.agate";
17         description = lib.mdDoc "The package to use";
18       };
20       addresses = mkOption {
21         type = types.listOf types.str;
22         default = [ "0.0.0.0:1965" ];
23         description = lib.mdDoc ''
24           Addresses to listen on, IP:PORT, if you haven't disabled forwarding
25           only set IPv4.
26         '';
27       };
29       contentDir = mkOption {
30         default = "/var/lib/agate/content";
31         type = types.path;
32         description = lib.mdDoc "Root of the content directory.";
33       };
35       certificatesDir = mkOption {
36         default = "/var/lib/agate/certificates";
37         type = types.path;
38         description = lib.mdDoc "Root of the certificate directory.";
39       };
41       hostnames = mkOption {
42         default = [ ];
43         type = types.listOf types.str;
44         description = lib.mdDoc ''
45           Domain name of this Gemini server, enables checking hostname and port
46           in requests. (multiple occurrences means basic vhosts)
47         '';
48       };
50       language = mkOption {
51         default = null;
52         type = types.nullOr types.str;
53         description = lib.mdDoc "RFC 4646 Language code for text/gemini documents.";
54       };
56       onlyTls_1_3 = mkOption {
57         default = false;
58         type = types.bool;
59         description = lib.mdDoc "Only use TLSv1.3 (default also allows TLSv1.2).";
60       };
62       extraArgs = mkOption {
63         type = types.listOf types.str;
64         default = [ "" ];
65         example = [ "--log-ip" ];
66         description = lib.mdDoc "Extra arguments to use running agate.";
67       };
68     };
69   };
71   config = mkIf cfg.enable {
72     # available for generating certs by hand
73     # it can be a bit arduous with openssl
74     environment.systemPackages = [ cfg.package ];
76     systemd.services.agate = {
77       description = "Agate";
78       wantedBy = [ "multi-user.target" ];
79       after = [ "network.target" "network-online.target" ];
81       script =
82         let
83           prefixKeyList = key: list: concatMap (v: [ key v ]) list;
84           addresses = prefixKeyList "--addr" cfg.addresses;
85           hostnames = prefixKeyList "--hostname" cfg.hostnames;
86         in
87         ''
88           exec ${cfg.package}/bin/agate ${
89             escapeShellArgs (
90               [
91                 "--content" "${cfg.contentDir}"
92                 "--certs" "${cfg.certificatesDir}"
93               ] ++
94               addresses ++
95               (optionals (cfg.hostnames != []) hostnames) ++
96               (optionals (cfg.language != null) [ "--lang" cfg.language ]) ++
97               (optionals cfg.onlyTls_1_3 [ "--only-tls13" ]) ++
98               (optionals (cfg.extraArgs != []) cfg.extraArgs)
99             )
100           }
101         '';
103       serviceConfig = {
104         Restart = "always";
105         RestartSec = "5s";
106         DynamicUser = true;
107         StateDirectory = "agate";
109         # Security options:
110         AmbientCapabilities = "";
111         CapabilityBoundingSet = "";
113         # ProtectClock= adds DeviceAllow=char-rtc r
114         DeviceAllow = "";
116         LockPersonality = true;
118         PrivateTmp = true;
119         PrivateDevices = true;
120         PrivateUsers = true;
122         ProtectClock = true;
123         ProtectControlGroups = true;
124         ProtectHostname = true;
125         ProtectKernelLogs = true;
126         ProtectKernelModules = true;
127         ProtectKernelTunables = true;
129         RestrictNamespaces = true;
130         RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
131         RestrictRealtime = true;
133         SystemCallArchitectures = "native";
134         SystemCallErrorNumber = "EPERM";
135         SystemCallFilter = [
136           "@system-service"
137           "~@cpu-emulation"
138           "~@debug"
139           "~@keyring"
140           "~@memlock"
141           "~@obsolete"
142           "~@privileged"
143           "~@setuid"
144         ];
145       };
146     };
147   };