# 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.
LoadModule mpm_event_module modules/mod_mpm_event.so
LoadModule unixd_module modules/mod_unixd.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule mime_module modules/mod_mime.so
LoadModule alias_module modules/mod_alias.so
LoadModule cgid_module modules/mod_cgid.so
LoadModule env_module modules/mod_env.so
LoadModule headers_module modules/mod_headers.so
LoadModule expires_module modules/mod_expires.so
# 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.
LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
LoadModule ssl_module modules/mod_ssl.so
# 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.
AllowOverride None
Require all denied
# The static asset directory, read only.
Options None
AllowOverride None
Require all granted
# These assets rarely change, so let browsers cache them. Keep the
# 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.
ExpiresActive On
ExpiresDefault "access plus 30 days"
# The cgit binary.
# 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.
SetHandler cgi-script
AllowOverride None
Require all granted
# 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.
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/
# The vhost that serves cgit. To run without TLS for now, change this opening
# line to port 80, delete the SSL lines, delete the Strict-Transport-Security
# line, and delete the vhost above so there is only one. Everything else stays
# as it is.
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
# 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, 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 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.
#
# 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