Deploying Cgit
Cgit is a hyperfast web frontend for Git repositories written in C. It provides a lightweight, efficient alternative to heavier Git web interfaces, making it ideal for hosting your own Git repository browser with minimal resource overhead.
Introduction to Cgit
Cgit is a CGI-based web interface that allows you to browse Git repositories through a web browser. Written in C for maximum performance, Cgit offers a fast, responsive experience even under heavy load. Whether you’re running a single repository or managing dozens of projects, Cgit provides an elegant way to share and explore your Git history.
The project is maintained by Jason A. Donenfeld and has been battle-tested in production environments for over a decade. Cgit implements the HTTP Git protocol, making repositories cloneable directly from the web interface, which means your developers can clone repositories using simple HTTP URLs.
Cgit includes intelligent caching mechanisms that reduce server I/O pressure and improve response times. It’s designed to be lightweight yet feature-rich, providing everything you need for Git repository hosting without the complexity and resource requirements of larger platforms. Cgit understands Git configuration files and can automatically discover repositories, making setup and maintenance straightforward.
Key Features
Cgit is packed with powerful features for Git repository hosting:
- Fast Performance: Written in C with built-in caching to minimize server I/O and maximize response speed
- Repository Browsing: Comprehensive navigation of logs, diffs, trees, and file contents with syntax highlighting
- HTTP Clone Support: Implements the dumb HTTP transport protocol for cloning repositories directly from the web interface
- Caching System: Intelligent HTML caching to reduce server load and improve response times
- Commit Feeds: Atom format feeds for monitoring repository changes and updates
- Repository Discovery: Automatic discovery and scanning of Git repositories in configured directories
- Archive Downloads: Generate on-the-fly archives (tar, zip) for tags and commits
- Plugin Support: Extensible architecture with plugin support for syntax highlighting and custom functionality
- Side-by-Side Diffs: Visual comparison of changes with side-by-side diff rendering
- Statistics: Simple time-based and author-based repository statistics
- Virtual Hosting: Support for multiple virtual hosts with macro expansion for domain-based organization
- GitWeb Compatibility: Understands GitWeb project lists for easy migration
- Git Configuration Integration: Reads gitweb.owner and other Git config settings automatically
- Filtering Framework: Extensive filtering system using Lua or custom scripts for customization
- Search Functionality: Built-in search across commits, authors, and commit messages
- About Pages: Display custom README or about pages for each repository
- Clone Instructions: Display HTTP clone URLs prominently for easy repository access
- Logo Support: Custom logos and branding for your Git interface
- Responsive Design: Clean, fast-loading interface that works on desktop and mobile
- Minimal Dependencies: Lightweight with minimal external dependencies for easy deployment
Prerequisites
Before deploying Cgit on Klutch.sh, ensure you have the following:
- A Klutch.sh account and dashboard access at klutch.sh/app
- A GitHub repository containing Cgit source code (or a fork of the official repository)
- Basic knowledge of Docker and containerization
- Understanding of Git and version control concepts
- Familiarity with web server configuration (nginx or similar)
- Knowledge of Git repository management and organization
- Understanding of HTTP and CGI protocols
Important Considerations
Deployment Steps
Follow these steps to deploy Cgit on Klutch.sh:
Create a Dockerfile
Create a
Dockerfilein the root of your repository to build and configure Cgit:FROM alpine:latestWORKDIR /app# Install build dependencies and runtime requirementsRUN apk add --no-cache \git \gcc \musl-dev \make \curl \xz \perl \openssl-dev \zlib-dev \nginx \supervisor# Build cgitRUN curl -fsSL https://git.zx2c4.com/cgit/snapshot/cgit-master.tar.xz | tar xJ && \cd cgit-* && \make get-git && \make && \make install# Copy nginx configurationCOPY nginx.conf /etc/nginx/nginx.confCOPY cgit.conf /etc/nginx/cgit.conf# Copy cgit configurationCOPY cgitrc /etc/cgitrc# Create directory for git repositoriesRUN mkdir -p /var/lib/git && \chown -R nobody:nobody /var/lib/git /var/cache/cgit# Copy supervisor configurationCOPY supervisord.conf /etc/supervisord.conf# Expose portEXPOSE 8080# Start servicesCMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]Create Nginx Configuration
Create
nginx.conffor serving Cgit:user nobody;worker_processes auto;error_log /var/log/nginx/error.log warn;pid /var/run/nginx.pid;events {worker_connections 1024;}http {include /etc/nginx/mime.types;default_type application/octet-stream;log_format main '$remote_addr - $remote_user [$time_local] "$request" ''$status $body_bytes_sent "$http_referer" ''"$http_user_agent" "$http_x_forwarded_for"';access_log /var/log/nginx/access.log main;sendfile on;tcp_nopush on;keepalive_timeout 65;gzip on;gzip_types text/plain text/css application/json application/javascript;include /etc/nginx/cgit.conf;}Create
cgit.conffor Cgit configuration:server {listen 8080;server_name _;root /usr/local/share/cgit;location ~ /cgit.cgi {try_files $uri =404;fastcgi_pass unix:/var/run/fcgiwrap.socket;fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;fastcgi_param REQUEST_METHOD $request_method;fastcgi_param QUERY_STRING $query_string;fastcgi_param CONTENT_TYPE $content_type;fastcgi_param CONTENT_LENGTH $content_length;fastcgi_param SCRIPT_NAME /cgit.cgi;fastcgi_param REQUEST_URI $request_uri;fastcgi_param HTTPS $https;include fastcgi_params;}location / {try_files $uri @cgit;}location @cgit {rewrite ^/(.*)$ /cgit.cgi?url=$1 last;}location = /cgit.css {alias /usr/local/share/cgit/cgit.css;}location = /cgit.png {alias /usr/local/share/cgit/cgit.png;}# Cache static fileslocation ~* \.(css|png|jpg|gif|js|ico|svg)$ {expires 30d;add_header Cache-Control "public, immutable";}}Create Cgit Configuration
Create
cgitrcwith your Cgit settings:# Basic cgit configuration# Web interface settingssite-name=My Git Repositoriessite-link=https://example-app.klutch.shlogo=/cgit.pnglogo-link=https://example-app.klutch.sh# Repository scanningscan-path=/var/lib/gitclone-url=https://example-app.klutch.sh/{{repo}}.git# Cachingcache-size=50cache-static-ttl=5cache-dynamic-ttl=5cache-repo-ttl=5cache-root=/var/cache/cgit# UI featuresenable-http-clone=1enable-git-clone=0enable-ssh-clone=0enable-index-owner=1enable-index-links=1enable-commit-graph=1enable-log-filecount=1enable-log-linecount=1enable-statistics=1max-stats=month# Searchenable-grep=1max-repo-count=100# About pagesreadme=about# Virtual hosting (optional)virtual-root=/# Custom CSS (optional)# css=/custom.css# Repository settingsrepo.defbranch=mainrepo.max-info-refs=1024repo.max-objects=1024000# Enable lua filteringenable-filter-overrides=1Create Supervisor Configuration
Create
supervisord.confto manage services:[supervisord]nodaemon=truelogfile=/var/log/supervisord.logpidfile=/var/run/supervisord.pid[program:nginx]command=/usr/sbin/nginx -g "daemon off;"autostart=trueautorestart=truestderr_logfile=/var/log/nginx/stderr.logstdout_logfile=/var/log/nginx/stdout.logstopsignal=QUIT[program:fcgiwrap]command=/usr/local/sbin/fcgiwrap -s unix:/var/run/fcgiwrap.socketautostart=trueautorestart=truestderr_logfile=/var/log/fcgiwrap_err.logstdout_logfile=/var/log/fcgiwrap_out.loguser=nobodyCreate .gitignore
Ensure sensitive files aren’t committed to GitHub by creating
.gitignore:.env.env.localcgitrc.localnginx.conf.localsupervisord.conf.locallogs/*.log.DS_Storecache/Push to GitHub
Commit and push your Cgit configuration to your GitHub repository:
Terminal window git add Dockerfile nginx.conf cgit.conf cgitrc supervisord.conf .gitignoregit commit -m "Add Klutch.sh deployment configuration for Cgit"git push origin mainDeploy on Klutch.sh
- Log in to your Klutch.sh dashboard at klutch.sh/app
- Click “Create New App” and select your GitHub repository containing Cgit
- Klutch.sh will automatically detect the Dockerfile in your repository
- Configure your deployment:
- Set your custom domain (e.g.,
git.example.com) - Configure HTTP traffic on port 8080
- Set your custom domain (e.g.,
- Click “Deploy” to start the deployment process
- Monitor the deployment logs to ensure successful startup
Configure Persistent Storage
After your deployment is complete, attach persistent storage for your Git repositories:
- From your app’s dashboard, navigate to the “Storage” or “Volumes” section
- Click “Add Volume”
- Set the mount path to
/var/lib/git(where Git repositories are stored) - Set the volume size based on your repository storage needs (starting with 100GB recommended)
- Confirm and wait for the volume to be attached
- Set another volume for cache if desired:
- Mount path:
/var/cache/cgit - Size: 50GB
- Mount path:
- Your Cgit instance will automatically use persistent volumes for storage
Initial Setup and Configuration
After your Cgit deployment is live, complete the initial setup:
Adding Git Repositories
-
SSH into your Klutch.sh deployment or access the container
-
Create a new bare Git repository:
Terminal window cd /var/lib/gitgit init --bare myproject.gitchown -R nobody:nobody myproject.git -
Configure the repository with metadata:
Terminal window cd /var/lib/git/myproject.gitecho "My Project" > descriptionecho "John Doe" > owner -
Cgit will automatically discover the repository on the next scan
Accessing Your Cgit Instance
- Navigate to your Cgit instance URL (e.g.,
https://git.example.com) - You’ll see the repository listing
- Click on a repository to browse its contents
- Use the clone URL displayed to clone repositories:
Terminal window git clone https://git.example.com/myproject.git
Configuring Repository Descriptions
Add descriptions to your repositories to appear in the listing:
# For each repositoryecho "My awesome project description" > /var/lib/git/myproject.git/descriptionecho "John Doe <john@example.com>" > /var/lib/git/myproject.git/ownerCreating About Pages
Add about pages to display in the repository view:
# Create README in the repositoryecho "# My Project
This is an awesome project.
## Getting Started
Clone the repository and start contributing!" > /var/lib/git/myproject.git/README.mdEnvironment Variables
Basic Configuration
While Cgit uses a configuration file rather than environment variables, you can set environment variables to customize behavior:
# Path to Git repositoriesGIT_SCAN_PATH=/var/lib/git
# Cgit cache directoryCGIT_CACHE_ROOT=/var/cache/cgit
# HTTP clone base URLCGIT_CLONE_URL=https://example-app.klutch.sh
# Site nameCGIT_SITE_NAME=My Git Repositories
# Log level for debuggingLOG_LEVEL=infoConfiguration File Customization
You can modify cgitrc to customize behavior via environment variable substitution:
# Repository settingsREPO_DEFBRANCH=mainREPO_MAX_INFO_REFS=1024
# UI settingsENABLE_COMMIT_GRAPH=1ENABLE_STATISTICS=1ENABLE_LOG_LINECOUNT=1
# Cache settingsCACHE_STATIC_TTL=5CACHE_DYNAMIC_TTL=5CACHE_SIZE=50Code Examples
Bash - Bulk Repository Import
Here’s a Bash example for importing multiple repositories into Cgit:
#!/bin/bash
REPO_BASE="/var/lib/git"SOURCE_DIR="/tmp/repos"
# Import repositories from a directoryimport_repositories() { for repo_dir in "$SOURCE_DIR"/*; do if [ -d "$repo_dir" ]; then repo_name=$(basename "$repo_dir") bare_repo="$REPO_BASE/$repo_name.git"
if [ ! -d "$bare_repo" ]; then echo "Importing $repo_name..."
# Create bare repository git clone --bare "$repo_dir" "$bare_repo"
# Set proper permissions chown -R nobody:nobody "$bare_repo"
# Add description if available if [ -f "$repo_dir/.description" ]; then cp "$repo_dir/.description" "$bare_repo/description" fi
echo "✓ $repo_name imported successfully" fi fi done}
# Configure repositoryconfigure_repo() { local repo_path="$1" local owner="$2"
echo "$owner" > "$repo_path/owner"
# Update config git config -f "$repo_path/config" gitweb.owner "$owner" git config -f "$repo_path/config" core.sharedRepository true}
import_repositoriesecho "All repositories imported"Shell - Repository Statistics Script
Here’s a Shell script to generate repository statistics for Cgit:
#!/bin/sh
REPO_BASE="/var/lib/git"STATS_FILE="/tmp/cgit_stats.txt"
# Generate repository statisticsgenerate_stats() { { echo "Cgit Repository Statistics" echo "==========================" echo "" echo "Last updated: $(date)" echo ""
repo_count=0 total_size=0
for repo in "$REPO_BASE"/*.git; do if [ -d "$repo" ]; then repo_name=$(basename "$repo" .git) repo_size=$(du -sh "$repo" | cut -f1) last_commit=$(git -C "$repo" log -1 --format=%ai 2>/dev/null || echo "N/A")
echo "Repository: $repo_name" echo " Size: $repo_size" echo " Last Commit: $last_commit"
repo_count=$((repo_count + 1)) size_bytes=$(du -sb "$repo" | cut -f1) total_size=$((total_size + size_bytes)) fi done
total_size_mb=$((total_size / 1024 / 1024))
echo "" echo "Summary" echo "=======" echo "Total repositories: $repo_count" echo "Total size: ${total_size_mb}MB" } > "$STATS_FILE"
cat "$STATS_FILE"}
# Monitor repository growthmonitor_repos() { echo "Monitoring repositories..."
for repo in "$REPO_BASE"/*.git; do if [ -d "$repo" ]; then repo_name=$(basename "$repo" .git) size=$(du -sh "$repo" | cut -f1) echo "✓ $repo_name: $size" fi done}
generate_statsmonitor_reposGit - Repository Cloning Script
Here’s a Git-based script to manage cloning and mirroring:
#!/bin/bash
REPO_BASE="/var/lib/git"REMOTE_SOURCE="${1:?Please provide remote repository URL}"REPO_NAME="${2:?Please provide repository name}"
# Create a bare clonecreate_bare_clone() { local source="$1" local dest="$2" local name="$3"
echo "Creating bare clone of $source..."
git clone --bare "$source" "$dest/$name.git"
if [ $? -eq 0 ]; then # Set ownership chown -R nobody:nobody "$dest/$name.git"
# Allow fetch updates git -C "$dest/$name.git" config uploadpack.allowAnySHA1InWant true
echo "✓ Bare repository created at $dest/$name.git" else echo "✗ Failed to create bare repository" exit 1 fi}
# Update an existing mirrorupdate_mirror() { local mirror_path="$1"
echo "Updating mirror $mirror_path..."
git -C "$mirror_path" remote update --prune
if [ $? -eq 0 ]; then echo "✓ Mirror updated successfully" else echo "✗ Failed to update mirror" fi}
create_bare_clone "$REMOTE_SOURCE" "$REPO_BASE" "$REPO_NAME"Best Practices
When deploying and managing Cgit on Klutch.sh, follow these best practices:
- Repository Organization: Organize your Git repositories in a logical directory structure for easier browsing and management
- Descriptive Names: Use clear, descriptive names for repositories and add meaningful descriptions
- Owner Information: Set owner information for each repository to track responsibility
- Regular Backups: Implement regular backup procedures for your Git repositories stored in persistent volumes
- Cache Configuration: Fine-tune cache settings based on your repository activity and traffic patterns
- Access Control: Implement authentication at the web server level if you need to restrict access to certain repositories
- Static Content: Configure web server caching headers for static assets (CSS, images) to reduce load
- Repository Maintenance: Periodically run
git gcon repositories to optimize storage and performance - Monitoring: Monitor disk space usage and repository growth to capacity plan appropriately
- Update Regularly: Keep Cgit updated to the latest version for security patches and bug fixes
- Security Headers: Configure appropriate HTTP security headers in your nginx configuration
- HTTPS: Always use HTTPS for production Cgit instances to protect data in transit
Troubleshooting
Common Issues and Solutions
Issue: Repositories not appearing in listing
- Verify repositories are in the correct location (
/var/lib/git) - Ensure repository directories end with
.git - Check that permissions allow the cgit user (nobody) to read repositories
- Verify
scan-pathis correctly configured incgitrc - Restart Cgit and check cache expiration settings
Issue: Clone not working
- Verify the HTTP clone URL is correct in
cgitrc - Ensure
enable-http-clone=1is set in configuration - Check that nginx is properly configured with fcgiwrap
- Test clone URL directly:
git clone https://git.example.com/repo.git - Check HTTP response headers for authentication requirements
Issue: Slow page load times
- Check cache settings in
cgitrcand consider increasing cache size - Monitor disk I/O on persistent volume
- Verify nginx worker processes match CPU count
- Enable gzip compression in nginx configuration
- Consider using a CDN for static assets
Issue: Permission denied errors
- Verify repository ownership:
chown -R nobody:nobody /var/lib/git - Check file permissions:
chmod -R 755 /var/lib/git - Ensure persistent volume has correct permissions
- Verify fcgiwrap is running as the nobody user
Issue: Nginx returns 404 errors
- Verify cgit.cgi binary exists:
which cgit.cgi - Check fcgiwrap socket exists:
ls -la /var/run/fcgiwrap.socket - Verify nginx configuration syntax:
nginx -t - Check error logs:
/var/log/nginx/error.log - Restart nginx service
Issue: Out of disk space
- Monitor persistent volume usage regularly
- Clear old cache entries:
rm -rf /var/cache/cgit/* - Run garbage collection on large repositories:
git gc - Consider increasing persistent volume size in Klutch.sh dashboard
Update Instructions
To update Cgit to the latest version:
-
Pull Latest Code
Terminal window git fetch origingit pull origin main -
Update Dockerfile Update the cgit version in your Dockerfile if using a specific version tag
-
Rebuild Container Push your changes to GitHub:
Terminal window git add Dockerfilegit commit -m "Update Cgit to latest version"git push origin main -
Redeploy on Klutch.sh
- Navigate to your app in the Klutch.sh dashboard
- Trigger a redeploy to rebuild with the latest Cgit
- Monitor deployment logs for successful build
-
Verify Update
- Navigate to your Cgit instance
- Check the footer for version information
- Test repository browsing functionality
Use Cases
Self-Hosted Git Repository Browser
Cgit is perfect for organizations that want to self-host their Git repositories with a clean, fast web interface. It’s ideal for teams that need to view and browse code without using GitHub or other cloud platforms.
Internal Code Repository Server
Run Cgit internally for a team’s private code repositories. The lightweight nature means it can run on modest hardware while serving dozens or hundreds of repositories efficiently.
Open Source Project Hosting
Host multiple open source projects with Cgit and allow anyone to clone and download your code. The HTTP clone support makes it easy for developers to work with your repositories.
Educational Institution Repository Server
Universities and coding schools can use Cgit to host student repositories and class projects. Simple setup and administration make it ideal for educational environments.
Legacy Repository Archive
Preserve and provide access to archived Git repositories that are no longer actively developed. Cgit’s read-only nature makes it perfect for archival purposes.
Developer Portfolio Showcase
Individual developers can use Cgit to showcase their code and projects. It’s lightweight enough to run on a small VPS while providing a professional repository browser.
Additional Resources
- Official Cgit Documentation
- Cgit about Page
- Cgit FAQ
- Git Official Documentation
- Nginx Configuration Guide
- CGI Specification
- Cgit Mailing List
- IRC Chat - Libera.Chat #cgit
Conclusion
Deploying Cgit on Klutch.sh gives you a lightweight, fast, and reliable Git repository browser that can serve your development team or open source projects. By following this guide, you’ve set up a production-ready Cgit instance that provides easy access to your Git repositories through an elegant web interface.
Cgit’s minimal resource footprint, combined with its powerful performance characteristics and straightforward configuration, makes it an excellent choice for organizations of any size. Whether you’re hosting a handful of personal projects or managing a large repository portfolio, Cgit provides the tools and flexibility you need.
Remember to maintain your persistent storage, implement proper access controls, monitor your deployment, and follow the best practices outlined in this guide. With Cgit running on Klutch.sh, you have a reliable, fast platform for Git repository hosting and browsing.
For additional support and to connect with the Cgit community, visit the official Cgit documentation, check the FAQ, or join the mailing list for help and discussions.
Author: Davaughn White