# cgit — Deployment Guide ## Overview cgit runs as a CGI application under a web server. This guide covers compilation, installation, web server configuration, and production tuning. ## Prerequisites Build dependencies: - GCC or Clang (C99 compiler) - GNU Make - OpenSSL or compatible TLS library (for libgit HTTPS) - zlib (for git object decompression) - Optional: Lua or LuaJIT (for Lua filters) - Optional: pkg-config (for Lua detection) Runtime dependencies: - A CGI-capable web server (Apache, Nginx+fcgiwrap, lighttpd) - Git repositories on the filesystem ## Building ```bash # Clone/download the source cd cgit/ # Build with defaults make # Or with custom settings make prefix=/usr CGIT_SCRIPT_PATH=/var/www/cgi-bin \ CGIT_CONFIG=/etc/cgitrc CACHE_ROOT=/var/cache/cgit # Install make install ``` ### Build Variables | Variable | Default | Description | |----------|---------|-------------| | `prefix` | `/usr/local` | Installation prefix | | `CGIT_SCRIPT_PATH` | `$(prefix)/lib/cgit` | CGI binary directory | | `CGIT_DATA_PATH` | `$(prefix)/share/cgit` | Static files (CSS, images) | | `CGIT_CONFIG` | `/etc/cgitrc` | Default config file path | | `CACHE_ROOT` | `/var/cache/cgit` | Default cache directory | | `CGIT_SCRIPT_NAME` | `"/"` | Default CGI script name | | `NO_LUA` | (unset) | Set to 1 to disable Lua | ### Installed Files ``` $(CGIT_SCRIPT_PATH)/cgit.cgi # CGI binary $(CGIT_DATA_PATH)/cgit.css # Stylesheet $(CGIT_DATA_PATH)/cgit.js # JavaScript $(CGIT_DATA_PATH)/cgit.png # Logo image $(CGIT_DATA_PATH)/robots.txt # Robots exclusion file ``` ## Apache Configuration ### CGI Module ```apache # Enable CGI LoadModule cgi_module modules/mod_cgi.so # Basic CGI setup ScriptAlias /cgit/ /usr/lib/cgit/cgit.cgi/ Alias /cgit-data/ /usr/share/cgit/ AllowOverride None Options +ExecCGI Require all granted AllowOverride None Require all granted ``` ### URL Rewriting (Clean URLs) ```apache # Enable clean URLs via mod_rewrite RewriteEngine On RewriteRule ^/cgit/(.*)$ /usr/lib/cgit/cgit.cgi/$1 [PT] ``` With corresponding cgitrc: ```ini virtual-root=/cgit/ css=/cgit-data/cgit.css logo=/cgit-data/cgit.png ``` ## Nginx Configuration Nginx does not support CGI natively. Use `fcgiwrap` or `spawn-fcgi`: ### With fcgiwrap ```bash # Install fcgiwrap # Start it (systemd, OpenRC, or manual) fcgiwrap -s unix:/run/fcgiwrap.sock & ``` ```nginx server { listen 80; server_name git.example.com; root /usr/share/cgit; # Serve static files directly location /cgit-data/ { alias /usr/share/cgit/; } # Pass CGI requests to fcgiwrap location /cgit { include fastcgi_params; fastcgi_param SCRIPT_FILENAME /usr/lib/cgit/cgit.cgi; fastcgi_param PATH_INFO $uri; fastcgi_param QUERY_STRING $args; fastcgi_param HTTP_HOST $server_name; fastcgi_pass unix:/run/fcgiwrap.sock; } } ``` ### With spawn-fcgi ```bash spawn-fcgi -s /run/cgit.sock -n -- /usr/bin/fcgiwrap ``` ## lighttpd Configuration ```lighttpd server.modules += ("mod_cgi", "mod_alias", "mod_rewrite") alias.url = ( "/cgit-data/" => "/usr/share/cgit/", "/cgit/" => "/usr/lib/cgit/cgit.cgi" ) cgi.assign = ( "cgit.cgi" => "" ) url.rewrite-once = ( "^/cgit/(.*)$" => "/cgit/cgit.cgi/$1" ) ``` ## Configuration File Create `/etc/cgitrc`: ```ini # Site identity root-title=My Git Server root-desc=Git repository browser css=/cgit-data/cgit.css logo=/cgit-data/cgit.png favicon=/cgit-data/favicon.ico # URL routing virtual-root=/cgit/ # Features enable-commit-graph=1 enable-blame=1 enable-http-clone=1 enable-index-links=1 snapshots=tar.gz tar.xz zip max-stats=quarter # Caching (recommended for production) cache-size=1000 cache-root=/var/cache/cgit cache-root-ttl=5 cache-repo-ttl=5 cache-static-ttl=-1 # Repository discovery scan-path=/srv/git/ section-from-path=1 enable-git-config=1 # Filters source-filter=exec:/usr/lib/cgit/filters/syntax-highlighting.py about-filter=exec:/usr/lib/cgit/filters/about-formatting.sh ``` ## Cache Directory Setup ```bash # Create cache directory mkdir -p /var/cache/cgit # Set ownership to web server user chown www-data:www-data /var/cache/cgit chmod 700 /var/cache/cgit # Optional: periodic cleanup cron job echo "*/30 * * * * find /var/cache/cgit -type f -mmin +60 -delete" | \ crontab -u www-data - ``` ## Repository Permissions The web server user needs read access to all git repositories: ```bash # Option 1: Add web server user to git group usermod -aG git www-data # Option 2: Set directory permissions chmod -R g+rX /srv/git/ # Option 3: Use ACLs setfacl -R -m u:www-data:rX /srv/git/ setfacl -R -d -m u:www-data:rX /srv/git/ ``` ## HTTPS Setup For production, serve cgit over HTTPS: ```nginx server { listen 443 ssl; server_name git.example.com; ssl_certificate /etc/ssl/certs/git.example.com.pem; ssl_certificate_key /etc/ssl/private/git.example.com.key; # ... cgit configuration ... } server { listen 80; server_name git.example.com; return 301 https://$server_name$request_uri; } ``` ## Performance Tuning ### Enable Caching The response cache is essential for performance: ```ini cache-size=1000 # number of cache entries cache-root-ttl=5 # repo list: 5 minutes cache-repo-ttl=5 # repo pages: 5 minutes cache-static-ttl=-1 # static content: forever cache-about-ttl=15 # about pages: 15 minutes ``` ### Limit Resource Usage ```ini max-repo-count=100 # repos per page max-commit-count=50 # commits per page max-blob-size=512 # max blob display (KB) max-message-length=120 # truncate long subjects max-repodesc-length=80 # truncate descriptions ``` ### Use Lua Filters Lua filters avoid fork/exec overhead: ```ini source-filter=lua:/usr/share/cgit/filters/syntax-highlight.lua email-filter=lua:/usr/share/cgit/filters/email-libravatar.lua ``` ### Optimize Git Access ```bash # Run periodic git gc on repositories for repo in /srv/git/*.git; do git -C "$repo" gc --auto done # Ensure pack files are optimized for repo in /srv/git/*.git; do git -C "$repo" repack -a -d done ``` ## Monitoring ### Check Cache Status ```bash # Count cache entries ls /var/cache/cgit/ | wc -l # Check cache hit rate (if access logs are enabled) grep "cgit.cgi" /var/log/nginx/access.log | tail -100 ``` ### Health Check ```bash # Verify cgit is responding curl -s -o /dev/null -w "%{http_code}" http://localhost/cgit/ ``` ## Docker Deployment ```dockerfile FROM alpine:latest RUN apk add --no-cache \ git make gcc musl-dev openssl-dev zlib-dev lua5.3-dev \ fcgiwrap nginx COPY cgit/ /build/cgit/ WORKDIR /build/cgit RUN make && make install COPY cgitrc /etc/cgitrc COPY nginx.conf /etc/nginx/conf.d/cgit.conf EXPOSE 80 CMD ["sh", "-c", "fcgiwrap -s unix:/run/fcgiwrap.sock & nginx -g 'daemon off;'"] ``` ## systemd Service ```ini # /etc/systemd/system/fcgiwrap-cgit.service [Unit] Description=fcgiwrap for cgit After=network.target [Service] ExecStart=/usr/bin/fcgiwrap -s unix:/run/fcgiwrap.sock User=www-data Group=www-data [Install] WantedBy=multi-user.target ``` ## Troubleshooting | Symptom | Cause | Solution | |---------|-------|----------| | 500 Internal Server Error | CGI binary not executable | `chmod +x cgit.cgi` | | Blank page | Missing CSS path | Check `css=` directive | | No repositories shown | Wrong `scan-path` | Verify path and permissions | | Cache errors | Permission denied | Fix cache dir ownership | | Lua filter fails | Lua not compiled in | Rebuild without `NO_LUA` | | Clone fails | `enable-http-clone=0` | Set to `1` | | Missing styles | Static file alias wrong | Check web server alias config | | Timeout on large repos | No caching | Enable `cache-size` |