본문 바로가기
Infra

Nexus Repository Manager 구축하기

by Machine-Geon 2026. 4. 25.
반응형

Ubuntu 서버에 Nexus Repository Manager 구축하기

Maven Central 같은 외부 저장소를 매번 거치지 않고, 사내에서 라이브러리를 캐싱하고 공유할 수 있는 Nexus Repository Manager를 Ubuntu 서버에 직접 설치했다. 설치부터 Gradle 연동 테스트까지의 전 과정을 정리한다.

왜 Nexus가 필요한가

Gradle이나 Maven으로 빌드할 때마다 외부 저장소(Maven Central 등)에서 라이브러리를 받아온다. 팀 규모가 커지고 빌드가 잦아지면 몇 가지 문제가 생긴다.

  • 같은 라이브러리를 팀원마다 반복해서 다운로드
  • 외부 저장소 장애 시 빌드 중단
  • 내부에서 만든 JAR을 팀에 공유할 표준 경로 부재

Nexus는 이 세 가지를 한 번에 해결한다.

  • Proxy Repository: 외부에서 받은 라이브러리를 캐싱. 두 번째부턴 사내망에서 바로 제공.
  • Hosted Repository: 내부에서 만든 JAR 배포.
  • Group Repository: 여러 저장소를 하나의 URL로 묶어서 노출.

환경

  • OS: Ubuntu Server 24.04 LTS
  • Java: OpenJDK 21
  • Nexus: 3.91.1 (Community Edition)
  • 사용 도구: Gradle 8.14.3

1. Java 설치

Nexus 3은 Java 17 또는 21이 필요하다.

sudo apt update
sudo apt install -y openjdk-21-jre-headless
java -version

jre-headless가 뭔가

  • JRE (Java Runtime Environment): Java 프로그램 실행만 하는 런타임. 개발은 JDK, 실행은 JRE로 충분.
  • headless: GUI 관련 라이브러리(AWT, Swing 등)를 뺀 버전. 서버용 최소 설치.

서버는 화면 띄울 일이 없으니 headless가 용량도 작고 보안 공격면도 좁다.

패키지 포함 내용 용도

openjdk-21-jre-headless JVM + 코어 라이브러리 (GUI 제외) 서버
openjdk-21-jre headless + GUI 라이브러리 데스크톱 앱
openjdk-21-jdk-headless JRE-headless + javac 등 서버에서 빌드
openjdk-21-jdk 전체 포함 개발용

2. Nexus 다운로드 및 압축 해제

최신 다운로드 URL은 Sonatype 공식 다운로드 페이지에서 확인 가능. 글 작성 시점 기준이다.

cd /tmp
wget https://download.sonatype.com/nexus/3/nexus-3.91.1-04-linux-x86_64.tar.gz
sudo tar xzf nexus-3.91.1-04-linux-x86_64.tar.gz -C /opt/

폴더 이름 정리

버전 정보가 붙은 폴더명을 /opt/nexus로 심플하게 변경.

sudo mv /opt/nexus-3.91.1-04 /opt/nexus

압축 해제 시 생기는 두 폴더의 역할:

  • /opt/nexus: 애플리케이션 바이너리. 업그레이드 시 교체되는 영역
  • /opt/sonatype-work: 데이터, 설정, 아티팩트 저장소. 절대 삭제 금지

3. 전용 사용자 생성

보안상 root로 서비스를 돌리지 않고 전용 사용자를 생성.

sudo useradd -M -d /opt/nexus -s /bin/bash nexus
sudo chown -R nexus:nexus /opt/nexus /opt/sonatype-work

chown이 하는 일

chown -R nexus:nexus /opt/nexus /opt/sonatype-work을 분해.

부분 의미

chown change owner (소유권 변경)
-R Recursive, 하위 파일/폴더 모두
nexus:nexus <유저>:<그룹>
경로 2개 대상 폴더들 (공백으로 구분)

tar로 압축 풀 때 sudo를 썼으니 기본 소유자가 root다. nexus 사용자로 서비스를 돌리려면 소유권을 넘겨줘야 로그 기록, 데이터 저장 등이 가능하다.

4. systemd 서비스 등록

재부팅 후에도 자동으로 기동되도록 systemd에 등록.

sudo nano /etc/systemd/system/nexus.service

내용:

[Unit]
Description=Nexus Repository Manager
After=network.target

[Service]
Type=forking
LimitNOFILE=65536
ExecStart=/opt/nexus/bin/nexus start
ExecStop=/opt/nexus/bin/nexus stop
User=nexus
Group=nexus
Restart=on-abort
TimeoutStartSec=300

[Install]
WantedBy=multi-user.target

각 설정 의미

항목 의미

Description 서비스 설명 (systemctl status에 표시)
After=network.target 네트워크 준비된 후 시작
Type=forking nexus 스크립트가 백그라운드로 fork하는 동작 방식
LimitNOFILE=65536 파일 디스크립터 한도
ExecStart / ExecStop 시작/중지 명령
User / Group nexus 사용자로 실행 (root 아님)
Restart=on-abort 비정상 종료 시 자동 재시작
TimeoutStartSec=300 기동 대기 시간 5분
WantedBy=multi-user.target 부팅 시 자동 시작

서비스 시작

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

첫 기동은 1~3분 소요. 로그를 실시간으로 따라가며 완료 여부를 확인.

tail -f /opt/sonatype-work/nexus3/log/nexus.log

Started Sonatype Nexus OSS 메시지가 보이면 준비 완료. Ctrl+C로 빠져나옴.

자주 쓰는 systemctl 명령

# 시작/중지/재시작
sudo systemctl start nexus
sudo systemctl stop nexus
sudo systemctl restart nexus

# 자동 시작 관리
sudo systemctl enable nexus
sudo systemctl disable nexus

# 상태 확인
sudo systemctl status nexus
sudo systemctl is-enabled nexus

# 실시간 로그
sudo journalctl -u nexus -f

5. 웹 UI 접속

서버 IP 확인:

ip addr show | grep inet

브라우저에서 http://<서버IP>:8081 접속. 방화벽이 활성화되어 있다면 8081 포트를 오픈.

sudo ufw status
sudo ufw allow 8081/tcp

초기 admin 비밀번호

sudo cat /opt/sonatype-work/nexus3/admin.password

admin 계정과 위 비밀번호로 로그인하면 초기 설정 마법사가 실행된다.

  1. 새 비밀번호 설정
  2. Anonymous access 설정 (사내망 사용 시 Enable 권장)

Anonymous Access 의미

  • Enable: 사용자들이 자격증명 없이 라이브러리 검색/다운로드 가능. 관리 편함. 사내망 한정이면 권장.
  • Disable: 모든 접근에 ID/비밀번호 필요. 빌드 도구도 credentials 설정 필요.

Anonymous는 읽기만 허용. 업로드(쓰기)는 항상 계정 인증이 필요하므로 Enable이라고 해서 아무나 저장소를 망가뜨릴 수 없다.

마법사 이후에도 Settings → Security → Anonymous Access에서 언제든 변경 가능.

6. 네트워크 설정 (고정 IP)

Nexus를 팀 공용으로 쓰려면 서버 IP가 변경되지 않아야 한다. DHCP로 계속 받으면 IP가 바뀔 수 있으니 고정 필요.

현재 네트워크 상태 확인

# 유선 인터페이스명 확인
ip addr

# 게이트웨이 확인
ip route | grep default

네트워크 기본 개념

고정 IP 설정 전에 네 가지 개념을 이해하면 도움이 된다.

  • IP 주소: 네트워크에서의 "이름". 예: 192.xxx.xx.xxx.
  • 서브넷 마스크: 네트워크를 "동네 단위로 묶는 경계선". /24면 앞쪽 24비트가 같은 네트워크.
  • 게이트웨이: "동네 밖으로 나가는 정문". 보통 라우터/공유기의 주소.
  • DNS: "도메인 이름 → IP 변환기". google.com 같은 이름을 IP로 변환.

이 네 가지가 모두 있어야 정상적인 인터넷 통신이 가능하다.

netplan 설정

Ubuntu 18.04 이후는 netplan을 사용.

# 기존 파일 백업
sudo cp /etc/netplan/50-cloud-init.yaml /etc/netplan/50-cloud-init.yaml.bak

# 편집
sudo nano /etc/netplan/50-cloud-init.yaml

설정 예시 (값은 본인 환경에 맞게):

# netplan: Ubuntu의 네트워크 설정 도구

network:
  # netplan 문법 버전 (현재 v2가 표준)
  version: 2

  # 유선 이더넷 설정 섹션
  ethernets:
    # 인터페이스 이름 (ip addr로 확인한 이름 그대로)
    enp3s0:
      # DHCP 자동 할당 끄기 (고정 IP 사용)
      dhcp4: false

      # 고정 IP + 서브넷 마스크
      addresses:
        - 192.xxx.x.xxx/24

      # 라우팅 설정
      routes:
        - to: default                # 기본 경로 (모든 외부 통신)
          via: 192.xxx.x.x           # 게이트웨이 IP

      # DNS 서버
      nameservers:
        addresses:
          - 8.8.8.8                  # Google DNS
          - 1.1.1.1                  # Cloudflare DNS

YAML 문법 주의사항

  • 들여쓰기는 스페이스 2칸 (탭 금지)
  • 같은 레벨은 같은 칸수로 정렬
  • -는 리스트 항목
  • : 뒤엔 반드시 스페이스 한 칸

권한 설정 후 적용

# 평문으로 저장되는 파일이라 권한 조이기
sudo chmod 600 /etc/netplan/50-cloud-init.yaml

# 안전 적용 (120초 안에 Enter 안 누르면 자동 원복)
sudo netplan try

연결이 정상이면 Enter를 눌러 확정. 문제가 생겨도 120초 뒤 자동으로 이전 설정으로 돌아가니 SSH가 끊겨도 복구 가능하다.

확인

ip addr show enp3s0 | grep inet
ping -c 2 8.8.8.8
ping -c 2 google.com

세 가지 모두 정상이면 완료.

7. Gradle 연동 테스트

설치가 끝났으니 실제로 동작하는지 확인. 간단한 테스트 프로젝트 작성.

settings.gradle

rootProject.name = 'nexus-test'

build.gradle

plugins {
    id 'java'
}

group = 'com.example.test'
version = '0.0.1'

repositories {
    maven {
        // Nexus의 maven-public 그룹 저장소 사용
        // 기본 설치 시 이미 존재하며, maven-central을 프록시함
        url 'http://<서버IP>:8081/repository/maven-public/'

        // HTTP라서 필요 (HTTPS 붙이면 제거)
        allowInsecureProtocol = true
    }
}

dependencies {
    // 캐싱 테스트용 라이브러리 몇 개
    implementation 'org.apache.commons:commons-lang3:3.14.0'
    implementation 'com.google.guava:guava:33.0.0-jre'
    implementation 'org.slf4j:slf4j-api:2.0.12'

    testImplementation 'org.junit.jupiter:junit-jupiter:5.10.2'
}

test {
    useJUnitPlatform()
}

간단한 실행 코드

src/main/java/com/example/test/App.java:

package com.example.test;

import com.google.common.base.Strings;
import org.apache.commons.lang3.StringUtils;

public class App {
    public static void main(String[] args) {
        String greeting = Strings.repeat("nexus ", 2).trim();
        System.out.println(StringUtils.capitalize(greeting) + " works!");
    }
}

빌드 실행

# 로컬 Gradle 캐시 비우고 순수 Nexus에서 받도록
rm -rf ~/.gradle/caches/modules-2

# 빌드
gradle build --refresh-dependencies

--refresh-dependencies는 로컬 캐시를 무시하고 원격에서 새로 받도록 강제.

결과 확인

빌드 성공 후 세 가지를 확인.

1. 빌드 메시지

BUILD SUCCESSFUL in 7s

2. Nexus UI에서 캐싱 확인

브라우저에서 http://<서버IP>:8081 접속 → Browse → maven-central 클릭 → 다음 경로 확인:

  • org/apache/commons/commons-lang3/3.14.0/
  • com/google/guava/guava/33.0.0-jre/
  • org/slf4j/slf4j-api/2.0.12/

파일들이 보이면 Gradle → Nexus → Maven Central 프록시 체인이 동작 중.

3. 두 번째 빌드 속도

gradle build --refresh-dependencies

캐시 비우고 돌려도 1초 만에 끝나면 완전히 Nexus에서만 받아왔다는 증거. (외부 인터넷 경유면 최소 5초 이상 소요)

8. 운영 팁

자동 시작 검증

재부팅 후 자동으로 올라오는지 확인:

sudo reboot
# 1~2분 대기 후
curl -I http://<서버IP>:8081

HTTP/1.1 200 OK 또는 302 응답이 오면 정상.

데이터 백업

Nexus의 모든 데이터는 /opt/sonatype-work/nexus3/에 위치. 주기적으로 이 폴더만 백업하면 복구 가능.

간단한 백업 예시:

tar czf nexus-backup-$(date +%Y%m%d).tar.gz /opt/sonatype-work/nexus3/

로그 위치

  • systemd 로그: sudo journalctl -u nexus
  • 애플리케이션 로그: /opt/sonatype-work/nexus3/log/nexus.log

9. 이후 고도화 방향

기본 구축 이후 필요해질 때 하나씩 추가하면 된다.

  • HTTPS 적용: 사내 인증서로 SSL 설정 후 allowInsecureProtocol = true 제거
  • 계정 체계 정비: 팀별 Role 분리, CI 전용 계정
  • 내부 JAR 배포: Hosted Repository에 publishing 설정 추가
  • 정기 백업 자동화: cron으로 주기 백업
  • 모니터링: Prometheus exporter로 메트릭 수집
반응형