at 23.11-pre 4.8 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 cfg = config.services.unit; 7 8 configFile = pkgs.writeText "unit.json" cfg.config; 9 10in { 11 options = { 12 services.unit = { 13 enable = mkEnableOption (lib.mdDoc "Unit App Server"); 14 package = mkOption { 15 type = types.package; 16 default = pkgs.unit; 17 defaultText = literalExpression "pkgs.unit"; 18 description = lib.mdDoc "Unit package to use."; 19 }; 20 user = mkOption { 21 type = types.str; 22 default = "unit"; 23 description = lib.mdDoc "User account under which unit runs."; 24 }; 25 group = mkOption { 26 type = types.str; 27 default = "unit"; 28 description = lib.mdDoc "Group account under which unit runs."; 29 }; 30 stateDir = mkOption { 31 type = types.path; 32 default = "/var/spool/unit"; 33 description = lib.mdDoc "Unit data directory."; 34 }; 35 logDir = mkOption { 36 type = types.path; 37 default = "/var/log/unit"; 38 description = lib.mdDoc "Unit log directory."; 39 }; 40 config = mkOption { 41 type = types.str; 42 default = '' 43 { 44 "listeners": {}, 45 "applications": {} 46 } 47 ''; 48 example = '' 49 { 50 "listeners": { 51 "*:8300": { 52 "application": "example-php-72" 53 } 54 }, 55 "applications": { 56 "example-php-72": { 57 "type": "php 7.2", 58 "processes": 4, 59 "user": "nginx", 60 "group": "nginx", 61 "root": "/var/www", 62 "index": "index.php", 63 "options": { 64 "file": "/etc/php.d/default.ini", 65 "admin": { 66 "max_execution_time": "30", 67 "max_input_time": "30", 68 "display_errors": "off", 69 "display_startup_errors": "off", 70 "open_basedir": "/dev/urandom:/proc/cpuinfo:/proc/meminfo:/etc/ssl/certs:/var/www", 71 "disable_functions": "exec,passthru,shell_exec,system" 72 } 73 } 74 } 75 } 76 } 77 ''; 78 description = lib.mdDoc "Unit configuration in JSON format. More details here https://unit.nginx.org/configuration"; 79 }; 80 }; 81 }; 82 83 config = mkIf cfg.enable { 84 85 environment.systemPackages = [ cfg.package ]; 86 87 systemd.tmpfiles.rules = [ 88 "d '${cfg.stateDir}' 0750 ${cfg.user} ${cfg.group} - -" 89 "d '${cfg.logDir}' 0750 ${cfg.user} ${cfg.group} - -" 90 ]; 91 92 systemd.services.unit = { 93 description = "Unit App Server"; 94 after = [ "network.target" ]; 95 wantedBy = [ "multi-user.target" ]; 96 preStart = '' 97 [ ! -e '${cfg.stateDir}/conf.json' ] || rm -f '${cfg.stateDir}/conf.json' 98 ''; 99 postStart = '' 100 ${pkgs.curl}/bin/curl -X PUT --data-binary '@${configFile}' --unix-socket '/run/unit/control.unit.sock' 'http://localhost/config' 101 ''; 102 serviceConfig = { 103 Type = "forking"; 104 PIDFile = "/run/unit/unit.pid"; 105 ExecStart = '' 106 ${cfg.package}/bin/unitd --control 'unix:/run/unit/control.unit.sock' --pid '/run/unit/unit.pid' \ 107 --log '${cfg.logDir}/unit.log' --statedir '${cfg.stateDir}' --tmpdir '/tmp' \ 108 --user ${cfg.user} --group ${cfg.group} 109 ''; 110 ExecStop = '' 111 ${pkgs.curl}/bin/curl -X DELETE --unix-socket '/run/unit/control.unit.sock' 'http://localhost/config' 112 ''; 113 # Runtime directory and mode 114 RuntimeDirectory = "unit"; 115 RuntimeDirectoryMode = "0750"; 116 # Access write directories 117 ReadWritePaths = [ cfg.stateDir cfg.logDir ]; 118 # Security 119 NoNewPrivileges = true; 120 # Sandboxing 121 ProtectSystem = "strict"; 122 ProtectHome = true; 123 PrivateTmp = true; 124 PrivateDevices = true; 125 PrivateUsers = false; 126 ProtectHostname = true; 127 ProtectClock = true; 128 ProtectKernelTunables = true; 129 ProtectKernelModules = true; 130 ProtectKernelLogs = true; 131 ProtectControlGroups = true; 132 RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ]; 133 LockPersonality = true; 134 MemoryDenyWriteExecute = true; 135 RestrictRealtime = true; 136 RestrictSUIDSGID = true; 137 PrivateMounts = true; 138 # System Call Filtering 139 SystemCallArchitectures = "native"; 140 }; 141 }; 142 143 users.users = optionalAttrs (cfg.user == "unit") { 144 unit = { 145 group = cfg.group; 146 isSystemUser = true; 147 }; 148 }; 149 150 users.groups = optionalAttrs (cfg.group == "unit") { 151 unit = { }; 152 }; 153 154 }; 155}