Как установить и настроить SonarQube на VPS
Ревью кода руками не масштабируется: дубли, забытые пароли в коде, растущая цикломатическая сложность — всё это разработчик пропускает, когда торопится закрыть тикет. SonarQube берёт эту рутину на себя: статически анализирует код при каждом коммите, считает технический долг и не пускает в прод сборку, которая не проходит quality gate. Разберём, как поставить его на свой VPS через Docker Compose, дать ему HTTPS и подключить к CI-пайплайну.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Что такое SonarQube и когда он оправдан
SonarQube — сервер статического анализа кода. Он подключается к CI, разбирает исходники на 30+ языках (Java, JS/TS, Python, PHP, Go, C# и другие) и находит три категории проблем: баги (логические ошибки, которые сломаются в рантайме), уязвимости (security hotspots — небезопасные паттерны вроде SQL-инъекций или захардкоженных секретов) и code smells (дублирование, сложность, нарушение конвенций). По каждому проекту считается технический долг в часах и покрытие тестами, если вы отдаёте отчёт о coverage.
Ставить SonarQube имеет смысл, когда у вас уже есть CI-пайплайн и команда больше одного человека — тогда единая планка качества снимает споры в код-ревью и ловит регрессии автоматически. Для соло-проекта или разового скрипта это оверкилл: Community-редакция бесплатна, но сама по себе прожорлива по памяти (под капотом Elasticsearch), и держать её ради одного репозитория нерентабельно. Если вы уже подняли GitLab CI-раннер или Jenkins, SonarQube логично встраивается следующим шагом.
Требования к серверу и подготовка ОС
SonarQube тянет за собой встроенный Elasticsearch, а тот требователен к памяти и к настройкам ядра Linux. Минимум для Community-редакции с парой небольших проектов — 2 ядра CPU и 4 ГБ RAM, но комфортно работать начинает от 8 ГБ, особенно если сканируете крупные монорепозитории или держите историю анализов за несколько месяцев. Диск — от 20 ГБ под саму базу и историю сканов, лучше SSD: Elasticsearch активно пишет индексы.
Работаем на Ubuntu 24.04 с root-доступом. Прежде чем поднимать контейнеры, поправьте лимиты ядра — без этого Elasticsearch внутри SonarQube не стартует и контейнер будет падать в рестарт-луп:
cat <<EOF >> /etc/sysctl.conf
vm.max_map_count=524288
fs.file-max=131072
EOF
sysctl -p
cat <<EOF >> /etc/security/limits.conf
sonarqube - nofile 131072
sonarqube - nproc 8192
EOF
vm.max_map_count — самая частая причина, по которой контейнер SonarQube не поднимается на свежем сервере: Elasticsearch требует минимум 262144 виртуальных memory-mapped областей, мы ставим с запасом. Проверить после sysctl -p, что значение применилось:
sysctl vm.max_map_count
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверУстановка через Docker Compose
Официальный и самый предсказуемый способ развернуть SonarQube — Docker Compose с отдельным контейнером PostgreSQL под метаданные. Если Docker ещё не стоит, поставьте его штатным скриптом:
curl -fsSL https://get.docker.com | sh
Создайте директорию проекта и docker-compose.yml:
mkdir -p /opt/sonarqube && cd /opt/sonarqube
services:
sonarqube:
image: sonarqube:community
container_name: sonarqube
restart: unless-stopped
depends_on:
- db
environment:
SONAR_JDBC_URL: jdbc:postgresql://db:5432/sonar
SONAR_JDBC_USERNAME: sonar
SONAR_JDBC_PASSWORD: замените_на_свой_пароль
volumes:
- sonarqube_data:/opt/sonarqube/data
- sonarqube_extensions:/opt/sonarqube/extensions
- sonarqube_logs:/opt/sonarqube/logs
ports:
- "127.0.0.1:9000:9000"
db:
image: postgres:16
container_name: sonarqube_db
restart: unless-stopped
environment:
POSTGRES_USER: sonar
POSTGRES_PASSWORD: замените_на_свой_пароль
POSTGRES_DB: sonar
volumes:
- postgresql_data:/var/lib/postgresql/data
volumes:
sonarqube_data:
sonarqube_extensions:
sonarqube_logs:
postgresql_data:
Обратите внимание на порт: сервис слушает только 127.0.0.1:9000, наружу его не пускаем — наружу будет смотреть только Nginx с HTTPS, об этом ниже. Пароли в примере — замените на свои перед запуском, не оставляйте дефолтные значения. Поднимаем стек:
docker compose up -d
docker compose logs -f sonarqube
Первый старт занимает пару минут — SonarQube инициализирует схему в PostgreSQL и поднимает встроенный Elasticsearch. В логах должно появиться SonarQube is operational. Если контейнер уходит в перезапуск с ошибкой про max virtual memory areas — значит, vm.max_map_count из предыдущего шага не применился или сервер не перечитал sysctl.
HTTPS через Nginx и защита доступа
Открывать 9000-й порт наружу без TLS не стоит — там ходят логины и токены доступа к анализам кода. Поставьте перед SonarQube Nginx как reverse-proxy и получите сертификат через Let's Encrypt:
server {
listen 80;
server_name sonar.example.com;
location / {
proxy_pass http://127.0.0.1:9000;
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;
client_max_body_size 20m;
}
}
После certbot --nginx -d sonar.example.com конфиг обновится на 443 с автоматическим редиректом с 80. Дальше закройте на фаерволе всё, кроме 22, 80 и 443:
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
Порт PostgreSQL и порт самого SonarQube (9000) наружу не открываются вовсе — трафик к ним ходит только внутри docker-сети и с loopback, что уже сильно сокращает поверхность атаки.
Первый вход и базовая настройка
Откройте https://sonar.example.com — по умолчанию логин и пароль admin/admin, система сразу попросит сменить пароль при первом входе. Сделайте это до того, как открывать доступ команде.
Дальше стоит зайти в Administration → Configuration → General Settings и проверить пару вещей: язык интерфейса, и если планируете авторизацию через существующий GitLab или другую SSO-систему — соответствующий раздел Authentication (в Community-редакции доступна интеграция через сторонние identity-провайдеры, но не все опции enterprise-плагинов).
Quality Gate — это набор условий, при невыполнении которых сборка помечается как проваленная. По умолчанию активен пресет Sonar way: покрытие новым кодом не ниже 80%, дублирование не выше 3%, отсутствие багов и уязвимостей в новом коде. Это разумная отправная точка — не переписывайте её в первый день, посмотрите пару недель на реальные отчёты и уже потом подстраивайте пороги под specifics вашего проекта. Слишком жёсткий gate с первого дня обычно приводит к тому, что команда просто перестаёт на него смотреть.
Подключение к CI-пайплайну
Анализ запускается сканером sonar-scanner, который прогоняется в CI и отправляет результат на сервер SonarQube по токену. Создайте токен в My Account → Security → Generate Tokens — сохраните его как секрет в CI, в открытом виде в репозиторий он попадать не должен.
Пример job для GitLab CI (используем официальный образ сканера, чтобы не ставить Java и sonar-scanner вручную):
sonarqube-check:
stage: test
image:
name: sonarsource/sonar-scanner-cli:latest
entrypoint: [""]
variables:
SONAR_HOST_URL: "https://sonar.example.com"
GIT_DEPTH: "0"
script:
- sonar-scanner
-Dsonar.projectKey=my-project
-Dsonar.sources=.
-Dsonar.login=$SONAR_TOKEN
allow_failure: false
SONAR_TOKEN кладётся в Settings → CI/CD → Variables как protected и masked. GIT_DEPTH: "0" важен для корректного определения "нового кода" — сканеру нужна полная история, а не мелкий shallow-clone. Для Jenkins логика аналогична: плагин SonarQube Scanner добавляет шаг withSonarQubeEnv в Jenkinsfile, а сам сервер регистрируется один раз в Manage Jenkins → Configure System.
Чтобы pipeline реально останавливался на проваленном gate, а не просто присылал уведомление, добавьте шаг ожидания результата (sonar.qualitygate.wait=true в параметрах сканера или отдельный webhook от SonarQube обратно в CI) — иначе сборка зелёная, даже если gate красный, просто потому что сканер успел отправить отчёт и завершиться раньше, чем сервер его обработал.
Обслуживание, бэкапы и обновления
SonarQube хранит всё состояние в PostgreSQL плюс индексы Elasticsearch в volume sonarqube_data. Бэкапить нужно оба места — потеря базы данных означает потерю истории анализов и настроенных проектов. Дамп PostgreSQL:
docker exec sonarqube_db pg_dump -U sonar sonar > /opt/backups/sonar_$(date +%F).sql
Дополните это бэкапом docker volume или регулярным rsync директории /var/lib/docker/volumes/, а лучше — cron-задачей, которая складывает дампы за пределы сервера (в S3-совместимое хранилище или на другой VPS).
Обновление SonarQube между мажорными версиями требует прогона миграций через Administration → System → Upgrade после смены тега образа — не просто docker compose pull && up -d, иначе схема БД разъедется с версией приложения. Перед мажорным апгрейдом обязательно снимайте дамп: откаты назад SonarQube не поддерживает штатно.
Память — второй по частоте источник проблем в проде. Если видите в логах OutOfMemoryError от процесса ce (Compute Engine, который считает метрики после скана) — увеличьте память контейнеру через переменные SONAR_CE_JAVAOPTS и SONAR_WEB_JAVAOPTS, либо, если сервер стабильно упирается в лимит, увеличьте RAM у самого VPS.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Можно ли обойтись без отдельного PostgreSQL, встроенной базой H2?
Технически SonarQube стартует и с H2, но это режим только для оценки продукта — он однопоточный, не переживает перезапуск без потери данных и официально не поддерживается для реальной работы. Для прода нужен внешний PostgreSQL, MySQL в актуальных версиях SonarQube уже не поддерживается.
SonarQube Community и платные редакции — в чём разница для повседневной работы?
Community покрывает статический анализ, quality gates и основные языки бесплатно. Платные редакции (Developer, Enterprise) добавляют анализ веток и pull request'ов прямо в интерфейсе, дополнительные языки (например, C/C++/COBOL), portfolio-отчёты для нескольких проектов сразу и расширенную безопасность. Для одного репозитория и базового CI Community обычно достаточно.
Контейнер падает сразу после старта, в логах про bootstrap checks failed — что делать?
Почти всегда это vm.max_map_count, реже — нехватка file descriptors. Проверьте sysctl vm.max_map_count, значение должно быть не меньше 262144 (мы ставили 524288 с запасом), и убедитесь, что sysctl применился именно на хосте, а не только внутри контейнера.
Сколько времени занимает анализ одного проекта?
Зависит от размера кодовой базы и от того, первый это скан или инкрементальный. Для проекта в несколько десятков тысяч строк первый полный скан может занять несколько минут — это ориентир, у вас будет отличаться в зависимости от языка, количества правил и мощности сервера. Инкрементальные сканы заметно быстрее, потому что анализируют в основном изменения.
Нужен ли SonarQube, если в команде уже есть линтеры (ESLint, Pylint и т.п.)?
Линтеры и SonarQube не взаимозаменяемы. Линтер — быстрая проверка стиля и очевидных ошибок прямо в IDE или pre-commit хуке. SonarQube даёт межфайловый анализ, отслеживание технического долга во времени, security hotspots и единую панель для всей команды с историей качества по каждому коммиту. Разумно использовать оба уровня вместе.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →