Настройка Git сервера с нуля
Любой начинающий DevOps начинает своё знакомство с Git. Этот инструмент стал неотъемлемой частью рабочего процесса разработчиков по всему миру. Во многих курсах и руководствах по DevOps описывается настройка серверов через популярные платформы, такие как GitLab, изредка через Gitea. Однако мне стало интересно рассмотреть другой путь — использование встроенного в Git инструмента под названием GitWeb.
В данной статье я подробно опишу процесс настройки системы управления репозиториями, используя лишь возможности самого Git. Этот подход может показаться необычным, но он позволяет лучше понять внутренние механизмы работы Git и получить новые навыки, которые могут оказаться полезными в вашей карьере DevOps.
В этом руководстве мы рассмотрим, как настроить собственный Git сервер на базе Debian 12. Весь процесс настройки Git сервера поделен на следующие задачи:
настройка SSH;
создание пользователей;
инициализация проекта;
конфигурация Git‑демона;
настройка веб‑интерфейса для просмотра репозиториев;
настройка дополнительных аспектов безопасности.
Настройка SSH на сервере
Первым шагом является установка и настройка SSH сервера, который обеспечит безопасный доступ к нашему серверу.
Установка пакета openssh-server
Для установки пакетаopenssh-server
выполните следующие команды:
apt update
apt install openssh-server
Настройка SSH сервера
Для начала надо открыть файл конфигурации SSH:
nano /etc/ssh/sshd_config
Рекомендуется изменить следующие параметры для повышения безопасности:
Port: измените стандартный порт на другой, чтобы уменьшить числа автоматических атак;
PermitRootLogin: отключите вход по пользователю root, исключительно после настройки отдельного пользователя для работы с сервером;
PasswordAuthentification: отключите вход по паролю, исключительно после настройки ключей;
PermitEmptyPasswords: отключите пустые пароли;
PubkeyAuthentification: включите аутентификацию по ключам. Обычно данный параметр включен по‑умолчанию.
После внесения изменений перезапустите SSH службу:
systemctl restart sshd
Создание пользователя admin
Зачем использовать отдельного пользователя с sudo?
На это есть ряд причин:
Пользователь root минует все ограничения системы, можно случайно исполнить критические команды, которые могут повредить систему;
Учетная запись root будет в первую очередь атакована злоумышленниками;
sudo позволяет отслеживать действия пользователей, все команды могут быть записаны в журнал.
Естественно, что существует гораздо больше причин почему стоит использовать отдельного пользователя, но моя статья не об этом, поэтому ограничимся этими пунктами.
Настройка пользователя admin
Для управления сервером создайте пользователя admin с правами sudo:
adduser admin
apt install sudo
usermod -aG sudo admin
su admin
cd
mkdir .ssh
chmod 700 .ssh
touch .ssh/authorized_keys
chmod 600 .ssh/authorized_keys
После установите в конфигурации SSH PermitRootLogin на отрицательное значение и отключите доступ к пользователю root:
sudo nano /etc/passwd
# Меняем root:x:0:0:root:/root:/bin/bash на root:x:0:0:root:/root:/sbin/nologin
Если попробовать зайти в root, то выведется следующие сообщение: This account is currently not available.
Создание пользователя git
Для работы с Git создадим отдельного пользователя git:
adduser git
su git
cd
mkdir .ssh
chmod 700 .ssh
touch .ssh/authorized_keys
chmod 600 .ssh/authorized_keys
Ограничение доступа к системе через git-shell
На данный момент пусть пользователь git и не имеет доступа к root правам, он все равно в той или иной мере взаимодействует с системой. Данный пользователь нужен исключительно для работы с репозиториями, однако он все еще имеет доступ к системным командам.
Данное поведение можно исправить используя специальную командную оболочку — git-shell.
git-shell — это ограниченная оболочка, предназначенная для пользователей Git, которые не должны иметь доступ к полноценной командной строке.
Мы можем задействовать данную оболочку следующим образом:
Добавим git-shell к другим оболочкам:
nano /etc/shells
Внесем следующее содержимое:
/bin/git-shell /usr/bin/git-shell
Cоздадим директорию git-shell-commands:
mkdir /home/git/git-shell-commands
Теперь изменим командную оболочку по-умолчанию для пользователя git:
chsh -s $(command -v git-shell) git
Теперь если мы войдем в пользователя git по SSH, то мы ничего не сможем сделать, так как там нету зарегистированных команд. Если надо создать репозиторий, то мы будем использовать пользователя admin, а затем менять права доступа на директорию через chown.
Однако если нам понадобится какие-то команды у пользователя git, то мы можем добавить свои собственные команды в директорию git-shell-commands.
Для чего нужна директория git-shell-commands
Данная директория используется для настройки ограниченной среды, когда Git используется через SSH в режиме git-shell. Если данной директории не будет существовать, то мы не сможем использовать пользователя git в интерактивном режиме.
Как добавить команду в git-shell
Для того, чтобы добавить команду для пользователя git, мы должны создать скрипт внутри директории git-shell-commands. Например, создадим скрипт для вывода существующих репозиториев:
Создадим скрипт:
touch /home/git/git-shell-commands/list-repos
Впишем следующее содержимое:
#!/bin/bash ls /srv/git/
Сделаем его исполняемым:
chmod +x /home/git/git-shell-commands/list-repos
Теперь мы можем выполнить команду list-repos и она выведет все репозитории.
Настройка SSH клиента для подключения к серверу
Генерация ключей на клиенте
Создайте необходимые SSH ключи на клиенте:
ssh-keygen -t ed25519 -f ~/.ssh/key_for_git -C "Arthur Lokhov "
ssh-keygen -t ed25519 -f ~/.ssh/key_for_admin -C "Arthur Lokhov "
Далее необходимо настроить клиент SSH для работы с только что созданными ключами. Для этого выполним команду:
nano ~/.ssh/config
И запишем следующее содержимое, также не забудем поменять HostName и Port:
Host server_git
HostName
StrictHostKeyChecking no
User git
Port
ForwardAgent yes
IdentityFile /home/username/.ssh/key_for_git
IdentitiesOnly yes
UserKnownHostsFile=/dev/null
AddKeysToAgent yes
ServerAliveInterval 60
ServerAliveCountMax 1200
Host server_admin
HostName
StrictHostKeyChecking no
User admin
Port
ForwardAgent yes
IdentityFile /home/username/.ssh/key_for_admin
IdentitiesOnly yes
UserKnownHostsFile=/dev/null
AddKeysToAgent yes
ServerAliveInterval 60
ServerAliveCountMax 1200
Последним шагом будет добавление публичных ключей на сервер. Ключи добавляются в соответствующие пользователям authorized_keys. Если вход через SSH проходит успешно, то отключите вход по паролю для SSH.
Создание «голого» репозитория
После настройки пользователей и SSH, следующий шаг — это инициализация проекта на сервере. В этом разделе рассмотрим как создать «голый» репозиторий, сделать первый коммит и настроить удаленный репозиторий для работы.
Но перед тем как перейти к практической части, я считаю нужным немного погрузиться в теорию.
Что такое «голый» репозиторий?
«Голый» репозиторий (‑bare) используется на сервере, чтобы хранить центральное хранилище кода. Он не содержит рабочей копии файлов и предназначен исключительно для обмена данными между разработчиками, то есть «голый» репозиторий представляет содержимое директории .git.
Как устроена директория .git?
Внутри директории .git находятся различные файлы и директории, которые Git использует для хранения информации о репозитории, включая историю изменений, настройки, ссылки и метаданные.
Данная директория состоит из следующих компонентов:
HEAD: Этот файл содержит ссылку на текущий коммит или ветку, с которой вы работаете;
branches/: данная директория используется для устаревшей механики управления ветками, которая фактически уже не используется в современных версиях Git. Директория обычная пуста и не играет никакой роли в управления ветками;
config: файл конфигурации репозитория, содержащий настройки, такие как информация о пользователе, удаленные репозитории, алиасы команд и другие параметры, специфичные для этого репозитория;
description: файл, который обычно используется в bare репозиториях для описания их назначения. В рабочих репозиториях он не имеет особого значения;
hooks/: директория для хранения скриптов, которые запускаются при определенных действиях Git, таких как коммиты, слияния, получение изменений и другие. Эти скрипты могут быть использованы для автоматизации задач и проверки;
info/: Содержит дополнительные файлы конфигурации, например, файл
exclude
, который используется для указания шаблонов, игнорируемых только в этом репозитории (локальный аналог .gitignore);objects/: директория, в которой хранятся все объекты данных, такие как коммиты, деревья, блобы (бинарные файлы) и теги. Эти объекты идентифицируются по их SHA-1 хэшам и являются основой для хранения истории и содержимого репозитория;
refs/: содержит ссылки на коммиты для веток (heads/), тегов (tags/) и удаленных веток (remotes/). Эти ссылки помогают Git отслеживать, где находятся ветки и теги;
logs/: содержит историю изменений ссылок (refs). Например, файл logs/HEAD хранит историю изменений, указывающих на коммиты, на которые ссылался HEAD, что позволяет отслеживать изменения веток.
Взаимодействие Git с директорией .git
Мы разобрали из чего данная директория состоит. Но не разобрали как Git взаимодействует с этими данными. Есть несколько взаимодействий Git с файлами в этой директории:
Коммит (commit): когда вы делаете коммит, Git берет файлы из индекса (index), создает новые объекты в objects/, и обновляет ссылки в refs/heads/ для текущей ветки;
Чекаут (checkout): когда вы переключаетесь между ветками, Git читает ссылки из refs/heads/ и обновляет рабочую директорию до состояния, соответствующего коммиту, на который указывает ссылка;
Пуш (push) и пул (pull): при обмене данными с удаленными репозиториями Git обновляет ссылки в refs/remotes/ и перемещает объекты в objects/;
Управления конфигурацией (config): Git читает файл config для применения настроек, таких как параметры пользователя и удаленные репозитории.
Инициализация проекта
ВАЖНО: Все команды на сервере с этого момента выполняются через пользователя admin
Установим Git, если он еще не установлен:
sudo apt install git
Создадим директорию для хранения проектов и настроим права доступа:
sudo mkdir -p /srv/git
sudo chown git:git /srv/git/
Создадим «голый» репозиторий:
cd /srv/git
sudo mkdir my_project.git
cd my_project.git
sudo git init --bare
cd ..
sudo chown git:git /srv/git/my_project.git/
Настройка локального репозитория и первый коммит
Теперь настроим локальный репозиторий, сделаем первый коммит и отправим его на сервер. Для этого выполним данные команды:
mkdir my_project
cd my_project
git init
echo "# My Project" > README.md
git add README.md
git commit -m "Initial commit"
git remote add origin git@hostname:/srv/git/my_project.git
git push -u origin main
Теперь в файле /srv/git/my_project/refs/heads/main будет хранится указатель HEAD(указатель на последний коммит, сделанный в текущей ветке) на текущий коммит. Он должен быть таким же как и указатель вашего коммита в локальном репозитории. Это будет доказательством того, что процесс прошел успешно.
Настройка демона Git
Git-демон позволяет предоставлять доступ к репозиториям через протокол git://, что обеспечивает быструю и легкую настройку для анонимного чтения.
Про команду git daemon
Данная команда, используется для управления Git-демоном, что можно понять из названия. С помощью этой команды мы и будет взаимодействовать с нашим демоном. С этой командой мы будем использовать следующие флаги:
reuseaddr означает, что сервер будет перезапускаться без ожидания тайм-аута существующих подключений;
export-all означает, что будут экспортированы все проекты из репозитория, иначе для каждого проекта надо создавать файл git-daemon-export-ok;
base-path означает, что данный путь будет автоматически подставляться. То есть вместо git://hostname/srv/git/my_project.git можно будет использовать git://hostname/my_project.git.
Создание службы для systemd.
Так как systemd является самой распространенной системой инициализации, то и примеры я буду приводить для нее. Сам же я использую Devuan с OpenRC, но смысла приводить настройки для другой системы инициализации я не вижу.
Теперь же перейдем к самому процессу.
Создадим файл службы для Git-демона:
sudo nano /etc/systemd/system/git-daemon.service
Пропишем следующее содержимое:
[Unit]
Description=Git daemon
[Service]
ExecStart=/usr/bin/git daemon --reuseaddr --export-all --base-path=/srv/git/ /srv/git/
Restart=always
RestartSec=500ms
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=git-daemon
User=git
Group=git
[Install]
WantedBy=multi-user.target
Запустим и активируем службу.
sudo systemctl enable git-daemon
sudo systemctl start git-daemon
sudo systemctl status git-daemon
Настройка GitWeb
GitWeb предоставляет веб-интерфейс для просмотра репозиториев Git. Мы рассмотрим два способы настройки:
Использование git instaweb
git instaweb позволяет быстро развернуть веб-интерфейс отдельно для каждого репозитория.
Установим lighttpd, если он еще не установлен:
sudo apt install lighttpd
Перейдем в директорию проекта и запустим git instaweb:
cd /srv/git/my_project.git
git instaweb
Перейдем в браузер и введем адрес http://hostname:1234, чтобы увидеть интерфейс GitWeb.
GitWeb, запущенный через команду git instaweb
Завершим работу сервера:
git instaweb --stop
Настройка GitWeb через Nginx
Установим необходимые пакеты:
sudo apt install nginx gitweb fcgiwrap
Настроим Nginx для работы с GitWeb. Создадим конфигурационный файл для работы сайта:
sudo nano /etc/nginx/sites-available/gitweb
Пропишем следующее содержимое:
server {
listen 80;
server_name example.com;
location /index.cgi {
root /usr/share/gitweb/;
include fastcgi_params;
gzip off;
fastcgi_param SCRIPT_NAME $uri;
fastcgi_param GITWEB_CONFIG /etc/gitweb.conf;
fastcgi_pass unix:/var/run/fcgiwrap.socket;
}
location / {
root /usr/share/gitweb/;
index index.cgi;
}
}
Активируем конфигурацию:
sudo ln -s /etc/nginx/sites-available/gitweb /etc/nginx/sites-enabled/gitweb
sudo rm /etc/nginx/sites-enabled/default
sudo systemctl restart nginx
Перейдем в браузер и введем адрес нашего сервера, чтобы увидеть интерфейс GitWeb:
GitWeb, запущенный через Nginx
Обновим конфигурацию GitWeb для правильного отображения наших репозиториев:
sudo nano /etc/gitweb.conf
Изменим путь к репозиториям:
$projectroot = "/srv/git";
Теперь наш Git сервер настроен, и у нас есть доступ к репозиториям через SSH, Git-демон и веб-интерфейс GitWeb.
Эта конфигурация обеспечивает как безопасность, так и удобство использования, а также поддержку анонимного и аутентифицированного доступа к репозиториям.
GitWeb, после изменения конфигурации
Дополнительные аспекты безопасности и оптимизаци
Защита от brute-force атак
Для дополнительной защиты нашего сервера можно установить и настроить такие инструменты, как fail2ban, которые будут блокировать IP (Internet Protocol)-адреса, совершившие слишком много неудачных попыток входа.
Установим пакет fail2ban:
sudo apt install fail2ban
Настроим fail2ban для защиты SSH:
sudo nano /etc/fail2ban/jail.local
Добавим следующие строки:
[sshd]
enabled = true
port = ssh
logpath = /var/log/auth.log
maxretry = 5
Создадим файл, необходимый для логов, если он не создан, и перезапустим fail2ban:
sudo touch /var/log/auth.log
sudo systemctl restart fail2ban
sudo systemctl status fail2ban
Настройка брандмауэра
Для ограничения доступа к нашему серверу настроим брандмауэр, например, ufw:
sudo apt install ufw
sudo ufw allow 443/tcp
sudo ufw allow 80/tcp
sudo ufw allow 20/tcp
# Также не забудьте открыть порт, через который у вас работает SSH
Командами выше мы установили ufw и разрешили запросы к портам 443, 20 и 80.
Теперь включим ufw:
sudo ufw enable
Вы можете попробовать закрыть 80-ый порт и открыть GitWeb в браузере, он не откроется.
Автоматическое обновление пакетов
Для обеспечения безопасности системы рекомендуется настроить автоматическое обновление пакетов.
Установим пакет unattended-upgrades и настроим его:
sudo apt install unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades
Теперь у нас автоматически будут скачиваться обновления безопасности.
Создание резервных копий
Для предотвращения потери данных важно настроить регулярное создание резервных копий. Мы можем использовать rsync или специализированные инструменты для создания резервных копий репозиториев и конфигураций сервера.
Установим rsync:
sudo apt install rsync
Настроим cron для автоматизации резервного копирования:
crontab -e
Добавим следующее задание, чтобы оно выполнялось ежедневно в 2 часа ночи:
0 2 * * * rsync -avz /srv/git/ /srv/git-backup/
Синтаксис crontab
Параметры идут в следующем порядке:
Минута
Час
День месяца
Месяц
День недели
Команда
Итог
В этом руководстве мы рассмотрели, как настроить собственный Git сервер на базе Debian 12, обеспечив при этом высокий уровень безопасности и функциональности. Мы прошли через установку и настройку SSH, создание пользователей, инициализацию проектов, настройку веб-интерфейса и рассмотрели дополнительные аспекты безопасности, такие как защита от brute-force атак, настройка брандмаэура и автоматическое обновления пакетов. Также мы настроили резервное копирование данных.
Этот сервер может послужить надежной опорой для управления вашими проектами и разработки програмнного обеспечения.
Что планируется улучшить?
На данный момент у меня в планах изменить или добавить следующие вещи:
Резервной копирование не в другую директорию, а на другой сервер;
Мониторинг через Prometheus и Grafana;
Настроенный CI/CD пайплайн для работы с нашими репозиториями.
На данный момент я обдумываю то, как лучше всего реализовать указанные выше вещи и что еще можно (или даже нужно) было бы добавить. Скорее всего мною будет сделана либо еще одна статья, посвещенная более глубокой настройки работы с репозиторием, либо будет дополнена эта.
P.S
Всем привет, меня зовут Артур Лохов и это моя первая статья на хабре. На выбор такой темы меня сподвигло то, что во многих курсах рассматривается настройка работы с репозиториями исключительно через GitLab, за редкими исключениями в виде Gitea. Я считаю, что любой DevOps должен знать как Git работает изнутри и как его настраивать с нуля, чтобы понимать что скрывается под тем же Gitlab и как он работает.
Одно дело уметь работь с инструментов, а другое дело уметь работать с инструментов и знать как он работает изнутри.
Если вы нашли какую-либо ошибку, пожалуйста дайте мне знать об этом, чтобы я мог ее исправить, ведь я мог забыть указать, что-либо важное. Также приветствуются советы по-тому, как можно улучшить сервер с Git. Идеи для улучшение, приведенные выше, скорее всего будут мною реализованы, когда я перейду к данным тематикам (CI/CD и мониторинг), и будут оформлены в виде цикла статей, которые будут являться логичиским продолжением.