Nexus Repository 3 은 기본적으로 내장 데이터베이스(H2)를 쓴다. 외부 PostgreSQL 로 바꾸는 기능은 Pro 에디션 기능이다. OSS(Community) 에디션에서는 환경 변수나 설정을 넣어도 동작하지 않는다. 라이선스를 먼저 확인한다.
에디션 확인은 관리 화면의 System > Information 이나 기동 로그에서 한다.
Pro 에디션에서 설정하는 곳은 환경 변수가 아니라 /nexus-data/etc/nexus.properties 다. NEXUS_DB_HOST 같은 환경 변수는 공식 설정 항목이 아니므로 넣어도 읽히지 않는다.
nexus.datastore.enabled=true
nexus.datastore.nexus.jdbcUrl=jdbc:postgresql://postgresql:5432/nexus
nexus.datastore.nexus.username=nexus
nexus.datastore.nexus.password=${PASSWORD}
컨테이너로 띄운다면 이 파일을 볼륨으로 넣는다.
services:
postgresql:
image: postgres:16-bookworm
container_name: nexus-postgres
environment:
POSTGRES_USER: nexus
POSTGRES_PASSWORD: ${PASSWORD}
POSTGRES_DB: nexus
volumes:
- ./volumes/postgresql/data:/var/lib/postgresql/data
networks: [service-network]
nexus3:
image: sonatype/nexus3:3.83.2
container_name: nexus3
depends_on: [postgresql]
ports:
- "8081:8081"
environment:
INSTALL4J_ADD_VM_PARAMS: "-Xms2703m -Xmx2703m -XX:MaxDirectMemorySize=2703m"
volumes:
- ./volumes/nexus/nexus-data:/nexus-data
networks: [service-network]
networks:
service-network:
driver: bridge
이미지 이름에 주의한다. PostgreSQL 공식 이미지는 postgres 이고 postgresql 이 아니다. Nexus 는 Docker Hub 에서 sonatype/nexus3 다.
기존 내장 DB 에서 PostgreSQL 로 데이터를 옮기려면 Sonatype 이 제공하는 마이그레이션 절차를 따라야 한다. 설정만 바꾸면 빈 저장소로 새로 시작한다.
nexus-data 는 컨테이너 안의 nexus 계정(UID 200)이 써야 한다. 호스트 디렉터리를 그냥 마운트하면 권한 오류로 기동이 멈추거나 아래 경고가 반복된다.
WARN [main] *SYSTEM java.util.prefs - Couldn't create user preferences directory.
mkdir -p ./volumes/nexus/nexus-data
chown -R 200:200 ./volumes/nexus/nexus-data
No active profile set, falling back to 1 default profile: "default" 는 Spring Boot 의 정보성 메시지이며 오류가 아니다. 이것을 원인으로 보고 시간을 쓰지 않는다.
INSTALL4J_ADD_VM_PARAMS 로 준다. 최소 요구치가 있으므로 임의로 낮추면 기동에 실패하거나 경고가 난다. -Xms 와 -Xmx 를 같게 주고, MaxDirectMemorySize 는 힙과 비슷하게 잡는 것이 권장 구성이다. 컨테이너 메모리 한도는 그 합보다 여유 있게 잡는다.
Nginx Proxy Manager 같은 프록시를 앞에 두면 Nexus 가 자기 주소를 잘못 만들어 로그인 후 내부 주소로 리다이렉트되는 일이 생긴다. Base URL 을 지정하고 프록시가 원래 호스트 정보를 넘기게 한다.
관리 화면의 System > Capabilities 에서 Base URL capability 를 추가하고 외부 주소를 넣는다.
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 0;
client_max_body_size 0 을 빠뜨리면 큰 아티팩트 업로드가 413 으로 막힌다.
Error response from daemon: login attempt to https://registry.example.com/v2/ failed with status: 404 Not Found
Docker 클라이언트는 레지스트리 API 를 항상 도메인 루트의 /v2/ 에서 찾는다. https://example.com/registry/v2/ 같은 하위 경로는 지원하지 않는다. 경로 기반 프록시로 붙이면 반드시 깨진다.
Nexus 쪽도 조건이 있다. Docker 호스티드·프록시 저장소는 자기 HTTP 커넥터 포트를 따로 가져야 한다. 저장소 설정에서 HTTP 포트(예: 5000)를 열고, 프록시는 그 포트로 보낸다.
nexus.example.com -> nexus3:8081 (관리 화면과 Maven·npm 저장소)
registry.example.com -> nexus3:5000 (Docker 저장소)
확인은 다음으로 한다.
curl -i https://registry.example.com/v2/
docker login registry.example.com
정상이면 401 Unauthorized 와 Www-Authenticate 헤더가 온다. 404 면 아직 Docker 커넥터가 아니라 다른 곳으로 가고 있는 것이다.
하위 경로를 꼭 써야 한다면 Nexus 의 Docker Subdomain 기능이나 Docker Bearer Token Realm 설정을 확인하되, 클라이언트가 지원하지 않는 이상 근본 해결은 서브도메인 분리다.
브라우저 화면에 이 메시지가 계속 뜨는 것은 프런트엔드가 백엔드와의 연결을 잃었다고 판단해 새로 고침하는 것이다. 프록시가 WebSocket 또는 긴 연결을 끊는 경우가 대부분이다.
proxy_read_timeout 600s;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
컨테이너가 실제로 재시작을 반복하고 있는 경우도 있으므로 먼저 확인한다.
docker ps -a --filter name=nexus3
docker logs --tail 100 nexus3