diff options
| author | Leitwolf | 2026-11-13 05:06:08 +0300 |
|---|---|---|
| committer | GitHub | 2026-11-13 05:06:08 +0300 |
| commit | d82258f9f3bb23a0f59d79b984ff527942efc0f0 (patch) | |
| tree | da8b19d9dbe959d85ab60b044295b3c1afb8cc3a /ops/git/nginx/git.conf | |
| parent | 189b15ca0909033a40626bc8f600686e561b9cbb (diff) | |
| parent | f980fee24c5302173fa00ab758b7c54213d2bb7a (diff) | |
| download | progmaweb-content/catalog-without-tala.tar.gz | |
Merge branch 'main' into content/catalog-without-talacontent/catalog-without-tala
Diffstat (limited to 'ops/git/nginx/git.conf')
| -rw-r--r-- | ops/git/nginx/git.conf | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/ops/git/nginx/git.conf b/ops/git/nginx/git.conf new file mode 100644 index 0000000..71c5b75 --- /dev/null +++ b/ops/git/nginx/git.conf @@ -0,0 +1,113 @@ +# SPDX-FileCopyrightText: 2026 Progmasoft <support@progmasoft.com> +# SPDX-License-Identifier: AGPL-3.0-or-later WITH AdditionRef-Progmasoft-Patent-Grant-1.1 + +# https://git.progmasoft.com: cgit over read-only mirrors, and clones over smart HTTP with +# git-http-backend (upload-pack only). Installed as /etc/nginx/conf.d/git.conf. + +limit_req_zone $binary_remote_addr zone=git_pages:10m rate=10r/s; +limit_req_zone $binary_remote_addr zone=git_clones:10m rate=1r/s; +limit_conn_zone $binary_remote_addr zone=git_connections:10m; + +server { + listen 80; + listen [::]:80; + server_name git.progmasoft.com; + + location ^~ /.well-known/acme-challenge/ { + root /var/lib/letsencrypt; + default_type text/plain; + } + + location / { + return 308 https://git.progmasoft.com$request_uri; + } +} + +server { + listen 443 ssl; + listen [::]:443 ssl; + http2 on; + server_name git.progmasoft.com; + + ssl_certificate /etc/letsencrypt/live/progmasoft.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/progmasoft.com/privkey.pem; + include /etc/letsencrypt/options-ssl-nginx.conf; + + # Nothing is uploaded here: a clone sends only the list of what it wants. + client_max_body_size 1m; + limit_conn git_connections 8; + + add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-Frame-Options "DENY" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always; + # cgit writes no scripts; its diffstat bars set their width in style attributes. + add_header Content-Security-Policy "default-src 'none'; style-src-elem 'self'; style-src-attr 'unsafe-inline'; img-src 'self'; base-uri 'none'; form-action 'self'; frame-ancestors 'none'" always; + + location ^~ /static/ { + alias /srv/git/www/static/; + expires 1d; + add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; + add_header X-Content-Type-Options "nosniff" always; + add_header Content-Security-Policy "default-src 'none'; style-src 'self'" always; + } + + location = /robots.txt { + default_type text/plain; + return 200 "User-agent: *\nDisallow: /*/snapshot/\nDisallow: /*/log/\nDisallow: /*/diff/\nDisallow: /*/patch/\n"; + } + + # Pushing is never possible: no receive-pack, and the dumb protocol is off. + location ~ ^/[A-Za-z0-9._-]+/git-receive-pack$ { + return 403; + } + + location ~ ^/(?<git_repo>[A-Za-z0-9._-]+?)(?:\.git)?/(?<git_path>info/refs|git-upload-pack)$ { + set $git_service ""; + if ($git_path = "info/refs") { + set $git_service $arg_service; + } + if ($git_path = "git-upload-pack") { + set $git_service "git-upload-pack"; + } + if ($git_service != "git-upload-pack") { + return 403; + } + limit_req zone=git_clones burst=10 nodelay; + + fastcgi_pass unix:/run/fcgiwrap/fcgiwrap-cgit.sock; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME /usr/libexec/git-core/git-http-backend; + fastcgi_param GIT_PROJECT_ROOT /srv/git/mirrors; + # No GIT_HTTP_EXPORT_ALL: only mirrors git-mirror marks with git-daemon-export-ok are served. + fastcgi_param PATH_INFO /$git_repo.git/$git_path; + fastcgi_param REMOTE_USER ""; + # The mirrors belong to gitmirror and are read as cgit; only this backend trusts them. + fastcgi_param GIT_CONFIG_COUNT 1; + fastcgi_param GIT_CONFIG_KEY_0 safe.directory; + fastcgi_param GIT_CONFIG_VALUE_0 /srv/git/mirrors/*; + fastcgi_read_timeout 300s; + # Nginx buffers the pack (to a file when it is large), so a slow reader never stalls + # git-http-backend behind fcgiwrap. + fastcgi_buffering on; + fastcgi_max_temp_file_size 2048m; + } + + location / { + limit_req zone=git_pages burst=40 nodelay; + # The menus of cgit (branch, diff options) submit themselves from inline handlers, which the + # policy above blocks; their buttons ("switch", "reload") do the same without a script. + sub_filter "" ""; + sub_filter_once off; + + fastcgi_pass unix:/run/fcgiwrap/fcgiwrap-cgit.sock; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME /var/www/cgi-bin/cgit; + fastcgi_param CGIT_CONFIG /etc/cgitrc; + fastcgi_param PATH_INFO $uri; + fastcgi_param QUERY_STRING $args; + fastcgi_param HTTP_HOST $server_name; + fastcgi_read_timeout 60s; + } +} |