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
|
Full guide: lightweight Git server on OpenBSD (git-shell + cgit)
This guide describes how to set up a light, secure, fully working Git server on OpenBSD. When you finish you will have:
SSH access to your repositories for push/pull (dedicated user, key‑only authentication).
A cgit web interface for browsing repositories at https://git.yourdomain.com.
An automatically renewed Let’s Encrypt SSL certificate.
All steps are performed on the OpenBSD server via SSH (preferably over a VPN, if direct SSH is blocked by your firewall rules).
0. Prerequisites
You have an OpenBSD server with a working httpd, pf, and a VPN tunnel (for example, the VPN network is 10.0.0.1 – adjust as needed).
Other websites may already be running on your server; their configuration in /etc/httpd.conf must be preserved.
A DNS A record for git.yourdomain.com points to your server’s public IP address (e.g., 203.0.113.10) and proxy/CDN (like Cloudflare’s orange cloud) is turned off (grey cloud / DNS‑only).
You have root access or can execute doas.
1. Install Git and create the dedicated user
bash
doas pkg_add git
Create a dedicated user that will own the repositories. In this guide we use the username gituser – you may choose any name.
bash
doas adduser
Answer the prompts as follows:
username : gituser
full name : Git Server
shell : ksh (we will change it to git-shell later)
home : /home/gituser
password : leave empty (only key‑based login will be used)
Set up the home directory:
bash
doas mkdir -p /home/gituser/.ssh
doas chmod 700 /home/gituser/.ssh
doas touch /home/gituser/.ssh/authorized_keys
doas chmod 600 /home/gituser/.ssh/authorized_keys
doas chown -R gituser:gituser /home/gituser
2. Configure SSH keys for the administrator
You need an SSH key pair that will be used to push to and manage the repositories.
If you already have a key, copy its public part (e.g. ~/.ssh/id_ed25519.pub) to the server.
If not, generate one on your local machine:
bash
ssh-keygen -t ed25519 -C "git admin key"
Assume the public key file is now available on the server at, for example, /tmp/your_key.pub. Add it to the gituser account with the necessary restrictions:
bash
echo 'no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ' | doas tee /home/gituser/.ssh/authorized_keys
doas cat /tmp/your_key.pub | doas tee -a /home/gituser/.ssh/authorized_keys
doas chown gituser:gituser /home/gituser/.ssh/authorized_keys
doas chmod 600 /home/gituser/.ssh/authorized_keys
Change the user’s shell to git-shell – this forbids interactive logins and only allows Git operations:
bash
doas chpass -s git-shell gituser
Test the connection from your local machine (adjust the IP or VPN address accordingly):
bash
ssh gituser@10.0.0.1
You should see a message like “PTY allocation request failed” (login is blocked) with no password prompt.
3. Create the repositories directory
bash
doas mkdir -p /var/www/git-repos
doas chown -R gituser:www /var/www/git-repos
doas chmod 750 /var/www/git-repos
Create a symbolic link so developers can use the short path /git:
bash
doas ln -sf /var/www/git-repos /git
Initialise a bare test repository:
bash
doas -u gituser git init --bare /var/www/git-repos/my_project.git
Now from your local machine you can push to it (replace the host address):
bash
git remote add origin gituser@10.0.0.1:/git/my_project.git
git push -u origin master
4. Install cgit and prepare the chroot
Install cgit:
bash
doas pkg_add cgit
Create the cgit configuration file:
bash
doas mkdir -p /var/www/conf
doas tee /var/www/conf/cgitrc << 'EOF'
scan-path=/git-repos
css=/cgit.css
logo=/cgit.png
enable-index-links=1
enable-http-clone=1
root-title=My Git Repositories
root-desc=Public projects
snapshots=tar.gz
readme=:README.md
EOF
Copy static assets (logo, CSS) – these are shipped with the cgit package:
bash
doas cp /var/www/cgit/cgit.png /var/www/cgit/ 2>/dev/null || true
doas cp /var/www/cgit/cgit.css /var/www/cgit/ 2>/dev/null || true
doas chown -R www:www /var/www/cgit
Add the web server user (www) to the gituser group so cgit can read the repositories:
bash
doas usermod -G www,gituser www
doas chmod 750 /var/www/git-repos
doas find /var/www/git-repos -type d -exec chmod 750 {} \;
doas find /var/www/git-repos -type f -exec chmod 640 {} \;
Critical step – because httpd on OpenBSD runs cgit inside a chroot at /var/www, you must copy the git binary and all its dependencies into that chroot:
bash
doas mkdir -p /var/www/usr/local/bin /var/www/usr/local/libexec /var/www/usr/lib /var/www/usr/local/lib /var/www/dev
# Copy git
doas cp /usr/local/bin/git /var/www/usr/local/bin/
# Copy the dynamic linker and required libraries
doas cp /usr/libexec/ld.so /var/www/usr/libexec/
for lib in $(ldd /usr/local/bin/git | awk '/\/usr\// {print $NF}' | sort -u); do
doas mkdir -p "/var/www/$(dirname "$lib")"
doas cp "$lib" "/var/www/$lib"
done
# Create /dev/null (needed even for reading operations)
doas mknod /var/www/dev/null c 2 2
doas chmod 666 /var/www/dev/null
Verify that git works inside the chroot:
bash
doas chroot /var/www /usr/local/bin/git --version
You should see the git version number. If the command fails, double‑check the copied libraries.
5. Configure httpd for the cgit subdomain
Edit /etc/httpd.conf and add the following blocks at the end (be careful to use only multi‑line location stanzas, no single‑line shortcuts):
text
# --- git.yourdomain.com (cgit) ---
server "git.yourdomain.com" {
listen on egress port 80
location * {
block return 301 "https://$HTTP_HOST$REQUEST_URI"
}
}
server "git.yourdomain.com" {
listen on egress tls port 443
log style combined
log access "git-access.log"
tls {
certificate "/etc/ssl/git.yourdomain.com.fullchain.pem"
key "/etc/ssl/private/git.yourdomain.com.key"
}
location "/cgit.css" {
root "/cgit"
no fastcgi
}
location "/cgit.png" {
root "/cgit"
no fastcgi
}
location "/*" {
root "/cgi-bin/cgit.cgi"
fastcgi socket "/run/slowcgi.sock"
}
location "/.git*" {
block
}
}
Check the syntax and restart httpd:
bash
doas httpd -n
doas rcctl restart httpd
6. SSL certificate for the subdomain
Add a section to /etc/acme-client.conf (if it does not already exist):
text
domain git.yourdomain.com {
domain key "/etc/ssl/private/git.yourdomain.com.key"
domain full chain certificate "/etc/ssl/git.yourdomain.com.fullchain.pem"
sign with letsencrypt
}
Issue the certificate:
bash
doas acme-client -v git.yourdomain.com
doas rcctl restart httpd
To renew the certificate automatically every week, append these lines to /etc/weekly.local:
bash
echo 'acme-client -v git.yourdomain.com' | doas tee -a /etc/weekly.local
echo 'rcctl restart httpd' | doas tee -a /etc/weekly.local
7. Start slowcgi and final verification
bash
doas rcctl enable slowcgi
doas rcctl start slowcgi
doas rcctl restart httpd
Open your browser and go to https://git.yourdomain.com. You should see the cgit page listing your repositories (initially only the test repository my_project.git).
If you see “No repositories found”, clear the cgit cache:
bash
doas rm -rf /var/cache/cgit/*
doas rcctl restart slowcgi httpd
Everything is ready! Your personal Git server is now fully operational.
Replace every placeholder (gituser, git.yourdomain.com, your_server_ip, etc.) with your actual values throughout the configuration.
|