lighttpd.conf.in: add some fine tuning and comments
[girocco/readme.git] / lighttpd.conf.in
blob11a41f7cba69d60b8d0840c22684808b4d6a1d3f
1 ##  To convert this file to lighttpd.conf using the current Girocco::Config
2 ##  values either do "make" or "make lighttpd.conf" or ./make-lighttpd-conf.sh
3 ##
4 # This is an example configuration of a virtualhost running Girocco, as set up
5 # at repo.or.cz; unfortunately, somewhat independent from Girocco::Config.
6 # It is not essential for Girocco to use a special virtualhost, however.
8 # Minimum lighttpd version 1.4.53 or later required for this config file
10 # Minimum lighttpd version 1.4.53 recommended
12 # Minimum lighttpd version 1.4.53 required for server.systemd-socket-activation
14 # Minimum lighttpd version 1.4.48 required for girocco https push support
16 # Versions prior to 1.4.50 have security issues with incoming requests
17 # having unnormalized URLs in them which can bypass access checks
19 # Versions prior to 1.4.52 accept invalid incoming requests that do
20 # not start the path with a '/'
22 # Prior to version 1.4.53, the private key for the server's
23 # certificate will have to be appended to the `server.pemfile`
24 # since `server.privkey` is not supported until version 1.4.53.
26 # Required lighttpd modules:
28 #   mod_openssl    -  for https and client push certs
29 #   mod_setenv     -  passing environment
30 #   mod_indexfile  -  (should be automatic)
31 #   mod_access     -  access checks
32 #   mod_alias      -  aliases (no regexp)
33 #   mod_redirect   -  regexp access etc.
34 #   mod_rewrite    -  regexp rewrites/aliases/etc.
35 #   mod_status     -  optional (local server status)
36 #   mod_cgi        -  standard cgi
37 #   mod_fastcgi    -  accelerated cgi
38 #   mod_dirlisting -  (should be automatic but unused)
39 #   mod_staticfile -  (should be automatic)
40 #   mod_accesslog  -  for logging requests
44 ## IPv4/IPv6 addresses
46 ## These are needed in multiple places and collected here in
47 ## convenience variables to avoid duplication.
49 var.httpport = 80    # for http:  connections
50 var.httpsport = 443  # for https: connections
51 @@if(!lighttpd_loopback_only)@@
52 # externally accessible web server
53 var.ipv4addr = "0.0.0.0"        # IPv4 INADDR_ANY
54 var.ipv6addr = "::"             # IPv6 IN6ADDR_ANY
55 @@endif@@
56 @@if(lighttpd_loopback_only)@@
57 # web server only accessible from localhost
58 var.ipv4addr = "127.0.0.1"
59 var.ipv6addr = "::1"
60 @@endif@@
62 # Suitable default PATH for CGI use
63 var.syspath = "@@var_getconfpath@@"
67 ## Standalone configuration
69 ## If this file is being included to provide a virtual
70 ## host service, then this configuration should have already
71 ## been done once somewhere else
74 @@if(lighttpd_standalone)@@
76 server.modules += (
77         "mod_openssl",
78         "mod_setenv",
79         "mod_access",
80         "mod_alias",
81         "mod_redirect",
82         "mod_rewrite",
83         "mod_status",
84         "mod_cgi",
85         "mod_fastcgi",
86         "mod_accesslog"
89 # This does not attempt to be a comprehensive list, but
90 # should be sufficient for Girocco on a standalone server
91 mimetype.assign = (
92         ".html" => "text/html",
93         ".htm"  => "text/html",
94         ".txt"  => "text/plain",
95         ".pem"  => "text/plain",
96         ".ico"  => "image/x-icon",
97         ".css"  => "text/css",
98         ".js"   => "application/javascript",
99         ".png"  => "image/png",
100         ".gif"  => "image/gif",
101         ".bmp"  => "image/bmp",
102         ".svg"  => "image/svg+xml",
103         ".svgz" => "image/svg+xml",
104         ".jpg"  => "image/jpeg",
105         ".jpeg" => "image/jpeg",
106         ".mp3"  => "audio/mpeg",
107         ""      => "application/octet-stream"
110 # This acts as a no-op if not activated via systemd, but without
111 # setting this it's not possible to pass sockets from systemd.
112 # Therefore just always set it in standalone mode
113 server.systemd-socket-activation = "enable"
115 # lighttpd has a problem passing sockets from systemd in that
116 # if systemd passes in an IPv6 socket, lighttpd will fail to bind
117 # a global `server.bind` value to an IPv4 socket.  Oops.
118 # That's why `server.bind` here uses the IPv6 address.
119 server.bind = "["+var.ipv6addr+"]"
120 server.port = var.httpport
122 # these are required and in standalone mode won't be set anywhere else
123 @@if(!lighttpd_unprivileged)@@
124 # run privileged at first and after initializing, drop privileges
125 # normally no need to set the groupname as it's inited from the username
126 server.username = "@@cgi_user@@"
127 server.pid-file = "/var/run/lighttpd.pid"
128 var.logbase = "/var/log/lighttpd/"
129 var.fcgisockbase = "/var/run/lighttpd/"
130 @@endif(!lighttpd_unprivileged)@@
131 @@if(lighttpd_unprivileged)@@
132 # put the log files in /tmp using tmpsuffix
133 server.pid-file = "/tmp/lighttpd-@@tmpsuffix@@.pid"
134 var.logbase = "/tmp/lighttpd-@@tmpsuffix@@_"
135 var.fcgisockbase = "/tmp/lighttpd-fcgi-"
136 @@endif(lighttpd_unprivileged)@@
137 server.errorlog = var.logbase+"error.log"
138 # Send CGI stderr to error log
139 server.breakagelog = server.errorlog
141 # Special checks a standalone server might be expected to do
142 $HTTP["url"] =~ "(?i)\.htaccess$" { url.access-deny = ( "" ) }
144 @@endif(lighttpd_standalone)@@
146 @@if(!lighttpd_standalone)@@
147 var.logbase = "/var/log/lighttpd/"
148 var.fcgisockbase = "/var/run/lighttpd/"
149 @@endif@@
151 # Lighttpd ignores exactly matching duplicate socket definitions
152 # therefore just go ahead and mention them to make sure they're active.
153 # Only the http sockets are here.
154 # See the bottom of this file for the https sockets.
156 $SERVER["socket"] == var.ipv4addr+":"+var.httpport {}
157 $SERVER["socket"] == "["+var.ipv6addr+"]:"+var.httpport {}
159 var.rdrbase = "${url.scheme}://${url.authority}" # helpful for redirects
160 var.botpat = "(?i)Slurp|Bot|Spider|Riddler|ltx71|Crawl"
162 @@if(!lighttpd_standalone)@@
163 # The configuration inside this virtual host conditional
164 # ends up only depending on the value of the 'Host:' header sent
165 # by the remote client since it contains no TLS-specific settings
166 $HTTP["host"] == "@@httpdnsname@@" { # "virtual" host @@httpdnsname@@
167 @@endif@@
169         # These help to prevent a bot from monopolizing a connection
170         server.max-keep-alive-requests = 7 # default is 100
171         server.max-keep-alive-idle = 2 # default is 5
173         # Without these little bits here to set server.name,
174         # if an HTTP/1.0 request comes in on a non-standard port
175         # and it lacks a Host: header, redirects might give the
176         # wrong answer without these.
177         $HTTP["scheme"] == "http" {
178                 server.name = "@@httpdnsname@@:"+var.httpport
179         }
180         else $HTTP["scheme"] == "https" {
181                 server.name = "@@httpdnsname@@:"+var.httpsport
182         }
184         # This is the standard "combined" log format modified as follows:
185         #    the REMOTE_USER (%u) has double-quotes around it
186         #    the received time is shown as [YYYY-mm-dd_HH:MM:SS +hhmm] (almost RFC 3339 format)
187         #        -- this is one character shorter than the default but sorts so much better
188         #    the %O value is prefixed with:
189         #        %I->  -- <bytes-received-including-request-and-headers>
190         #    the first line of the request ("%r") is prefixed with
191         #        %X%k: -- <connection-status><keepalive-request-num>
192         #    these fields are added to the end:
193         #        :%{local}p   -- :<actual-server-port>
194         #        %Dus         -- <request-time-in-microseconds>
195         #        "%o{Content-Range}" -- <outgoing Content-Range header>
196         accesslog.format = "%h %l \"%u\" %{[%F_%T %z]}t %X%k:\"%r\" %>s %I->%O \"%{Referer}i\" \"%{User-Agent}i\" :%{local}p %Dus \"%{Content-Range}o\""
198         # lighttpd does not permit a separate error log per host
200         # This may need to be adjusted as needed
201         accesslog.filename = var.logbase+"@@nickname@@-access.log"
203         # Send CGI stderr to error log (done above for standalone mode)
204         #global { server.breakagelog = server.errorlog }
206         # Avoid breaking gitweb
207         server.force-lowercase-filenames = "disable"
209         # lighttpd "normalization" suffers from many defects;
210         # no available configuration is standards compliant.
211         # Failing to enable any "normalization" (the default
212         # through version 1.4.53) allows URL-encoded items
213         # to bypass access and other checks.  Enabling even
214         # the bare minimum (this configuration here), causes
215         # anomalies that reject standards-complying URLs and
216         # potentially corrupt regular expressions in the config
217         # file.  The problems with the code are rampant.
218         # This is the only possible acceptable configuration.
219         # Worse yet, it can't even be set on a per-connection basis!
220         global {
221                 # yes, just always stomp on any misguided
222                 # global config for these items
223                 server.http-parseopts := (
224                         "url-path-2f-decode"       => "disable",
225                         "url-normalize-unreserved" => "enable",
226                         "url-path-dotseg-remove"   => "enable")
227         }
229         server.document-root = "@@webroot@@"
230         static-file.disable-pathinfo = "enable" # should be default
231         cgi.execute-x-only = "enable" # why is this not the default???
232         cgi.local-redir = "enable" # match Apache -- required by RFC 3875
234         # The standard Apache Girocco configuration follows
235         # symlinks as a prerequisite to make ".htaccess" files work.
236         # That's not a consideration here, but to be compatible
237         # with any symlinks that might be in use, it's enabled.
238         server.follow-symlink = "enable"
240         # Send bare "/" directly to gitweb
241         url.rewrite-repeat = ( "^/(?:\?|$)" => "/w${qsa}" )
243         # The magic /[bchrw] prefix always forces selection of the
244         # prefix-indicated cgi handler.
246         $HTTP["url"] =~ "^/w(?:/|$)" {
247                 $REQUEST_HEADER["user-agent"] =~ var.botpat {
248                         $HTTP["query-string"] =~ "(?x)
249                                 a=(?:
250                                         blame |
251                                         blame_data |
252                                         blame_incremental |
253                                         blob_plain |
254                                         blobdiff |
255                                         diff |
256                                         snapshot |
257                                         commitdiff |
258                                         history |
259                                         refs |
260                                         shortlog
261                                 ) |
262                                 a=log.*?f= |
263                                 f=.*?a=log" {
264                                 url.access-deny = ( "" )
265                         }
266                         else $HTTP["url"] =~ "(?x)/(?:
267                                         blame |
268                                         blame_data |
269                                         blame_incremental |
270                                         blob_plain |
271                                         blobdiff |
272                                         diff |
273                                         snapshot |
274                                         commitdiff |
275                                         history |
276                                         refs |
277                                         shortlog
278                                 )" {
279                                 url.access-deny = ( "" )
280                         }
281                         else $HTTP["query-string"] =~ "(.*h=.*;)hb=[^;]*(.*)" {
282                                 url.redirect-code = 303
283                                 url.redirect = ( "^([^?#]*)" => var.rdrbase + "$1%1%2" )
284                         }
285                 }
286                 #alias.url = ( "/w" => "@@cgiroot@@/gitweb.cgi" ) # would munge DOCUMENT_ROOT
287                 fastcgi.server = ( "/w" => ( "gitweb" => (
288                         "socket" => var.fcgisockbase+"gitweb-@@tmpsuffix@@",
289                         "check-local" => "disable",
290                         # lighttpd cannot handle gitweb exiting gracefully after each 100 requests;
291                         # to kludge around lighttpd's limitations, use gitweb-gc.sh instead.
292                         #"bin-path" => "@@cgiroot@@/gitweb.cgi",
293                         "bin-path" => "@@basedir@@/bin/gitweb-gc.sh",
294                         "min-procs" => 1, # default is min(4, max-procs)
295                         "max-procs" => @@var_online_cpus@@, # default is 4
296                         "idle-timeout" => 180, # seconds (default is 60)
297                         # Unlike mod_cgi, mod_fastcgi by default passes through
298                         # the server's environment (the exact opposite of Apache)
299                         # In order to be consistent we use bin-copy-environment (which
300                         # would be better named bin-clean-environment) plus bin-environment
301                         # to get an environment that matches the one sent to mod_cgi executables
302                         "bin-copy-environment" => ( "" ), # cleans env like mod_cgi does
303                         "bin-environment" => ( "PATH" => var.syspath ), # adds consistent PATH
304                 )))
305         }
306         else $HTTP["url"] =~ "^/b(?:/|$)" {
307                 $REQUEST_HEADER["user-agent"] =~ var.botpat { url.access-deny = ( "" ) }
308                 alias.url = ( "/b" => "@@cgiroot@@/bundles.cgi" )
309                 cgi.assign = ( "" => "" )
310                 # CGI scripts will likely behave poorly without this
311                 setenv.set-environment += ( "PATH" => var.syspath )
312                 # Send Apache-identical DOCUMENT_ROOT not lighttpd crazy one
313                 setenv.set-environment += ( "DOCUMENT_ROOT" => server.document-root )
314         }
315         # setenv.set-environment GIT_HTTP_BACKEND_BIN to override Config.pm $git_http_backend_bin
316         else $HTTP["url"] =~ "^/r(?:/|$)" {
317                 $REQUEST_HEADER["user-agent"] =~ var.botpat { url.access-deny = ( "" ) }
318                 setenv.set-environment += ( "REQUIRE_SSL_CLIENT_VERIFY_SUCCESS" => "1" )
319                 alias.url = ( "/r" => "@@basedir@@/bin/git-http-backend-verify" )
320                 cgi.assign = ( "" => "" )
321                 # CGI scripts will likely behave poorly without this
322                 setenv.set-environment += ( "PATH" => var.syspath )
323                 # Send Apache-identical DOCUMENT_ROOT not lighttpd crazy one
324                 setenv.set-environment += ( "DOCUMENT_ROOT" => server.document-root )
325         }
326         # /h/ => html pages pre-generated via the html.cgi template script
327         else $HTTP["url"] =~ "^/h/.+\.html$" {
328                 mimetype.assign = ( "" => "text/html; charset=utf-8" )
329                 alias.url = ( "/h/" => "@@cgiroot@@/html/" )
330         }
332         # A top-level .cgi suffix selects that cgi if it's not gitweb, bundles or html
333         else $HTTP["url"] =~ "^/(?!(?i)gitweb\.cgi|bundles\.cgi|html\.cgi(?:/|$))([^/]+\.cgi(?:/.*)?)$" {
334                 alias.url = ( "/" => "@@cgiroot@@/" )
335                 cgi.assign = ( "" => "" )
336                 # CGI scripts will likely behave poorly without this
337                 setenv.set-environment += ( "PATH" => var.syspath )
338                 # Send Apache-identical DOCUMENT_ROOT not lighttpd crazy one
339                 setenv.set-environment += ( "DOCUMENT_ROOT" => server.document-root )
340         }
342         # Any requests without the magic /[bchrw] are treated as Git requests if they
343         # are one of the few possible Git URLs otherwise they go to bundles or gitweb
345         # Change the setting of $SmartHTTPOnly in Girocco::Config.pm to
346         # change whether or not non-smart HTTP fetch access will be allowed.
348         @@if(!SmartHTTPOnly)@@
349         # This accelerates non-smart HTTP access to loose objects, packs and info
350         $HTTP["url"] =~ "(?x)
351                 ^/(?![bchw]/)(?:r/)?
352                 ((?:[a-zA-Z0-9][a-zA-Z0-9+._-]*(?<!\.git)/)*[a-zA-Z0-9][a-zA-Z0-9+._-]*?)(?:\.git)?/(
353                         HEAD |
354                         objects/info/alternates |
355                         objects/info/http-alternates |
356                         objects/info/packs |
357                         objects/[0-9a-f]{2}/[0-9a-f]{38} |
358                         objects/pack/pack-[0-9a-f]{40}\.(?:pack|idx) )$" {
359                 $REQUEST_HEADER["user-agent"] =~ var.botpat { url.access-deny = ( "" ) }
360                 url.rewrite-once = (
361                         "^[^?]*\.git/" => "", # skip rewrite if not needed
362                         "" => "/r/%1.git/%2"
363                 )
364                 alias.url = (
365                         "/r/" => "@@reporoot@@/",
366                         "/" => "@@reporoot@@/"
367                 )
368                 cgi.assign = ()
369         }
370         @@endif@@
371         @@if(SmartHTTPOnly)@@
372         # This can never match but allows an "else" to always be used next
373         $HTTP["url"] =~ "^(?=0)1" {}
374         @@endif@@
376         else $HTTP["url"] =~ "(?x)
377                 ^/(?![bchrw]/)
378                 ((?:[a-zA-Z0-9][a-zA-Z0-9+._-]*(?<!\.git)/)*[a-zA-Z0-9][a-zA-Z0-9+._-]*?)(?:\.git)?/(
379                         info/refs |
380                         git-upload-pack |
381                         git-receive-pack |
382                         [a-zA-Z0-9][a-zA-Z0-9+._-]*\.bundle )$" {
383                 url.rewrite-once = (
384                         "^[^?]*\.git/" => "", # skip rewrite if not needed
385                         "" => "/r/%1.git/%2${qsa}"
386                 )
387                 $REQUEST_HEADER["user-agent"] =~ var.botpat { url.access-deny = ( "" ) }
388                 setenv.set-environment += ( "REQUIRE_SSL_CLIENT_VERIFY_SUCCESS" => "1" )
389                 alias.url = ( "/" => "@@basedir@@/bin/git-http-backend-verify/" )
390                 cgi.assign = ( "" => "" )
391                 # CGI scripts will likely behave poorly without this
392                 setenv.set-environment += ( "PATH" => var.syspath )
393                 # Send Apache-identical DOCUMENT_ROOT not lighttpd crazy one
394                 setenv.set-environment += ( "DOCUMENT_ROOT" => server.document-root )
395         }
397         # Everything else off to bundles.cgi or gitweb.cgi
398         else $HTTP["url"] =~ "(?x)
399                 ^/(?![bchrw]/)
400                 ((?:[a-zA-Z0-9][a-zA-Z0-9+._-]*(?<!\.git)/)*[a-zA-Z0-9][a-zA-Z0-9+._-]*?\.git/bundles)$" {
401                 $REQUEST_HEADER["user-agent"] =~ var.botpat { url.access-deny = ( "" ) }
402                 alias.url = ( "/" => "@@cgiroot@@/bundles.cgi/" )
403                 cgi.assign = ( "" => "" )
404                 # CGI scripts will likely behave poorly without this
405                 setenv.set-environment += ( "PATH" => var.syspath )
406                 # Send Apache-identical DOCUMENT_ROOT not lighttpd crazy one
407                 setenv.set-environment += ( "DOCUMENT_ROOT" => server.document-root )
408         }
409         else $HTTP["url"] =~ "(?x)
410                 ^/(?![bchrw]/)
411                 ((?:[a-zA-Z0-9][a-zA-Z0-9+._-]*(?<!\.git)/)*[a-zA-Z0-9][a-zA-Z0-9+._-]*?\.git(?!/bundles)(?:/.*)?)$" {
412                 url.rewrite-once = ( "" => "/w/%1${qsa}" )
413         }
415         # mod_rewrite is always required for this lighttpd configuration
416         # which means the trailing ".git" is optional in some cases,
417         # the leading /h is optional for *.html, snapshots are
418         # always throttled, some bogus Git http protocol requests will be
419         # detected early and, if non-smart HTTP is allowed, access to the
420         # /info/refs file will be accelerated in non-smart HTTP mode.
422         # Make the leading /h optional for requests that name a first or second level .html template
423         # Without having file tests available, this is not as flexible.
424         else $HTTP["url"] =~ "^/(?![bchrw]/)(([a-zA-Z]+/)?[^/]+\.html)$" {
425                 mimetype.assign = ( "" => "text/html; charset=utf-8" )
426                 alias.url = ( "/" => "@@cgiroot@@/html/" )
427         }
429         # Redirect bare gitweb /w requests without .git
430         else $HTTP["url"] =~ "(?x)^/w/
431                 ((?:[a-zA-Z0-9][a-zA-Z0-9+._-]*(?<!\.git)/)*[a-zA-Z0-9][a-zA-Z0-9+._-]*(?<!\.git))$" {
432                 url.redirect = ( "" => var.rdrbase + "/w/%1.git${qsa}" )
433         }
435         # Redirect bare gitweb non-/w requests without .git
436         # Without having file tests available, this is problematic.
437         # It's necessary to avoid redirecting requests for static files
438         # that are part of the website itself, but we can do a reasonable approximation
439         # since we know that no users or project names will be allowed to be created
440         # with any of the case-insensitive extensions in %Girocco::Config::reserved_suffixes
441         else $HTTP["url"] =~ "(?x)
442                 ^/(?![bchrw](?:/|$))
443                 ((?:[a-zA-Z0-9][a-zA-Z0-9+._-]*(?<!\.git)/)*[a-zA-Z0-9][a-zA-Z0-9+._-]*(?<!\.git))$" {
444                 # This is a big gnarly mess!
445                 # We need to exclude any query string when checking for prohibited extensions.
446                 # And $HTTP["url"] conveniently lets us do that.
447                 # Attempting to do it in the `url.redirect` pattern itself means it would have to
448                 # be anchored to the beginning part up to and excluding any first `?` character.
449                 # Unfortunately, that causes a rather bad exponential explosion in `pcre_exec`
450                 # likely because the negative assertion patterns are anchored to the end.
451                 # Therefore we do the check in two stages, first against $HTTP["url"] only
452                 # anchored at the end and then let the redirect pattern match take care of
453                 # figuring out where the non-querystring part of the url ends to insert `.git`.
454                 $HTTP["url"] =~ "(?ix)
455                         @@reserved()@@ # replaced with reserved extension negative assertions
456                         $" {
457                         url.redirect = ( "^/([^?]*)(.*)$" => var.rdrbase + "/$1.git$2" )
458                 }
459         }
461         # Snapshot/blob_plain requests are only allowed via the PATH_INFO mechanism
462         $HTTP["query-string"] =~ "(?i)(^|[&;])a=(?:snapshot|blob_plain)([&;]|$)" {
463                 url.access-deny = ( "" )
464         }
466         # Redirect snapshot requests to snapshot.cgi
467         else $HTTP["url"] =~ "(?x)
468                 ^/(?![bchr]/)(?:w/)?
469                 ((?:[a-zA-Z0-9][a-zA-Z0-9+._-]*(?<!\.git)/)*[a-zA-Z0-9][a-zA-Z0-9+._-]*?\.git/
470                         snapshot(?:/.*)?)$" {
471                 alias.url = (
472                         "/w/" => "@@cgiroot@@/snapshot.cgi/",
473                         "/" => "@@cgiroot@@/snapshot.cgi/"
474                 )
475                 fastcgi.server = ()
476                 cgi.assign = ( "" => "" )
477                 # CGI scripts will likely behave poorly without this
478                 setenv.set-environment += ( "PATH" => var.syspath )
479                 # Send Apache-identical DOCUMENT_ROOT not lighttpd crazy one
480                 setenv.set-environment += ( "DOCUMENT_ROOT" => server.document-root )
481         }
483         # The fancy .no_blob_plain processing is not handled with lighttpd...yet!
485         # Of the 11 possible Git protocol URLs (i.e. passed to git-http-backend-verify),
486         # 9 are only valid with GET/HEAD and the other two are only valid with POST
487         # Furthermore, 7 are only valid when non-smart is allowed and
488         # 1 is only valid when smart-only is enabled if it has the correct query string.
490         # These two always require POST
491         $HTTP["request-method"] != "POST" {
492                 $HTTP["url"] =~ "(?x)^/(?![bchw]/)(?:r/)?
493                         (?:[a-zA-Z0-9][a-zA-Z0-9+._-]*(?<!\.git)/)*[a-zA-Z0-9][a-zA-Z0-9+._-]*?(?:\.git)?/(?:
494                                 git-upload-pack |
495                                 git-receive-pack )$" {
496                         url.access-deny = ( "" )
497                 }
498         }
500         @@if(SmartHTTPOnly)@@
501         # These 7 are always forbidden when non-smart HTTP is disabled
502         $HTTP["url"] =~ "(?x)^/(?![bchw]/)(?:r/)?
503                 (?:[a-zA-Z0-9][a-zA-Z0-9+._-]*(?<!\.git)/)*[a-zA-Z0-9][a-zA-Z0-9+._-]*?(?:\.git)?/(?:
504                         HEAD |
505                         objects/info/alternates |
506                         objects/info/http-alternates |
507                         objects/info/packs |
508                         objects/[0-9a-f]{2}/[0-9a-f]{38} |
509                         objects/pack/pack-[0-9a-f]{40}\.(?:pack|idx) )$" {
510                 url.access-deny = ( "" )
511         }
512         # This one is forbidden without the magic query string when non-smart is disabled
513         $HTTP["url"] =~ "(?x)^/(?![bchw]/)(?:r/)?
514                         (?:[a-zA-Z0-9][a-zA-Z0-9+._-]*(?<!\.git)/)*[a-zA-Z0-9][a-zA-Z0-9+._-]*?(?:\.git)?/
515                                 info/refs $" {
516                 $HTTP["request-method"] !~ "^(?:GET|HEAD)$" {
517                         url.access-deny = ( "" )
518                 }
519                 else $HTTP["query-string"] !~ "(^|&)service=git-(?:upload|receive)-pack(&|$)" {
520                         url.access-deny = ( "" )
521                 }
522         }
523         # This one requires GET (or HEAD)
524         $HTTP["request-method"] !~ "^(?:GET|HEAD)$" {
525                 $HTTP["url"] =~ "(?x)^/r/
526                         (?:[a-zA-Z0-9][a-zA-Z0-9+._-]*(?<!\.git)/)*[a-zA-Z0-9][a-zA-Z0-9+._-]*?(?:\.git)?/
527                                 [a-zA-Z0-9][a-zA-Z0-9+._-]*\.bundle $" {
528                         url.access-deny = ( "" )
529                 }
530         }
531         @@endif@@
533         @@if(!SmartHTTPOnly)@@
534         # These 9 require GET (or HEAD)
535         $HTTP["request-method"] !~ "^(?:GET|HEAD)$" {
536                 $HTTP["url"] =~ "(?x)^/(?![bchw]/)(?:r/)?
537                         (?:[a-zA-Z0-9][a-zA-Z0-9+._-]*(?<!\.git)/)*[a-zA-Z0-9][a-zA-Z0-9+._-]*?(?:\.git)?/(?:
538                                 HEAD |
539                                 info/refs |
540                                 objects/info/alternates |
541                                 objects/info/http-alternates |
542                                 objects/info/packs |
543                                 objects/[0-9a-f]{2}/[0-9a-f]{38} |
544                                 objects/pack/pack-[0-9a-f]{40}\.(?:pack|idx) |
545                                 [a-zA-Z0-9][a-zA-Z0-9+._-]*\.bundle )$" {
546                         url.access-deny = ( "" )
547                 }
548         }
549         # This one can be accelerated when accessed with non-smart HTTP
550         $HTTP["request-method"] =~ "^(?:GET|HEAD)$" {
551                 $HTTP["query-string"] !~ "(^|&)service=git-(?:upload|receive)-pack(&|$)" {
552                         $HTTP["url"] =~ "(?x)^/(?![bchw]/)(?:r/)?
553                                 ((?:[a-zA-Z0-9][a-zA-Z0-9+._-]*(?<!\.git)/)*[a-zA-Z0-9][a-zA-Z0-9+._-]*?)(?:\.git)?/
554                                         info/refs $" {
555                                 $REQUEST_HEADER["user-agent"] =~ var.botpat { url.access-deny = ( "" ) }
556                                 url.rewrite-once = (
557                                         "^[^?]*\.git/" => "", # skip rewrite if not needed
558                                         "" => "/r/%1.git/info/refs"
559                                 )
560                                 alias.url = (
561                                         "/r/" => "@@reporoot@@/",
562                                         "/" => "@@reporoot@@/"
563                                 )
564                                 cgi.assign = ()
565                         }
566                 }
567         }
568         @@endif@@
570 @@if(!lighttpd_standalone)@@
571 } # "virtual" host @@httpdnsname@@
572 @@endif@@
574 # Change the setting of $TLSHost in Girocco::Config.pm to change
575 # whether or not the following TLS configuration is enabled.
577 @@if(TLSHost)@@
581 ## Lighttpd TLS Virtual Host Info
583 ## Yes, lighttpd can do TLS virtual hosting.
584 ## By default, if $Girocco::Config::lighttpd_standalone is false
585 ## and $Girocco::Config::TLSHost is true then this config file
586 ## will be set up for TLS virtual hosting.
588 ## But there's a catch.
590 ## For Lighttpd TLS virtual hosting, the correct server certificate
591 ## will be set inside a $HTTP["host"] conditional which will trigger
592 ## based on the incoming SNI (server name indication).
594 ## The gotcha is that Lighttpd requires a valid server certificate and
595 ## private key to always be set at the same level where TLS is enabled (either
596 ## the $SERVER["socket"] section or the global configuration).
598 ## This configuration will not do that (if $lighttp_standalone is false)
599 ## on the assumption that this configuration file has been included by
600 ## a global configuration that has already configured TLS to listen on the
601 ## intended address+port and has already provided a valid TLS server
602 ## certificate and private key for that TLS address+port.  In which case
603 ## when the incoming SNI matches our Girocco host, it will be overridden
604 ## with the Girocco server certificate and key configured in this file.
606 ## If that is not the case (when $lighttpd_standalone is false), then
607 ## lighttpd will complain at startup about a missing "ssl.pemfile" due
608 ## to the "ssl.enable" below.
610 ## If $Girocco::Config::lighttpd_tls_virtualhost is false, then the TLS
611 ## virtual host config part will be omitted (it's always omitted when
612 ## $lighttpd_standalone is true) even when not $lighttpd_standalone.
614 ## Recall that a correctly operating web browser (or other client such as git)
615 ## will NEVER SEND an SNI value when a literal IPv4 or IPv6 address has been
616 ## specified (i.e. https://127.0.0.1/ and https://[::1]/) which means that
617 ## when TLS virtual host mode is enabled an actual host name must be used
618 ## to get the correct certificate (i.e. https://localhost/).
621 $SERVER["socket"] == var.ipv4addr+":"+var.httpsport { # IPv4 TLS
623 # ---- BEGIN LINES TO DUPLICATE ----
625         # Activate TLS mode
627         ssl.engine = "enable"
628         @@if(lighttpd_standalone)@@
629         # cipher-list must be set or the default wide-open list will be used
630         ssl.cipher-list = "ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!eNULL:!LOW:!MEDIUM:!RC4:!SSLv2:!CAMELLIA:!CHACHA20:!aGOST:!DSS:!ECDSA:@STRENGTH"
631         #ssl.read-ahead = "disable" # disable read-ahead on resource constrained systems
632         @@endif(lighttpd_standalone)@@
634         @@if(!lighttpd_standalone)@@
635         @@if(lighttpd_tls_virtualhost)@@
636         $HTTP["host"] == "@@httpdnsname@@" { # "virtual" host @@httpdnsname@@
637         @@endif(lighttpd_tls_virtualhost)@@
638         @@endif(!lighttpd_standalone)@@
640                 # These certificate files will all be automatically generated, but the
641                 # paths here may need to be corrected to match the paths
642                 # (especially $certsdir) from Config.pm
644                 ssl.pemfile = "@@certsdir@@/girocco_www_fullchain.pem"
645                 ssl.privkey = "@@certsdir@@/girocco_www_key.pem"
646                 # When using a www server cert signed by a pre-trusted root, only
647                 # the above two lines should be changed.  Changing either of the
648                 # below two lines will likely break https client authentication.
649                 ssl.ca-file = "@@certsdir@@/girocco_root_crt.pem"
650                 ssl.ca-dn-file = "@@certsdir@@/girocco_client_crt.pem"
652                 ssl.verifyclient.activate = "enable"
653                 ssl.verifyclient.enforce = "disable"
654                 ssl.verifyclient.depth = 3
655                 ssl.verifyclient.username = "SSL_CLIENT_S_DN"
657         @@if(!lighttpd_standalone)@@
658         @@if(lighttpd_tls_virtualhost)@@
659         } # "virtual" host @@httpdnsname@@
660         @@endif(lighttpd_tls_virtualhost)@@
661         @@endif(!lighttpd_standalone)@@
663 # ---- END LINES TO DUPLICATE ----
667 $SERVER["socket"] == "["+var.ipv6addr+"]:"+var.httpsport { # IPv6 TLS
669 # ---- BEGIN DUPLICATE LINES ----
671 ##  *** IMPORTANT ***
673 ##  ALL the entire contents from the '$SERVER["socket"] ==' section above
674 ##  must be copied here.
676 ##  To avoid this duplication, the contents of the '$SERVER["socket"] =='
677 ##  section above can be moved to a separate file and then included both
678 ##  here and above using an include directive.  Be careful not to place
679 ##  the new include file in one of the directories the standard
680 ##  configuration blindly includes all files from.
682 # ---- END DUPLICATE LINES ----
686 @@endif(TLSHost)@@