OSEN-НИЙ SAAALEСкидка 50% на виртуальный хостинг и VDS
до 30.11.2025 Подробнее
Выберите продукт

Gitea на VDS: установка, systemd, SSL и Nginx reverse proxy

Самостоятельный Git без лишней тяжеловесности: развернём Gitea на VDS с обратным прокси Nginx и SSL. Оформим как systemd‑сервис, подключим SSH для git, включим бэкапы и покажем безопасные пресеты конфигов.
Gitea на VDS: установка, systemd, SSL и Nginx reverse proxy

Gitea — лёгкая и быстрая альтернатива тяжёлым платформам управления репозиториями. Она отлично подходит для команд, которым нужен приватный Git с минимальными накладными расходами. В этой инструкции развернём Gitea на облачном VDS: настроим systemd‑сервис, поднимем Nginx reverse proxy с HTTPS, включим SSH для git и подготовим резервное копирование. Материал ориентирован на Debian/Ubuntu.

План развёртывания и требования

Мы установим Gitea в режиме приложения, слушающего локальный порт, а снаружи будем публиковать её через Nginx как обратный прокси. Такой подход упрощает выпуск и ротацию TLS‑сертификатов, даёт гибкость при настройке заголовков и буферов, а также удобен для масштабирования.

Минимальные требования к VDS: 1 vCPU, 1–2 ГБ RAM, 20 ГБ диска. Для 5–10 пользователей и десятков репозиториев этого достаточно; для Git LFS или CI закладывайте больше диска и ОЗУ. Нужен домен для HTTPS, открытые порты 22/80/443 и корректные A/AAAA‑записи. Если домена ещё нет — поможет регистрация доменов.

Почему не слушать 443 прямо в Gitea? Разделение ролей «приложение на localhost» и «Nginx на внешнем интерфейсе» упрощает сопровождение: TLS‑политики, лимиты, компрессия и защита от аномалий сосредоточены в одном месте — в конфигурации Nginx.

Подготовка системы

Начнём с обновления пакетов и установки базового окружения. Имя пользователя сервиса — git, данные храним в /var/lib/gitea, конфиг — в /etc/gitea.

sudo apt update
sudo apt install -y nginx git unzip curl tar coreutils ca-certificates
sudo apt install -y certbot python3-certbot-nginx

# Системный пользователь без shell
sudo adduser --system --shell /usr/sbin/nologin --gecos 'Gitea' --group --disabled-password --home /home/git git

# Каталоги для данных и конфигов
sudo mkdir -p /var/lib/gitea/{custom,data,log}
sudo mkdir -p /etc/gitea

# Права и владельцы
sudo chown -R git:git /var/lib/gitea
sudo chmod -R 750 /var/lib/gitea
sudo chown root:git /etc/gitea
sudo chmod 770 /etc/gitea

Если используется UFW или другой файрвол, откройте порты 22, 80 и 443. Для UFW это выглядит так:

sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status

Установка Gitea (бинарь) и базовая конфигурация

Удобнее всего использовать подготовленный бинарь: его легко обновлять без изменения схемы каталогов. Замените версию на актуальную стабильную из релизов проекта.

GITEA_VERSION=1.22.3
sudo curl -fL -o /usr/local/bin/gitea https://dl.gitea.com/gitea/${GITEA_VERSION}/gitea-${GITEA_VERSION}-linux-amd64
sudo chmod 755 /usr/local/bin/gitea
sudo chown root:root /usr/local/bin/gitea

# Создаём файл конфига
sudo tee /etc/gitea/app.ini > /dev/null << 'EOF'
APP_NAME = Gitea
RUN_MODE = prod
RUN_USER = git

[server]
PROTOCOL = http
DOMAIN = gitea.example.com
ROOT_URL = https://gitea.example.com/
HTTP_ADDR = 127.0.0.1
HTTP_PORT = 3000
DISABLE_SSH = false
START_SSH_SERVER = false
SSH_PORT = 22
SSH_DOMAIN = gitea.example.com
LFS_START_SERVER = true
LFS_JWT_SECRET = replace_me_lfs_secret

[database]
DB_TYPE = sqlite3
PATH = /var/lib/gitea/data/gitea.db

[security]
INSTALL_LOCK = true
SECRET_KEY = replace_me_secret

[service]
REGISTER_EMAIL_CONFIRM = false
ENABLE_NOTIFY_MAIL = false
DISABLE_REGISTRATION = true
REQUIRE_SIGNIN_VIEW = false

[session]
COOKIE_SECURE = true

[log]
MODE = console
LEVEL = info

[repository]
ROOT = /var/lib/gitea/data/repositories

[lfs]
PATH = /var/lib/gitea/data/lfs
EOF

# Права доступа на конфиг
sudo chown root:git /etc/gitea/app.ini
sudo chmod 640 /etc/gitea/app.ini

Секреты лучше сгенерировать случайно и заменить плейсхолдеры:

openssl rand -hex 32

В примере используется SQLite — для небольших команд достаточно. Если ожидается рост, переходите на PostgreSQL: выше производительность и удобнее бэкап. В этом случае замените секцию [database] на параметры подключения.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

systemd‑сервис с базовым hardening

Создадим юнит для Gitea. Ограничим привилегии, доступ к ФС и укажем каталоги, доступные на запись.

sudo tee /etc/systemd/system/gitea.service > /dev/null << 'EOF'
[Unit]
Description=Gitea (Git with a cup of tea)
After=network-online.target
Wants=network-online.target

[Service]
Type=notify
User=git
Group=git
WorkingDirectory=/var/lib/gitea
Environment=GITEA_WORK_DIR=/var/lib/gitea
Environment=GITEA_CUSTOM=/var/lib/gitea/custom
ExecStart=/usr/local/bin/gitea web --config /etc/gitea/app.ini
Restart=always
RestartSec=3s

# Журналирование
StandardOutput=journal
StandardError=journal

# Базовое hardening
NoNewPrivileges=yes
PrivateTmp=yes
PrivateDevices=yes
ProtectSystem=full
ProtectHome=yes
ProtectKernelTunables=yes
ProtectControlGroups=yes
ProtectKernelModules=yes
LockPersonality=yes
MemoryDenyWriteExecute=yes
CapabilityBoundingSet=

# Каталоги, доступные на запись
ReadWritePaths=/var/lib/gitea /etc/gitea

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now gitea
sudo systemctl status gitea

На этом этапе Gitea должна слушать 127.0.0.1:3000. Проверьте журнал на ошибки конфигурации и права каталогов.

Nginx reverse proxy: редирект на HTTPS, проксирование и WebSocket

Настроим Nginx как обратный прокси с редиректом на HTTPS и поддержкой веб‑сокетов (уведомления). Пробрасываем реальные IP и имя хоста, увеличиваем таймауты для долгих Git‑операций и настраиваем лимиты для LFS.

sudo tee /etc/nginx/sites-available/gitea.conf > /dev/null << 'EOF'
server {
    listen 80;
    listen [::]:80;
    server_name gitea.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name gitea.example.com;

    # Временные пути к сертификатам (certbot пропишет актуальные)
    ssl_certificate /etc/letsencrypt/live/gitea.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/gitea.example.com/privkey.pem;

    # Рекомендуемые настройки TLS
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;

    # Ограничения и таймауты
    client_max_body_size 1G;
    keepalive_timeout 65s;

    # Основной прокси
    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        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 https;
        proxy_set_header X-Forwarded-Host $host;

        # WebSocket для уведомлений
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # Долгие операции (clone/push)
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
    }

    # Git LFS: разумно отключить буферизацию для крупных загрузок
    location ~ ^/.+\.git/info/lfs/ {
        proxy_pass http://127.0.0.1:3000;
        proxy_request_buffering off;
        client_max_body_size 2G;
    }
}
EOF

sudo nginx -t
sudo systemctl reload nginx

Замените gitea.example.com на ваш FQDN. После выпуска сертификата сайт будет доступен по HTTPS.

Схема: Nginx как обратный прокси перед Gitea с HTTPS и WebSocket

SSL: выпуск Let’s Encrypt и автоматическое продление

Для бесплатного сертификата используйте certbot с плагином Nginx: он пропишет пути к сертификатам и редиректы. Если нужен коммерческий сертификат, доступен вариант с GlobalSign — смотрите SSL-сертификаты.

sudo certbot --nginx -d gitea.example.com --agree-tos -m admin@example.com --redirect
sudo systemctl reload nginx

# Проверим задачи автопродления
sudo systemctl list-timers | grep certbot

При планировании HSTS и постоянных редиректов пригодится разбор тонкостей миграции домена и политик безопасности: смотрите материал о 301, HSTS и SSL.

SSH для git: внешний OpenSSH и ключи пользователей

Gitea может не поднимать собственный SSH‑сервер и использовать системный OpenSSH. Современная интеграция — через AuthorizedKeysCommand: ключи пользователей проверяет бинарь Gitea, без записи в authorized_keys.

# Интеграция Gitea с внешним OpenSSH
sudo tee -a /etc/ssh/sshd_config > /dev/null << 'EOF'
# Gitea external SSH integration
AuthorizedKeysCommand /usr/local/bin/gitea --config /etc/gitea/app.ini keys -e
AuthorizedKeysCommandUser git
EOF

sudo systemctl restart ssh

Проверьте, что в app.ini указаны DISABLE_SSH = false, START_SSH_SERVER = false, корректные SSH_PORT и SSH_DOMAIN. Пользователи добавляют публичные ключи в веб‑интерфейсе, после чего clone/push по SSH работают из коробки.

FastFox SSL
Надежные SSL-сертификаты
Мы предлагаем широкий спектр SSL-сертификатов от GlobalSign по самым низким ценам. Поможем с покупкой и установкой SSL бесплатно!

Проверка clone/push

Создайте тестовый репозиторий в Gitea и попробуйте клон по SSH и HTTPS.

git clone ssh://git@gitea.example.com:22/vasya/hello.git
git clone https://gitea.example.com/vasya/hello.git

Тонкая настройка Gitea: регистрация, приватность, LFS

Рекомендую отключить саморегистрацию (DISABLE_REGISTRATION = true) и включить 2FA в политике организации. Если нужен публичный просмотр без логина — REQUIRE_SIGNIN_VIEW = false. Для Git LFS проверьте путь к хранилищу и свободное место.

Если Gitea — внутренняя система, задайте политику паролей (MIN_PASSWORD_LENGTH, PASSWORD_COMPLEXITY) и корректно настройте почту для уведомлений и reset паролей. В продакшене COOKIE_SECURE = true обязателен.

Производительность обратного прокси Nginx

Git‑операции могут держать соединения минутами, поэтому увеличены таймауты прокси. Для крупных репозиториев можно поднять proxy_max_temp_file_size или отключить буферизацию на отдельных локациях. Сжимать Git‑пакеты не нужно, но HTML/JSON интерфейса разумно отдавать с gzip/brotli, если это в политике компании. Для нестабильных клиентов проверьте keepalive_timeout и сетевые sysctl.

Резервное копирование: gitea dump и systemd‑таймер

Gitea умеет собирать единый архив, включающий репозитории, вложения, LFS и базу данных (включая SQLite). Это простой способ ежедневного бэкапа.

# Каталог для бэкапов
sudo mkdir -p /var/backups/gitea
sudo chown git:git /var/backups/gitea

# Скрипт бэкапа
sudo tee /usr/local/bin/gitea-backup > /dev/null << 'EOF'
#!/usr/bin/env bash
set -euo pipefail
TS=$(date +%Y%m%d-%H%M%S)
OUT=/var/backups/gitea/gitea-$TS.tar.gz
/usr/local/bin/gitea dump --config /etc/gitea/app.ini --file $OUT --skip-attachments=false --skip-lfs=false
find /var/backups/gitea -type f -mtime +14 -name 'gitea-*.tar.gz' -delete
EOF

sudo chmod 750 /usr/local/bin/gitea-backup
sudo chown root:root /usr/local/bin/gitea-backup

# Юнит и таймер
sudo tee /etc/systemd/system/gitea-backup.service > /dev/null << 'EOF'
[Unit]
Description=Gitea backup

[Service]
Type=oneshot
User=git
Group=git
ExecStart=/usr/local/bin/gitea-backup
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=full
ReadWritePaths=/var/backups/gitea
EOF

sudo tee /etc/systemd/system/gitea-backup.timer > /dev/null << 'EOF'
[Unit]
Description=Daily Gitea backup

[Timer] 
Persistent=true

[Install]
WantedBy=timers.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now gitea-backup.timer
sudo systemctl list-timers | grep gitea-backup

Храните резервные копии вне того же диска VDS (объектное хранилище, отдельный сервер). Регулярно выполняйте пробные восстановление на тестовом инстансе — это единственный способ убедиться, что бэкапы рабочие.

Концепт: systemd‑таймер и архив бэкапа для инстанса Gitea

Обновления Gitea

Обновление бинарной установки — это скачивание нового файла, замена и перезапуск сервиса. Перед обновлением сделайте бэкап.

GITEA_VERSION=1.22.4
sudo systemctl stop gitea
sudo curl -fL -o /usr/local/bin/gitea.new https://dl.gitea.com/gitea/${GITEA_VERSION}/gitea-${GITEA_VERSION}-linux-amd64
sudo mv /usr/local/bin/gitea.new /usr/local/bin/gitea
sudo chmod 755 /usr/local/bin/gitea
sudo chown root:root /usr/local/bin/gitea
sudo systemctl start gitea
sudo journalctl -u gitea -n 100 --no-pager

Диагностика типовых проблем

Нет HTTPS: проверьте DNS, файрвол и валидность сертификата. nginx -t должен проходить без ошибок, а systemctl status nginx — быть активным. 502 — чаще падение Gitea: смотрим journalctl -u gitea, права /var/lib/gitea и пользователя git.

Не работает SSH: проверьте путь в AuthorizedKeysCommand, доступ пользователя git к /etc/gitea/app.ini и журналы journalctl -u ssh. При строгих политиках возможно потребуются правила SELinux/AppArmor.

Медленный clone по HTTPS: увеличьте proxy_read_timeout/proxy_send_timeout, оцените пропускную способность диска и сетевые sysctl; для больших аплоадов помогает proxy_request_buffering off.

Рекомендации по безопасности

  • Отключите саморегистрацию и включите 2FA на уровне организации.
  • Ограничьте роли: доступ к админке только группе доверенных пользователей.
  • Добавьте базовые заголовки в Nginx: CSP, X‑Frame‑Options, X‑Content‑Type‑Options.
  • Регулярно обновляйте Gitea и системные пакеты; при необходимости включите unattended‑upgrades.
  • Следите за журналами: journalctl -u gitea, логи Nginx и активность SSH. Для управления секретами в инфраструктуре посмотрите практику с sops + age.

Итоги

Мы развернули Gitea на VDS с аккуратной архитектурой: приложение слушает localhost, снаружи — Nginx с TLS, а управление выполнением — через systemd. Добавили SSH для git, настроили резервные копии и обсудили тонкости производительности и безопасности. Дальше можно подключить PostgreSQL, e‑mail‑уведомления, веб‑хуки и мониторинг. Если требуется домен или сертификаты, используйте регистрация доменов и SSL-сертификаты.

Поделиться статьей

Вам будет интересно

systemd-run: ограничиваем CPU и RAM для одноразовых задач и интерактивных команд OpenAI Статья написана AI (GPT 5)

systemd-run: ограничиваем CPU и RAM для одноразовых задач и интерактивных команд

Как быстро ограничить CPU и память для разовых команд без unit-файлов: используем systemd-run, transient units в режимах --service ...
OpenSearch на VDS: практический гид по памяти JVM heap, ISM-политикам и снапшотам OpenAI Статья написана AI (GPT 5)

OpenSearch на VDS: практический гид по памяти JVM heap, ISM-политикам и снапшотам

Поднимем OpenSearch на VDS: настроим JVM heap без сюрпризов с GC, спроектируем ISM с rollover и удалением, организуем регулярные s ...
ACME DNS‑01 через RFC2136: свой DNS‑API без облаков OpenAI Статья написана AI (GPT 5)

ACME DNS‑01 через RFC2136: свой DNS‑API без облаков

DNS‑01 решает выпуск wildcard и закрытых сервисов, но нужен API к авторитетному DNS. Покажу, как поднять свой «API» на RFC2136: BI ...