Настройка Gitlab self-managed за Nginx reverse proxyРазвернул я себе Gitlab self-managed на своем домашнем сервере в локальной сети, и захотелось мне чтобы он был доступен из интернета.
Свой сервер чтобы хранить нужные мне проекты в управляемом мной хранилище, их никто случайно не удалит, а доступ из интернет чтобы мне самому иметь доступ в любой момент и делиться с другими.
Сразу можно найти инструкцию на сайте Gitlab и дальше идти по ссылкам, но у меня сходу не завелось и проблема была немного глубже, точнее их было несколько:
TLS-терминация на внешнем сервере работала, но авторизация всегда выдавала 422SSH-доступа к репозиториям Gitlab, а надоДля начала определимся с желаемым результатом:
10.8.3.3) расположен за Nginx reverse proxy (10.8.1.2), который расположен на внешней виртуалке, Nginx обеспечивает httpsА вот так это выглядит схематично:

У Gitlab есть свой Nginx, его мы почти не будем трогать, во всех остальных случаях речь будет идти про Nginx на внешней виртуалке. В любом случае договоримся что сервер Gitlab имеет IP
10.8.3.3, а внешний сервер Nginx10.8.1.2.
Для настройки на Gitlab внешней TLS-терминации есть документация, а еще здесь пример.
У себя на сервере Gitlab (10.8.3.3) в конфиге /etc/gitlab/gitlab.rb:
external_urltrusted_proxies и real_ip_trusted_addresses диапазоны адресов внутренних сетей и белый IP виртуалки с Nginx (10.8.1.2)80 порт без httpsproxy_set_headers должна быть раскоментированаexternal_url 'https://domain.zone'
gitlab_rails['trusted_proxies'] = ['10.8.0.0/16', '192.168.0.0/16', '{WHITE_IP}']
nginx['listen_port'] = 80
nginx['listen_https'] = false
nginx['real_ip_trusted_addresses'] = ['10.8.0.0/16', '192.168.0.0/16', '{WHITE_IP}']
nginx['proxy_set_headers'] = {
  "Host" => "$http_host_with_default",
  "X-Real-IP" => "$remote_addr",
  "X-Forwarded-For" => "$proxy_add_x_forwarded_for",
  "X-Forwarded-Proto" => "https",
  "X-Forwarded-Ssl" => "on",
  "Upgrade" => "$http_upgrade",
  "Connection" => "$connection_upgrade"
}
После правок конфига выполняем реконфигурацию:
$ gitlab-ctl reconfigure
Конфиг для хоста в Nginx на прокси сервере 10.8.1.2 выглядит достаточно просто:
server {
    listen 443 ssl;
    server_name domain.zone;
    location /.well-known/acme-challenge/ {
        root /var/lib/letsencrypt;
    }
    ssl_certificate /etc/letsencrypt/live/domain.zone/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/domain.zone/privkey.pem;
    
    location / {
        proxy_pass http://10.8.3.3;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Port $server_port;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Ssl on;
    }
}
Некоторую информацию по заголовкам можно почерпнуть из этого обсуждения, важно правильно передать X-Forwarded-Proto и X-Forwarded-Ssl чтобы избежать части проблем с CSRF-токеном.
Все выше достаточно просто и очевидно. Но неочевидным оказалось что любая авторизация в Gitlab заканчивалась ошибкой:

Поиски были долгими, не буду томить, а сразу покажу в чем была проблема (это обсуждение побудило смотреть на куки):

Здесь видно что на запрос авторизации сервер отправляет куки.
Если присмотреться, то дата истечения куки
__gitlab_sessionв прошлом (неправильно), а заголовокDateв настоящем (правильно). Из-за неверного значенияexpiresкуки не устанавливаются браузером, и при отправке запроса авторизации сервер Gitlab не получает сессионную куку для авторизации.
Видимо заголовок Date отправляет сервер Gitlab и прокси его не трогает, а заголовок с куками модифицируется прокси сервером.
Намек на исправление проблемы я нашел в уже упоминаемом обсуждении, в этом комментарии.
Проблема в настройках времени на сервере с Nginx (
10.8.1.2).
Смотрим текущее время сервера:
$ timedatectl 
               Local time: Сб 2022-01-01 12:00:06 MSK
           Universal time: Сб 2022-01-01 09:00:06 UTC
                 RTC time: Вт 2024-12-24 06:30:44
                Time zone: Europe/Moscow (MSK, +0300)
System clock synchronized: no
              NTP service: n/a
          RTC in local TZ: no
Видно что есть разница аж в годах между Universal time и RTC time.
На самом деле это я сделал специально для скриншотов статьи, разница при возникновении проблемы была в несколько часов.
Теперь установим и запустим NTPD:
$ sudo apt install ntp
$ sudo systemctl start ntpd
$ sudo systemctl enable ntpd
Еще раз проверим текуще время и убедимся что оно правильное:
$ timedatectl 
               Local time: Вт 2024-12-24 09:40:45 MSK
           Universal time: Вт 2024-12-24 06:40:45 UTC
                 RTC time: Вт 2024-12-24 06:40:45
                Time zone: Europe/Moscow (MSK, +0300)
System clock synchronized: no
              NTP service: n/a
          RTC in local TZ: no
Теперь дата истечения куки будет верная и авторизация должна пройти успешно.
А как же работа с git через SSH? На данный момент это не будет работать, потому что запросы по SSH будут уходить на Nginx (10.8.1.2), а не на Gitlab (10.8.3.3).
Я решил использовать порт 2222 для git, потому что с Nginx сервером (10.8.1.2) мне нужно работать по SSH штатно на 22 порту. Схема такая:
client => nginx(10.8.1.2):2222 => gitlab(10.8.3.3):2222
В конфиге Gitlab есть директива
gitlab_rails['gitlab_shell_ssh_port']для указания порта SSH, но это лишь изменит порт в URL репозиториях, не более того:

Тем не менее значение в конфиге Gitlab (10.8.1.2) нужно установить:
gitlab_rails['gitlab_shell_ssh_port'] = 2222
И обязательно выполняем реконфигурацию Gitlab чтобы в URL появился порт для SSH:
$ gitlab-ctl reconfigure
Затем на сервере Gitlab в конфиг SSH-сервера (10.8.3.3), в моем случае OpenSSH, нужно добавить возможность работать и на порту 2222 (кроме 22) создав файл /etc/ssh/sshd_config.d/50_config.conf со следующим содержимым:
Port 22
Port 2222
После правки конфига рестарт службы SSH на сервере Gitlab(10.8.3.3):
$ sudo systemctl restart ssh
Теперь нужно перенаправить трафик с Nginx (10.8.1.2) на Gitlab (10.8.3.3) через iptables. Выполняем команды на сервере с Nginx (10.8.1.2):
# разрешаем IP-переадресацию
$ sudo echo 1 > /proc/sys/net/ipv4/ip_forward
# устанавливаем правило перенаправления tcp трафика с порта 2222 на 10.8.3.3:2222
$ sudo iptables -t nat -A PREROUTING -p tcp --dport 2222 -j DNAT --to-destination 10.8.3.3:2222
Можно протестировать, работа по SSH через 2222 порт будет работать через сервер с Nginx на сервер с Gitlab.

Желаемое достигнуто, хоть и пришлось повозиться, зато как приятно иметь свое хранилище репозиториев под управлением Gitlab где можно сохранить важные для себя репозитории :)