Tutorial completo de referência para subir e operar o Sonatype Nexus Repository Manager 3 (OSS) em um servidor. O foco aqui é o uso como cache/proxy de dependências Maven e npm, registry Docker privado e repositório raw para artefatos diversos, atrás de um nginx com TLS Let’s Encrypt.
1. Visão geral
O Sonatype Nexus Repository é um gerenciador de artefatos universal. Ele cumpre três papéis:
- Proxy de registries públicos — em vez de bater no Maven Central, npm registry ou Docker Hub a cada build, o Nexus baixa uma vez e serve do cache local. Reduz banda, deixa o build mais rápido e funciona offline.
- Hosted (privado) — hospeda artefatos próprios (jars internos, pacotes npm privados, imagens Docker da empresa).
- Group (agrupamento) — combina vários repositórios do mesmo formato numa única URL pública. Cliente vê 1 endpoint, Nexus resolve internamente a ordem de busca.
Formatos suportados (OSS 3.x)
maven2, npm, docker, raw, pypi, helm, nuget, rubygems, gitlfs, r, apt, yum, conda, cocoapods, bower, go, composer.
Tipos de repositório
| Tipo | Função | Exemplo |
|---|---|---|
proxy | Espelha um remoto, cacheia downloads | maven-central -> repo1.maven.org |
hosted | Armazena artefatos publicados por você | maven-releases, docker-internal |
group | Combina proxy + hosted num só endpoint | maven-public, npm-group |
OSS vs Pro
| Recurso | OSS | Pro |
|---|---|---|
| Maven, npm, Docker, raw, pypi etc. | sim | sim |
| Cleanup policies | sim | sim |
| LDAP / SAML | LDAP apenas | LDAP + SAML + Crowd |
| HA / cluster | nao | sim |
| Staging / RBAC granular | nao | sim |
| Blob store S3 / Azure | nao | sim |
| Repository Firewall integration | nao | sim |
| Suporte comercial | nao | sim |
Para uso em ambiente interno e cache de CI, OSS atende sobrando.
2. Arquitetura
flowchart LR
subgraph Dev[Dev / CI]
A[mvn / gradle]
B[npm / pnpm]
C[docker push]
end
subgraph Edge[Servidor - nginx-proxy]
N1[nexus.example.com<br/>TLS LE]
N2[registry.example.com<br/>TLS LE - docker hosted]
N3[docker-proxy.example.com<br/>TLS LE - docker proxy]
end
subgraph Nexus[container sonatype/nexus3]
UI[Web UI / REST<br/>:8081]
DH[connector docker hosted<br/>:5001]
DP[connector docker proxy<br/>:5002]
BS[(blob store<br/>/nexus-data/blobs)]
DB[(H2 / Postgres<br/>/nexus-data/db)]
end
A -->|HTTPS 443| N1 --> UI
B -->|HTTPS 443| N1
C -->|HTTPS 443| N2 --> DH
C -.pull.-> N3 --> DP
UI --> BS
UI --> DB
DH --> BS
DP --> BSFluxo de um docker push do CI:
sequenceDiagram
participant CI as CI Runner
participant NG as nginx-proxy
participant NX as Nexus (5001)
participant FS as blob store
CI->>NG: POST /v2/myimg/blobs/uploads/ (Bearer)
NG->>NX: proxy (HTTP, proxy_request_buffering off)
NX->>NX: valida token (Docker Bearer Realm)
NX->>FS: grava layer
NX-->>NG: 201 Created
NG-->>CI: 201 Created
CI->>NG: PUT /v2/myimg/manifests/tag
NG->>NX: proxy
NX->>FS: grava manifest
NX-->>CI: 201 Created3. Pré-requisitos
- Docker Engine 24+ e Docker Compose v2
- 4 GB de RAM dedicados ao container (Nexus e uma JVM, ~2 GB heap + 2 GB direct memory + overhead). Em servidor pequeno, planeje 6 GB totais com folga
- Volume rapido (SSD/NVMe) montado em
/nexus-data. Storage de blobs cresce rapido se for cachear muito (Maven Central completo passa de 30 GB) - Dominio com DNS apontando pro servidor:
nexus.example.com,registry.example.com - nginx-proxy ja rodando com Let’s Encrypt
- Network Docker compartilhada (
proxy) entre nginx e Nexus
Sanity check:
docker network ls | grep proxy
df -h /var/lib/docker
free -h4. Instalacao com docker compose
A imagem oficial e sonatype/nexus3. O processo dentro do container roda como UID 200, entao o volume precisa ser gravavel por esse uid (use volume nomeado do Docker em vez de bind mount para evitar dor de cabeca com permissoes).
Edite /opt/docker/docker-compose.yaml (ou um override dedicado):
services:
nexus:
image: sonatype/nexus3:3.74.0
container_name: nexus
restart: unless-stopped
ulimits:
nofile:
soft: 65536
hard: 65536
environment:
# Heap fixo (Xms = Xmx evita resize) + direct memory para indices
INSTALL4J_ADD_VM_PARAMS: >-
-Xms2g -Xmx2g -XX:MaxDirectMemorySize=2g
-Djava.util.prefs.userRoot=/nexus-data/javaprefs
volumes:
- nexus-data:/nexus-data
networks:
- proxy
# Sem ports: expondo so' via nginx
expose:
- "8081"
- "5001"
- "5002"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8081/service/rest/v1/status"]
interval: 30s
timeout: 10s
retries: 10
start_period: 180s
volumes:
nexus-data:
driver: local
networks:
proxy:
external: trueSuba:
docker compose up -d nexus
docker compose logs -f nexusO primeiro boot leva 2-3 minutos. Aguarde a linha Started Sonatype Nexus OSS X.Y.Z.
Pontos de atencao
- Nao use
latestem producao (rebuilds quebram). Pin na minor (3.74.0). - Se preferir bind mount, garanta
chown -R 200:200 /caminho/no/host. INSTALL4J_ADD_VM_PARAMSprecisa estar numa unica linha logica (use>-do YAML).- A porta
8081e o web/REST. As portas5001e5002so funcionam depois de criar os connectors Docker (passo 8).
5. Bootstrap inicial
A senha inicial do admin e gerada no primeiro boot e gravada num arquivo dentro do volume:
docker exec nexus cat /nexus-data/admin.passwordAcesse https://nexus.example.com (depois que o nginx estiver configurado, secao 9; pode usar kubectl port-forward/SSH tunnel pro 8081 enquanto isso).
Setup wizard:
- Clique em “Sign In” -> usuario
admin+ senha do arquivo - Defina uma nova senha forte e guarde no gerenciador
- Anonymous access: para ambiente interno onde voce confia na rede, marque “Enable anonymous access”. Para Internet exposto, mantenha disabled (forca login pra pull).
- Finalize
Apague o arquivo de senha:
docker exec nexus rm /nexus-data/admin.password6. Repositorios Maven
Vamos criar a hierarquia padrao: 1 proxy + 2 hosted + 1 group.
6.1 maven-central (proxy)
Administration -> Repository -> Repositories -> Create repository -> maven2 (proxy)
- Name:
maven-central - Online: marcado
- Remote storage:
https://repo1.maven.org/maven2/ - Version policy:
Release - Layout policy:
Strict - Blob store:
default - Strict Content Type Validation: marcado
6.2 maven-releases (hosted)
Create repository -> maven2 (hosted)
- Name:
maven-releases - Version policy:
Release - Deployment policy:
Disable redeploy(impede sobrescrever release; bloqueia bug comum)
6.3 maven-snapshots (hosted)
Create repository -> maven2 (hosted)
- Name:
maven-snapshots - Version policy:
Snapshot - Deployment policy:
Allow redeploy
6.4 maven-public (group)
Create repository -> maven2 (group)
- Name:
maven-public - Members (nesta ordem):
maven-releases,maven-snapshots,maven-central
A URL publica vira: https://nexus.example.com/repository/maven-public/
6.5 Configuracao do cliente
~/.m2/settings.xml:
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0">
<mirrors>
<mirror>
<id>nexus</id>
<name>Nexus Public</name>
<url>https://nexus.example.com/repository/maven-public/</url>
<mirrorOf>*</mirrorOf>
</mirror>
</mirrors>
<servers>
<server>
<id>nexus-releases</id>
<username>${env.NEXUS_USER}</username>
<password>${env.NEXUS_PASS}</password>
</server>
<server>
<id>nexus-snapshots</id>
<username>${env.NEXUS_USER}</username>
<password>${env.NEXUS_PASS}</password>
</server>
</servers>
<profiles>
<profile>
<id>nexus</id>
<repositories>
<repository>
<id>central</id>
<url>https://nexus.example.com/repository/maven-public/</url>
<releases><enabled>true</enabled></releases>
<snapshots><enabled>true</enabled></snapshots>
</repository>
</repositories>
</profile>
</profiles>
<activeProfiles>
<activeProfile>nexus</activeProfile>
</activeProfiles>
</settings>Gradle (build.gradle de uma aplicacao Spring Boot, por exemplo):
repositories {
maven {
url 'https://nexus.example.com/repository/maven-public/'
}
}
publishing {
repositories {
maven {
def releasesRepoUrl = 'https://nexus.example.com/repository/maven-releases/'
def snapshotsRepoUrl = 'https://nexus.example.com/repository/maven-snapshots/'
url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
credentials {
username = System.getenv('NEXUS_USER')
password = System.getenv('NEXUS_PASS')
}
}
}
}7. Repositorios npm
7.1 Criar
npm-proxy(proxy dehttps://registry.npmjs.org/)npm-hosted(hosted, para pacotes internos; deploymentAllow redeploy off)npm-group(group, ordem:npm-hosted,npm-proxy)
URL publica: https://nexus.example.com/repository/npm-group/
7.2 Habilitar realm npm
Security -> Realms -> mova npm Bearer Token Realm para “Active”. Isso permite npm login direto contra o Nexus.
7.3 Configurar .npmrc
Dois caminhos: login interativo (gera authToken) ou auth basico em base64.
Opcao A — npm login (recomendado):
npm login --registry=https://nexus.example.com/repository/npm-group/
# usuario / senha / email do NexusResultado no ~/.npmrc:
registry=https://nexus.example.com/repository/npm-group/
//nexus.example.com/repository/npm-group/:_authToken=NpmToken.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
always-auth=trueOpcao B — auth basico (CI/CD):
echo -n 'ci-user:s3nh4-forte' | base64
# Y2ktdXNlcjpzM25oNC1mb3J0ZQ==.npmrc:
registry=https://nexus.example.com/repository/npm-group/
_auth=Y2ktdXNlcjpzM25oNC1mb3J0ZQ==
email=ci@example.com
always-auth=true7.4 Publicar pacote interno
package.json:
{
"name": "@empresa/ui-components",
"version": "1.0.0",
"publishConfig": {
"registry": "https://nexus.example.com/repository/npm-hosted/"
}
}npm publish7.5 Migrar um frontend Vue
Em um frontend Vue (ou monorepo equivalente), basta criar um .npmrc na raiz do projeto com registry=... apontando para npm-group. Commitar sem _authToken; o token vai como secret no CI.
8. Docker Registry
Docker e o caso mais sensivel — clientes Docker tem restricoes que dificultam path-based routing.
8.1 Criar repositorios
docker-hub(proxy dehttps://registry-1.docker.io, indiceUse Docker Hub)docker-hosted(hosted; deploymentAllow redeployparalatest/tags moveis, ouDisablese voce versiona estritamente)docker-group(group:docker-hosted+docker-hub)
8.2 Conectores HTTP
No editor do repositorio, secao Repository Connectors:
| Repositorio | HTTP connector | HTTPS connector |
|---|---|---|
| docker-hosted | 5001 | (deixar vazio, TLS no nginx) |
| docker-group | 5002 | (idem) |
Marque “Force basic authentication” desativado (vamos usar Bearer). Marque “Allow anonymous docker pull” se quiser pull sem login pelo group.
Para que os connectors funcionem, exponha as portas no compose (passo 4 ja tem expose: 5001 5002).
8.3 Habilitar Docker Bearer Token Realm
Security -> Realms -> mova Docker Bearer Token Realm para “Active”. Sem isso, docker login falha com erros bizarros.
8.4 Por que subdominios > subpath
O Docker client envia requests para /v2/... na raiz do host. Se voce expoe Nexus em https://nexus.example.com/repository/docker-hosted/, o client manda /v2/ e o nginx tem que reescrever — funciona para pull, quebra para push (uploads de blobs grandes, auth challenge, etc).
A pratica padrao e:
registry.example.com-> connector5001(docker-hosted, push/pull internos)docker.example.com(ou outro) -> connector5002(docker-group, pull cacheado)
Cada subdominio respondendo /v2/ na raiz. O Nexus mapeia o subdominio para o repo via porta.
8.5 Login e uso
docker login registry.example.com
# username / password
docker tag api-backend:1.2.3 \
registry.example.com/api-backend:1.2.3
docker push registry.example.com/api-backend:1.2.3
# Pull cacheado de Docker Hub via group
docker pull docker.example.com/library/postgres:16-alpine9. Nginx reverse proxy
Tres server blocks: web UI, docker-hosted, docker-group.
/opt/docker/nginx/conf.d/nexus.conf:
# Web UI + REST API
server {
listen 443 ssl http2;
server_name nexus.example.com;
ssl_certificate /etc/letsencrypt/live/nexus.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/nexus.example.com/privkey.pem;
client_max_body_size 1G;
location / {
proxy_pass http://nexus:8081;
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;
proxy_read_timeout 600s;
}
}/opt/docker/nginx/conf.d/register.conf (docker hosted):
server {
listen 443 ssl http2;
server_name registry.example.com;
ssl_certificate /etc/letsencrypt/live/registry.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/registry.example.com/privkey.pem;
# Layers Docker podem passar de 1GB
client_max_body_size 5G;
chunked_transfer_encoding on;
proxy_request_buffering off;
proxy_buffering off;
# Sinaliza ao cliente que e API v2
add_header Docker-Distribution-Api-Version registry/2.0 always;
location / {
proxy_pass http://nexus:5001;
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;
proxy_read_timeout 900s;
proxy_send_timeout 900s;
}
}/opt/docker/nginx/conf.d/docker-proxy.conf (docker group, opcional):
server {
listen 443 ssl http2;
server_name docker.example.com;
ssl_certificate /etc/letsencrypt/live/docker.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/docker.example.com/privkey.pem;
client_max_body_size 5G;
chunked_transfer_encoding on;
proxy_request_buffering off;
proxy_buffering off;
add_header Docker-Distribution-Api-Version registry/2.0 always;
location / {
proxy_pass http://nexus:5002;
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;
proxy_read_timeout 900s;
}
}Recarrega:
docker exec nginx-proxy nginx -t && docker exec nginx-proxy nginx -s reloadPontos criticos para Docker:
proxy_request_buffering off— sem isso, layers grandes estouram disco do nginx ou time outclient_max_body_sizegenerosochunked_transfer_encoding on— Docker manda blobs em chunkedDocker-Distribution-Api-Version— alguns clients chamamGET /v2/so’ pra checar essa header
10. Realms e autenticacao
Security -> Realms. Ative em ordem:
Local Authenticating Realm(sempre)Local Authorizing Realm(sempre)Docker Bearer Token Realm(se usar Docker)npm Bearer Token Realm(se usar npm login)LDAP Realm(opcional)
Usuarios e roles
Security -> Users -> Create local user:
ci-botpara CI/CDdevpara acesso humano
Security -> Roles -> Create role:
| Role | Privilegios |
|---|---|
developers | nx-repository-view-*-*-read, nx-repository-view-*-*-browse |
maven-publishers | nx-repository-view-maven2-maven-releases-*, idem snapshots |
docker-publishers | nx-repository-view-docker-docker-hosted-add, -edit, -read |
ci-bot | union das tres anteriores |
Atribua roles aos usuarios em Users -> <user> -> Roles.
LDAP (opcional)
Security -> LDAP -> Create connection. Util se voce ja tem Keycloak/AD; para ambiente single-user nao compensa.
11. Cleanup policies
Sem limpeza, o blob store cresce indefinidamente. Crie politicas e agende a task de cleanup.
Administration -> Repository -> Cleanup Policies -> Create Cleanup Policy:
Policy: snapshots-old
- Format:
maven2 - Component age:
30dias - Component usage: deixar vazio
- (Pro apenas) Retain N versions
Policy: docker-untagged
- Format:
docker - Asset regex: deixar vazio
- Components:
Only untagged components
Aplique no repo: Repositories -> <repo> -> Cleanup -> Apply.
Agendar tasks
Administration -> System -> Tasks -> Create task:
- Admin - Cleanup repositories using their associated policies — diaria 03:00
- Admin - Compact blob store — semanal 04:00 (libera espaco efetivamente)
- Maven - Delete unused SNAPSHOT — semanal (mantém ultimo N)
- Docker - Delete unused manifests and images — semanal
As tasks fazem soft delete (marcam como deletado). O compact blob store e quem efetivamente libera disco.
12. Backup
Nexus 3 modernos (3.71+) usam H2 (ou Postgres no Pro). Em versoes antigas era OrientDB.
Backup logico (recomendado)
Administration -> System -> Tasks -> Create task -> Admin - Export databases for backup:
- Output path:
/nexus-data/backup - Schedule: diaria 02:00
Isso exporta um dump consistente sem precisar parar o Nexus.
Backup do blob store + configs
Os arquivos binarios ficam em /nexus-data/blobs/. Strategy mais seguro:
# 1. Roda a task de export pra ter db consistente
# 2. Tar dos blobs + db dump
docker exec nexus tar czf /tmp/nexus-backup.tar.gz \
/nexus-data/backup \
/nexus-data/blobs \
/nexus-data/etc
docker cp nexus:/tmp/nexus-backup.tar.gz /root/backups/nexus-$(date +%F).tar.gzPara backup completo offline (mais lento, mais seguro):
docker compose stop nexus
tar czf /root/backups/nexus-full-$(date +%F).tar.gz \
-C /var/lib/docker/volumes/infra_nexus-data/_data .
docker compose start nexusRestore
- Parar Nexus
- Apagar conteudo do volume
- Extrair tar
- Subir Nexus
- Se backup logico:
Administration -> System -> Tasks -> Admin - Restore databases from backupno proximo boot (Nexus detecta o dump em/nexus-data/backupe oferece restore)
Teste o restore numa VM separada antes de precisar.
13. HA e storage
OSS nao tem HA — instancia unica, ponto. Se cair, cai. Mitigacoes:
- Healthcheck no compose +
restart: unless-stopped - Monitor com Uptime Kuma ou similar
- Backup automatizado (secao 12)
- Volume em disco com snapshots (LVM, ZFS, BTRFS)
Blob store: OSS aceita filesystem local. S3/Azure blob store sao recursos Pro. Para crescer:
Administration -> Repository -> Blob Stores -> Create -> File
Name: blobs-extra
Path: /nexus-data/blobs-extraRepos novos podem usar o blob novo. Repos existentes nao migram facilmente — planeje antes.
14. Integracao com CI (GitHub Actions / Gitea Actions)
Secrets
No GitHub Actions (ou Gitea Actions), configure:
NEXUS_USER=ci-botNEXUS_PASS= senha forte doci-bot
Push de imagem Docker
.github/workflows/build.yml:
name: build-and-push
on:
push:
tags: ['v*']
jobs:
docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Log in to Nexus registry
run: |
echo "${{ secrets.NEXUS_PASS }}" \
| docker login registry.example.com \
-u "${{ secrets.NEXUS_USER }}" --password-stdin
- name: Build
run: |
docker build -t registry.example.com/api-backend:${GITHUB_REF_NAME} .
- name: Push
run: |
docker push registry.example.com/api-backend:${GITHUB_REF_NAME}Maven deploy (Gradle)
- name: Publish to Nexus
env:
NEXUS_USER: ${{ secrets.NEXUS_USER }}
NEXUS_PASS: ${{ secrets.NEXUS_PASS }}
run: ./gradlew publishnpm publish
- name: Setup .npmrc
run: |
cat > ~/.npmrc <<EOF
registry=https://nexus.example.com/repository/npm-group/
//nexus.example.com/repository/npm-hosted/:_authToken=${{ secrets.NEXUS_NPM_TOKEN }}
always-auth=true
EOF
- run: npm publish --registry=https://nexus.example.com/repository/npm-hosted/15. Troubleshooting
”503 Service Unavailable” no UI
Quase sempre OOM da JVM. Cheque:
docker stats nexus
docker exec nexus tail -100 /nexus-data/log/nexus.log | grep -i "OutOfMemory\|GC"Suba -Xmx no INSTALL4J_ADD_VM_PARAMS (mas garanta RAM no host).
”Repository does not allow updating assets”
Voce tentou re-publicar um release com a mesma versao. Comportamento correto da policy Disable redeploy. Solucoes:
- Bumpa a versao
- (Apenas em dev) temporariamente troca a policy para
Allow redeploy
docker push: “blob upload invalid” ou trava em 50%
Problema de buffering no nginx. Garanta:
proxy_request_buffering off;
client_max_body_size 5G;E que a porta interna do connector docker bate com o proxy_pass.
docker login retorna unauthorized: authentication required mesmo com senha certa
Faltou ativar o Docker Bearer Token Realm em Security -> Realms.
Disk full
du -sh /var/lib/docker/volumes/infra_nexus-data/_data/blobs/*Rodar manualmente:
Admin - Cleanup repositories using their associated policiesAdmin - Compact blob store
Se urgente, considere apagar repos proxy inteiros (eles re-cacheiam sob demanda).
”Index out of date” em busca
Administration -> System -> Tasks -> Create task -> Repair - Rebuild repository search index. Roda uma vez.
Permissoes ao migrar para bind mount
docker compose stop nexus
chown -R 200:200 /caminho/do/bind
docker compose start nexus16. Referencias
- Docs oficiais: https://help.sonatype.com/repomanager3
- Imagem Docker oficial: https://github.com/sonatype/docker-nexus3
- Docker Hub: https://hub.docker.com/r/sonatype/nexus3
- npm com user tokens: https://support.sonatype.com/hc/en-us/articles/115015110067-Repository-Using-User-Tokens-with-npm
- Cleanup policies: https://help.sonatype.com/repomanager3/nexus-repository-administration/repository-management/cleanup-policies
- Maven repos: https://help.sonatype.com/repomanager3/nexus-repository-administration/formats/maven-repositories
- Docker SSL/connectors guide: https://help.sonatype.com/repomanager3/nexus-repository-administration/formats/docker-registry