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 계정과 위 비밀번호로 로그인하면 초기 설정 마법사가 실행된다.
- 새 비밀번호 설정
- 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로 메트릭 수집
'Infra' 카테고리의 다른 글
| Rocky Linux LVM 디스크 확장, 왜 명령을 4번 쳐야 할까 (0) | 2026.05.10 |
|---|---|
| 다중 브랜치 개발 환경에서 Flyway 교차 오염 막기 (0) | 2026.05.04 |
| Nexus Repository Manager에 HTTPS 적용하고 Docker Registry 추가하기 (0) | 2026.04.28 |