Поднимаем Git сервер на OpenBSD

Если вам хочется иметь запасное (или даже основное) хранилище для ваших программных проектов, и вы не очень доверяете Github и его собратьям, то ваша дорога лежит в сторону selfhosted git сервера. Давайте поднимем его, используя машину на OpenBSD, и сверху накрутим простой web ui, для просмотра репозиториев через браузер.

Тему базовой настройки сервера и сертификата я оставлю за скобками, скажу только что и httpd, и acme-client содержатся в базовой системе, работают просто прекрасно и обладают хорошей документацией.

Gitdaemon

Помимо базовой системы нам потребуются ещё два пакета, сам git и простой генератор статического сайта из git репозиториев - stagit. Я выбрал именно его потому что мне нравилось пользоваться решениями на его основе, например вот этим сайтом.

pkg_add git stagit

Git сервер будет работать из под своего собственного пользователя, так что давайте его заведем.

В OpenBSD принято добавлять к сервисным учеткам префикс _, то есть наш пользователь должен называться _git. Однако, по эстетическим причинам, я префикс не использую. Я, конечно же, не прав.

Не делайте так.

# -m приведет к созданию домашней директории для пользователя
user add -m git

Чтобы мы могли лить изменения со своего локального компьютера на сервер по ssh, давайте добавим на него наш публичный ключ.

cd /home/git
mkdir -p .ssh && chmod 700 .ssh
touch .ssh/authorized_keys && chmod 600 .ssh/authorized_keys

cat > .ssh/authorized_keys << "END"
no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-ed25519 *** you@example.com
END

chown -R git:git .ssh

Перед ключом мы указали ряд настроек, которые ограничивают возможности ssh соединения с этим ключом. Чтобы добавить ещё безопасности, стоит урезать возможности нашего служебного пользователя. Для этого мы поменяем ему shell на git-shell, позволяющий выполнять только операции над git репозиториями.

chsh -s /usr/local/bin/git-shell git

Всё что нам осталось, это создать директорию для хранения наших репозиториев и натравить на неё gitdaemon.

mkdir -p /git/
chown -R git:git /git

rcctl enable gitdaemon
rcctl set gitdaemon flags --export-all --base-path="/git"
rcctl set gitdaemon user git
rcctl start gitdaemon

rcctl это системная утилита, которая используется для конфигурирования и настройки сервисов и демонов в OpenBSD. В данном случае мы указываем с какими аргументами командной строки сервис должен запускаться и под каким пользователем работать.

Если вы хотите увидеть, с какими аргументами демон будет работать прямо сейчас, наберите rcctl get gitdaemon.

Для добавления нового репозитория я использую небольшой скрипт, который приведу полностью.

#!/usr/bin/env sh

set -e

REPO=$1

if [ -z $REPO ]
then
    echo "You should specify repository name"
    exit 1
fi

mkdir -p /git/$REPO
cd /git/$REPO
git init --bare

echo "Owner name" > owner
echo "git://git.example.com/$REPO" > url
${EDITOR:-vi} description

chown -R git:git /git/$REPO

В качестве аргумента скрипт принимает название репозитория, которое будет так же использоваться в качестве названия директории для него. Помимо директории мы заполняем владельца и общедоступный url для скачивания на просмотр. Для заполнения описания мы открываем текстовый редактор. Все эти вещи будут использоваться stagit для генерации сайта.

На этом моменте стоит попробовать создать новый репозиторий и закачать в него какие-либо изменения, чтобы убедиться что всё работает правильно. Для скачивания репозитория по ssh воспользуйтесь адресом вида ssh://git@example.com:/git/repo-name.

Stagit

Теперь, когда git daemon исправно работает, самое время прикрутить хоть какой-то интерфейс, чтобы любопытствующие могли покопаться в ваших проектах не скачивая их себе.

Для начала давайте отредактируем /etc/httpd.conf и добавим туда новый сервер для нашей веб морды.

server "git.example.com" {
    listen on * tls port 443
    root "/htdocs/git"
    tls {
        certificate "/etc/ssl/example.com.fullchain.pem"
        key "/etc/ssl/private/example.com.key"
    }

    location "./well-known/acme-challenge/*" {
        root "/acme"
        request strip 2
    }

    location "*/style.css" {
        request rewrite "/style.css"
    }

    location "*/logo.png" {
        request rewrite "/logo.png"
    }

    location "*/favicon.png" {
        request rewrite "/favicon.png"
    }
}

Я исхожу из того, что вы используете https на своем сайте, если это не так - конфиг станет ещё проще.

Последние три блока нужны исключительно по той причине, что stagit генерирует относительные ссылки на логотип, стили и favicon сайта. Чтобы не подкладывать их в каждый репозиторий, я просто делаю редирект с любого урла, оканчивающегося запросом одного из этих файлов, на корень, где они, собственно и лежат.

Данный конфиг будет раздавать пользователям статику из директории /var/www/htdocs/git, которую нам надо создать и передать во владение пользователю git, так как контент в ней будет генерироваться из него (но об этом чуть позже).

mkdir -p /var/www/htdocs/git
chown -R git:git /var/www/htdocs/git

Чтобы проверить что мы правильно написали конфиг, стоит воспользоваться командой httpd -n, которая заставляет сервер распарсить и проверить конфиги, но ничего не запускать. Если всё ок, то давайте перезапустим httpd.

rcctl restart httpd

Делать генерацию сайта руками после каждого обновления репозиториев – занятие недостойное человека, поэтому давайте поручим его компьютеру.

Для этого нам нужно создать скрипт, выполняющийся каждый раз после того, как сервер получил какие-либо изменения. Нам нужно создать файл по адресу /usr/local/share/git-core/templates/hooks/post-receive и записать туда приведенный ниже скрипт.

#!/usr/bin/env sh

set -e

# удаляем индекс, если он уже есть
rm -rf /var/www/htdocs/git/index.html

# обходим все имеющиеся у нас репозитории
cd /git/
for repo in */ ; do
    mkdir -p /var/www/htdocs/git/$repo
    cd /var/www/htdocs/git/$repo
    stagit /git/$repo
done

# создаем новый индекс файл
cd /var/www/htdocs/git/
stagit-index /git/* >> index.html

Не забудьте сделать этот хук исполняемым.

chmod +x /usr/local/share/git-core/templates/hooks/post-receive

Теперь всё должно работать. Попробуйте запушить что-нибудь в свой репозиторий и зайти на главную страницу веб интерфейса.

Интерфейс очень простой и полностью статичный, речь не идет ни о каких пулл-реквестах или поиске по коду, но если вам это и не нужно, то stagit должен вам понравиться.

Внешний вид можно настроить с помощью css файла. Погружаться в эту тему я не буду, если хотите, можете посмотреть на мой собственный css файл.