summaryrefslogtreecommitdiff
path: root/docs/handbook/cgit/deployment.md
blob: 8c991726af77f1acd0337342612b7061c4d81e84 (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
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
# 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/

<Directory "/usr/lib/cgit/">
    AllowOverride None
    Options +ExecCGI
    Require all granted
</Directory>

<Directory "/usr/share/cgit/">
    AllowOverride None
    Require all granted
</Directory>
```

### 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` |