Diff options
Diffstat (limited to 'custom')
| -rw-r--r-- | custom/servers/nginx.conf | 378 |
1 file changed, 68 insertions, 310 deletions
diff --git a/custom/servers/nginx.conf b/custom/servers/nginx.conf index 7f09682..85a71ba 100644 --- a/custom/servers/nginx.conf +++ b/custom/servers/nginx.conf @@ -1,316 +1,74 @@ -# nginx configuration for cgit. +# An nginx server block that serves cgit at the root of git.example.org. +# Include it from the http block of nginx.conf, which supplies the user, the +# MIME types and the logs. nginx cannot run CGI programs itself, so it hands +# them to fcgiwrap over the socket listed below. # -# Written for the nginx 1.30 stable branch, at 1.30.6 when last reviewed. +# The paths are one common layout, so adjust them to your system. +# cgit.cgi /usr/lib/cgit, from make install with the two-line cgit.conf in README +# static files /usr/share/cgit, from the same install +# fcgiwrap socket /run/fcgiwrap.socket +# repositories /var/lib/git, the scan-path custom/cgitrc suggests +# git-http-backend /usr/libexec/git-core, the directory git --exec-path prints +# certificate /etc/ssl/certs/git.example.org.pem +# key /etc/ssl/private/git.example.org.key # -# This is a complete nginx.conf rather than a snippet for conf.d or -# sites-enabled, so nothing here is included from elsewhere. Install it and -# reload, or point nginx straight at it to try it out. -# nginx -t -c /path/to/nginx.conf # check the syntax -# nginx -c /path/to/nginx.conf # run it -# -# Paths assumed below, edit them to match your install. -# cgit CGI binary /usr/lib/cgit/cgit.cgi -# static assets /usr/share/cgit (cgit.css cgit.js cgit.png favicon.ico robots.txt) -# cgit config /etc/cgitrc -# public url https://git.example.org/ (cgit at the domain root) -# -# cgit is one CGI executable. It learns the repository and the page from -# PATH_INFO and reads page options such as h= and id= from QUERY_STRING, so -# nginx must pass PATH_INFO through to the binary. The five static assets are -# served straight off disk 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 -# that socket exists. On Debian and Ubuntu the packaged systemd socket -# provides /run/fcgiwrap.socket, so enabling it is enough. -# apt install fcgiwrap -# systemctl enable --now fcgiwrap.socket -# The socket must be readable by nginx's user. The packaged unit runs fcgiwrap -# as www-data, which nginx also uses on those systems. Without systemd you can -# run -# spawn-fcgi -s /run/fcgiwrap.socket -M 660 -- /usr/sbin/fcgiwrap -# or run fcgiwrap over TCP and point fastcgi_pass at 127.0.0.1:9000. - - -# The user nginx drops to after binding the ports. It is www-data on Debian -# and Ubuntu, nginx on RHEL and Fedora, and http on Arch and Alpine. It has to -# match whatever owns the fcgiwrap socket. -user www-data; -worker_processes auto; -pid /run/nginx.pid; - -# Startup and worker errors. Per-site request logs are set in the vhost. -error_log /var/log/nginx/error.log warn; - -events { - worker_connections 1024; -} - - -http { - # 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; - image/png png; - image/vnd.microsoft.icon ico; - text/plain txt; - } - default_type application/octet-stream; - - sendfile on; - tcp_nopush on; - keepalive_timeout 65; - - # Drop the version number from the Server header and from error pages. - server_tokens off; - - # cgit pages are large and highly compressible, so this is the cheapest - # speedup available. text/html is always compressed and cannot be listed. - # Snapshot tarballs are deliberately absent, since they arrive compressed - # already and running them through gzip again only burns CPU. - gzip on; - gzip_vary on; - gzip_proxied any; - gzip_min_length 1024; - gzip_types text/css text/javascript text/plain application/atom+xml; - - - # 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; - server_name _; - return 444; +# The commented examples add HTTPS, which the bundled auth filters need +# before they log anyone in, and smart HTTP clone and push through +# git-http-backend. + +server { + listen 80; + listen [::]:80; + server_name git.example.org; + + # HTTPS on 443 beside plain HTTP. + #listen 443 ssl; + #listen [::]:443 ssl; + #ssl_certificate /etc/ssl/certs/git.example.org.pem; + #ssl_certificate_key /etc/ssl/private/git.example.org.key; + + # Sends plain HTTP on to HTTPS. + #if ($scheme = http) { + # return 301 https://$host$request_uri; + #} + + root /usr/share/cgit; + + # The five files cgit links to at the root are served off disk. They are + # matched by their full names, so a repository file such as + # /demo/tree/cgit.css still goes to cgit. + location ~ ^/(cgit\.css|cgit\.js|cgit\.png|favicon\.ico|robots\.txt)$ { } - server { - listen 443 ssl default_server; - listen [::]:443 ssl default_server; - server_name _; - # Refuse the TLS handshake itself when the SNI name is unknown, which - # also spares this block from needing a certificate. Requires nginx - # 1.19.4 or newer. On older builds point ssl_certificate at any cert, - # a self-signed one included, and rely on the return below. - ssl_reject_handshake on; - # A client can still handshake against a real name and then send some - # other Host header. Those requests route here after the handshake, - # past the rejection above, so close them too. - return 444; - } - - - # Bounce plain HTTP up to HTTPS. Delete this whole server block if you - # serve plain HTTP only. - server { - listen 80; - listen [::]:80; - server_name git.example.org; - - # ACME http-01 challenge files, if you use certbot in webroot mode. - location ^~ /.well-known/acme-challenge/ { - root /var/www/html; - } - - location / { - return 301 https://$host$request_uri; - } - } - - - # The site itself, written for TLS on 443. For a quick plain-HTTP test, - # change the two listen lines to port 80, delete the redirect block above, - # and delete the http2, ssl and Strict-Transport-Security lines below. - # Everything else stays as it is. - server { - listen 443 ssl; - listen [::]:443 ssl; - # nginx 1.25.1 and newer. On older builds delete this and write the - # listen lines as "listen 443 ssl http2;" instead. - http2 on; - server_name git.example.org; - - ssl_certificate /etc/letsencrypt/live/git.example.org/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/git.example.org/privkey.pem; - ssl_protocols TLSv1.2 TLSv1.3; - ssl_ciphers HIGH:!aNULL:!MD5; - # Let the client pick, which is the modern advice once the ancient - # protocol versions are already excluded above. - ssl_prefer_server_ciphers off; - # Resumption, so a browser paging through a repository is not made to - # redo a full handshake on every connection. - ssl_session_cache shared:SSL:10m; - ssl_session_timeout 1d; - ssl_session_tickets off; - - # Site-wide security headers are set here so they also cover the - # static assets nginx serves. On raw repository bytes cgit sends a - # nosniff and the stricter policy "default-src 'none'" of its own. - # - # add_header appends and never replaces what cgit sent, so a raw page - # carries both policies and the browser enforces the stricter one, - # while the doubled nosniff line is harmless. Keep it that way. Any - # construct that rewrites response headers here could strip the - # protection cgit puts on raw repository content. - # - # 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. - # 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; - - # The browser features a git viewer never asks for, camera and - # location among them, are refused outright for everything served - # here, repository files included. - add_header Permissions-Policy "accelerometer=(), autoplay=(), camera=(), display-capture=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), usb=()" always; - - # Cross-origin isolation. The opener policy cuts any window.opener - # link between cgit and pages that open it, and the resource policy - # stops other origins from embedding what cgit serves, a hotlinked - # raw file for example. git clients are not browsers and ignore both, - # so clone and snapshot downloads keep working. The stricter - # Cross-Origin-Embedder-Policy is deliberately absent because it - # would break the avatar filters mentioned above. - add_header Cross-Origin-Opener-Policy "same-origin" always; - add_header Cross-Origin-Resource-Policy "same-origin" always; - - # Two years of forced HTTPS. This config already redirects every - # plain request to TLS, so browsers may as well stop asking. Delete - # this line if you convert the vhost to plain HTTP, and know it is - # hard to undo once browsers have seen it. - add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always; - - # The document root is the directory that holds the static assets. - # cgit's default css, js, logo and favicon settings are absolute links - # to these files, so they 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, - # and it stops after 4096 bytes. Nothing else here accepts an upload, - # so keep the cap far below the nginx default of 1m. - client_max_body_size 64k; - - access_log /var/log/nginx/cgit.access.log combined; - error_log /var/log/nginx/cgit.error.log; - - # Match the assets by their exact root-level names, never by bare - # 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; - try_files $uri =404; - } - - # Everything else is a cgit url. - location / { - # 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 - # path and is the usual cause of a failed request. - fastcgi_param SCRIPT_FILENAME /usr/lib/cgit/cgit.cgi; - - # cgit builds its link base, the virtual root, from SCRIPT_NAME. - # The stock parameters set SCRIPT_NAME to the whole request path, - # which would make cgit prepend that path to every link. Served at - # the domain root the script has no prefix, so force SCRIPT_NAME - # empty and cgit uses / as its base. A sub-path install sets it - # instead, see the end of this file. - fastcgi_param SCRIPT_NAME ""; - - # How cgit learns the repository and page. At the domain root the - # whole request path is the PATH_INFO. - fastcgi_param PATH_INFO $uri; - - # Page options such as h=branch and id=sha. - fastcgi_param QUERY_STRING $query_string; - - # Which config cgit reads. It checks CGIT_CONFIG and falls back to - # the compiled-in /etc/cgitrc. Setting it makes the location - # explicit and lets you move cgitrc without recompiling. - fastcgi_param CGIT_CONFIG /etc/cgitrc; - - # The browser's Host header, so cgit builds clone urls against the - # name the visitor used rather than server_name. - fastcgi_param HTTP_HOST $http_host; - - # The real scheme, so cgit builds correct https clone urls. - fastcgi_param HTTPS $https if_not_empty; - - # The routine remainder, needed by fcgiwrap and by the login form. - fastcgi_param REQUEST_METHOD $request_method; - fastcgi_param CONTENT_TYPE $content_type; - fastcgi_param CONTENT_LENGTH $content_length; - fastcgi_param REQUEST_URI $request_uri; - fastcgi_param DOCUMENT_URI $document_uri; - fastcgi_param DOCUMENT_ROOT $document_root; - fastcgi_param SERVER_PROTOCOL $server_protocol; - fastcgi_param REQUEST_SCHEME $scheme; - fastcgi_param GATEWAY_INTERFACE CGI/1.1; - fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; - fastcgi_param REMOTE_ADDR $remote_addr; - fastcgi_param REMOTE_PORT $remote_port; - fastcgi_param SERVER_ADDR $server_addr; - fastcgi_param SERVER_PORT $server_port; - fastcgi_param SERVER_NAME $server_name; - - fastcgi_pass unix:/run/fcgiwrap.socket; - - # Large outputs such as snapshot tarballs and blame on big files - # can take a while, so give cgit room and stream rather than buffer. - fastcgi_read_timeout 300s; - fastcgi_buffering off; - - # Ordinary cgit pages carry no expiry time, 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. - } + # Smart HTTP clone and push at the urls cgit gives the repositories go to + # git-http-backend. It finds them under GIT_PROJECT_ROOT and, with + # GIT_HTTP_EXPORT_ALL, serves them without a git-daemon-export-ok file. + # The safe.directory setting lets it open them while another user owns + # them. Push is refused until a repository sets http.receivepack or the + # server authenticates the user, and nginx's 1m limit on a request body + # is lifted for it. + #location ~ ^/.+/(info/refs|git-upload-pack|git-receive-pack)$ { + # client_max_body_size 0; + # include fastcgi_params; + # fastcgi_param SCRIPT_FILENAME /usr/libexec/git-core/git-http-backend; + # fastcgi_param PATH_INFO $uri; + # fastcgi_param GIT_PROJECT_ROOT /var/lib/git; + # fastcgi_param GIT_HTTP_EXPORT_ALL ""; + # fastcgi_param GIT_CONFIG_COUNT 1; + # fastcgi_param GIT_CONFIG_KEY_0 safe.directory; + # fastcgi_param GIT_CONFIG_VALUE_0 *; + # fastcgi_pass unix:/run/fcgiwrap.socket; + #} + + # Everything else goes to cgit. fastcgi_params passes the query string + # and takes SCRIPT_NAME from the first group of the split, which is + # empty, so cgit's links start at the root. The second group is the whole + # path, which cgit reads as PATH_INFO. + location / { + fastcgi_split_path_info ^()(.*)$; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME /usr/lib/cgit/cgit.cgi; + fastcgi_param PATH_INFO $fastcgi_path_info; + fastcgi_pass unix:/run/fcgiwrap.socket; } } - - -# To serve cgit at https://git.example.org/cgit/ instead of the root, split -# the url so SCRIPT_NAME is the prefix and PATH_INFO is the rest. Keep every -# other fastcgi_param from the location above. -# -# location /cgit/ { -# fastcgi_split_path_info ^(/cgit)(/.*)$; -# fastcgi_param SCRIPT_FILENAME /usr/lib/cgit/cgit.cgi; -# fastcgi_param SCRIPT_NAME $fastcgi_script_name; -# fastcgi_param PATH_INFO $fastcgi_path_info; -# ... -# fastcgi_pass unix:/run/fcgiwrap.socket; -# } -# -# Serve the assets from the sub-path too, again anchored to the exact names. -# -# location ~ ^/cgit/(cgit\.css|cgit\.js|cgit\.png|favicon\.ico|robots\.txt)$ { -# alias /usr/share/cgit/$1; -# expires 30d; -# access_log off; -# } -# -# cgit's default css, js, logo and favicon settings point at the domain root, -# so under a sub-path also set them to the /cgit/ paths in cgitrc. cgit -# derives the /cgit prefix from SCRIPT_NAME. If links come out wrong, pin it -# in cgitrc with virtual-root=/cgit/. |
