Причины завести свой Git обычно набираются постепенно. Заказчик просит, чтобы код не лежал у стороннего сервиса. Бесплатные минуты CI заканчиваются к середине месяца. Приватных репозиториев становится больше, чем помещается в тариф. Или просто хочется, чтобы доступ к своему коду не зависел от чужих решений.
Gitea закрывает это за полчаса и умещается на сервере за 5 € в месяц. Внешне — почти тот же GitHub: репозитории, issues, pull request'ы, вики, встроенный CI. Внутри — один бинарник на Go, который потребляет меньше памяти, чем вкладка браузера.
Сколько ресурсов нужно
Gitea написана экономно, и это её главное практическое достоинство:
| Сценарий | Тариф |
|---|---|
| 1–3 человека, репозитории с кодом | Старт — 1 ядро, 2 ГБ, 5 € |
| Команда до 10 человек, встроенный CI | Лёгкий — 2 ядра, 4 ГБ, 10 € |
| CI с тяжёлыми сборками, docker build | Оптимальный — 4 ядра, 8 ГБ, 20 € |
Сам Gitea в покое занимает около 150–200 МБ памяти. Всё остальное съедает не он, а сборки: если планируете гонять CI с компиляцией или сборкой образов, закладывайте ресурсы именно под это.
Про диск: репозитории с кодом весят немного, счёт обычно идёт на сотни мегабайт. Место уходит на другое — историю сборок, артефакты и загруженные в issues файлы.
Шаг 1. Подготовить сервер
Закажите VPS с Ubuntu 24.04 и пройдите базовую настройку — на сервере будет лежать весь ваш код, поэтому защиту откладывать нельзя: 7 шагов безопасности.
Направьте домен: A-запись git.example.com → IP сервера.
Установите Docker и общий reverse proxy с автоматическим SSL, если его ещё нет: Docker на VPS.
Шаг 2. Развернуть Gitea
mkdir -p /opt/gitea && cd /opt/gitea
nano docker-compose.yml
services:
gitea:
image: gitea/gitea:1
container_name: gitea
restart: unless-stopped
environment:
- USER_UID=1000
- USER_GID=1000
- GITEA__database__DB_TYPE=postgres
- GITEA__database__HOST=gitea-db:5432
- GITEA__database__NAME=gitea
- GITEA__database__USER=gitea
- GITEA__database__PASSWD=${DB_PASSWORD}
- GITEA__server__DOMAIN=git.example.com
- GITEA__server__ROOT_URL=https://git.example.com/
- GITEA__server__SSH_DOMAIN=git.example.com
- GITEA__server__SSH_PORT=2222
- GITEA__service__DISABLE_REGISTRATION=true
volumes:
- gitea_data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "2222:22"
networks:
- web
- internal
depends_on:
- gitea-db
gitea-db:
image: postgres:16
container_name: gitea-db
restart: unless-stopped
environment:
POSTGRES_DB: gitea
POSTGRES_USER: gitea
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- gitea_db:/var/lib/postgresql/data
networks:
- internal
volumes:
gitea_data:
gitea_db:
networks:
web:
external: true
internal:
Пароль базы — в отдельный файл:
nano .env
DB_PASSWORD=длинный_пароль
chmod 600 .env
docker compose up -d
Два момента в конфиге заслуживают внимания.
DISABLE_REGISTRATION=true — закрывает самостоятельную регистрацию. Без этого ваш Git через неделю найдут сканерами, и в нём заведутся чужие аккаунты. Пользователей будете создавать сами, из админки.
Порт 2222 — по нему работает Git по SSH. Порт 22 на хосте занят вашим системным SSH, поэтому Gitea вешается на соседний.
Добавьте домен в Caddyfile:
git.example.com {
reverse_proxy gitea:3000
}
docker exec caddy caddy reload --config /etc/caddy/Caddyfile
Откройте порт для Git по SSH:
ufw allow 2222/tcp
Шаг 3. Первый запуск
Откройте https://git.example.com — появится страница первоначальной настройки. База уже подключена переменными окружения, поэтому большую часть полей трогать не нужно.
Проверьте только два блока:
- Базовый URL сайта — должен быть
https://git.example.com/, иначе кнопки клонирования будут выдавать неправильные адреса - Учётная запись администратора — создайте её сразу, прямо на этой странице. Первый зарегистрированный пользователь автоматически становится администратором, и если оставить это на потом, им станет кто-то другой
После установки зайдите в админку и заведите остальных пользователей вручную.
Шаг 4. Подключить ключ и проверить
Gitea, как и GitHub, работает по SSH-ключам. Публичный ключ добавляется в профиле: Настройки → SSH-ключи.
Если ключа ещё нет, он создаётся на вашем компьютере одной командой:
ssh-keygen -t ed25519 -C "gitea"
Подробнее про ключи и подключение: Как подключиться к VPS по SSH.
Поскольку Git работает на нестандартном порту, удобнее прописать его один раз в конфиге SSH у себя на компьютере — тогда адреса репозиториев будут выглядеть привычно:
nano ~/.ssh/config
Host git.example.com
Port 2222
User git
IdentityFile ~/.ssh/id_ed25519
Проверка:
ssh -T git@git.example.com
Ответ вида Hi there, вы успешно аутентифицированы означает, что всё работает. Дальше репозитории клонируются как обычно:
git clone git@git.example.com:username/project.git
Шаг 5. Перенести репозитории с GitHub
Gitea умеет забирать репозитории целиком, вместе с историей, ветками, тегами, issues и pull request'ами.
В интерфейсе: «+» → Новая миграция → GitHub, дальше адрес репозитория и токен доступа GitHub, если репозиторий приватный.
Отметьте галочками, что переносить. Issues и метки переносятся, привязка к аккаунтам GitHub — нет: авторы комментариев будут указаны текстом.
После переноса на своей машине останется переключить адрес удалённого репозитория:
git remote set-url origin git@git.example.com:username/project.git
git remote -v
Оставьте зеркало на GitHub на первое время. В настройках репозитория Gitea есть пункт push-зеркалирования: изменения будут уезжать и туда. Если со своим сервером что-то случится, код останется доступен.
Шаг 6. Встроенный CI
Gitea Actions повторяет синтаксис GitHub Actions — готовые workflow-файлы чаще всего работают без переделки.
Включите в админке: Настройки сайта → Actions → включить. Затем добавьте runner — процесс, который выполняет задачи:
docker run -d --name gitea-runner --restart unless-stopped \
-v /var/run/docker.sock:/var/run/docker.sock \
-e GITEA_INSTANCE_URL=https://git.example.com \
-e GITEA_RUNNER_REGISTRATION_TOKEN=ТОКЕН_ИЗ_АДМИНКИ \
gitea/act_runner:latest
Токен берётся в админке: Actions → Runners → создать токен регистрации.
Обратите внимание на строку с
docker.sock. Она даёт runner'у доступ к Docker на хосте — это удобно для сборки образов, но означает, что любой, кто может запустить сборку, фактически получает права root на сервере. На личном сервере с двумя-тремя доверенными людьми это приемлемо. Если пользователей больше или репозитории публичные — так делать не стоит.
Простой пример автодеплоя: после push в main код обновляется на боевом сервере.
nano .gitea/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Обновить код на сервере
run: |
echo "${{ secrets.SSH_KEY }}" > key
chmod 600 key
ssh -i key -o StrictHostKeyChecking=no deploy@ВАШ_IP "cd /opt/app && git pull && systemctl restart app"
Ключ кладётся в Настройки репозитория → Секреты, в код он не попадает.
Как подготовить на принимающей стороне пользователя, службу и перезапуск: Деплой Node.js и Python на VPS.
Бэкапы
Весь Gitea — это база и том с данными. Резервная копия снимается двумя командами:
docker exec gitea-db pg_dump -U gitea gitea > /opt/backups/gitea-$(date +%F).sql
docker run --rm -v gitea_data:/data -v /opt/backups:/backup alpine tar -czf /backup/gitea-data-$(date +%F).tar.gz /data
У Gitea есть и собственная команда полного дампа — она складывает в один архив базу, репозитории, вложения и настройки:
docker exec -u git gitea /usr/local/bin/gitea dump -c /data/gitea/conf/app.ini
Как поставить это на расписание и хранить копии вне сервера: Бэкапы VPS за 10 минут.
Повторю мысль, которую легко пропустить: теперь единственная копия вашего кода — на вашем сервере. Раньше эту роль неявно играл GitHub. Бэкапы из приятного дополнения превратились в обязательное условие.
Обновление
cd /opt/gitea
docker compose pull
docker compose up -d
Gitea сама применит миграции базы при первом запуске новой версии. Перед сменой мажорной версии снимайте копию — откат окажется быстрее, чем разбирательство.
Следите за тем, чтобы сервер был жив и не кончалось место: Мониторинг VPS.
Когда свой Git не нужен
Честно про обратную сторону.
Ответственность за доступность. Упал сервер — команда не может работать. У GitHub на это есть дежурные инженеры, у вас — вы.
Открытые проекты теряют аудиторию. Если код должен быть виден сообществу, GitHub даёт то, что свой сервер дать не может: поиск, звёзды, случайных контрибьюторов.
Экономия появляется не сразу. Для одного разработчика бесплатного тарифа GitHub хватает с избытком. Своё имеет смысл ставить, когда упираетесь в лимиты CI, когда пользователей несколько или когда есть требование держать код у себя.
Чаще всего работает связка: основной Git свой, зеркало открытых проектов — на GitHub.
Частые вопросы
Чем Gitea отличается от GitLab? GitLab функциональнее, но тяжелее: официальный минимум — 4 ГБ памяти, комфортно с 8 ГБ. Gitea укладывается в 200 МБ и покрывает то, что реально нужно небольшой команде. Для сервера за 5 € выбор очевиден.
Сколько репозиториев потянет один сервер? Количество почти не влияет на нагрузку — Gitea хранит их файлами на диске. Ограничение в месте и в том, сколько сборок CI идёт одновременно.
Можно ли держать Gitea рядом с сайтом на одном сервере? Да, если оба в контейнерах и есть общий reverse proxy. Gitea потребляет немного, но CI-сборки дают пики нагрузки — на сервере с боевым сайтом это стоит учитывать.
Что с большими файлами? Git LFS поддерживается и включается в настройках. Учитывайте место: медиафайлы в репозитории съедают диск быстрее всего.
Безопасно ли выставлять Git наружу?
При закрытой регистрации, двухфакторной авторизации и входе по SSH-ключам — да. Главное не забыть DISABLE_REGISTRATION=true с самого начала.
Можно ли работать без домена, по IP? Технически да, но тогда не будет HTTPS-сертификата, и браузер будет ругаться на каждом заходе. Домен стоит дешевле, чем это неудобство.
Итог
Свой Git — это один контейнер, база и полчаса настройки. На выходе вы получаете репозитории без лимитов, CI без счётчика минут и код, который лежит там, где решили вы.
Порог входа низкий: тариф «Старт» за 5 € в месяц закрывает потребности небольшой команды. Но вместе с контролем приходит и ответственность — настройте бэкапы в первый же день и оставьте зеркало на GitHub, пока не убедитесь, что всё работает стабильно.

