MAATRIX / Блог / Nexus Repository на сервере: частые ошибки и решения

Nexus Repository на сервере: частые ошибки и решения

MAATRIX

Nexus Repository удобен именно тем, что закрывает Maven, npm, Docker и PyPI одним сервисом — но именно поэтому у него столько разных точек отказа. Сегодня падает джоба в CI, потому что push в Docker-репозиторий вернул 401, завтра сам Nexus не встаёт после рестарта с OutOfMemoryError в логе, послезавтра диск на сервере внезапно кончился, хотя вы вроде ничего крупного не заливали. Разберём эти ситуации по схеме «симптом — причина — решение», с командами и конкретными файлами конфигурации.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

С чего начинать диагностику Nexus Repository

Прежде чем чинить что-то конкретное, убедитесь, что сам процесс жив и на что он жалуется. Три источника правды: статус сервиса, лог приложения и служебный REST-эндпоинт.

systemctl status nexus
tail -100 /opt/sonatype-work/nexus3/log/nexus.log
curl -s http://127.0.0.1:8081/service/rest/v1/status

Пустой ответ 200 OK от /service/rest/v1/status означает, что ядро Nexus поднялось и готово принимать запросы — тогда проблема, скорее всего, не в самом Nexus, а в реверс-прокси, авторизации конкретного репозитория или сети. Если статус недоступен вообще, смотрите nexus.log: там почти всегда явно написано, что пошло не так — нехватка памяти, занятый порт, повреждённый файл конфигурации. Отдельно держите в уме, где что лежит: рабочие данные (база, blob-хранилища, логи) — в /opt/sonatype-work/nexus3, сам дистрибутив с бинарниками — отдельно в /opt/nexus. Это разделение важно при обновлениях и бэкапах: обновлять можно дистрибутив, не трогая данные.

Nexus не стартует или падает: OutOfMemoryError

Самая частая причина отказа — банальная нехватка памяти. Nexus — Java-приложение на встроенном OrientDB/H2 и Jetty, и ему по умолчанию выделяется фиксированный размер кучи, который на маленьком VPS может просто не влезть в физическую память. В логе это выглядит так:

java.lang.OutOfMemoryError: Java heap space

или процесс падает молча, а dmesg показывает, что OOM killer убил java из-за нехватки RAM на всей системе. Настройки JVM для Nexus 3 задаются не в systemd-юните напрямую, а в файле nexus.vmoptions рядом с бинарником:

# /opt/nexus/bin/nexus.vmoptions
-Xms1200M
-Xmx1200M
-XX:MaxDirectMemorySize=2G

Значения по умолчанию рассчитаны на сервер с приличным запасом RAM. Для продакшена с реальной нагрузкой Sonatype рекомендует от 4 ГБ RAM на сам процесс Nexus, и это не пустая перестраховка — при нескольких одновременных индексациях Maven-репозитория или синхронизации крупного Docker-прокси потребление памяти растёт быстро. Если сервер целиком укладывается в 2 ГБ, снижение -Xmx спасёт от падения по OOM, но не спасёт от медленной работы под нагрузкой — здесь правильный путь не «ужать до предела», а увеличить память сервера. После правки vmoptions обязательно перезапустите сервис:

systemctl restart nexus
journalctl -u nexus -f

Проверьте по логу, что процесс действительно поднялся и не упал повторно в первые секунды — так по свежим правкам heap сразу видно, хватило памяти или нет.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

401/403 при публикации в Maven, npm, PyPI

Push или publish отваливается с 401 Unauthorized или 403 Forbidden, хотя логин и пароль вы вводите правильные. Здесь почти всегда дело не в самом пароле, а в правах доступа: в Nexus авторизация построена на связке «пользователь → роль → набор привилегий», и по умолчанию новый пользователь не имеет прав писать в конкретный репозиторий, даже если может в него читать.

Проверьте цепочку в Server Administration → Security → Roles и Privileges: у роли пользователя должна быть привилегия nx-repository-view-{format}-{repository}-add и -edit (или широкая nx-repository-view-*-*-* для админских ролей) на нужный репозиторий и формат. Для npm и Maven типичная ошибка — репозиторий подключён как hosted, но пользователь состоит только в роли с правами на proxy-репозитории.

Отдельная частая причина именно для Maven — не авторизация вовсе, а отсутствие креда в settings.xml у клиента:

<servers>
  <server>
    <id>nexus-releases</id>
    <username>deployer</username>
    <password>СильныйПароль</password>
  </server>
</servers>

Значение id в settings.xml должно буква в букву совпадать с id репозитория в pom.xml в блоке distributionManagement — при малейшем расхождении Maven просто не подставит креды, и сервер честно вернёт 401. Для npm аналогичная ловушка — токен из npm login не прописался в .npmrc проекта, а лежит только в глобальном; проверьте это командой npm whoami --registry=https://nexus.example.com/repository/npm-hosted/.

Docker-репозиторий не пробрасывается через реверс-прокси

Docker-репозиторий в Nexus устроен иначе, чем Maven или npm: он требует отдельного HTTP/HTTPS-коннектора с собственным портом, потому что Docker-клиент не умеет ходить по вложенному пути /repository/.... Если вы просто открыли Docker-репозиторий как обычный путь за общим Nginx на 443, docker login и docker push будут падать с ошибками вида «404 page not found» или «unauthorized: authentication required» даже при верных правах.

Правильная схема — выделенный порт для конкретного Docker-репозитория в настройках репозитория (HTTP или HTTPS Connector, например 8082), и отдельный server-блок в Nginx именно под этот порт:

server {
    listen 443 ssl;
    server_name docker.example.com;

    client_max_body_size 0;

    location / {
        proxy_pass http://127.0.0.1:8082;
        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;
    }
}

Ключевых момента два. Первый — client_max_body_size 0, иначе крупные слои образов будут обрываться на 413, как и в любом другом реверс-прокси перед реестром образов. Второй — домен Docker-репозитория должен резолвиться отдельно от основного домена Nexus (поддомен вроде docker.example.com), потому что Docker всегда обращается к порту 443 своего хоста и не умеет работать с путём в URL. Если общая логика реверс-прокси перед сервисами вам ещё не знакома, полезно заранее разобраться с типовыми граблями Nginx — они повторяются в любом сервисе за прокси, не только в Nexus.

Диск переполнен: blob-хранилища и cleanup policies

Nexus копит данные охотно и без напоминаний: каждый прокси-репозиторий кеширует всё, что через него когда-либо прошло, а хостируемые репозитории растут с каждым push. Через несколько месяцев активного использования /opt/sonatype-work/nexus3/blobs легко становится главным потребителем места на диске.

du -sh /opt/sonatype-work/nexus3/blobs/*
df -h

Первый шаг — не удалять файлы вручную (blob-хранилище Nexus имеет собственную структуру с метаданными, и ручное вмешательство его сломает), а настроить Cleanup Policies в Server Administration → Repository → Cleanup Policies. Задайте условия — например, удалять компоненты старше N дней или не скачивавшиеся дольше определённого срока — привяжите политику к репозиторию и запустите задачу очистки вручную или по расписанию через System → Tasks:

Task type: Cleanup repositories using their associated policy(ies)

Важный нюанс: применение cleanup policy помечает компоненты к удалению, но реальное освобождение места на диске в blob-хранилище происходит только после отдельной задачи Compact blob store — без неё старые данные логически удалены, но физически всё ещё занимают диск. Для прокси-репозиториев дополнительно проверьте Remove non-cataloged components — он чистит артефакты, которые больше не числятся в метаданных апстрима. Если место кончилось уже сейчас и разбираться с политиками некогда, экстренно освободить пару гигабайт можно через принудительный запуск Compact blob store на самом «тяжёлом» хранилище — но это разовая мера, а не замена регулярной чистки. Общие принципы того, что забивает диск на сервере и как с этим бороться системно, разобраны в статье про нехватку места на VPS.

Proxy-репозиторий не тянет пакеты у апстрима

Симптом: клиент запрашивает пакет через прокси-репозиторий Nexus (например, npm-proxy на registry.npmjs.org или Maven-proxy на Maven Central), а получает 404 или зависает надолго, хотя пакет точно существует. Причины здесь обычно сетевые, а не в самом Nexus.

Первое, что проверить — доступность апстрима напрямую с сервера:

curl -I https://registry.npmjs.org/express

Если сервер вообще не может достучаться до внешнего адреса (нет прямого доступа в интернет, нужен исходящий прокси), Nexus нужно явно настроить на использование HTTP-прокси в Server Administration → System → HTTP. Без этого прокси-репозиторий будет молча таймаутиться на каждом запросе. Вторая типичная причина — сертификат апстрима не в доверенном хранилище JVM, если у вас корпоративный или самоподписанный TLS где-то в цепочке; тогда в логе будет PKIX path building failed, и сертификат нужно добавить в keystore, которым пользуется Nexus.

Третья, менее очевидная причина — просто устаревший кеш метаданных. Nexus кеширует не только сами артефакты, но и ответы «not found» на определённое время, заданное в настройках прокси-репозитория (Negative Cache TTL). Если пакет только что появился в апстриме, а Nexus уже успел закешировать 404, повторный запрос вернёт тот же 404 до истечения TTL. Решение — вручную инвалидировать кеш через Invalidate cache в настройках репозитория, либо снизить Negative Cache TTL для быстро обновляющихся репозиториев.

Nexus не выдерживает нагрузку CI/CD и тормозит

Отдельная категория проблем — не ошибка, а деградация: Nexus поднимается и работает, но при параллельных запросах от CI-раннеров операции публикации становятся медленными, а иногда упираются в таймауты клиента. Чаще всего это тот же дефицит ресурсов, только не памяти, а диска и CPU: встроенная база Nexus и blob-хранилище активно пишут на диск, и на медленном сетевом или перегруженном диске это становится узким местом при нескольких параллельных пайплайнах.

Проверить, не диск ли тормозит систему, можно стандартными средствами мониторинга нагрузки на I/O, а если Nexus обслуживает несколько CI-раннеров одновременно — закладывать ресурсы стоит с запасом заранее, а не по факту первых жалоб команды. Если у вас уже настроен GitLab CI Runner или Jenkins рядом с Nexus на одном сервере, конкуренция за диск и память между ними — частый источник именно таких симптомов; при росте нагрузки логичнее развести артефактный сервер и раннеры CI по разным машинам, чем выжимать больше из одной. Практика настройки самого раннера и его типовые проблемы разобраны в статье про GitLab CI Runner на сервере — многие узкие места там пересекаются с Nexus, потому что оба сервиса активно пишут на диск при каждой сборке.

Если после чистки, cleanup policies и корректного heap Nexus всё ещё задыхается под нагрузкой команды, вопрос обычно не в настройках, а в самом сервере: артефактный менеджер любит одновременно быстрый диск, приличный объём RAM под JVM и стабильный канал наружу для проксирования апстримов. У MAATRIX можно арендовать VPS с NVMe-диском и нужным объёмом памяти под такие задачи в локациях RU, US и UK, с оплатой из России картой или криптой.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Сколько RAM нужно под Nexus Repository?

Минимум для тестового стенда — 2 ГБ, но для рабочей нагрузки с несколькими репозиториями и CI Sonatype рекомендует от 4 ГБ, иначе будут регулярные OutOfMemoryError под нагрузкой.

Почему после cleanup policy место на диске не освободилось?

Политика только помечает компоненты к удалению; физически blob-хранилище освобождается лишь после отдельной задачи Compact blob store.

Можно ли держать Docker- и Maven-репозитории на одном порту?

Нет, Docker-репозиторий требует отдельного HTTP/HTTPS-коннектора и, как правило, отдельного поддомена — Docker-клиент не умеет работать с вложенным путём в URL.

Почему прокси-репозиторий отдаёт 404 на пакет, который точно есть в апстриме?

Часто это устаревший негативный кеш (Negative Cache TTL); инвалидируйте кеш вручную в настройках репозитория или уменьшите TTL.

Где хранятся данные Nexus и что нужно бэкапить?

Все рабочие данные — база, blob-хранилища, конфигурация — лежат в /opt/sonatype-work/nexus3; именно эту директорию (а не каталог с дистрибутивом) нужно включать в резервное копирование.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →