1 # NixOS module for lighttpd web server
3 { config, lib, pkgs, ... }:
9 cfg = config.services.lighttpd;
11 # List of known lighttpd modules, ordered by how the lighttpd documentation
12 # recommends them being imported:
13 # https://redmine.lighttpd.net/projects/1/wiki/Server_modulesDetails
15 # Some modules are always imported and should not appear in the config:
16 # disallowedModules = [ "mod_indexfile" "mod_dirlisting" "mod_staticfile" ];
18 # For full module list, see the output of running ./configure in the lighttpd
40 # Remaining list of modules, order assumed to be unimportant.
56 "mod_openssl" # since v1.4.46
61 "mod_vhostdb" # since v1.4.46
63 "mod_wstunnel" # since v1.4.46
66 maybeModuleString = moduleName:
67 optionalString (elem moduleName cfg.enableModules) ''"${moduleName}"'';
69 modulesIncludeString = concatStringsSep ",\n"
70 (filter (x: x != "") (map maybeModuleString allKnownModules));
72 configFile = if cfg.configText != "" then
73 pkgs.writeText "lighttpd.conf" ''
77 pkgs.writeText "lighttpd.conf" ''
78 server.document-root = "${cfg.document-root}"
79 server.port = ${toString cfg.port}
80 server.username = "lighttpd"
81 server.groupname = "lighttpd"
83 # As for why all modules are loaded here, instead of having small
84 # server.modules += () entries in each sub-service extraConfig snippet,
87 # https://redmine.lighttpd.net/projects/1/wiki/Server_modulesDetails
88 # https://redmine.lighttpd.net/issues/2337
90 # Basically, lighttpd doesn't want to load (or even silently ignore) a
91 # module for a second time, and there is no way to check if a module has
92 # been loaded already. So if two services were to put the same module in
93 # server.modules += (), that would break the lighttpd configuration.
95 ${modulesIncludeString}
98 # Logging (logs end up in systemd journal)
99 accesslog.use-syslog = "enable"
100 server.errorlog-use-syslog = "enable"
102 ${lib.optionalString cfg.enableUpstreamMimeTypes ''
103 include "${pkgs.lighttpd}/share/lighttpd/doc/config/conf.d/mime.conf"
106 static-file.exclude-extensions = ( ".fcgi", ".php", ".rb", "~", ".inc" )
107 index-file.names = ( "index.html" )
109 ${optionalString cfg.mod_userdir ''
110 userdir.path = "public_html"
113 ${optionalString cfg.mod_status ''
114 status.status-url = "/server-status"
115 status.statistics-url = "/server-statistics"
116 status.config-url = "/server-config"
128 services.lighttpd = {
134 Enable the lighttpd web server.
138 package = mkPackageOption pkgs "lighttpd" { };
144 TCP port number for lighttpd to bind to.
148 document-root = mkOption {
149 default = "/srv/www";
152 Document-root of the web server. Must be readable by the "lighttpd" user.
156 mod_userdir = mkOption {
160 If true, requests in the form /~user/page.html are rewritten to take
161 the file public_html/page.html from the home directory of the user.
165 enableModules = mkOption {
166 type = types.listOf types.str;
168 example = [ "mod_cgi" "mod_status" ];
170 List of lighttpd modules to enable. Sub-services take care of
171 enabling modules as needed, so this option is mainly for when you
172 want to add custom stuff to
173 {option}`services.lighttpd.extraConfig` that depends on a
178 enableUpstreamMimeTypes = mkOption {
182 Whether to include the list of mime types bundled with lighttpd
183 (upstream). If you disable this, no mime types will be added by
184 NixOS and you will have to add your own mime types in
185 {option}`services.lighttpd.extraConfig`.
189 mod_status = mkOption {
193 Show server status overview at /server-status, statistics at
194 /server-statistics and list of loaded modules at /server-config.
198 configText = mkOption {
201 example = "...verbatim config file contents...";
203 Overridable config file contents to use for lighttpd. By default, use
204 the contents automatically generated by NixOS.
208 extraConfig = mkOption {
212 These configuration lines will be appended to the generated lighttpd
213 config file. Note that this mechanism does not work when the manual
214 {option}`configText` option is used.
222 config = mkIf cfg.enable {
225 { assertion = all (x: elem x allKnownModules) cfg.enableModules;
227 One (or more) modules in services.lighttpd.enableModules are
230 Known modules: ${toString allKnownModules}
232 services.lighttpd.enableModules: ${toString cfg.enableModules}
237 services.lighttpd.enableModules = mkMerge
238 [ (mkIf cfg.mod_status [ "mod_status" ])
239 (mkIf cfg.mod_userdir [ "mod_userdir" ])
240 # always load mod_accesslog so that we can log to the journal
244 systemd.services.lighttpd = {
245 description = "Lighttpd Web Server";
246 after = [ "network.target" ];
247 wantedBy = [ "multi-user.target" ];
248 serviceConfig.ExecStart = "${cfg.package}/sbin/lighttpd -D -f ${configFile}";
249 serviceConfig.ExecReload = "${pkgs.coreutils}/bin/kill -SIGUSR1 $MAINPID";
250 # SIGINT => graceful shutdown
251 serviceConfig.KillSignal = "SIGINT";
254 users.users.lighttpd = {
256 description = "lighttpd web server privilege separation user";
257 uid = config.ids.uids.lighttpd;
260 users.groups.lighttpd.gid = config.ids.gids.lighttpd;