Community
0
HostiServer
2026-10-09 11:19

Gitea / Forgejo у Docker: повний self-hosted стек

⏱️ Час читання: ~13 хвилин | 📅 Оновлено: жовтень 2026

Gitea / Forgejo у Docker: повний self-hosted стек

Усі чотири попередні статті серії спирались на те, що код живе десь зовні — на GitHub, GitLab чи будь-якій іншій зовнішній платформі. Self-hosted Git знімає цю залежність повністю: повний контроль над кодом, приватність без винятків для сторонніх сервісів, відсутність ліцензійних обмежень для внутрішніх чи закритих проєктів, а заразом — власний Docker registry і власний CI, які не рахують хвилини збірки і не обмежують приватні репозиторії.

У результаті цієї статті на одному VPS підніметься повноцінна платформа з чотирьох сервісів: Forgejo (сам Git-сервер і веб-інтерфейс), PostgreSQL, act runner (виконавець CI-пайплайнів) і Nginx — усе в одному docker-compose.yml.

Ця стаття замикає одразу дві серії. З Docker-серії вона спирається на все пройдене раніше: Compose з кількома сервісами (стаття 2), Nginx і SSL (стаття 3), принцип автодеплою (стаття 4). З серії «CI/CD з нуля» — на концепцію self-hosted runner'а і синтаксис Actions-подібних pipeline.

2. Gitea vs Forgejo

Forgejo — форк Gitea, що відокремився у 2022 році через розбіжності щодо відкритості управління проєктом. Він розвивається як community-driven ініціатива під егідою Codeberg, тоді як Gitea лишається під окремим керівництвом.

Функціонально обидва проєкти на сьогодні практично ідентичні, а API повністю сумісний — міграція бази даних і репозиторіїв в обидва боки проходить без втрат. Різниця здебільшого в назвах Docker-образів та деталях governance-моделі. Усе, що описано далі в цій статті, стосується обох варіантів однаково; як основний приклад тут узято Forgejo.

3. Архітектура стека

Стек складається з чотирьох сервісів:

Сервіс Роль
forgejo Веб-інтерфейс і сам Git-сервер
db PostgreSQL — сховище даних Forgejo
runner act runner — виконавець CI-пайплайнів
nginx Reverse proxy і термінація SSL

Мережа forgejo-net ізолює forgejo, db і runner в одному внутрішньому просторі; назовні виходить тільки nginx через порти 80 і 443. За збереження даних відповідають два volumes: forgejo-data тримає самі репозиторії, конфігурацію і Git LFS-об'єкти, pgdata — базу даних. SSH для git-операцій виходить назовні окремим портом (типово 2222 → 22 усередині контейнера), або прокидається на хост через окремий механізм — про це нижче.

Архітектура self-hosted стека: Forgejo, PostgreSQL, act runner і Nginx у мережі forgejo-net

4. docker-compose.yml

Повний стек в одному файлі:

services:
  forgejo:
    image: codeberg.org/forgejo/forgejo:9
    environment:
      FORGEJO__server__ROOT_URL: https://git.example.com
      FORGEJO__server__SSH_DOMAIN: git.example.com
      FORGEJO__server__SSH_PORT: "2222"
      FORGEJO__database__DB_TYPE: postgres
      FORGEJO__database__HOST: db:5432
      FORGEJO__database__NAME: forgejo
      FORGEJO__database__USER: forgejo
      FORGEJO__database__PASSWD: ${DB_PASSWORD}
    volumes:
      - forgejo-data:/data
    ports:
      - "2222:22"
    depends_on:
      db:
        condition: service_healthy
    networks: [forgejo-net]
    restart: unless-stopped

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: forgejo
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: forgejo
    volumes: [pgdata:/var/lib/postgresql/data]
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U forgejo -d forgejo"]
      interval: 5s
      timeout: 5s
      retries: 10
    networks: [forgejo-net]
    restart: unless-stopped

  runner:
    image: code.forgejo.org/forgejo/runner:3
    environment:
      FORGEJO_INSTANCE_URL: https://git.example.com
      FORGEJO_RUNNER_REGISTRATION_TOKEN: ${RUNNER_TOKEN}
    volumes:
      - runner-data:/data
      - /var/run/docker.sock:/var/run/docker.sock
    networks: [forgejo-net]
    restart: unless-stopped

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
      - /etc/letsencrypt:/etc/letsencrypt:ro
    depends_on: [forgejo]
    networks: [forgejo-net]
    restart: unless-stopped

volumes:
  forgejo-data:
  pgdata:
  runner-data:

networks:
  forgejo-net:

Залежність forgejo від db через condition: service_healthy працює за тим самим принципом, що й зв'язка app → db у статті 2 цієї серії: без healthcheck Forgejo може спробувати підключитись до бази раніше, ніж PostgreSQL дійсно готовий приймати з'єднання.

Конфігурація Forgejo через змінні середовища з префіксом FORGEJO__ — рекомендований спосіб, зручніший за bind-mount готового app.ini: усі налаштування лишаються видимими прямо в docker-compose.yml, без окремого файлу, який легко забути синхронізувати при переносі на інший сервер. Ключові змінні — SERVER__ROOT_URL (публічна адреса), SERVER__SSH_DOMAIN (домен для git-клонів по SSH), блок database__* з типом і доступом до PostgreSQL, і за потреби — секція mailer для сповіщень поштою. Сервіс runner реєструється до Forgejo за токеном (детальніше в розділі 8) і зберігає свій стан у власному volume.

5. SSH і клонування

За замовчуванням Forgejo всередині контейнера слухає SSH на стандартному порту 22. Назовні цей порт маппиться на 2222, щоб не конфліктувати із системним SSH-сервером самого хоста, який уже займає 22-й порт для адміністрування сервера.

У конфігурації Forgejo це відображається парою SSH_PORT=2222 і SSH_DOMAIN=git.example.com — саме ці значення й визначають, як виглядатиме команда клонування для будь-якого репозиторію:

git clone git@git.example.com:2222/user/repo.git

Є й альтернативний шлях — SSH passthrough через AuthorizedKeysCommand на самому хості, коли системний SSH хоста перенаправляє git-запити всередину контейнера. Це дозволяє лишити стандартний порт 22 для git-клонів без додаткового :2222 в адресі, але налаштовується помітно складніше за простий проброс порту.

6. Перший запуск і налаштування

При першому старті Forgejo за замовчуванням показує Installation wizard прямо в браузері — кілька кроків налаштування бази даних, адміністратора і загальних параметрів. Цей крок можна повністю обійти, заздалегідь передавши всі потрібні значення через змінні середовища і додавши INSTALL_LOCK=true — тоді контейнер стартує одразу в готовому до роботи стані, без інтерактивного майстра.

Перший акаунт, зареєстрований у системі, за замовчуванням автоматично стає адміністратором; альтернативно адміна можна задати явно через FORGEJO__security__ADMIN_USER. Решта — SSH-ключі користувачів, організації, видимість репозиторіїв — налаштовується вже через звичайний веб-інтерфейс так само, як у хмарних аналогах.

7. Nginx + SSL

Конфігурація Nginx тут майже один в один повторює статтю 3 серії: proxy_pass http://forgejo:3000; і той самий набір заголовків — Host, X-Real-IP, X-Forwarded-Proto. SSL отримується тим самим шляхом через Let's Encrypt і Certbot у режимі webroot, з тим самим deploy hook'ом на reload після поновлення сертифіката.

Важливий нюанс саме для Git-сервера: Nginx проксіює лише веб-трафік (HTTP/HTTPS). SSH-трафік для git-операцій він не зачіпає взагалі — той іде напряму на порт 2222, в обхід Nginx, прямо до контейнера forgejo.

8. Act Runner

Act runner — офіційний виконавець CI-пайплайнів від команди Gitea/Forgejo. Він виконує файли з .forgejo/workflows/*.yml, формат яких сумісний із синтаксисом GitHub Actions — переважна більшість простих workflow переносяться майже без правок.

Реєстрація runner'а до інстансу Forgejo відбувається за токеном: Settings → Actions → Runners → New runner у веб-інтерфейсі видає одноразовий токен, який передається runner-контейнеру через змінну середовища при першому старті.

Є два режими виконання завдань. Docker-in-Docker ізолює runner повністю — завдання виконуються у вкладеному Docker-демоні, недоступному решті хоста, але налаштовується складніше. Простіший варіант — прокинути хостовий /var/run/docker.sock прямо в контейнер runner'а: налаштування мінімальне, проте runner у такому разі отримує фактичний доступ до Docker хоста, за тією ж логікою ризику, що й Traefik зі статті 3 цієї серії.

Labels, призначені runner'у при реєстрації, визначають, які значення runs-on: у workflow-файлах він здатен обслуговувати — той самий принцип, що й у self-hosted runner'ах GitHub Actions чи GitLab CI.

9. Перший pipeline

Файл .forgejo/workflows/deploy.yml пишеться синтаксисом, ідентичним GitHub Actions. Стандартний потік — той самий абстрактний pipeline зі статті 4 серії: тригер на push, checkout коду, збірка Docker-образу, публікація — тільки тепер усе це виконується на власному runner'і, а не на чужій інфраструктурі хмарної CI-платформи.

ℹ️ Детальний синтаксис: покрокове налаштування workflow-файлів для Gitea/Forgejo Actions розібрано в окремому матеріалі серії «CI/CD з нуля», присвяченому саме цій платформі.

10. Forgejo Container Registry

У Forgejo вбудований OCI-сумісний container registry, доступний прямо за адресою вашого інстансу — git.example.com — як альтернатива Docker Hub чи ghcr.io зі статті 4. Образи зберігаються поруч із самими репозиторіями, а авторизація використовує той самий токен, що й для git-операцій — окремого облікового запису для registry заводити не потрібно.

Це замикає стек у єдине ціле: Forgejo одночасно виконує роль Git-сервера, CI-платформи і registry — усі три компоненти, які в попередній статті серії були рознесені по різних зовнішніх сервісах, тепер живуть на одному VPS під вашим повним контролем.

Порівняння: вбудований Forgejo Container Registry проти зовнішнього Docker Hub або ghcr.io

11. Бекап і оновлення

Надійний бекап складається з трьох кроків: зупинити Forgejo, заархівувати volume forgejo-data (репозиторії, конфігурація, LFS-об'єкти), окремо зняти дамп бази через pg_dump. Обидва файли варто зберігати разом, позначивши датою — відновлення з неузгоджених у часі архіву репозиторіїв і дампу бази може призвести до неконсистентного стану.

Оновлення версії — звичний для серії патерн: docker compose pull, тоді docker compose up -d. Forgejo підтримує rolling-міграції бази даних автоматично при старті нової версії, тож у більшості випадків додаткових ручних кроків не потрібно. Виняток — мажорні оновлення: перед ними варто звірятись із CHANGELOG конкретної версії, оскільки деякі мажорні переходи вимагають окремого ручного кроку до запуску нового образу.

12. Висновок і підсумок серії

Шлях усієї серії — від docker run hello-world у першій статті до повного self-hosted стека, що поєднує Git, CI, registry і SSL в одному docker-compose.yml на одному сервері. Кожна наступна стаття знімала одне конкретне обмеження попередньої: ручний запуск контейнерів → декларативний опис стека → production-готовність → автоматичний деплой → повна незалежність від зовнішніх платформ.

Весь цей стек відтворюється на будь-якому новому VPS приблизно за тридцять хвилин: git clone конфігураційного репозиторію з docker-compose.yml і .env, тоді docker compose up -d — і платформа піднята.

Логічне продовження для тих, кому одного сервера вже недостатньо, — Docker Swarm: той самий підхід до опису стека, але розподілений по кількох нодах, із автоматичним failover при падінні однієї з них.

📚 Навігація серії:
Ви читаєте частину 5 з 5 «Gitea / Forgejo у Docker: повний self-hosted стек» — фінальну статтю серії.
Попередня: Частина 4. Docker + CI/CD: автоматичний деплой ←

🚀 VPS під власний Git + CI + registry

Чотири сервіси одночасно — Git-сервер, база даних, CI-runner і reverse proxy — це вже помітне навантаження на CPU і диск, особливо в момент виконання pipeline. Hostiserver дає ресурси, розраховані саме на такий self-hosted стек.

🖥️ Виділені Сервери

  • Від $90/міс, повний контроль над залізом для активних CI-навантажень
  • Без сусідів по ресурсах: збірка образів на runner'і не залежить від чужих контейнерів
  • 24/7 підтримка: допоможемо з мережами, SSH-портом і реєстрацією runner'а

💻 Cloud (VPS) Хостинг

  • Від $19.95/міс, KVM-ізоляція, виділені vCPU і RAM
  • NVMe-диски: швидкі git-операції, LFS і збірка Docker-образів прямо на runner'і
  • Виділена IP-адреса: стабільний домен для git-клонів по SSH і для SSL
  • Легко масштабувати: більше ресурсів під runner, коли пайплайнів стає більше

💬 Не впевнені, який варіант вам необхідний?
💬 Напишіть нам і ми зі всім допоможемо!

Часті запитання

Gitea чи Forgejo — що обрати для нового проєкту?

Функціонально різниця мінімальна, тож вибір частіше залежить від governance-моделі: Forgejo розвивається як community-driven проєкт під Codeberg, Gitea — під окремим керівництвом. Оскільки API повністю сумісний, цей вибір не є незворотним — перейти з одного на інший можна пізніше без втрати даних.

Чи можна мігрувати існуючий інстанс Gitea на Forgejo без втрат?

Так, завдяки повній сумісності API і структури бази даних міграція в обидва боки проходить без втрати репозиторіїв, issues чи налаштувань. На практиці це зводиться до заміни Docker-образу і підняття стека наново з тим самим volume бази даних.

Чому SSH виходить назовні на порту 2222, а не на стандартному 22?

Порт 22 на самому VPS вже зайнятий системним SSH-сервером, через який адмініструється сам хост. 2222 → 22 всередині контейнера — найпростіший спосіб уникнути конфлікту. Якщо потрібен саме стандартний порт 22 для git-клонів, є альтернатива через AuthorizedKeysCommand на хості, але вона складніша в налаштуванні.

Docker-in-Docker чи host docker socket для act runner — що обрати?

Host docker socket простіший у налаштуванні — достатньо прокинути /var/run/docker.sock — але дає runner'у фактичний доступ до Docker хоста, а отже й непрямий root-доступ. Docker-in-Docker ізольований повністю, але складніший у конфігурації. Для одного довіреного проєкту на власному сервері host-сокет зазвичай прийнятний компроміс; для CI, що виконує код із зовнішніх pull request-ів, варто обирати ізольований варіант.

Чи потрібен окремий Docker registry, якщо вже є Docker Hub?

Необов'язково, але вбудований у Forgejo registry усуває ще одну зовнішню залежність і ще один обліковий запис для авторизації — токен той самий, що й для git-операцій. Якщо мета саме повна незалежність від зовнішніх сервісів, використання вбудованого registry логічно завершує цю ідею.

Як правильно бекапити Forgejo, щоб не отримати неконсистентний стан?

Ключовий момент — узгодженість у часі: архів volume forgejo-data і дамп бази даних через pg_dump знімаються в одній точці в часі, бажано на коротко зупиненому сервісі, і зберігаються разом з однаковою позначкою дати. Відновлення зі старого дампу бази і нового архіву репозиторіїв (чи навпаки) може призвести до розбіжностей між метаданими в базі і реальним станом Git-репозиторіїв.

Чи обов'язково проходити Installation wizard через браузер?

Ні. Якщо всі потрібні параметри (база даних, адміністратор, домен) задані заздалегідь через змінні середовища з префіксом FORGEJO__, а також встановлено INSTALL_LOCK=true, контейнер стартує одразу в готовому стані — зручно для відтворюваного розгортання з конфігурації, без ручного проходження майстра щоразу.

Contents

Поділіться цією статтею

VPS з підтримкою від

$19 95 / міс

Виділені сервери від

$80 / міс

CDN починаючи від

$0 / міс

 

Користуючись цим сайтом, ви погоджуєтеся на використання файлів cookies відповідно до нашої Політики Конфіденційності.