Skip to content
Go back

Artifact Repository Management with Nexus

Edit page

What is an Artifact?

An artifact is a compiled, packaged version of your application that’s ready to be deployed. Think of it as the final product of your build process - it’s your source code transformed into a distributable format.

When you write code and run a build process, your application gets compiled and packaged into a single file. This could be:

Instead of deploying raw source code to production (which would be slow and risky), you deploy these pre-built artifacts. They’re versioned, tested, and ready to run.

Why Do We Need an Artifact Repository?

The Problem Without Artifact Repositories

Imagine you’re building an application. Your CI/CD pipeline runs, creates a JAR file, and… where does it go?

Without a proper artifact repository:

The Solution: Artifact Repository

An artifact repository manager like Nexus gives you:

  1. Centralized Storage: One place for all your build artifacts across all projects
  2. Version Management: Keep multiple versions of the same artifact with proper versioning
  3. Access Control: Control who can upload/download artifacts
  4. Fast Deployments: Artifacts are pre-built and ready to deploy instantly
  5. Dependency Management: Your projects can pull dependencies from both public repos (like Maven Central) and your private repos
  6. Team Collaboration: Different teams can share and reuse artifacts
  7. Audit Trail: Track every upload, download, and deployment
  8. Storage Optimization: Implement cleanup policies to manage disk space

Think of Nexus as a “container registry for everything” - not just Docker images, but JARs, WARs, NPM packages, Python wheels, and more, all in one place.

Setting Up Nexus on AWS EC2

Step 1: Creating the EC2 Instance

Let’s walk through creating an EC2 instance properly. Nexus is a heavy application, so we need adequate resources.

Launch Instance:

  1. Go to AWS Console → EC2 → Launch Instance

  2. Name: nexus-server

  3. AMI: Ubuntu Server 22.04 LTS (or latest stable)

  4. Instance Type: t3.medium minimum (2 vCPU, 4GB RAM)

    • Nexus is resource-hungry. Going below this will cause performance issues and potential crashes
    • For production, consider t3.large or bigger
  5. Key Pair: Create or select an existing key pair

    • Download the .pem file if creating new
    • Save it securely - you’ll need it for SSH access
  6. Storage: 160GB GP3 SSD

    • Nexus stores all your artifacts, so plan for growth
    • You can start with 80GB minimum, but 160GB gives breathing room

Step 2: Configure Security Group

Security groups act as virtual firewalls. We need to open specific ports:

Create a new security group or edit existing:

  1. Inbound Rules:

    Type: SSH
    Protocol: TCP
    Port: 22
    Source: Your IP (or 0.0.0.0/0 for testing - not recommended for production)
    Description: SSH access
    
    Type: Custom TCP
    Protocol: TCP
    Port: 8081
    Source: Your IP or your company's IP range
    Description: Nexus web interface
  2. Outbound Rules: Leave default (allow all outbound traffic)

Why these ports?

Step 3: SSH into the Instance

Once your instance is running:

# Make your key file secure (required by SSH)
chmod 400 /path/to/your-key.pem

# SSH into your instance
ssh -i /path/to/your-key.pem ubuntu@<your-ec2-public-ip>

You should see the Ubuntu welcome message. You’re in!

Installing Nexus

Step 1: Update the System

sudo apt update
sudo apt upgrade -y

Step 2: Install Java 17

Nexus requires Java to run. As of recent versions, Java 17 is recommended.

# Install OpenJDK 17
sudo apt install openjdk-17-jdk -y

# Verify installation
java -version

You should see output showing Java 17.

Step 3: Download and Extract Nexus

# Navigate to /opt directory (common for third-party software)
cd /opt

# Download Nexus (check for latest version at sonatype.com)
sudo wget https://download.sonatype.com/nexus/3/latest-unix.tar.gz

# Extract the archive
sudo tar -xvzf latest-unix.tar.gz

# This creates two directories:
# 1. nexus-<version> - The application itself
# 2. sonatype-work - Data, logs, and configuration

Step 4: Understanding the Directory Structure

After extraction, you’ll have two important directories:

/opt/nexus-<version>/

This contains the Nexus application binaries. Don’t modify this unless you know what you’re doing.

nexus/
├── bin/        # Start/stop scripts
├── etc/        # Configuration files
├── lib/        # Java libraries
└── public/     # Web interface files

/opt/sonatype-work/

This is where your data lives. This is what you backup.

sonatype-work/
└── nexus3/
    ├── admin.password    # Initial admin password
    ├── db/               # Internal database
    ├── log/              # Application logs
    ├── tmp/              # Temporary files
    ├── blobs/            # Actual artifact storage
    └── etc/              # Runtime configuration

Key point about sonatype-work:

Step 5: Create a Dedicated Nexus User

Running services as root is a security risk. If the service gets compromised, attackers have full system access.

Best practice: Create a dedicated user with minimal permissions.

# Create a system user named 'nexus'
sudo adduser --system --no-create-home --group nexus

# This creates:
# - A user 'nexus'
# - A group 'nexus'
# - No home directory (not needed for a service account)
# - System account (can't login directly)

Step 6: Set Ownership and Permissions

The nexus user needs to read/write to both directories.

# Change ownership of nexus directory
sudo chown -R nexus:nexus /opt/nexus-<version>

# Change ownership of sonatype-work
sudo chown -R nexus:nexus /opt/sonatype-work

What this does:

Step 7: Configure Nexus to Run as Nexus User

Edit the Nexus configuration file:

sudo nano /opt/nexus-<version>/bin/nexus.rc

Uncomment and set:

run_as_user="nexus"

Save and exit (Ctrl+X, then Y, then Enter).

Why this matters: This tells the Nexus startup script to run the process as the nexus user, not root. Even if you start the script as root, it will switch to the nexus user.

Step 8: Start Nexus

# Switch to nexus user
sudo su - nexus

# Navigate to bin directory
cd /opt/nexus-<version>/bin

# Start Nexus
./nexus start

# Check if it's starting
tail -f /opt/sonatype-work/nexus3/log/nexus.log

Wait for the message: Started Sonatype Nexus

This can take 2-5 minutes on first startup.

Step 9: Verify Nexus is Running

# Check process
ps aux | grep nexus

# Check port listening
netstat -lntp | grep 8081

You should see:

Step 10: Access Nexus Web Interface

Open your browser and navigate to:

http://<your-ec2-public-ip>:8081

You should see the Nexus welcome page!

First-Time Login

Getting the Admin Password

Nexus creates a default admin user with a random password on first startup.

# View the generated password
sudo cat /opt/sonatype-work/nexus3/admin.password

Copy this password.

Login Steps

  1. Click “Sign In” in the top right
  2. Username: admin
  3. Password: The password from admin.password file
  4. Follow the setup wizard:
    • Change the admin password (choose a strong one!)
    • Configure anonymous access (recommend: disable for production)
    • Complete setup

After first login, the admin.password file is deleted automatically.

Understanding Nexus Repository Types

Nexus supports three repository types. Understanding these is crucial:

1. Hosted Repository

What: A repository you manage that stores your internal artifacts.

Use Case:

Example Scenario: Your Java team builds a common authentication library. Instead of copying code between projects, they:

  1. Build the library into a JAR
  2. Publish it to a hosted Maven repository in Nexus
  3. Other projects add it as a dependency
<!-- Other projects reference it -->
<dependency>
    <groupId>com.yourcompany</groupId>
    <artifactId>auth-lib</artifactId>
    <version>1.2.0</version>
</dependency>

2. Proxy Repository

What: Acts as a caching intermediary to external repositories.

Use Case:

Why this is brilliant:

Without proxy:

Your Build → Internet → Maven Central (every time)

With proxy:

First time:  Your Build → Nexus (miss) → Maven Central → Nexus (cache) → Your Build
Second time: Your Build → Nexus (hit) → Your Build

Benefits:

Example: Create a proxy repository pointing to https://repo1.maven.org/maven2/. When your build requests a dependency, Nexus checks its cache first. If not found, it downloads from Maven Central, caches it, and serves it.

3. Group Repository

What: A virtual repository that combines multiple repositories under a single URL.

Use Case: Simplify configuration by giving developers one URL instead of many.

Example Scenario:

You have:

Create a group called maven-public that includes all three.

Now developers configure just one URL:

<repository>
    <id>nexus</id>
    <url>http://nexus.yourcompany.com:8081/repository/maven-public/</url>
</repository>

Nexus searches all three repositories when resolving dependencies. Clean and simple!

Publishing Artifacts to Nexus

Setting Up Permissions

Before publishing, you need proper access control.

Step 1: Create a Role

  1. Go to Settings (gear icon) → SecurityRolesCreate Role
  2. Type: Nexus role
  3. Role ID: maven-deployer
  4. Role Name: Maven Deployment Role
  5. Privileges: Add these:
    • nx-repository-view-maven2-*-* (view all maven repositories)
    • nx-repository-view-maven2-*-add (upload to maven repos)
    • nx-repository-view-maven2-*-edit (edit artifacts)

Why different roles?

Step 2: Create a User

  1. SettingsSecurityUsersCreate User
  2. Username: ci-deployer
  3. Password: Strong password (save it securely)
  4. Roles: Select maven-deployer
  5. Save

This user will be used by your build tools and CI/CD pipelines.

Publishing with Gradle

Gradle is a popular build tool for Java projects. Let’s configure it to publish to Nexus.

File: build.gradle

plugins {
    id 'java'
    id 'maven-publish'
}

group = 'com.yourcompany'
version = '1.0.0-SNAPSHOT'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web:3.0.0'
    testImplementation 'junit:junit:4.13.2'
}

publishing {
    publications {
        maven(MavenPublication) {
            from components.java
            
            groupId = 'com.yourcompany'
            artifactId = 'my-awesome-app'
            version = '1.0.0-SNAPSHOT'
        }
    }
    
    repositories {
        maven {
            name = 'nexus'
            def releasesRepoUrl = "http://your-nexus-server:8081/repository/maven-releases/"
            def snapshotsRepoUrl = "http://your-nexus-server:8081/repository/maven-snapshots/"
            
            // Choose repo based on version
            url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
            
            credentials {
                username = project.findProperty("nexusUsername") ?: System.getenv("NEXUS_USERNAME")
                password = project.findProperty("nexusPassword") ?: System.getenv("NEXUS_PASSWORD")
            }
        }
    }
}

File: gradle.properties

# Store credentials here (add this file to .gitignore!)
nexusUsername=ci-deployer
nexusPassword=your-secure-password

Security Note: Never commit credentials to Git! Better approach:

# Set as environment variables
export NEXUS_USERNAME=ci-deployer
export NEXUS_PASSWORD=your-secure-password

Build and Publish

# Build the project
./gradlew build

# Publish to Nexus
./gradlew publish

You should see output indicating the artifact was uploaded to Nexus!

Publishing with Maven

Maven is another widely-used Java build tool.

File: pom.xml

<project>
    <groupId>com.yourcompany</groupId>
    <artifactId>my-awesome-app</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    
    <distributionManagement>
        <repository>
            <id>nexus-releases</id>
            <name>Nexus Release Repository</name>
            <url>http://your-nexus-server:8081/repository/maven-releases/</url>
        </repository>
        <snapshotRepository>
            <id>nexus-snapshots</id>
            <name>Nexus Snapshot Repository</name>
            <url>http://your-nexus-server:8081/repository/maven-snapshots/</url>
        </snapshotRepository>
    </distributionManagement>
</project>

File: ~/.m2/settings.xml

Maven stores credentials separately from your project (more secure).

<settings>
    <servers>
        <server>
            <id>nexus-releases</id>
            <username>ci-deployer</username>
            <password>your-secure-password</password>
        </server>
        <server>
            <id>nexus-snapshots</id>
            <username>ci-deployer</username>
            <password>your-secure-password</password>
        </server>
    </servers>
</settings>

Important: The <id> in settings.xml must match the <id> in your pom.xml distributionManagement section.

Build and Deploy

# Build the project (creates JAR)
mvn package

# Deploy to Nexus
mvn deploy

The mvn deploy command automatically chooses the correct repository (releases or snapshots) based on your version.

Nexus REST API

The web interface is great, but automation requires APIs. Nexus provides a comprehensive REST API.

Common API Operations

1. List All Repositories

curl -u admin:your-password -X GET \
  "http://your-nexus-server:8081/service/rest/v1/repositories"

2. List Components in a Repository

curl -u admin:your-password -X GET \
  "http://your-nexus-server:8081/service/rest/v1/components?repository=maven-releases"

3. Upload a Component

curl -u ci-deployer:password -X POST \
  "http://your-nexus-server:8081/service/rest/v1/components?repository=maven-releases" \
  -F "maven2.groupId=com.yourcompany" \
  -F "maven2.artifactId=my-app" \
  -F "maven2.version=1.0.0" \
  -F "maven2.asset1=@my-app-1.0.0.jar" \
  -F "maven2.asset1.extension=jar"

4. Download an Artifact

curl -u admin:your-password -O \
  "http://your-nexus-server:8081/repository/maven-releases/com/yourcompany/my-app/1.0.0/my-app-1.0.0.jar"

5. Delete a Component

curl -u admin:your-password -X DELETE \
  "http://your-nexus-server:8081/service/rest/v1/components/{componentId}"

API Documentation

Always refer to the official API documentation:

http://your-nexus-server:8081/service/rest/swagger.json

Or use the interactive Swagger UI at Nexus’s documentation site.

Pro tip: Use tools like Postman or write Python scripts for complex API interactions.

Understanding Blob Stores

What are Blob Stores?

Blob stores are the physical storage backend where Nexus actually saves your artifacts. Think of them as the “hard drive” for Nexus.

Repository (logical) → Blob Store (physical storage)

Blob Store Structure

sonatype-work/nexus3/blobs/
└── default/           # Default blob store
    ├── content/       # Actual artifact files
    │   └── vol-01/
    │       └── chap-01/
    │           └── ...files...
    └── metadata/      # Blob metadata

Important Characteristics

  1. Immutable Assignment: Once you create a repository and assign it to a blob store, you cannot change it. This decision is permanent.

  2. Storage Types:

    • File: Stores on local filesystem
    • S3: Stores in AWS S3 buckets
    • Azure: Stores in Azure Blob Storage
    • Google Cloud: Stores in Google Cloud Storage

Creating a New Blob Store

Via UI:

  1. SettingsBlob StoresCreate Blob Store
  2. Type: File (or cloud provider)
  3. Name: production-artifacts
  4. Path: Leave default or specify custom path
  5. Save

When to Create Separate Blob Stores:

Example: Creating a Repository with Custom Blob Store

  1. Create blob store: docker-storage
  2. Create repository:
    • Type: docker (hosted)
    • Name: docker-private
    • Blob Store: Select docker-storage
    • HTTP: 8082 (Docker needs a dedicated port)

Now all Docker images pushed to this repository are stored in the docker-storage blob store.

Blob Store Status

Check blob store health:

Monitor disk space regularly!

# Check disk usage on Linux
df -h /opt/sonatype-work

Components vs Assets

This is a confusing concept at first, but important to understand.

Components

Components are the logical, abstract representation of what you uploaded.

Example: A Maven artifact with:

This is one component.

Assets

Assets are the actual physical files that make up a component.

That same Maven component might consist of multiple assets:

These are four assets belonging to one component.

Analogy

Think of it like a music album:

Why This Matters

When you:

In the Nexus UI:

Cleanup Policies

Over time, your artifact repository grows. Old snapshots, unused versions, and test artifacts accumulate. Cleanup policies automate the deletion of artifacts based on rules you define.

Why Cleanup Policies Matter

Without cleanup:

Common Cleanup Scenarios

  1. Delete old snapshots: Keep only last 30 days of SNAPSHOT versions
  2. Remove unused artifacts: Delete artifacts not downloaded in 90 days
  3. Limit version count: Keep only last 5 versions of each artifact
  4. Clean test artifacts: Delete anything tagged as “test” after 7 days

Creating a Cleanup Policy

Step 1: Create the Policy

  1. SettingsCleanup PoliciesCreate Cleanup Policy

  2. Name: delete-old-snapshots

  3. Format: maven2

  4. Criteria:

    Release Type: Snapshot
    Last Downloaded: 30 days ago
  5. Save

This policy targets Maven SNAPSHOT artifacts not downloaded in the last 30 days.

Step 2: Attach to Repository

  1. SettingsRepositories → Select maven-snapshots
  2. Cleanup Policies: Select delete-old-snapshots
  3. Save

The policy is now attached but won’t run until you schedule it.

Scheduling Cleanup Tasks

Cleanup policies define what to delete. Cleanup tasks define when to delete.

Create a Cleanup Task:

  1. SettingsTasksCreate Task

  2. Type: Admin - Cleanup repositories using their associated policies

  3. Name: Nightly Snapshot Cleanup

  4. Repository: maven-snapshots (or * for all)

  5. Schedule: Cron expression

    0 0 2 * * ?    # Every day at 2:00 AM
  6. Save

Now, every night at 2 AM, Nexus will run the cleanup policy and delete matching artifacts.

Compact Blob Store Task

When you delete artifacts, the space isn’t immediately freed. You need to run a compact task.

Why? Nexus uses a soft delete initially for safety. Compacting permanently removes deleted artifacts and reclaims disk space.

Create Compact Task:

  1. SettingsTasksCreate Task

  2. Type: Admin - Compact blob store

  3. Blob Store: default (or specific one)

  4. Schedule: Weekly

    0 0 3 * * SUN    # Every Sunday at 3:00 AM
  5. Save

Best Practice: Run compact tasks after cleanup tasks, not during business hours (it’s I/O intensive).

Example Cleanup Strategy

Here’s a complete, production-ready cleanup strategy:

Policy: delete-old-snapshots
- Repository: maven-snapshots
- Release Type: Snapshot
- Last Downloaded: > 30 days
- Schedule: Daily at 2:00 AM

Policy: delete-stale-releases
- Repository: maven-releases
- Last Downloaded: > 180 days
- Schedule: Weekly on Sunday at 2:00 AM

Policy: docker-image-retention
- Repository: docker-private
- Component Age: > 90 days
- Schedule: Daily at 3:00 AM

Task: Compact Blob Store
- All Blob Stores
- Schedule: Weekly on Sunday at 4:00 AM

Complete Workflow: From Code to Nexus

Let’s tie everything together with a real-world example.

Scenario

You’re developing a Java microservice that will be deployed to Kubernetes. Here’s the full workflow:

1. Developer writes code

2. Commits to Git (GitHub/GitLab)

3. CI/CD Pipeline triggers (Jenkins/GitLab CI)

4. Build tool compiles code (Maven/Gradle)

5. Tests run

6. Artifact is created (JAR file)

7. Artifact is published to Nexus

8. CD Pipeline pulls artifact from Nexus

9. Deploys to Kubernetes

GitLab CI Example

.gitlab-ci.yml:

stages:
  - build
  - publish

variables:
  MAVEN_OPTS: "-Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository"

build:
  stage: build
  image: maven:3.8-openjdk-17
  script:
    - mvn clean package
  artifacts:
    paths:
      - target/*.jar
    expire_in: 1 day

publish:
  stage: publish
  image: maven:3.8-openjdk-17
  only:
    - main
  script:
    - mvn deploy -s settings.xml
  dependencies:
    - build

settings.xml (stored as CI/CD variable or secret):

<settings>
  <servers>
    <server>
      <id>nexus-snapshots</id>
      <username>${env.NEXUS_USERNAME}</username>
      <password>${env.NEXUS_PASSWORD}</password>
    </server>
  </servers>
</settings>

In GitLab:

Now, every commit to main automatically builds and publishes to Nexus!

Troubleshooting Common Issues

Nexus Won’t Start

# Check logs
tail -f /opt/sonatype-work/nexus3/log/nexus.log

# Common issues:
# - Not enough RAM (needs 4GB minimum)
# - Port 8081 already in use
# - Wrong file permissions
# - Java not installed or wrong version

Out of Memory

Edit /opt/nexus/bin/nexus.vmoptions:

-Xms2G
-Xmx4G

Restart Nexus.

Disk Full

# Check usage
df -h

# Run cleanup manually:
# Settings → Tasks → Select cleanup task → Run

# Compact blob store:
# Settings → Tasks → Select compact task → Run

Can’t Upload Artifacts

Check:

Best Practices

  1. Backups: Regularly backup /opt/sonatype-work

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

    • Use strong passwords
    • Enable HTTPS (not covered here, but crucial for production)
    • Regularly update Nexus
    • Use token authentication for CI/CD
  3. Monitoring:

    • Set up disk space alerts
    • Monitor Nexus logs for errors
    • Track repository growth
  4. Organization:

    • Use clear naming conventions for repositories
    • Separate repositories by team/project when it makes sense
    • Document your repository structure
  5. Performance:

    • Use group repositories to reduce configuration complexity
    • Set up proxy repositories for external dependencies
    • Run cleanup policies regularly

Nexus is powerful but can feel overwhelming at first. Start simple: install it, create a hosted repository, publish one artifact. Then gradually add proxy repositories, cleanup policies, and integrate with CI/CD. Before you know it, you’ll have a robust artifact management system that makes deployments faster and more reliable.


Edit page
Share this post on:

Previous Post
Docker & Containerization: A Complete Guide
Next Post
Version Control with Git