Перейти к содержанию

Свой Git-сервер в контейнере: сколько на самом деле стоит независимость от GitHub

Опубликовано
  • Админы
Forgejo, Gitea и GitLab CE — три способа держать репозитории у себя
Forgejo, Gitea и GitLab CE — три способа держать репозитории у себя

Вопрос «а что если завтра GitHub не откроется» из умозрительного стал вполне конкретным: минувшим понедельником платформа провела в аварийном состоянии почти восемь часов подряд. Отказывала каждая пятая попытка обратиться к вебу или API, а архивы и сырое содержимое репозиториев не отдавались примерно в половине случаев.

Реакция сообщества оказалась предсказуемой — обсуждение замен на Hacker News перевалило за пять сотен голосов, а Cursor тем же днём открыл бету собственного хранилища репозиториев. Разбираться будем не с эмоциями, а с арифметикой: какие компоненты вашей работы физически лежат на чужих серверах, чем их заменить и во сколько человеко-часов встанет содержание замены.

Инвентаризация: что у вас на самом деле чужое

Прежде чем выбирать форж, стоит разложить хозяйство по полочкам. «Код» — далеко не единственный пункт списка:

  • Репозитории. Тут беспокоиться не о чем: модель git распределённая, полная история лежит на каждой машине разработчика. Единственный слой, переживающий гибель платформы сам по себе.
  • Задачи, запросы на слияние, ревью, обсуждения. К git не имеют отношения — это записи в базе платформы, доступные только через её API.
  • Сборочные конвейеры. Описания хранятся в репозитории, а вот исполнители, кэши и секреты — уже нет.
  • Релизы и бинарники. Ссылка вида github.com/.../releases/download/... внутри вашего установщика означает, что авария GitHub ломает установку у ваших пользователей.
  • Образы и пакеты. ghcr.io — это тоже GitHub.
  • Pages. Сайт с документацией.
  • Вход и права. Об этом ниже отдельно.

❗ Главное

Есть мера, которая не требует смены платформы вообще. Проверьте, тянет ли что-нибудь на критическом пути файлы из releases или образы из ghcr.io — и заведите зеркало. По соотношению «затраты к снятой боли» это самое выгодное действие из всего списка.

Хроника понедельника по официальной ленте

Ниже — отметки со страницы статуса GitHub, время указано в UTC.

UTCФормулировка из ленты
13:40«Мы расследуем сообщения о деградации производительности некоторых сервисов GitHub»
13:45«Наблюдаем примерно 20 % ошибок в разных сценариях, включая Pull Requests, Issues и другие»
14:58около 20 % ошибок на вебе и API; архивы и raw-содержимое — порядка 50 % ошибок
15:42в списке пострадавших также SAML- и OIDC-аутентификация, SCIM и Team Sync
17:34«Мы определили проблемный компонент и приняли меры», остаточное влияние сохраняется
20:45спорадические сбои аутентификации Copilot продолжаются; через CLI и GitHub App работает
21:15инцидент закрыт, подробный разбор причин обещан отдельно

От первого сообщения до закрытия — 7 часов 35 минут. В списке пострадавшего: операции git, API, вебхуки, Issues, Pull Requests, Actions, Pages, Copilot.

📌 Заметка

Строчка за 15:42 интереснее остальных. Легла не «выдача страничек», а корпоративный вход и синхронизация команд. Организация, у которой доступ к репозиториям построен вокруг SSO, в этот момент не могла выдать доступ ни новому сотруднику, ни новой машине в конвейере — вообще никаким способом.

Компоненты стека и порты по умолчанию — по официальной документации Forgejo, Gitea и GitLab
Компоненты стека и порты по умолчанию — по официальной документации Forgejo, Gitea и GitLab

Как выбирать, если не по числу галочек

Табличка «у кого больше функций» бесполезна: задачи, запросы на слияние, вики, LFS и API есть у всех трёх кандидатов. Расхождения начинаются там, где считают память, и там, где решают, куда проекту двигаться.

Ресурсные ориентиры: для GitLab взяты из docs.gitlab.com, у Forgejo и Gitea официального минимума в документации не заявлено
Ресурсные ориентиры: для GitLab взяты из docs.gitlab.com, у Forgejo и Gitea официального минимума в документации не заявлено

Когда форж не нужен вовсе

Задача «иметь свою копию нескольких репозиториев» решается голым bare-репозиторием по SSH, без единого дополнительного сервиса:

# на сервере
sudo adduser --disabled-password git
sudo -u git mkdir -p /home/git/repos/myproject.git
sudo -u git git init --bare /home/git/repos/myproject.git

# на рабочей машине
git remote add mirror git@myserver:/home/git/repos/myproject.git
git push --mirror mirror

Обновлять нечего, поверхность атаки не выходит за пределы sshd. Веб-интерфейса, задач и сборок не будет — но их в этой постановке и не просили.

Forgejo и Gitea — родня с разной родословной

Forgejo появился в октябре 2022 года как ответвление Gitea; жёстким форком, по формулировке самого проекта, он стал в начале 2024-го. До версии v8.0 включительно распространялся под MIT, с v9.0 — под GPL-3.0+. Домены принадлежат берлинской некоммерческой организации Codeberg e.V.

⚠️ Осторожно

Страница «сравнение с Gitea» на сайте Forgejo — позиция стороны спора, а не независимая экспертиза. Проверяемое оттуда: даты, смена лицензии, принадлежность доменов. Оценки в духе «максимизируют прибыль» проверке не поддаются — выводы делайте сами.

Актуальные номера версий на день публикации: Forgejo 16.0.2 (стабильная ветка, выпуск 30 июля 2026, сопровождение до 29 октября 2026) и 15.0.6 в ветке долгой поддержки — до 15 июля 2027. У Gitea свежая — 1.27.2, вышла 14 августа 2026.

Compose-файл из документации Forgejo:

networks:
  forgejo:
    external: false

services:
  server:
    image: codeberg.org/forgejo/forgejo:16
    container_name: forgejo
    environment:
      - USER_UID=1000
      - USER_GID=1000
    restart: always
    networks:
      - forgejo
    volumes:
      - ./forgejo:/data
      - /etc/localtime:/etc/localtime:ro
    ports:
      - '3000:3000'
      - '222:22'

Различий с Gitea ровно три: название сети, образ docker.gitea.com/gitea:1.27.2 и дополнительный проброс /etc/timezone:

services:
  server:
    image: docker.gitea.com/gitea:1.27.2
    container_name: gitea
    environment:
      - USER_UID=1000
      - USER_GID=1000
    restart: always
    volumes:
      - ./gitea:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "3000:3000"
      - "222:22"

⛔ Так делать нельзя

Порт 3000:3000 наружу выставлять нельзя, а мастер первичной настройки нельзя оставлять доступным. При первом старте Forgejo и Gitea показывают форму установки без всякой авторизации — администратором станет тот, кто откроет её первым. Верная последовательность: контейнер слушает 127.0.0.1:3000, перед ним ставится обратный прокси с TLS, и только затем вы заходите по HTTPS и проходите установку.

Привязка к петлевому интерфейсу — правка одной строки:

    ports:
      - '127.0.0.1:3000:3000'
      - '222:22'

И четыре строки в Caddyfile, сертификат Caddy оформит сам:

git.example.com {
    reverse_proxy 127.0.0.1:3000
}

ℹ️ Справка

Откуда берётся 222. В контейнере работает собственный SSH-демон форжа, к системному sshd отношения не имеющий, — отсюда адреса клонирования вида ssh://git@git.example.com:222/user/repo.git. Хочется привычной короткой записи без номера порта — есть два пути. Либо контейнерный SSH переезжает на 22, а системный уходит на другой номер; либо ключи прокидываются через хостовый authorized_keys с командой-обёрткой. Первый вариант ставится быстрее, второй меньше рискует, когда на машине живёт что-то ещё.

Заявленного минимума по памяти у Forgejo и Gitea в документации нет — ни в разделе про бинарник, ни в разделе про контейнеры. Эмпирический ориентир для команды из нескольких человек: гигабайта на весь стек с SQLite обычно достаточно. Как только к схеме добавляются исполнители сборок, ориентир перестаёт работать: конвейер потребляет столько, сколько потребляет ваш проект.

Резервная копия, которая копия

Встроенная команда снятия дампа есть у обоих проектов. Вариант из документации для контейнера (пример на Gitea; у Forgejo команда называется forgejo dump):

docker exec -u git -it -w /tmp $(docker ps -qf 'name=^gitea$') \
  bash -c '/usr/local/bin/gitea dump -c /data/gitea/conf/app.ini'

Внутри получившегося архива: app.ini, каталоги custom/ и data/ (вложения, аватары, LFS, индексы, файл SQLite), полный слепок repos/, SQL-дамп gitea-db.sql и журналы. Последние для восстановления не требуются.

⚠️ Осторожно

В документации Gitea есть прямая оговорка: ради консистентности сервис на время снятия дампа положено останавливать. Снимок с работающего экземпляра рискует застать базу и файлы репозиториев в рассогласованном состоянии. В домашних условиях это означает короткое ночное окно с docker compose stop, а не расчёт на «авось совпадёт».

Сборки: место, где «один контейнер» заканчивается

Оба форжа умеют конвейеры с синтаксисом, похожим на GitHub Actions. Именно похожим: документация Forgejo не даёт себя обмануть и пишет прямым текстом — «GitHub Actions и Forgejo Actions — не одно и то же, и что-то может не заработать сразу». Контекст github отдан как псевдоним к forgejo ради переносимости, но совпадения возможностей никто не обещает.

Задокументированные ограничения:

  • запрос на слияние из форка получает урезанный доступ к секретам и токен только на чтение;
  • OIDC для событий pull_request из форков выключен;
  • пользовательский образ контейнера не обновляется автоматически никогда — только первая загрузка;
  • сезонный перевод часов ломает расписания: сдвиг вперёд пропускает запуск, сдвиг назад запускает дважды;
  • переиспользуемые workflow раскрываются только внутри своего экземпляра, ссылка на чужой сервер не сработает.

🔒 Безопасность

Исполнителю почти всегда просят выдать /var/run/docker.sock. Владение этим сокетом равносильно правам root на хосте: кто создаёт контейнеры, тот монтирует корень файловой системы. При наличии публичных репозиториев и внешних участников держать такого исполнителя на одной машине с самим форжем недопустимо. Минимум приличий — отдельная виртуалка под исполнителя плюс явный запрет запускать конвейеры из форков.

GitLab CE: за что платим шестнадцатью гигабайтами

Здесь другая весовая категория, и документация не скрывает цифр. Одноузловая установка: базовая линия — 8 vCPU и 16 ГБ оперативной памяти; в стеснённых условиях допустимы 8 ГБ с оговоркой про производительность; 40 ГБ на узел приложения плюс отдельно место под репозитории и базы.

Официальный запуск редакции CE:

sudo docker run --detach \
  --hostname gitlab.example.com \
  --env GITLAB_OMNIBUS_CONFIG="external_url 'http://gitlab.example.com'" \
  --publish 443:443 --publish 80:80 --publish 22:22 \
  --name gitlab \
  --restart always \
  --volume $GITLAB_HOME/config:/etc/gitlab \
  --volume $GITLAB_HOME/logs:/var/log/gitlab \
  --volume $GITLAB_HOME/data:/var/opt/gitlab \
  --shm-size 256m \
  gitlab/gitlab-ce:<version>-ce.0

Один образ упаковывает приложение на Rails, PostgreSQL, Redis, Sidekiq, Nginx, Prometheus и ещё десяток частей. Отсюда и --shm-size 256m, и аппетит к памяти, и старт, измеряемый минутами.

Что достаётся взамен: вложенные группы (их отсутствие у Gitea зафиксировано в её же сравнительной таблице), разрешение конфликтов слияния прямо в интерфейсе, конвейеры без отдельной обвязки и куда более развитый инструментарий ревью.

⚠️ Осторожно

Оборотная сторона обнаружилась в тот же день, что и авария GitHub. 17 августа 2026 года GitLab выкатил критические патч-версии 19.2.4, 19.1.6, 19.0.8 и 18.11.11. Закрыты CVE-2026-19478 — внедрение кода через директиву GraphQL, CVSS 9.4 — и CVE-2026-19650, подделка межсайтового запроса в обработчике multiplex-запросов GraphQL, CVSS 7.1. Уязвимы CE и EE начиная с 18.2. Держите форж у себя — значит реагировать на такие письма придётся вам, и не «на неделе», а в тот же день.

Переезд: чему верить и что проверять руками

Импорт репозиториев с GitHub вместе с метаданными есть и у Gitea, и у Forgejo — в форме миграции присутствуют флажки для задач, запросов на слияние, релизов, меток и вех. Документация Gitea при этом до странности скупа: сказано лишь, что для переноса подобных элементов понадобится указать как минимум имя пользователя. Перечня переносимого нет, списка ограничений нет. Про GitLab упомянут сторонний инструмент — и снова без подробностей.

Обещаний, таким образом, немного. Проверять придётся на собственных данных.

✅ Как правильно

  1. Форж поднят, но рабочий процесс не тронут — GitHub пока главный.
  2. Переносится один средний репозиторий с задачами и запросами на слияние. Смотреть глазами: авторы комментариев, даты, ссылки вида #123, вложения.
  3. Остальные репозитории зеркалируются в одну сторону: GitHub — источник, форж — копия.
  4. Так живём минимум месяц, обязательно захватив одно обновление форжа. Прошло без ручного вмешательства — можно думать дальше.
  5. Направление меняется: источником становится форж, GitHub остаётся зеркалом для посторонних.

Четвёртый шаг пропускают чаще всех — а именно он отвечает на вопрос, потянете ли вы это в долгую.

Постоянные издержки, которые никто не считает

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

  • Обновления по чужому расписанию. Патчи безопасности выходят когда выходят — история с GitLab 19.2.4 ровно про это.
  • Копии, которые вы разворачивали. По составу достаточно дампа базы и каталога /data; резервная копия, ни разу не восстановленная, резервной копией не является.
  • Рост диска. Репозитории, LFS, реестр пакетов и артефакты сборок пухнут независимо друг от друга, и место обычно кончается под артефактами.
  • Наблюдение. Форж, упавший в пятницу и обнаруженный в понедельник, хуже отсутствующего форжа. Нужно хотя бы уведомление о недоступности и о заканчивающемся месте.
  • Доступность. У GitHub набежало 7 часов 35 минут за один день. У одиночного VPS без реплики за год может набежать больше — просто эти часы никто не считает и в новости они не попадают.

💬 Вопрос к сообществу

Расскажите, у кого что в бою. Переехавшие на Forgejo или Gitea — сколько часов в месяц уходит на присмотр и что после GitHub оказалось неожиданно неудобным? Отдельно любопытно про исполнителей сборок: держите их рядом с форжем или увели на отдельную машину?


Источники

Featured Replies

No posts to show

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.
Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

Последние посетители 0

  • Ни одного зарегистрированного пользователя не просматривает данную страницу
Яндекс.Метрика

Account

Navigation

Поиск

Поиск

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.