Set up Nexus Repository Manager OSS with SSL-enabled Docker registry, Maven repositories, and automated backups for secure artifact management in enterprise environments.
Prerequisites
- Root access to server
- Domain name with DNS access
- Minimum 4GB RAM
- Java 17 compatible system
What this solves
Nexus Repository Manager provides centralized artifact management for Docker images, Maven packages, npm modules, and other development artifacts. This tutorial sets up Nexus OSS with SSL/TLS encryption, Docker registry authentication, and automated backup strategies for production environments.
Step-by-step installation
Update system packages
Start by updating your package manager to ensure you get the latest versions of dependencies.
sudo apt update && sudo apt upgrade -y
Install Java 17
Nexus Repository Manager requires Java 17 or later. Install OpenJDK 17 which provides the required runtime environment.
sudo apt install -y openjdk-17-jdk wget unzip
Verify Java installation:
java -version
Create Nexus user and directories
Create a dedicated system user for Nexus and set up the required directory structure with proper permissions.
sudo useradd --system --no-create-home --shell /bin/false nexus
sudo mkdir -p /opt/nexus /opt/sonatype-work
sudo chown nexus:nexus /opt/nexus /opt/sonatype-work
Download and install Nexus Repository Manager
Download the latest Nexus OSS release and extract it to the installation directory.
cd /tmp
wget https://download.sonatype.com/nexus/3/latest-unix.tar.gz
sudo tar -xzf latest-unix.tar.gz -C /opt/
sudo mv /opt/nexus-3.* /opt/nexus/nexus-3
sudo ln -s /opt/nexus/nexus-3 /opt/nexus/current
sudo chown -R nexus:nexus /opt/nexus /opt/sonatype-work
Configure Nexus JVM settings
Optimize Java memory settings for production use. Adjust these values based on your server's available RAM.
-Xms2g
-Xmx2g
-XX:MaxDirectMemorySize=3g
-XX:+UnlockExperimentalVMOptions
-XX:+UseCGroupMemoryLimitForHeap
-XX:+UseG1GC
-XX:+UseStringDeduplication
-Dkaraf.home=.
-Dkaraf.base=.
-Dkaraf.etc=etc/karaf
-Djava.util.logging.config.file=etc/karaf/java.util.logging.properties
-Dkaraf.data=../sonatype-work/nexus3
-Dkaraf.log=../sonatype-work/nexus3/log
-Djava.io.tmpdir=../sonatype-work/nexus3/tmp
Set proper ownership on the configuration file:
sudo chown nexus:nexus /opt/nexus/current/bin/nexus.vmoptions
Configure Nexus application properties
Set the data directory location and configure basic application settings.
# Nexus default properties
nexus.port=8081
nexus.host=0.0.0.0
nexus.context-path=/
Data directory
karaf.data=/opt/sonatype-work/nexus3
karaf.log=/opt/sonatype-work/nexus3/log
Create systemd service
Set up a systemd service to manage Nexus startup, shutdown, and automatic restart on boot.
[Unit]
Description=Nexus Repository Manager
After=network.target
[Service]
Type=forking
LimitNOFILE=65536
ExecStart=/opt/nexus/current/bin/nexus start
ExecStop=/opt/nexus/current/bin/nexus stop
User=nexus
Restart=on-abort
TimeoutSec=600
[Install]
WantedBy=multi-user.target
Configure Nexus to run as the nexus user:
echo 'run_as_user="nexus"' | sudo tee /opt/nexus/current/bin/nexus.rc
sudo systemctl daemon-reload
sudo systemctl enable nexus
sudo systemctl start nexus
Configure firewall
Open the required ports for Nexus web interface and Docker registry access.
sudo ufw allow 8081/tcp
sudo ufw allow 8082/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
Initial Nexus setup
Wait for Nexus to start completely, then retrieve the initial admin password.
sudo journalctl -u nexus -f
Once you see "Started Sonatype Nexus OSS" in the logs, retrieve the admin password:
sudo cat /opt/sonatype-work/nexus3/admin.password
Configure SSL/TLS with NGINX reverse proxy
Install and configure NGINX
Set up NGINX as a reverse proxy to handle SSL termination and provide better performance.
sudo apt install -y nginx certbot python3-certbot-nginx
Configure NGINX for Nexus
Create a virtual host configuration for Nexus with Docker registry support.
upstream nexus {
server 127.0.0.1:8081;
}
upstream docker-registry {
server 127.0.0.1:8082;
}
server {
listen 80;
server_name nexus.example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name nexus.example.com;
client_max_body_size 1G;
ssl_certificate /etc/letsencrypt/live/nexus.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/nexus.example.com/privkey.pem;
location / {
proxy_pass http://nexus;
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_set_header X-Forwarded-Host $host;
proxy_connect_timeout 300;
proxy_send_timeout 300;
proxy_read_timeout 300;
send_timeout 300;
}
}
server {
listen 80;
server_name docker.example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name docker.example.com;
client_max_body_size 0;
chunked_transfer_encoding on;
ssl_certificate /etc/letsencrypt/live/docker.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/docker.example.com/privkey.pem;
location / {
proxy_pass http://docker-registry;
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_connect_timeout 300;
proxy_send_timeout 300;
proxy_read_timeout 300;
send_timeout 300;
}
}
Enable NGINX configuration and obtain SSL certificates
Enable the site configuration and obtain Let's Encrypt SSL certificates.
sudo ln -s /etc/nginx/sites-available/nexus /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl enable nginx
sudo systemctl start nginx
Obtain SSL certificates (replace with your actual domain names):
sudo certbot --nginx -d nexus.example.com -d docker.example.com
Set up Docker registry with authentication
Access Nexus web interface
Open your web browser and navigate to https://nexus.example.com. Log in with username "admin" and the password from the admin.password file.
Create Docker hosted repository
In the Nexus web interface, create a new Docker hosted repository:
- Go to Settings (gear icon) → Repositories → Create repository
- Select "docker (hosted)"
- Configure the repository with these settings:
- Name: docker-private
- HTTP port: 8082
- Enable Docker V1 API: Unchecked
- Allow anonymous docker pull: Unchecked
Create Docker proxy repository
Create a proxy repository for Docker Hub to cache images locally:
- Create repository → docker (proxy)
- Configure with these settings:
- Name: docker-proxy
- Remote storage: https://registry-1.docker.io
- Docker Index: Use Docker Hub
- HTTP port: 8083
Create Docker group repository
Create a group repository that combines hosted and proxy repositories:
- Create repository → docker (group)
- Configure with these settings:
- Name: docker-group
- HTTP port: 8084
- Member repositories: docker-private, docker-proxy
Configure Docker authentication
Create a role and user for Docker registry access:
- Go to Settings → Security → Roles → Create role
- Role ID: docker-user
- Role name: Docker User
- Privileges: nx-repository-view-docker--
Create a user:
- Go to Settings → Security → Users → Create user
- ID: dockeruser
- Password: Use a strong password
- Roles: docker-user
Configure Maven and npm repositories
Create Maven hosted repository
Set up a private Maven repository for your artifacts:
- Create repository → maven2 (hosted)
- Configure with these settings:
- Name: maven-private
- Version policy: Mixed
- Layout policy: Strict
- Deployment policy: Allow redeploy
Create Maven proxy repository
Create a proxy for Maven Central to cache dependencies:
- Create repository → maven2 (proxy)
- Configure with these settings:
- Name: maven-central
- Remote storage: https://repo1.maven.org/maven2/
- Version policy: Release
Create npm hosted repository
Set up a private npm repository for Node.js packages:
- Create repository → npm (hosted)
- Configure with these settings:
- Name: npm-private
- Deployment policy: Allow redeploy
Create npm proxy repository
Create a proxy for the npm registry:
- Create repository → npm (proxy)
- Configure with these settings:
- Name: npm-proxy
- Remote storage: https://registry.npmjs.org
Backup automation and monitoring setup
Create backup script
Set up automated backups of Nexus data and configuration.
#!/bin/bash
BACKUP_DIR="/opt/nexus-backups"
DATE=$(date +"%Y%m%d_%H%M%S")
BACKUP_NAME="nexus-backup-$DATE"
RETENTION_DAYS=30
Create backup directory
mkdir -p $BACKUP_DIR
Stop Nexus service
sudo systemctl stop nexus
Create backup
echo "Creating backup: $BACKUP_NAME"
tar -czf $BACKUP_DIR/$BACKUP_NAME.tar.gz \
-C /opt sonatype-work/nexus3 \
--exclude='sonatype-work/nexus3/log' \
--exclude='sonatype-work/nexus3/tmp'
Start Nexus service
sudo systemctl start nexus
Remove old backups
find $BACKUP_DIR -name "nexus-backup-*.tar.gz" -mtime +$RETENTION_DAYS -delete
Log completion
echo "Backup completed: $BACKUP_DIR/$BACKUP_NAME.tar.gz"
echo "Backup size: $(du -h $BACKUP_DIR/$BACKUP_NAME.tar.gz | cut -f1)"
Optional: Upload to remote storage
aws s3 cp $BACKUP_DIR/$BACKUP_NAME.tar.gz s3://your-backup-bucket/nexus/
Make the script executable and set proper ownership:
sudo chmod 755 /opt/nexus/backup-nexus.sh
sudo chown nexus:nexus /opt/nexus/backup-nexus.sh
sudo mkdir -p /opt/nexus-backups
sudo chown nexus:nexus /opt/nexus-backups
Schedule automated backups
Set up a cron job to run daily backups at 2 AM.
sudo crontab -u nexus -e
Add the following line to the crontab:
0 2 * /opt/nexus/backup-nexus.sh >> /opt/nexus-backups/backup.log 2>&1
Configure log rotation
Set up log rotation to prevent log files from consuming excessive disk space.
/opt/sonatype-work/nexus3/log/*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
copytruncate
su nexus nexus
}
Set up basic monitoring
Create a simple health check script to monitor Nexus availability.
#!/bin/bash
NEXUS_URL="https://nexus.example.com/service/rest/v1/status"
TIMEOUT=10
LOGFILE="/var/log/nexus-health.log"
Check if Nexus is responding
if curl -f -s --connect-timeout $TIMEOUT $NEXUS_URL > /dev/null; then
echo "$(date): Nexus is healthy" >> $LOGFILE
exit 0
else
echo "$(date): Nexus health check failed" >> $LOGFILE
# Optional: Send alert email or notification
# echo "Nexus health check failed" | mail -s "Nexus Alert" admin@example.com
exit 1
fi
Make the script executable and schedule it:
sudo chmod 755 /opt/nexus/health-check.sh
sudo crontab -e
Add health check to run every 5 minutes:
/5 * /opt/nexus/health-check.sh
Verify your setup
Check that all services are running properly:
sudo systemctl status nexus
sudo systemctl status nginx
sudo ss -tlnp | grep -E ':80|:443|:8081|:8082'
curl -I https://nexus.example.com
curl -I https://docker.example.com
Test Docker registry authentication:
docker login docker.example.com
docker pull hello-world
docker tag hello-world docker.example.com/hello-world:latest
docker push docker.example.com/hello-world:latest
Verify Maven repository access:
curl -u admin:your-password https://nexus.example.com/repository/maven-public/
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Nexus won't start | Insufficient memory or wrong Java version | Check Java version with java -version and adjust heap size in nexus.vmoptions |
| Docker push fails with 403 | Authentication not configured properly | Verify Docker repository allows deployment and user has correct permissions |
| SSL certificate errors | Certificate not properly configured | Renew certificates with sudo certbot renew and restart nginx |
| Repository not accessible | Firewall blocking ports | Check firewall rules and ensure ports 80, 443, 8082 are open |
| Out of disk space | Blob store growing without cleanup | Configure cleanup policies in Nexus admin interface |
| Performance issues | Insufficient memory allocation | Increase Xmx and MaxDirectMemorySize in nexus.vmoptions |
Next steps
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Configuration
NEXUS_VERSION="3.44.0-01"
NEXUS_USER="nexus"
NEXUS_HOME="/opt/nexus"
NEXUS_DATA="/opt/sonatype-work"
NEXUS_PORT="${1:-8081}"
DOCKER_PORT="${2:-8082}"
usage() {
echo "Usage: $0 [nexus_port] [docker_port]"
echo " nexus_port: Port for Nexus web interface (default: 8081)"
echo " docker_port: Port for Docker registry (default: 8082)"
exit 1
}
log() {
echo -e "${GREEN}[INFO]${NC} $1"
}
warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
error() {
echo -e "${RED}[ERROR]${NC} $1"
exit 1
}
cleanup() {
warn "Script failed. Cleaning up..."
systemctl stop nexus 2>/dev/null || true
systemctl disable nexus 2>/dev/null || true
rm -f /etc/systemd/system/nexus.service
userdel -f nexus 2>/dev/null || true
rm -rf /opt/nexus /opt/sonatype-work /tmp/latest-unix.tar.gz
}
trap cleanup ERR
check_prerequisites() {
if [[ $EUID -ne 0 ]]; then
error "This script must be run as root"
fi
if ! command -v systemctl &> /dev/null; then
error "systemd is required"
fi
}
detect_distro() {
if [ ! -f /etc/os-release ]; then
error "Cannot detect operating system"
fi
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_UPDATE="apt update && apt upgrade -y"
PKG_INSTALL="apt install -y"
FIREWALL_CMD="ufw"
JAVA_PKG="openjdk-17-jdk"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_UPDATE="dnf update -y"
PKG_INSTALL="dnf install -y"
FIREWALL_CMD="firewall-cmd"
JAVA_PKG="java-17-openjdk java-17-openjdk-devel"
;;
amzn)
PKG_MGR="yum"
PKG_UPDATE="yum update -y"
PKG_INSTALL="yum install -y"
FIREWALL_CMD="firewall-cmd"
JAVA_PKG="java-17-openjdk java-17-openjdk-devel"
;;
*)
error "Unsupported distribution: $ID"
;;
esac
log "Detected distribution: $PRETTY_NAME"
}
update_system() {
log "[1/10] Updating system packages..."
$PKG_UPDATE
}
install_java() {
log "[2/10] Installing Java 17..."
$PKG_INSTALL $JAVA_PKG wget unzip
if ! java -version 2>&1 | grep -q "17"; then
error "Java 17 installation failed"
fi
}
create_nexus_user() {
log "[3/10] Creating Nexus user and directories..."
if ! id "$NEXUS_USER" &>/dev/null; then
useradd --system --no-create-home --shell /bin/false $NEXUS_USER
fi
mkdir -p $NEXUS_HOME $NEXUS_DATA
chown $NEXUS_USER:$NEXUS_USER $NEXUS_HOME $NEXUS_DATA
}
download_nexus() {
log "[4/10] Downloading and installing Nexus Repository Manager..."
cd /tmp
wget -O latest-unix.tar.gz "https://download.sonatype.com/nexus/3/latest-unix.tar.gz"
tar -xzf latest-unix.tar.gz -C /opt/
NEXUS_DIR=$(find /opt -maxdepth 1 -name "nexus-3.*" -type d | head -1)
if [ -z "$NEXUS_DIR" ]; then
error "Could not find extracted Nexus directory"
fi
mv "$NEXUS_DIR" $NEXUS_HOME/nexus-3
ln -sf $NEXUS_HOME/nexus-3 $NEXUS_HOME/current
chown -R $NEXUS_USER:$NEXUS_USER $NEXUS_HOME $NEXUS_DATA
rm -f /tmp/latest-unix.tar.gz
}
configure_jvm() {
log "[5/10] Configuring JVM settings..."
cat > $NEXUS_HOME/current/bin/nexus.vmoptions << 'EOF'
-Xms2g
-Xmx2g
-XX:MaxDirectMemorySize=3g
-XX:+UnlockExperimentalVMOptions
-XX:+UseG1GC
-XX:+UseStringDeduplication
-Dkaraf.home=.
-Dkaraf.base=.
-Dkaraf.etc=etc/karaf
-Djava.util.logging.config.file=etc/karaf/java.util.logging.properties
-Dkaraf.data=../sonatype-work/nexus3
-Dkaraf.log=../sonatype-work/nexus3/log
-Djava.io.tmpdir=../sonatype-work/nexus3/tmp
EOF
chown $NEXUS_USER:$NEXUS_USER $NEXUS_HOME/current/bin/nexus.vmoptions
}
configure_properties() {
log "[6/10] Configuring application properties..."
cat > $NEXUS_HOME/current/etc/nexus-default.properties << EOF
# Nexus default properties
nexus.port=$NEXUS_PORT
nexus.host=0.0.0.0
nexus.context-path=/
# Data directory
karaf.data=$NEXUS_DATA/nexus3
karaf.log=$NEXUS_DATA/nexus3/log
EOF
chown $NEXUS_USER:$NEXUS_USER $NEXUS_HOME/current/etc/nexus-default.properties
}
create_service() {
log "[7/10] Creating systemd service..."
echo "run_as_user=\"$NEXUS_USER\"" > $NEXUS_HOME/current/bin/nexus.rc
chown $NEXUS_USER:$NEXUS_USER $NEXUS_HOME/current/bin/nexus.rc
cat > /etc/systemd/system/nexus.service << EOF
[Unit]
Description=Nexus Repository Manager
After=network.target
[Service]
Type=forking
LimitNOFILE=65536
ExecStart=$NEXUS_HOME/current/bin/nexus start
ExecStop=$NEXUS_HOME/current/bin/nexus stop
User=$NEXUS_USER
Restart=on-abort
TimeoutSec=600
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable nexus
}
configure_firewall() {
log "[8/10] Configuring firewall..."
if [ "$FIREWALL_CMD" = "ufw" ]; then
if command -v ufw &> /dev/null; then
ufw allow $NEXUS_PORT/tcp
ufw allow $DOCKER_PORT/tcp
ufw allow 80/tcp
ufw allow 443/tcp
fi
else
if command -v firewall-cmd &> /dev/null; then
firewall-cmd --permanent --add-port=$NEXUS_PORT/tcp
firewall-cmd --permanent --add-port=$DOCKER_PORT/tcp
firewall-cmd --permanent --add-port=80/tcp
firewall-cmd --permanent --add-port=443/tcp
firewall-cmd --reload
fi
fi
}
start_nexus() {
log "[9/10] Starting Nexus service..."
systemctl start nexus
# Wait for Nexus to start
log "Waiting for Nexus to start (this may take a few minutes)..."
for i in {1..60}; do
if systemctl is-active --quiet nexus && curl -sf http://localhost:$NEXUS_PORT >/dev/null 2>&1; then
break
fi
sleep 10
if [ $i -eq 60 ]; then
error "Nexus failed to start within 10 minutes"
fi
done
}
verify_installation() {
log "[10/10] Verifying installation..."
if ! systemctl is-active --quiet nexus; then
error "Nexus service is not running"
fi
if ! curl -sf http://localhost:$NEXUS_PORT >/dev/null 2>&1; then
error "Nexus web interface is not accessible"
fi
log "Installation completed successfully!"
echo
log "Nexus Repository Manager is now running:"
log " Web interface: http://$(hostname -I | awk '{print $1}'):$NEXUS_PORT"
log " Default admin username: admin"
if [ -f "$NEXUS_DATA/nexus3/admin.password" ]; then
ADMIN_PASSWORD=$(cat $NEXUS_DATA/nexus3/admin.password)
log " Default admin password: $ADMIN_PASSWORD"
warn "Save this password! The password file will be deleted after first login."
fi
echo
log "Next steps:"
log "1. Access the web interface and complete the setup wizard"
log "2. Change the admin password"
log "3. Configure repositories as needed"
log "4. Set up SSL/TLS with a reverse proxy (recommended for production)"
}
main() {
if [[ $# -gt 2 ]]; then
usage
fi
check_prerequisites
detect_distro
update_system
install_java
create_nexus_user
download_nexus
configure_jvm
configure_properties
create_service
configure_firewall
start_nexus
verify_installation
}
main "$@"
Review the script before running. Execute with: bash install.sh