Forgejo на сервере: частые ошибки и решения
Forgejo уже больше двух лет живёт своей жизнью отдельно от Gitea, но большинство статей в рунете до сих пор путают одно с другим, а логи молчат о сути проблемы. Если у вас упал контейнер после апдейта, git push отваливается по SSH или runner для Actions висит в статусе offline — ниже разобраны конкретные причины и рабочие решения, без пересказа официального FAQ.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Откуда взялся Forgejo и почему это не просто «второй Gitea»
Forgejo — форк Gitea, появившийся в конце 2022 года после того, как часть команды Gitea перевела компанию, стоящую за проектом, в закрытую модель управления. Форк остался под управлением некоммерческого сообщества (Codeberg e.V.) и полностью открытым — включая CI/CD-часть, которая в Gitea местами закрыта.
Технически до сих пор Forgejo и Gitea совместимы на уровне базы данных и структуры репозиториев процентов на 95: миграция в обе стороны в большинстве случаев работает штатным dump/restore. Но конфиги, имена бинарников, дефолтные порты runner'а и синтаксис некоторых директив в app.ini уже разошлись, поэтому копировать гайды по Gitea один в один — источник половины ошибок из этого текста. Если вы ещё выбираете между инструментами, разница разобрана в статье Gitea против GitLab — там же логика, применимая и к выбору в пользу Forgejo.
Дальше — по конкретным узлам, где всё чаще всего ломается.
Установка: docker compose против бинарника
Быстрее и надёжнее всего поднимать Forgejo через Docker Compose — так проще откатывать версии и не тащить зависимости в систему. Рабочий минимальный стек:
version: "3.8"
services:
forgejo:
image: codeberg.org/forgejo/forgejo:9
container_name: forgejo
environment:
- USER_UID=1000
- USER_GID=1000
- FORGEJO__database__DB_TYPE=postgres
- FORGEJO__database__HOST=db:5432
- FORGEJO__database__NAME=forgejo
- FORGEJO__database__USER=forgejo
- FORGEJO__database__PASSWD=change_me
restart: unless-stopped
volumes:
- ./forgejo:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000"
- "2222:22"
depends_on:
- db
db:
image: postgres:16-alpine
container_name: forgejo-db
restart: unless-stopped
environment:
- POSTGRES_USER=forgejo
- POSTGRES_PASSWORD=change_me
- POSTGRES_DB=forgejo
volumes:
- ./forgejo-db:/var/lib/postgresql/data
Частые ошибки на этом шаге:
- Образ
gitea/giteaвместоcodeberg.org/forgejo/forgejo. Docker Hub охотно предлагает автодополнение до gitea — если скопировали compose из старого гайда, проверьте имя образа вручную. - SQLite на проде. Дефолтный
DB_TYPE=sqlite3заводится за минуту, но при параллельных операциях (несколько CI-джобов пушат одновременно) база блокируется, и пуши начинают падать сdatabase is locked. Для чего-то серьёзнее одного личного проекта сразу берите Postgres. USER_UID/USER_GIDне совпадают с владельцем./forgejoна хосте. Контейнер стартует, но при первом обращении к/dataпадает сpermission denied— решение в следующем разделе.
Если ставите не в Docker, а бинарником на голую систему — процесс почти идентичен установке Gitea, разница только в имени пакета (forgejo вместо gitea) и systemd-юните forgejo.service.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверПрава доступа: permission denied и битые volume
Самая частая жалоба новичков — контейнер запускается, но веб-интерфейс отдаёт 500, а в логах:
Fatal: PID: open /data/forgejo/forgejo.pid: permission denied
Причина почти всегда одна: каталог, смонтированный как /data, принадлежит не тому UID, что указан в USER_UID. Проверяем и чиним:
ls -ln ./forgejo
# смотрим первую цифру владельца — она должна совпадать с USER_UID из compose
chown -R 1000:1000 ./forgejo
docker compose restart forgejo
Второй распространённый случай — Forgejo стоит не в Docker, а как systemd-сервис от пользователя git, и после ручного git clone под root в каталоге репозиториев появляются файлы с владельцем root. Веб-интерфейс их не видит или падает при попытке пуша. Лечится массовым возвратом прав:
chown -R git:git /var/lib/forgejo/data/gitea-repositories
Никогда не работайте с репозиториями Forgejo напрямую от root или от своего личного пользователя — только через встроенный веб-интерфейс или под системным пользователем git/forgejo, от имени которого крутится сервис. Это правило экономит часы разбора прав доступа.
SSH-доступ: конфликт портов и authorized_keys
Forgejo умеет либо использовать собственный встроенный SSH-сервер, либо работать через системный OpenSSH с генерацией authorized_keys. Здесь два типовых затыка.
Порт 22 занят. Если на сервере уже крутится системный sshd (а он крутится почти всегда), встроенный SSH-сервер Forgejo не может забрать порт 22. В docker-compose.yml выше это уже учтено пробросом 2222:22 — но тогда клоны по SSH нужно делать с явным портом:
git clone ssh://git@your-server.ru:2222/user/repo.git
Или прописать алиас в ~/.ssh/config, чтобы не вспоминать порт каждый раз:
Host forgejo.your-server.ru
HostName your-server.ru
Port 2222
User git
git push просит пароль вместо ключа. Обычно значит, что ключ добавлен в профиль пользователя в веб-интерфейсе, но Forgejo настроен на режим SSH_CREATE_AUTHORIZED_KEYS_FILE=false, либо файл .ssh/authorized_keys системного пользователя git был перезаписан вручную и потерял маркеры Forgejo. Проверка:
grep "forgejo" /home/git/.ssh/authorized_keys | wc -l
Если результат 0 при том, что ключи в интерфейсе есть — пересоздайте файл штатной командой:
sudo -u git forgejo admin regenerate keys
Для установки в Docker то же самое делается через docker exec forgejo forgejo admin regenerate keys.
Nginx, ROOT_URL и SSL
Ошибка, которая ловит почти всех: после того как Forgejo повешен за nginx с доменом, интерфейс открывается, но все внутренние ссылки, клоны по HTTPS и вебхуки ведут на http://localhost:3000. Причина — несовпадение ROOT_URL в app.ini с реальным адресом:
[server]
ROOT_URL = https://git.your-domain.ru/
DOMAIN = git.your-domain.ru
HTTP_PORT = 3000
После правки — обязательно docker compose restart forgejo, на лету app.ini не перечитывается.
Сам конфиг nginx как реверс-прокси — стандартный, но с двумя нюансами, которые именно в Forgejo дают о себе знать чаще, чем в обычных сайтах:
server {
listen 443 ssl http2;
server_name git.your-domain.ru;
client_max_body_size 512M;
location / {
proxy_pass http://127.0.0.1:3000;
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-Proto $scheme;
proxy_read_timeout 300s;
}
}
client_max_body_sizeпо умолчанию 1M — этого хватает на пару коммитов, но крупныйgit pushс бинарными файлами или загрузка релиза через веб отвалится с 413. Для репозиториев с LFS ставьте не меньше 512M, а лучше0(без лимита), если сервер не публичный.proxy_read_timeoutпо умолчанию у nginx — 60 секунд. Клонирование большого репозитория по HTTPS или долгий clone с полной историей упирается в этот таймаут и обрывается на середине. 300 секунд обычно достаточный запас.
Если сертификат не выпускается через certbot из-за того, что домен ещё не проксируется на 80/443 в момент выпуска — это уже не специфика Forgejo, а общая грабля Let's Encrypt, разобранная в статье про частые ошибки Let's Encrypt. Общая логика с nginx-конфигами реверс-прокси — в статье про nginx как реверс-прокси.
Forgejo Actions: runner не подключается
Forgejo Actions — родной аналог GitHub Actions, но он не встроен «из коробки»: runner нужно ставить и регистрировать отдельно. Типичный сценарий провала — в .gitea/workflows/*.yml лежит пайплайн, а джобы висят в очереди бесконечно, потому что runner не зарегистрирован или отвалился.
Проверка статуса runner'а:
- В
app.iniсекция Actions должна быть явно включена:
[actions]
ENABLED = true
- Runner (это отдельный бинарник/контейнер
forgejo-runner) регистрируется токеном, который генерируется в самой Forgejo — в настройках инстанса или конкретного репозитория, раздел Actions → Runners.
docker run --rm -it \
-v ./runner-data:/data \
codeberg.org/forgejo/runner:6 \
forgejo-runner register \
--instance https://git.your-domain.ru \
--token <ТОКЕН_ИЗ_ИНТЕРФЕЙСА> \
--name runner-01 \
--no-interactive
- Если runner использует Docker executor для запуска джобов в контейнерах (стандартный сценарий), ему нужен доступ к Docker-сокету хоста:
services:
runner:
image: codeberg.org/forgejo/runner:6
volumes:
- ./runner-data:/data
- /var/run/docker.sock:/var/run/docker.sock
restart: unless-stopped
Без проброса сокета джобы падают с ошибкой вроде Cannot connect to the Docker daemon в самом первом шаге — легко спутать с проблемой в самом workflow-файле, хотя дело в инфраструктуре runner'а.
Ещё одна частая причина «зависших» джобов — токен runner'а был отозван в интерфейсе (например, при ротации секретов), а сам процесс runner об этом не узнал и продолжает пытаться поллить API с невалидным токеном. Лечится удалением старой регистрации и повторным register с новым токеном.
Миграция с Gitea и бэкап
Переезд с Gitea на Forgejo в большинстве случаев проходит штатным дампом — форматы БД и репозиториев совместимы на уровне, достаточном для восстановления:
# на старом сервере с Gitea
gitea dump -c /etc/gitea/app.ini -f gitea-dump.zip
# переносим архив на новый сервер и разворачиваем в Forgejo
forgejo dump restore -f gitea-dump.zip
Нюанс: если версии сильно разъехались (например, мигрируете с Gitea 1.19 на свежий Forgejo), между дампом и восстановлением стоит поднять промежуточную версию и дать пройти миграциям схемы БД, а не прыгать напрямую — иначе restore падает на несовпадении схемы. Если репозиториев немного, надёжнее перенести их вручную через git clone --mirror + git push --mirror в новый инстанс — так меньше риска потерять issues и PR при сбое миграции.
Для регулярных бэкапов уже работающего Forgejo — тот же dump по cron с ротацией архивов, либо снятие бэкапа тома Postgres отдельно от git-данных. Если нужен инструмент с версионированием и дедупликацией снапшотов, а не просто zip-архив раз в сутки — почитайте про настройку BorgBackup на сервере, он неплохо сочетается с volume Forgejo.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Сколько RAM нужно для Forgejo на небольшом проекте?
Для команды из 5-10 человек и десятка репозиториев хватает 1-2 ГБ на саму Forgejo плюс отдельно память под Postgres — обычно ещё 512 МБ-1 ГБ. Если параллельно крутите Actions runner с Docker executor, закладывайте память ещё и под сами джобы: сборка фронтенда легко съедает гигабайт-полтора на время выполнения. Общая логика расчёта похожа на разобранную в статье сколько RAM нужно для Gitea — цифры близки, потому что движок общий.
Можно ли использовать SQLite и не думать о Postgres?
Можно для личных проектов и небольших команд без активного CI, но при параллельных операциях запись блокируется, и любой конкурентный доступ (несколько пушей одновременно, работающий runner) увеличивает риск ошибок database is locked. Для рабочего инстанса с Actions Postgres — не роскошь, а страховка от рандомных сбоев.
Почему после обновления образа перестали приходить вебхуки?
Чаще всего вебхук использует внутренний адрес контейнера (http://forgejo:3000), который недоступен извне, либо после обновления сбросился ROOT_URL. Проверьте актуальность ROOT_URL в app.ini и адрес непосредственно в настройках вебхука в репозитории — Forgejo не обновляет уже сохранённые URL вебхуков автоматически при смене домена.
Форк отстаёт от Gitea по фичам?
По базовому функционалу — нет. Расхождения в основном в сторону Actions (у Forgejo эта часть развивается активнее и полностью открыта) и в деталях UI — на практике для типового self-hosted Git-хостинга это не критично.
Пропали SSH-ключи пользователей после миграции?
Ключи хранятся в базе и переносятся вместе с дампом, но файл authorized_keys генерируется заново — после restore выполните forgejo admin regenerate keys, иначе SSH не заработает, даже если в интерфейсе ключи видны.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →