grafana-alloy: don't build the frontend twice
[NixPkgs.git] / nixos / modules / services / misc / db-rest.nix
blobfbf8b327af049a17cf33ec3675c31ba65a7024f9
1 { config, pkgs, lib, ... }:
2 let
3   inherit (lib) mkOption types mkIf mkMerge mkDefault mkEnableOption mkPackageOption maintainers;
4   cfg = config.services.db-rest;
5 in
7   options = {
8     services.db-rest = {
9       enable = mkEnableOption "db-rest service";
11       user = mkOption {
12         type = types.str;
13         default = "db-rest";
14         description = "User account under which db-rest runs.";
15       };
17       group = mkOption {
18         type = types.str;
19         default = "db-rest";
20         description = "Group under which db-rest runs.";
21       };
23       host = mkOption {
24         type = types.str;
25         default = "127.0.0.1";
26         description = "The host address the db-rest server should listen on.";
27       };
29       port = mkOption {
30         type = types.port;
31         default = 3000;
32         description = "The port the db-rest server should listen on.";
33       };
35       redis = {
36         enable = mkOption {
37           type = types.bool;
38           default = false;
39           description = "Enable caching with redis for db-rest.";
40         };
42         createLocally = mkOption {
43           type = types.bool;
44           default = true;
45           description = "Configure a local redis server for db-rest.";
46         };
48         host = mkOption {
49           type = with types; nullOr str;
50           default = null;
51           description = "Redis host.";
52         };
54         port = mkOption {
55           type = with types; nullOr port;
56           default = null;
57           description = "Redis port.";
58         };
60         user = mkOption {
61           type = with types; nullOr str;
62           default = null;
63           description = "Optional username used for authentication with redis.";
64         };
66         passwordFile = mkOption {
67           type = with types; nullOr path;
68           default = null;
69           example = "/run/keys/db-rest/pasword-redis-db";
70           description = "Path to a file containing the redis password.";
71         };
73         useSSL = mkOption {
74           type = types.bool;
75           default = true;
76           description = "Use SSL if using a redis network connection.";
77         };
78       };
80       package = mkPackageOption pkgs "db-rest" { };
81     };
82   };
84   config = mkIf cfg.enable {
85     assertions = [
86       {
87         assertion = (cfg.redis.enable && !cfg.redis.createLocally) -> (cfg.redis.host != null && cfg.redis.port != null);
88         message = ''
89           {option}`services.db-rest.redis.createLocally` and redis network connection ({option}`services.db-rest.redis.host` or {option}`services.db-rest.redis.port`) enabled. Disable either of them.
90         '';
91       }
92       {
93         assertion = (cfg.redis.enable && !cfg.redis.createLocally) -> (cfg.redis.passwordFile != null);
94         message = ''
95           {option}`services.db-rest.redis.createLocally` is disabled, but {option}`services.db-rest.redis.passwordFile` is not set.
96         '';
97       }
98     ];
100     systemd.services.db-rest = mkMerge [
101       {
102         description = "db-rest service";
103         after = [ "network.target" ]
104           ++ lib.optional cfg.redis.createLocally "redis-db-rest.service";
105         requires = lib.optional cfg.redis.createLocally "redis-db-rest.service";
106         wantedBy = [ "multi-user.target" ];
107         serviceConfig = {
108           Type = "simple";
109           Restart = "always";
110           RestartSec = 5;
111           WorkingDirectory = cfg.package;
112           User = cfg.user;
113           Group = cfg.group;
114           RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
115           MemoryDenyWriteExecute = false;
116           LoadCredential = lib.optional (cfg.redis.enable && cfg.redis.passwordFile != null) "REDIS_PASSWORD:${cfg.redis.passwordFile}";
117           ExecStart = mkDefault "${cfg.package}/bin/db-rest";
119           RemoveIPC = true;
120           NoNewPrivileges = true;
121           PrivateDevices = true;
122           ProtectClock = true;
123           ProtectKernelLogs = true;
124           ProtectControlGroups = true;
125           ProtectKernelModules = true;
126           PrivateMounts = true;
127           SystemCallArchitectures = "native";
128           ProtectHostname = true;
129           LockPersonality = true;
130           ProtectKernelTunables = true;
131           RestrictRealtime = true;
132           RestrictSUIDSGID = true;
133           RestrictNamespaces = true;
134           ProtectSystem = "strict";
135           ProtectProc = "invisible";
136           ProcSubset = "pid";
137           ProtectHome = true;
138           PrivateUsers = true;
139           PrivateTmp = true;
140           CapabilityBoundingSet = "";
141         };
142         environment = {
143           NODE_ENV = "production";
144           NODE_EXTRA_CA_CERTS = "/etc/ssl/certs/ca-certificates.crt";
145           HOSTNAME = cfg.host;
146           PORT = toString cfg.port;
147         };
148       }
149       (mkIf cfg.redis.enable (if cfg.redis.createLocally then
150         { environment.REDIS_URL = config.services.redis.servers.db-rest.unixSocket; }
151       else
152         {
153           script =
154             let
155               username = lib.optionalString (cfg.redis.user != null) (cfg.redis.user);
156               host = cfg.redis.host;
157               port = toString cfg.redis.port;
158               protocol = if cfg.redis.useSSL then "rediss" else "redis";
159             in
160             ''
161               export REDIS_URL="${protocol}://${username}:$(${config.systemd.package}/bin/systemd-creds cat REDIS_PASSWORD)@${host}:${port}"
162               exec ${cfg.package}/bin/db-rest
163             '';
164         }))
165     ];
167     users.users = lib.mkMerge [
168       (lib.mkIf (cfg.user == "db-rest") {
169         db-rest = {
170           isSystemUser = true;
171           group = cfg.group;
172         };
173       })
174       (lib.mkIf cfg.redis.createLocally { ${cfg.user}.extraGroups = [ "redis-db-rest" ]; })
175     ];
177     users.groups = lib.mkIf (cfg.group == "db-rest") { db-rest = { }; };
179     services.redis.servers.db-rest.enable = cfg.redis.enable && cfg.redis.createLocally;
180   };
181   meta.maintainers = with maintainers; [ marie ];