at 25.11-pre 7.6 kB view raw
1# NixOS module for lighttpd web server 2 3{ 4 config, 5 lib, 6 pkgs, 7 ... 8}: 9 10with lib; 11 12let 13 14 cfg = config.services.lighttpd; 15 16 # List of known lighttpd modules, ordered by how the lighttpd documentation 17 # recommends them being imported: 18 # https://redmine.lighttpd.net/projects/1/wiki/Server_modulesDetails 19 # 20 # Some modules are always imported and should not appear in the config: 21 # disallowedModules = [ "mod_indexfile" "mod_dirlisting" "mod_staticfile" ]; 22 # 23 # For full module list, see the output of running ./configure in the lighttpd 24 # source. 25 allKnownModules = [ 26 "mod_rewrite" 27 "mod_redirect" 28 "mod_alias" 29 "mod_access" 30 "mod_auth" 31 "mod_status" 32 "mod_simple_vhost" 33 "mod_evhost" 34 "mod_userdir" 35 "mod_secdownload" 36 "mod_fastcgi" 37 "mod_proxy" 38 "mod_cgi" 39 "mod_ssi" 40 "mod_compress" 41 "mod_usertrack" 42 "mod_expire" 43 "mod_rrdtool" 44 "mod_accesslog" 45 # Remaining list of modules, order assumed to be unimportant. 46 "mod_authn_dbi" 47 "mod_authn_file" 48 "mod_authn_gssapi" 49 "mod_authn_ldap" 50 "mod_authn_mysql" 51 "mod_authn_pam" 52 "mod_authn_sasl" 53 "mod_cml" 54 "mod_deflate" 55 "mod_evasive" 56 "mod_extforward" 57 "mod_flv_streaming" 58 "mod_geoip" 59 "mod_magnet" 60 "mod_mysql_vhost" 61 "mod_openssl" # since v1.4.46 62 "mod_scgi" 63 "mod_setenv" 64 "mod_trigger_b4_dl" 65 "mod_uploadprogress" 66 "mod_vhostdb" # since v1.4.46 67 "mod_webdav" 68 "mod_wstunnel" # since v1.4.46 69 ]; 70 71 maybeModuleString = 72 moduleName: optionalString (elem moduleName cfg.enableModules) ''"${moduleName}"''; 73 74 modulesIncludeString = concatStringsSep ",\n" ( 75 filter (x: x != "") (map maybeModuleString allKnownModules) 76 ); 77 78 configFile = 79 if cfg.configText != "" then 80 pkgs.writeText "lighttpd.conf" '' 81 ${cfg.configText} 82 '' 83 else 84 pkgs.writeText "lighttpd.conf" '' 85 server.document-root = "${cfg.document-root}" 86 server.port = ${toString cfg.port} 87 server.username = "lighttpd" 88 server.groupname = "lighttpd" 89 90 # As for why all modules are loaded here, instead of having small 91 # server.modules += () entries in each sub-service extraConfig snippet, 92 # read this: 93 # 94 # https://redmine.lighttpd.net/projects/1/wiki/Server_modulesDetails 95 # https://redmine.lighttpd.net/issues/2337 96 # 97 # Basically, lighttpd doesn't want to load (or even silently ignore) a 98 # module for a second time, and there is no way to check if a module has 99 # been loaded already. So if two services were to put the same module in 100 # server.modules += (), that would break the lighttpd configuration. 101 server.modules = ( 102 ${modulesIncludeString} 103 ) 104 105 # Logging (logs end up in systemd journal) 106 accesslog.use-syslog = "enable" 107 server.errorlog-use-syslog = "enable" 108 109 ${lib.optionalString cfg.enableUpstreamMimeTypes '' 110 include "${pkgs.lighttpd}/share/lighttpd/doc/config/conf.d/mime.conf" 111 ''} 112 113 static-file.exclude-extensions = ( ".fcgi", ".php", ".rb", "~", ".inc" ) 114 index-file.names = ( "index.html" ) 115 116 ${optionalString cfg.mod_userdir '' 117 userdir.path = "public_html" 118 ''} 119 120 ${optionalString cfg.mod_status '' 121 status.status-url = "/server-status" 122 status.statistics-url = "/server-statistics" 123 status.config-url = "/server-config" 124 ''} 125 126 ${cfg.extraConfig} 127 ''; 128 129in 130 131{ 132 133 options = { 134 135 services.lighttpd = { 136 137 enable = mkOption { 138 default = false; 139 type = types.bool; 140 description = '' 141 Enable the lighttpd web server. 142 ''; 143 }; 144 145 package = mkPackageOption pkgs "lighttpd" { }; 146 147 port = mkOption { 148 default = 80; 149 type = types.port; 150 description = '' 151 TCP port number for lighttpd to bind to. 152 ''; 153 }; 154 155 document-root = mkOption { 156 default = "/srv/www"; 157 type = types.path; 158 description = '' 159 Document-root of the web server. Must be readable by the "lighttpd" user. 160 ''; 161 }; 162 163 mod_userdir = mkOption { 164 default = false; 165 type = types.bool; 166 description = '' 167 If true, requests in the form /~user/page.html are rewritten to take 168 the file public_html/page.html from the home directory of the user. 169 ''; 170 }; 171 172 enableModules = mkOption { 173 type = types.listOf types.str; 174 default = [ ]; 175 example = [ 176 "mod_cgi" 177 "mod_status" 178 ]; 179 description = '' 180 List of lighttpd modules to enable. Sub-services take care of 181 enabling modules as needed, so this option is mainly for when you 182 want to add custom stuff to 183 {option}`services.lighttpd.extraConfig` that depends on a 184 certain module. 185 ''; 186 }; 187 188 enableUpstreamMimeTypes = mkOption { 189 type = types.bool; 190 default = true; 191 description = '' 192 Whether to include the list of mime types bundled with lighttpd 193 (upstream). If you disable this, no mime types will be added by 194 NixOS and you will have to add your own mime types in 195 {option}`services.lighttpd.extraConfig`. 196 ''; 197 }; 198 199 mod_status = mkOption { 200 default = false; 201 type = types.bool; 202 description = '' 203 Show server status overview at /server-status, statistics at 204 /server-statistics and list of loaded modules at /server-config. 205 ''; 206 }; 207 208 configText = mkOption { 209 default = ""; 210 type = types.lines; 211 example = "...verbatim config file contents..."; 212 description = '' 213 Overridable config file contents to use for lighttpd. By default, use 214 the contents automatically generated by NixOS. 215 ''; 216 }; 217 218 extraConfig = mkOption { 219 default = ""; 220 type = types.lines; 221 description = '' 222 These configuration lines will be appended to the generated lighttpd 223 config file. Note that this mechanism does not work when the manual 224 {option}`configText` option is used. 225 ''; 226 }; 227 228 }; 229 230 }; 231 232 config = mkIf cfg.enable { 233 234 assertions = [ 235 { 236 assertion = all (x: elem x allKnownModules) cfg.enableModules; 237 message = '' 238 One (or more) modules in services.lighttpd.enableModules are 239 unrecognized. 240 241 Known modules: ${toString allKnownModules} 242 243 services.lighttpd.enableModules: ${toString cfg.enableModules} 244 ''; 245 } 246 ]; 247 248 services.lighttpd.enableModules = mkMerge [ 249 (mkIf cfg.mod_status [ "mod_status" ]) 250 (mkIf cfg.mod_userdir [ "mod_userdir" ]) 251 # always load mod_accesslog so that we can log to the journal 252 [ "mod_accesslog" ] 253 ]; 254 255 systemd.services.lighttpd = { 256 description = "Lighttpd Web Server"; 257 after = [ "network.target" ]; 258 wantedBy = [ "multi-user.target" ]; 259 serviceConfig.ExecStart = "${cfg.package}/sbin/lighttpd -D -f ${configFile}"; 260 serviceConfig.ExecReload = "${pkgs.coreutils}/bin/kill -SIGUSR1 $MAINPID"; 261 # SIGINT => graceful shutdown 262 serviceConfig.KillSignal = "SIGINT"; 263 }; 264 265 users.users.lighttpd = { 266 group = "lighttpd"; 267 description = "lighttpd web server privilege separation user"; 268 uid = config.ids.uids.lighttpd; 269 }; 270 271 users.groups.lighttpd.gid = config.ids.gids.lighttpd; 272 }; 273}