FreeBSD CGit
Posted on Wed 06 August 2014 in english
I copied this setup for a FreeBSD based git server with nginx and cgit from various sites and thus I should call it my Frankenstein jail...
First we must create a new jail, copy the resolv.conf, followed by the installation of various packages, namely:
# pkg install nginx fcgiwrap git cgit gitolite
GIT
Let's create a new user and a dedicated directory for storing our repositories now:
# pw groupadd -n git -g 9418
# pw useradd -n git -u 9418 -g git -c "Git User Account" -d /git \
-s /usr/local/libexec/git-core/git-shell -h -
#
# mkdir -p /git/base
#
# chown -R git:git /git
# chmod -R 0755 /git
As we want to clone via SSH we must copy our id_rsa.pub (public SSH key) to our server into $HOME/.ssh/authorized_keys.
Make sure it has the right permissions:
# cd /git
# mkdir .ssh
# mv KEYFILE.pub /git/.ssh/authorized_keys
# chmod 600 /git/.ssh/authorized_keys
# chown -R git:git /git/.ssh/
Everything should be fine now, so let's create our first repository:
$ mkdir /git/base/test.git
$ cd /git/base/test.git && git init --bare --shared
The last step to a clonable repo is configuring the SSH daemon:
# echo 'sshd_enable="YES"' >> /etc/rc.conf
# service sshd start
On the client try:
$ git clone git@IP_OF_YOUR_SERVER:base/test.git
Cloning into 'test'...
Warning: Permanently added 'IP_OF_YOUR_SERVER' (ECDSA) to the list of known hosts.
warning: You appear to have cloned an empty repository.
Checking connectivity... done.
Now you're able to pull and push from/to your own git server. Congratulations!
CGit and Nginx
Enable Nginx and its dependency fcgiwrap (for CGit) in rc.conf config file:
$ echo 'fcgiwrap_enable="YES"' >> /etc/rc.conf
$ echo 'fcgiwrap_user="www"' >> /etc/rc.conf
$ echo 'nginx_enable="YES"' >> /etc/rc.conf
CGit wants its config file in /usr/local/etc/cgitrc:
css=/cgit.css
logo=/cgit.png
robots=noindex, nofollow
virtual-root=/
root-title=Lechindianer's CGIT
root-desc=...and now for something completely different
clone-url=http://git.lan/$CGIT_REPO_URL git@git.lan:$CGIT_REPO_URL
enable-index-links=1
enable-log-filecount=1
enable-log-linecount=1
enable-commit-graph=1
enable-remote-branches=1
snapshots=tar.gz tar.bz
max-stats=quarter
root-readme=/usr/local/www/cgit/about.htm
repo.group=various
repo.url=test
repo.path=/git/base/test.git
repo.desc=This is my test git repository
repo.owner=Pascal Schmid
repo.clone-url=http://git.lan/test/
For all various kinds of knobs of cgit see. I wanted to have a copy of the 3-clause BSD license on my website, so I put it into the root-readme. The enable- lines should be self-explanatory. If you have an old webgit server and want to adopt values set "enable-git-config=1" so every value starting with gitweb. will get mapped to the corresponding cgit.* one.
And for our webserver /usr/local/etc/nginx/nginx.conf use something like this:
user www;
worker_processes 4;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
error_log /var/log/nginx.error.log error;
sendfile on;
keepalive_timeout 70;
server {
listen 443;
server_name git2;
ssl on;
ssl_certificate /path/to/your/SSL/SERVER.pem;
ssl_certificate_key /path/to/your/SSL/SERVER.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
#ssl_ciphers EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:EECDH+RC4:RSA+RC4:!MD5;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSKULL:!MD5:!DSS;
ssl_session_timeout 5m;
ssl_prefer_server_ciphers on;
index cgit.cgi;
access_log /var/log/git.access.log;
root /usr/local/www/cgit;
try_files $uri @cgit;
# Require auth for requests sent to cgit that originated in location /
location @cgit {
# $document_root is now set properly, and you don't need to override it
index cgit.cgi;
fastcgi_param SCRIPT_FILENAME $document_root/cgit.cgi;
fastcgi_param GIT_HTTP_EXPORT_ALL "";
fastcgi_param PATH_INFO $uri;
fastcgi_param QUERY_STRING $args;
fastcgi_param HTTP_HOST $server_name;
fastcgi_pass unix:/var/run/fcgiwrap/fcgiwrap.sock;
include fastcgi_params;
gzip off;
#rewrite ^ https://$server_name$request_uri permanent;
rewrite ^/([^/]+/.*)?$ /cgit.cgi?url=$1 break;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/local/www/nginx-dist;
}
}
}
Create SSL keys:
# cd /usr/local/etc/
# mkdir ssl
# cd ssl
# openssl req -new -x509 -days 365 -nodes -out /path/to/your/SSL/SERVER.pem -keyout /path/to/your/SSL/SERVER.key -newkey rsa:2048
Start the services:
# service fcgiwrap start && service nginx start
The worker_processes value should represent your available CPU cores as mentioned in the Linode Nginx SSL tutorial.
Regarding the SSL cipher suites - choose a source you put more trust in:
For the keepalive_timeout value see the official Nginx documentation.
Gitolite
The problem with managing several git repositories with the authorized_keys file is that every allowed commiter can
write in every repo on your server. It's controlled by that one entry.
You don't want this presumably so we have to find another mechanism to handle your commiters permissions. This is where
Gitolite comes in handy. It's the successor of the meanwhile discontinued Gitosis.
The workflow is the following: Create a repo with your public ssh key and in this repo you will manage the permissions of all your other repos.
Gitolite uses a modified version of git's $HOME/.ssh/authorized_keys - when you open it you can see:
command="/usr/local/libexec/gitolite/gitolite-shell $USER",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa [very long public key] $USER@$HOST
The git-shell gets wrapped in this specialized auth_keys, so the first step to set up your Gitosis config is to delete the old auth_keys file. Then copy your public key in a directory where you can reach it with your git user. You must change your git user's shell from git-shell to something like /bin/sh for gitolite to work. Don't worry - the user is only allowed to do git-ish things allowed by the command above.
# rm -rf /git/base /git/.ssh
# chpass -s /bin/sh git
# su - git
$ gitolite setup -pk KEYFILE.pub
Now you can clone your gitolite-admin repo and make changes to its REPO/conf/gitolite.conf. See for more info on creating repos and giving permissions.
IMPORTANT: Gitolite has given my directories the wrong permissions so cgit was unable to show its content. To fix this issue change the UMASK value in gitolite's '.gitolite.rc' from 0077 to 0022 as suggested in the Arch Linux Wiki (works only for new repositories).
I had to fire off the following 2 command too:
# find /git/repositories/ -type d -exec chmod og+rx {} \;
# find /git/repositories/ -type f -exec chmod og+r {} \;
Voilà