grafana-alloy: don't build the frontend twice
[NixPkgs.git] / nixos / modules / services / misc / rmfakecloud.nix
blob6cc87753aa25544bc08facf1f37bdedaa9c40410
1 { config, lib, pkgs, ... }:
3 with lib;
5 let
6   cfg = config.services.rmfakecloud;
7   serviceDataDir = "/var/lib/rmfakecloud";
9 in {
10   options = {
11     services.rmfakecloud = {
12       enable = mkEnableOption "rmfakecloud remarkable self-hosted cloud";
14       package = mkPackageOption pkgs "rmfakecloud" {
15         extraDescription = ''
16           ::: {.note}
17           The default does not include the web user interface.
18           :::
19         '';
20       };
22       storageUrl = mkOption {
23         type = types.str;
24         example = "https://local.appspot.com";
25         description = ''
26           URL used by the tablet to access the rmfakecloud service.
27         '';
28       };
30       port = mkOption {
31         type = types.port;
32         default = 3000;
33         description = ''
34           Listening port number.
35         '';
36       };
38       logLevel = mkOption {
39         type = types.enum [ "info" "debug" "warn" "error" ];
40         default = "info";
41         description = ''
42           Logging level.
43         '';
44       };
46       extraSettings = mkOption {
47         type = with types; attrsOf str;
48         default = { };
49         example = { DATADIR = "/custom/path/for/rmfakecloud/data"; };
50         description = ''
51           Extra settings in the form of a set of key-value pairs.
52           For tokens and secrets, use `environmentFile` instead.
54           Available settings are listed on
55           https://ddvk.github.io/rmfakecloud/install/configuration/.
56         '';
57       };
59       environmentFile = mkOption {
60         type = with types; nullOr path;
61         default = null;
62         example = "/etc/secrets/rmfakecloud.env";
63         description = ''
64           Path to an environment file loaded for the rmfakecloud service.
66           This can be used to securely store tokens and secrets outside of the
67           world-readable Nix store. Since this file is read by systemd, it may
68           have permission 0400 and be owned by root.
69         '';
70       };
71     };
72   };
74   config = mkIf cfg.enable {
75     systemd.services.rmfakecloud = {
76       description = "rmfakecloud remarkable self-hosted cloud";
78       environment = {
79         STORAGE_URL = cfg.storageUrl;
80         PORT = toString cfg.port;
81         LOGLEVEL = cfg.logLevel;
82       } // cfg.extraSettings;
84       preStart = ''
85         # Generate the secret key used to sign client session tokens.
86         # Replacing it invalidates the previously established sessions.
87         if [ -z "$JWT_SECRET_KEY" ] && [ ! -f jwt_secret_key ]; then
88           (umask 077; touch jwt_secret_key)
89           cat /dev/urandom | tr -cd '[:alnum:]' | head -c 48 >> jwt_secret_key
90         fi
91       '';
93       script = ''
94         if [ -z "$JWT_SECRET_KEY" ]; then
95           export JWT_SECRET_KEY="$(cat jwt_secret_key)"
96         fi
98         ${cfg.package}/bin/rmfakecloud
99       '';
101       wantedBy = [ "multi-user.target" ];
102       wants = [ "network-online.target" ];
103       after = [ "network-online.target" ];
105       serviceConfig = {
106         Type = "simple";
107         Restart = "always";
109         EnvironmentFile =
110           mkIf (cfg.environmentFile != null) cfg.environmentFile;
112         AmbientCapabilities =
113           mkIf (cfg.port < 1024) [ "CAP_NET_BIND_SERVICE" ];
115         DynamicUser = true;
116         PrivateDevices = true;
117         ProtectHome = true;
118         ProtectKernelTunables = true;
119         ProtectKernelModules = true;
120         ProtectControlGroups = true;
121         CapabilityBoundingSet = [ "" ];
122         DevicePolicy = "closed";
123         LockPersonality = true;
124         MemoryDenyWriteExecute = true;
125         ProtectClock = true;
126         ProtectHostname = true;
127         ProtectKernelLogs = true;
128         ProtectProc = "invisible";
129         ProcSubset = "pid";
130         RemoveIPC = true;
131         RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
132         RestrictNamespaces = true;
133         RestrictRealtime = true;
134         RestrictSUIDSGID = true;
135         SystemCallArchitectures = "native";
136         WorkingDirectory = serviceDataDir;
137         StateDirectory = baseNameOf serviceDataDir;
138         UMask = "0027";
139       };
140     };
141   };
143   meta.maintainers = with maintainers; [ pacien ];