1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
|
# nginx configuration for cgit.
#
# nginx cannot run CGI programs itself, so a small bridge called fcgiwrap
# runs the cgit.cgi binary and speaks FastCGI to nginx. Starting fcgiwrap is
# covered in the notes at the end of this file.
#
# 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. 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.
# --- Optional HTTP to HTTPS redirect ----------------------------------------
# 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;
}
# Everything else moves to HTTPS.
location / {
return 301 https://$host$request_uri;
}
}
# --- Main site --------------------------------------------------------------
# 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 four ssl
# lines below. Everything else stays the same.
server {
listen 443 ssl;
listen [::]:443 ssl;
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;
# --- Security headers ---------------------------------------------------
# These sit here, not in cgit, because they must also cover the static
# assets nginx serves directly. 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. 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'" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer" always;
# Enable only once you serve HTTPS exclusively, since it is hard to undo.
#add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
# 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.
root /usr/share/cgit;
# Upload cap for large form posts. Snapshots are generated rather than
# uploaded, so this does not limit them.
client_max_body_size 64m;
access_log /var/log/nginx/cgit.access.log;
error_log /var/log/nginx/cgit.error.log;
# --- Static assets, served directly -------------------------------------
# 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.
location ~ ^/(cgit\.css|cgit\.js|cgit\.png|favicon\.ico|robots\.txt)$ {
expires 30d;
access_log off;
try_files $uri =404;
}
# --- cgit, the catch-all ------------------------------------------------
# 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 / {
# nginx's standard FastCGI parameters, some of which are overridden
# below. A later fastcgi_param wins, so include order does not matter.
include fastcgi_params;
# 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, id=sha and the snapshot format.
fastcgi_param QUERY_STRING $query_string;
# Where the static assets live, kept consistent with root above.
fastcgi_param DOCUMENT_ROOT $document_root;
# 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;
# 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 real scheme, so cgit builds correct https clone URLs.
fastcgi_param HTTPS $https if_not_empty;
# Hand off to the fcgiwrap socket. See the notes for how to create it.
# A TCP fcgiwrap would use for example 127.0.0.1:9000 here.
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;
}
}
# --- Notes, starting fcgiwrap -----------------------------------------------
# cgit is a CGI binary and fcgiwrap is the CGI to FastCGI bridge nginx talks
# to. 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.
# --- Alternative, serving cgit under a sub-path -----------------------------
# 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.
#
# location /cgit/ {
# include fastcgi_params;
# 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_param QUERY_STRING $query_string;
# fastcgi_param HTTP_HOST $http_host;
# fastcgi_param CGIT_CONFIG /etc/cgitrc;
# fastcgi_param HTTPS $https if_not_empty;
# 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=/cgit.css and logo=/cgit.png point at the domain root, so
# under a sub-path also set css=/cgit/cgit.css and logo=/cgit/cgit.png in
# cgitrc. cgit derives the /cgit prefix from SCRIPT_NAME. If links come out
# wrong, pin it in cgitrc with virtual-root=/cgit/.
|