blob: 4345a9eec26ee475fa08d8c3ad47e8cb978d2e8b (plain)
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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
# Apache httpd 2.4 configuration for cgit.
#
# This is a complete httpd.conf rather than a vhost snippet, so nothing here
# is included from elsewhere and no distro base config is assumed. Check it
# and run it with
#     httpd -t -f /path/to/apache.conf     # check the syntax
#     httpd -f /path/to/apache.conf        # run it
# To use it as an ordinary vhost file instead, drop everything above the
# virtual hosts and let your distro's httpd.conf supply it.
#
# Apache runs the cgit.cgi binary directly through mod_cgid, so no FastCGI
# bridge is needed.
#
# 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.
# ScriptAlias runs the binary and forwards the trailing path as PATH_INFO, so
# no extra path tuning is needed. cgit builds its own link base from
# SCRIPT_NAME. The five static assets are served straight off disk. mod_alias
# resolves Alias and ScriptAlias in order and the first match wins, so the
# static Alias lines come before the catch-all ScriptAlias to stop the two
# routes from shadowing each other.


# ServerRoot is what every relative path below resolves against, including the
# module paths. It is /etc/httpd on RHEL and Fedora and /etc/apache2 on Debian
# and Ubuntu, where the modules live in /usr/lib/apache2/modules and the
# LoadModule lines need that absolute path instead of the relative one.
ServerRoot /etc/httpd
PidFile    /var/run/httpd.pid

# Where Apache puts its runtime scratch, the mutexes and the SSL session
# cache. It is /var/run/httpd on RHEL and Fedora and /var/run/apache2 on
# Debian and Ubuntu. The directory has to exist and be writable before Apache
# starts, which is normally the packaging's job.
DefaultRuntimeDir /var/run/httpd

Listen 80
Listen 443

# Set globally so Apache does not have to guess a name at startup, which it
# warns about. Each vhost overrides it with its own.
ServerName git.example.org

# Drop the version number from the Server header and from error pages.
ServerTokens Prod
ServerSignature Off


# mod_cgid suits the threaded MPMs that ship by default. Use mod_cgi instead
# only on the old prefork MPM. mod_alias provides Alias and ScriptAlias,
# mod_env provides SetEnv, and the rest are the core pieces a standalone
# config cannot do without. On Debian and Ubuntu run
#     a2enmod cgid alias env headers expires ssl
# rather than editing these lines. The guards make double-loading harmless.
<IfModule !mpm_event_module>
    LoadModule mpm_event_module     modules/mod_mpm_event.so
</IfModule>
<IfModule !unixd_module>
    LoadModule unixd_module         modules/mod_unixd.so
</IfModule>
<IfModule !authz_core_module>
    LoadModule authz_core_module    modules/mod_authz_core.so
</IfModule>
<IfModule !log_config_module>
    LoadModule log_config_module    modules/mod_log_config.so
</IfModule>
<IfModule !mime_module>
    LoadModule mime_module          modules/mod_mime.so
</IfModule>
<IfModule !alias_module>
    LoadModule alias_module         modules/mod_alias.so
</IfModule>
<IfModule !cgid_module>
    LoadModule cgid_module          modules/mod_cgid.so
</IfModule>
<IfModule !env_module>
    LoadModule env_module           modules/mod_env.so
</IfModule>
<IfModule !headers_module>
    LoadModule headers_module       modules/mod_headers.so
</IfModule>
<IfModule !expires_module>
    LoadModule expires_module       modules/mod_expires.so
</IfModule>
# TLS. Delete these two along with the HTTPS vhost to run plain HTTP only.
# mod_socache_shmcb backs the SSL session cache and mod_ssl expects it.
<IfModule !socache_shmcb_module>
    LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
</IfModule>
<IfModule !ssl_module>
    LoadModule ssl_module           modules/mod_ssl.so
</IfModule>


# The user Apache drops to after binding the ports. It is apache on RHEL and
# Fedora, www-data on Debian and Ubuntu, and http on Arch.
User  apache
Group apache


# The combined format comes from the distro config rather than from Apache
# itself, so a standalone config has to define it before any CustomLog uses it.
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
ErrorLog /var/log/apache2/error.log
LogLevel warn


# The usual "TypesConfig conf/mime.types" would pull in a second file. Exactly
# five static files are served off disk, so their types are declared here
# instead. Everything else Apache returns comes from cgit, which sets its own
# Content-Type.
AddType text/css                 .css
AddType text/javascript          .js
AddType image/png                .png
AddType image/vnd.microsoft.icon .ico
AddType text/plain               .txt


# Deny the whole filesystem, then open only the two directories cgit needs.
# Without this a misplaced Alias could expose anything readable on the host.
<Directory />
    AllowOverride None
    Require all denied
</Directory>

# The static asset directory, read only.
<Directory "/usr/share/cgit">
    Options None
    AllowOverride None
    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
    # one visitor's page be served to another from a shared cache.
    <IfModule mod_expires.c>
        ExpiresActive On
        ExpiresDefault "access plus 30 days"
    </IfModule>
</Directory>

# The cgit binary.
<Directory "/usr/lib/cgit">
    # Allow CGI execution here. ScriptAlias implies it, stating it makes the
    # intent clear.
    Options +ExecCGI
    # Run cgit.cgi as a CGI even if it is ever reached through a plain Alias
    # rather than ScriptAlias.
    SetHandler cgi-script
    AllowOverride None
    Require all granted
</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
# 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.
<VirtualHost *:80>
    ServerName git.example.org

    ErrorLog  /var/log/apache2/cgit_error.log
    CustomLog /var/log/apache2/cgit_access.log combined

    Redirect permanent / https://git.example.org/
</VirtualHost>


# The vhost that serves cgit. To run without TLS for now, change this opening
# line to port 80, delete the SSL lines, and delete the vhost above so there
# is only one. Everything else stays as it is.
<VirtualHost *:443>
    ServerName git.example.org

    ErrorLog  /var/log/apache2/cgit_ssl_error.log
    CustomLog /var/log/apache2/cgit_ssl_access.log combined

    # Point these at your certificate.
    SSLEngine on
    SSLCertificateFile    /etc/ssl/certs/git.example.org.crt
    SSLCertificateKeyFile /etc/ssl/private/git.example.org.key
    # Subtractive rather than naming the versions to keep, since a mod_ssl
    # built before TLS 1.3 rejects the +TLSv1.3 token outright and refuses to
    # start. This form enables 1.3 wherever it exists.
    SSLProtocol           all -SSLv3 -TLSv1 -TLSv1.1

    # Which config cgit reads. It falls back to the compiled-in /etc/cgitrc,
    # the same path used here, but setting it makes the location explicit and
    # lets you point at a per-vhost file later.
    SetEnv CGIT_CONFIG /etc/cgitrc

    # 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.
    LimitRequestBody 65536

    # Security headers are set here, not in cgit, so they also cover the static
    # assets Apache serves. script-src stays self because cgit loads only its
    # own cgit.js, and style-src allows inline for the diffstat bars. If you
    # enable the gravatar or libravatar avatar filter, add its host to img-src,
    # for example https://www.gravatar.com.
    Header always set 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'"
    Header always set X-Content-Type-Options "nosniff"
    Header always set Referrer-Policy "no-referrer"
    # Enable only once you serve HTTPS exclusively, since it is hard to undo.
    #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.
    Alias /cgit.css    /usr/share/cgit/cgit.css
    Alias /cgit.js     /usr/share/cgit/cgit.js
    Alias /cgit.png    /usr/share/cgit/cgit.png
    Alias /favicon.ico /usr/share/cgit/favicon.ico
    Alias /robots.txt  /usr/share/cgit/robots.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.
    ScriptAlias / /usr/lib/cgit/cgit.cgi/
</VirtualHost>


# The SSL session cache is a global mod_ssl setting, so it sits outside the
# vhosts. Resumption keeps a browser paging through a repository from redoing
# a full handshake on every connection. Delete along with the HTTPS vhost if
# you serve plain HTTP.
<IfModule mod_ssl.c>
    # Relative, so it lands in DefaultRuntimeDir and follows it across distros.
    SSLSessionCache        "shmcb:ssl_scache(512000)"
    SSLSessionCacheTimeout 300
</IfModule>


# To serve cgit at https://git.example.org/cgit/ instead of the root, change
# the ScriptAlias to
#     ScriptAlias /cgit/ /usr/lib/cgit/cgit.cgi/
# and move the static assets under the same prefix, for example
#     Alias /cgit/cgit.css /usr/share/cgit/cgit.css
# SCRIPT_NAME then becomes /cgit and cgit auto-detects it. If links come out
# wrong, pin the base in cgitrc with virtual-root=/cgit.