diff options
context:
space:
mode:
Diffstat (limited to 'custom/servers')
-rw-r--r--custom/servers/apache.conf60
-rw-r--r--custom/servers/lighttpd.conf32
-rw-r--r--custom/servers/nginx.conf73
3 files changed, 71 insertions, 94 deletions
diff --git a/custom/servers/apache.conf b/custom/servers/apache.conf
index 3c035f7..bbd3e75 100644
--- a/custom/servers/apache.conf
+++ b/custom/servers/apache.conf
@@ -136,9 +136,9 @@ AddType text/plain .txt
Require all granted
# These assets rarely change, so let browsers cache them. Keep the
- # caching scoped to this directory. cgit sends no caching headers of its
- # own, so a server-wide ExpiresDefault would stamp freshness onto its
- # pages, fight the no-store cgit puts on the login page, and could let
+ # caching scoped to this directory. Ordinary cgit pages carry no caching
+ # headers, so a server-wide ExpiresDefault would stamp freshness onto
+ # them, fight the no-store cgit puts on the login page, and could let
# one visitor's page be served to another from a shared cache.
<IfModule mod_expires.c>
ExpiresActive On
@@ -148,8 +148,7 @@ AddType text/plain .txt
# The cgit binary.
<Directory "/usr/lib/cgit">
- # Allow CGI execution here. ScriptAlias implies it, stating it makes the
- # intent clear.
+ # Allow CGI execution here.
Options +ExecCGI
# Run cgit.cgi as a CGI even if it is ever reached through a plain Alias
# rather than ScriptAlias.
@@ -159,8 +158,8 @@ AddType text/plain .txt
</Directory>
-# This vhost only bounces plain HTTP up to HTTPS. It serves no cgit itself,
-# every cgit directive lives in the HTTPS vhost below. To run without TLS for
+# This vhost only bounces plain HTTP up to HTTPS. It serves no cgit itself.
+# Every cgit directive lives in the HTTPS vhost below. To run without TLS for
# now, convert the HTTPS vhost to port 80 and delete this whole block rather
# than editing it, since deleting only the Redirect line would leave a vhost
# that serves nothing.
@@ -205,27 +204,25 @@ AddType text/plain .txt
# Site-wide security headers are set here so they also cover the static
# assets Apache serves. cgit itself sends only the headers the proxy
# cannot supply. Those are Status, Content-Type, Content-Length and
- # Content-Disposition on downloads, a no-store Cache-Control on
- # unauthenticated responses, the auth filter's Set-Cookie, and on raw
+ # Content-Disposition on downloads, Location on redirects, a no-store
+ # Cache-Control on unauthenticated responses, the auth filter's
+ # Set-Cookie, and on raw
# repository bytes a nosniff of its own next to the stricter policy
# "default-src 'none'". Everything else, this policy included, is the
# proxy's job.
#
# The word setifempty is load bearing on the two headers cgit can also
# emit. "Header always set" replaces a same-named header even when the
- # CGI sent it, which was verified against Apache 2.4.67 and would swap
- # the strict policy on raw repository content for this looser site one.
- # setifempty yields to whatever cgit sent and still covers every response
- # without one, the HTML pages, the static assets, and with always also
- # Apache's own error pages. Referrer-Policy stays a plain set because
- # cgit never emits it, so there is nothing to overwrite.
+ # CGI sent it, which would swap the strict policy on raw repository
+ # content for this looser site one. setifempty yields to whatever cgit
+ # sent. Referrer-Policy stays a plain set because cgit never emits it.
#
- # script-src stays self because cgit loads only its own cgit.js, and
- # style-src allows inline for the diffstat bars. form-action self covers
- # the login form, the only form cgit renders. If you enable the gravatar
- # or libravatar avatar filter, add its host to img-src, for example
- # https://www.gravatar.com.
- Header always setifempty Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; object-src 'none'; base-uri 'none'; frame-ancestors 'self'; form-action 'self'"
+ # form-action self covers the login form, the only form cgit renders. If
+ # you enable the gravatar or libravatar avatar filter, add its host to
+ # img-src, for example https://www.gravatar.com. A head-include or
+ # repo.head-content that injects a <style> block needs 'unsafe-inline'
+ # added to style-src.
+ Header always setifempty Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; object-src 'none'; base-uri 'none'; frame-ancestors 'self'; form-action 'self'"
Header always setifempty X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "no-referrer"
@@ -250,12 +247,10 @@ AddType text/plain .txt
# once browsers have seen it.
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains"
- # These five files are the only things served off disk. Each Alias maps
- # one URL to one file. Because they come before the ScriptAlias below, a
- # request for /cgit.css is answered from disk and never reaches cgit.
- # cgit.css and cgit.js are the paths cgit's HTML points at by default, so
- # if you relocate the assets update both these Alias targets and the css,
- # js, logo and favicon settings in cgitrc to agree.
+ # These five files are the only things served off disk. cgit.css and
+ # cgit.js are the paths cgit's HTML points at by default, so if you
+ # relocate the assets update both these Alias targets and the css, js,
+ # logo and favicon settings in cgitrc to agree.
Alias /cgit.css /usr/share/cgit/cgit.css
Alias /cgit.js /usr/share/cgit/cgit.js
Alias /cgit.png /usr/share/cgit/cgit.png
@@ -265,13 +260,10 @@ AddType text/plain .txt
# ScriptAlias maps a URL prefix to a path, marks it executable, and
# forwards the rest of the URL as PATH_INFO. Mapping / makes cgit the
# handler for every URL the static Aliases above did not already claim.
- #
- # The trailing slash on cgit.cgi/ is load bearing. It tells Apache that
- # cgit.cgi is the program and the rest of the URL is PATH_INFO. So a
- # request for /torvalds/linux/tree/kernel?h=next runs the binary with
- # PATH_INFO set to /torvalds/linux/tree/kernel and QUERY_STRING set to
- # h=next. cgit derives its link base from SCRIPT_NAME, which at the domain
- # root is / and needs no tuning. For a sub-path install see the note below.
+ # The trailing slash on cgit.cgi/ is load bearing, telling Apache that
+ # cgit.cgi is the program and the rest of the URL is PATH_INFO. cgit
+ # derives its link base from SCRIPT_NAME, which at the domain root is /
+ # and needs no tuning. For a sub-path install see the note below.
ScriptAlias / /usr/lib/cgit/cgit.cgi/
</VirtualHost>
diff --git a/custom/servers/lighttpd.conf b/custom/servers/lighttpd.conf
index dcfb43d..27c325d 100644
--- a/custom/servers/lighttpd.conf
+++ b/custom/servers/lighttpd.conf
@@ -22,10 +22,9 @@
# straight off disk and must never be routed through cgit.
-# A plain assignment rather than "+=", since this config stands on its own and
-# there is no distro base list to append to. mod_alias maps URL paths onto
-# files, mod_setenv injects CGIT_CONFIG and the response headers, and mod_cgi
-# runs cgit.cgi. Adding mod_accesslog here is what the access log below needs.
+# A plain assignment rather than "+=", since this config stands on its own
+# and there is no distro base list to append to. Adding mod_accesslog here
+# is what the access log below needs.
server.modules = (
"mod_alias",
"mod_setenv",
@@ -37,8 +36,8 @@ server.modules = (
server.port = 80
server.username = "http" # Debian and Ubuntu use www-data
server.groupname = "http"
-server.document-root = "/usr/share/cgit" # a valid docroot must exist, the
- # alias rules below do the routing
+server.document-root = "/usr/share/cgit" # a valid docroot must exist. The
+ # alias rules below do the routing.
server.pid-file = "/run/lighttpd.pid"
server.errorlog = "/var/log/lighttpd/error.log"
accesslog.filename = "/var/log/lighttpd/access.log"
@@ -76,8 +75,9 @@ $HTTP["host"] == "git.example.org" {
# Site-wide security headers are set here so they also cover the static
# assets lighttpd serves. cgit itself sends only the headers the server
# cannot supply. Those are Status, Content-Type, Content-Length and
- # Content-Disposition on downloads, a no-store Cache-Control on
- # unauthenticated responses, the auth filter's Set-Cookie, and on raw
+ # Content-Disposition on downloads, Location on redirects, a no-store
+ # Cache-Control on unauthenticated responses, the auth filter's
+ # Set-Cookie, and on raw
# repository bytes a nosniff of its own next to the stricter policy
# "default-src 'none'". Everything else, this policy included, is the
# server's job.
@@ -89,10 +89,10 @@ $HTTP["host"] == "git.example.org" {
# what cgit sent, swapping the strict policy on raw repository content
# for this looser site one. Never switch add to set.
#
- # script-src stays self because cgit loads only its own cgit.js, and
- # style-src allows inline for the diffstat bars. form-action self covers
- # the login form, the only form cgit renders. If you enable the gravatar
- # or libravatar avatar filter, add its host to img-src.
+ # form-action self covers the login form, the only form cgit renders. If
+ # you enable the gravatar or libravatar avatar filter, add its host to
+ # img-src. A head-include or repo.head-content that injects a <style>
+ # block needs 'unsafe-inline' added to style-src.
#
# Permissions-Policy refuses the browser features a git viewer never asks
# for, camera and location among them, for everything served here,
@@ -104,7 +104,7 @@ $HTTP["host"] == "git.example.org" {
# Cross-Origin-Embedder-Policy is deliberately absent because it would
# break the avatar filters mentioned above.
setenv.add-response-header = (
- "Content-Security-Policy" => "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; object-src 'none'; base-uri 'none'; frame-ancestors 'self'; form-action 'self'",
+ "Content-Security-Policy" => "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; object-src 'none'; base-uri 'none'; frame-ancestors 'self'; form-action 'self'",
"X-Content-Type-Options" => "nosniff",
"Referrer-Policy" => "no-referrer",
"Permissions-Policy" => "accelerometer=(), autoplay=(), camera=(), display-capture=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), usb=()",
@@ -116,10 +116,8 @@ $HTTP["host"] == "git.example.org" {
# it is hard to undo once browsers have seen it.
#setenv.add-response-header += ( "Strict-Transport-Security" => "max-age=63072000; includeSubDomains" )
- # Register the cgit binary as a CGI program. The key cgit.cgi matches the
- # binary's name and the empty value means the file is itself the program,
- # with no interpreter in front of it. This is what makes lighttpd split
- # the trailing path off as PATH_INFO, so never drop it.
+ # Register the cgit binary as a CGI program. The empty value means the
+ # file is itself the program rather than input to an interpreter.
cgi.assign = ( "cgit.cgi" => "" )
# Routing. lighttpd's alias.url is first-match in declaration order, not
diff --git a/custom/servers/nginx.conf b/custom/servers/nginx.conf
index cf1e49f..3ffa2ba 100644
--- a/custom/servers/nginx.conf
+++ b/custom/servers/nginx.conf
@@ -16,8 +16,7 @@
# PATH_INFO and reads page options such as h= and id= from QUERY_STRING, so
# nginx must pass PATH_INFO through to the binary. cgit builds its own link
# base from SCRIPT_NAME. The five static assets are served straight off disk
-# and must never be routed through cgit. Passing PATH_INFO through is the
-# single most important part of the config below.
+# and must never be routed through cgit.
#
# nginx cannot run CGI programs itself, so a small bridge called fcgiwrap runs
# the cgit.cgi binary and speaks FastCGI to nginx. Nothing below works until
@@ -48,11 +47,10 @@ events {
http {
- # nginx's compiled-in type table knows only text/html, and the usual
- # "include mime.types" would pull in a second file. Exactly five static
- # files are served off disk, so their types are declared here instead and
- # this config keeps standing on its own. Everything else nginx returns
- # comes from cgit, which sets its own Content-Type.
+ # nginx's built-in type table covers none of these five extensions, and
+ # the usual "include mime.types" would pull in a second file, so the five
+ # types are declared here. Everything else nginx returns comes from cgit,
+ # which sets its own Content-Type.
types {
text/css css;
text/javascript js;
@@ -80,14 +78,11 @@ http {
gzip_types text/css text/javascript text/plain application/atom+xml;
- # Requests carrying a Host header this config does not serve, a raw IP or
- # an invented name from a scanning bot, land in these two blocks and are
- # dropped without a response. cgit keys its page cache on the Host header
- # so clone URLs stay honest, which means every invented hostname reaching
- # it would mint a cache entry of its own and evict a real page to make
- # room. Refusing strangers here keeps the cache to the names the site
- # actually answers to. 444 is nginx shorthand for closing the connection
- # without replying.
+ # Requests carrying a Host header this config does not serve are dropped
+ # without a response. cgit keys its page cache on the Host header, so
+ # every invented hostname reaching it would mint a cache entry of its
+ # own and evict a real page. 444 is nginx shorthand for closing the
+ # connection without replying.
server {
listen 80 default_server;
listen [::]:80 default_server;
@@ -158,8 +153,9 @@ http {
# Site-wide security headers sit here because they must also cover the
# static assets nginx serves directly. cgit itself sends only the
# headers the proxy cannot supply. Those are Status, Content-Type,
- # Content-Length and Content-Disposition on downloads, a no-store
- # Cache-Control on unauthenticated responses, the auth filter's
+ # Content-Length and Content-Disposition on downloads, Location on
+ # redirects, a no-store Cache-Control on unauthenticated responses,
+ # the auth filter's
# Set-Cookie, and on raw repository bytes a nosniff of its own next to
# the stricter policy "default-src 'none'". Everything else, this
# policy included, is the proxy's job.
@@ -170,13 +166,13 @@ http {
# construct that rewrites response headers here could strip the
# protection cgit puts on raw repository content.
#
- # cgit loads only its own /cgit.js and uses inline style on the
- # diffstat bars, so script-src stays self while style-src allows
- # inline. form-action self covers the login form, the only form cgit
+ # form-action self covers the login form, the only form cgit
# renders. always applies them to error responses too. If you enable
# the gravatar or libravatar avatar filter, add its host to img-src,
# for example https://www.gravatar.com or https://seccdn.libravatar.org.
- add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; object-src 'none'; base-uri 'none'; frame-ancestors 'self'; form-action 'self'" always;
+ # A head-include or repo.head-content that injects a <style> block
+ # needs 'unsafe-inline' added to style-src.
+ add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; object-src 'none'; base-uri 'none'; frame-ancestors 'self'; form-action 'self'" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer" always;
@@ -203,8 +199,7 @@ http {
# The document root is the directory that holds the static assets. cgit
# emits absolute links to /cgit.css and /cgit.png by default, so those
- # files must resolve at the root of the URL space. Pointing root at the
- # asset directory makes /cgit.css map to /usr/share/cgit/cgit.css.
+ # files must resolve at the root of the URL space.
root /usr/share/cgit;
# The only request body cgit ever reads is the auth-filter login form,
@@ -216,15 +211,11 @@ http {
error_log /var/log/nginx/cgit.error.log;
# Match the assets by their exact root-level names, never by bare
- # extension. cgit routes on PATH_INFO and a repository can hold files
- # ending in .css or .png, so /myrepo/tree/style.css and /myrepo/plain/
- # logo.png are real cgit URLs. A broad extension match would capture
- # those, look for them on disk, and return 404 before cgit could render
- # them. Anchoring the regex at the start of the path matches /cgit.css
- # but not /myrepo/tree/cgit.css, so it can never shadow a repository
- # file. An nginx regex location is matched before the prefix location
- # below, so these assets win for their exact URLs and cgit wins for the
- # rest.
+ # extension. A repository can hold files ending in .css or .png, and
+ # /myrepo/tree/style.css is a real cgit URL a broad match would
+ # capture and 404. The regex anchored at ^/ matches /cgit.css but
+ # never /myrepo/tree/cgit.css, and a regex location beats the prefix
+ # location below, so assets win their exact URLs and cgit the rest.
location ~ ^/(cgit\.css|cgit\.js|cgit\.png|favicon\.ico|robots\.txt)$ {
expires 30d;
access_log off;
@@ -234,13 +225,10 @@ http {
# Everything that is not a static asset above is a cgit URL, the repo
# index, a repository, a page within a repository, a snapshot, a feed.
location / {
- # The CGI environment. This is normally "include fastcgi_params",
- # which would be a second file, so the list is written out here.
- # Of all of it cgit itself reads only CGIT_CONFIG, PATH_INFO,
- # QUERY_STRING, SCRIPT_NAME, REQUEST_METHOD, CONTENT_LENGTH,
- # HTTP_HOST, HTTPS, SERVER_NAME, SERVER_PORT, HTTP_COOKIE and
- # HTTP_REFERER. The cookie and referer arrive on their own, since
- # nginx forwards request headers as HTTP_* without being asked.
+ # The CGI environment, normally "include fastcgi_params", written
+ # out here so this config stands alone. The cookie and referer
+ # arrive on their own, since nginx forwards request headers as
+ # HTTP_* without being asked.
# The program fcgiwrap runs. It must be the cgit binary itself, not
# $document_root$fastcgi_script_name, which would try to run a repo
@@ -291,8 +279,7 @@ http {
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
- # Hand off to the fcgiwrap socket. A TCP fcgiwrap would use for
- # example 127.0.0.1:9000 here.
+ # Hand off to the fcgiwrap socket.
fastcgi_pass unix:/run/fcgiwrap.socket;
# Large outputs such as snapshot tarballs and blame on big files
@@ -300,8 +287,8 @@ http {
fastcgi_read_timeout 300s;
fastcgi_buffering off;
- # cgit sends no caching headers of its own, so browsers refetch
- # dynamic pages and cgit's internal cache keeps that cheap. Do not
+ # Ordinary cgit pages carry no caching headers, so browsers
+ # refetch them and cgit's internal cache keeps that cheap. Do not
# add a blanket expires or Cache-Control in this location. It
# would fight the no-store cgit puts on the login page and could
# let one visitor's page be served to another from a shared cache.