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