← Все статьи
Полезные статьи

Свой Git-сервер на VPS: Gitea вместо GitHub

Как поднять личный Git-сервер на VPS: установка Gitea в Docker, доступ по SSH, перенос репозиториев с GitHub, встроенный CI и бэкапы.

Причины завести свой 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, пока не убедитесь, что всё работает стабильно.

Выбрать сервер под Git →

Команда Puws.Cloud
Puws.Cloud
Начать

СЕРВЕР ДЛЯ ВАШЕГО ПРОЕКТА

Начните
с тарифа.

ПОЛЕЗНОЕ О СЕРВЕРАХИнструкции
и советы.
Открыть блог
Наш Аптайм