Nexus CasC is a configuration as code plugin for sonatype nexus 3.
This plugin allows to specify a YAML file to configure a Nexus instance on startup.
This repository maintains a fork with releases kept in track with the nexus releases.
This plugin CANNOT be updated beyond 3.77.x.
Reason: complete BWC Break in OSS NEXUS 3.78.0 (March 2025):
"Breaking change for custom plugins: Nexus Repository migrates to Spring Boot architecture.
Custom OSGi bundle deployment no longer supported."
https://help.sonatype.com/en/sonatype-nexus-repository-3-78-0-release-notes.html#breaking-change-for-custom-plugins--nexus-repository-migrates-to-spring-boot-architecture
https://help.sonatype.com/en/sonatype-nexus-repository-3-feature-status.html#osgi-bundle-capability
Forked from: https://github.com/larhauga/nexus-casc-plugin/ Who forked from: https://github.com/AdaptiveConsulting/nexus-casc-plugin Who forked from: https://github.com/sventschui/nexus-casc-plugin
The original provider was unable to maintain the project.
Changes in chronological order:
- The groupId has changed to avoid clashing with the original project
- The build process now produces a
.kar
archive and can be directly deployed in upstream Nexus via thedeploy
directory (providing the API versions match) - Unit tests and integration tests have been enabled
- Basic CI has been added
- Releases are currently pushed to our private repository, this may change in the future
- plugin image is now also shipped as independent image, and plugin is extracted from it to a shared folder at runtime for sonatype/nexus image to mount and use.
- docker-compose.yml is now for actual deploy, and previous dev tests one renamed to "-dev".
As the plugin is now released as a separate image, build is required only when a new version is released.
Build requires either simply docker
or, for non-docker builds:
- Java 17 (and 11) JDK (OpenJDK is fine)
- Maven (3.6.3 or higher preferred).
- docker compose for (either integration dev tests, using docker-compose-dev.yaml )
Note: it's possible to do docker builds and extract the plugin from the image, without the need to build it locally.
docker build --progress=plain . --build-arg ALL_PROXY="http://myhttpproxy.corp.example.com:8080" --build-arg no_proxy=".example.com" --build-arg DOCKER_MIRROR="myregistry.corp.example.com" --build-arg MAVEN_MIRROR="http://myregistry.corp.example.com:8080/repository/maven-public/" --build-arg GROOVY_MIRROR="http://myregistry.corp.example.com:8080/repository/maven-public/" --tag myregistry.corp.example.com/nexus-casc-plugin:3.77.2
Build builder context
docker buildx create --name multiarch-builder --driver docker-container || true # in case it already exists
Actual build using above builder context
docker buildx build . --builder multiarch-builder --platform linux/amd64,linux/arm64 --tag myregistry.corp.example.com/nexus-casc-plugin:3.77.2 --push
When inside a corp:
# buildkit with extra root ca certificate:
docker build -f Dockerfile_ca . -t moby/buildkit:buildx-stable-1 --build-arg DOCKER_MIRROR="myregistry.corp.example.com" --build-arg CA_URL="https://myregistry.corp.example.com/my-root-ca.crt"
# actual build:
docker buildx build --builder multiarch-builder --platform linux/amd64,linux/arm64 . --build-arg ALL_PROXY="http://myhttpproxy.corp.example.com:8080" --build-arg no_proxy=".example.com" --build-arg DOCKER_MIRROR="myregistry.corp.example.com" --build-arg MAVEN_MIRROR="http://myregistry.corp.example.com:8080/repository/maven-public/" --build-arg GROOVY_MIRROR="http://myregistry.corp.example.com:8080/repository/maven-public/" --tag "myregistry.corp.example.com/nexus-casc-plugin:3.77.2"
To update the maven wrapper:
./mvnw wrapper:wrapper -N # -Dmaven=3.9.9
To just build the .kar
archive:
#./mvnw package
./mvnw clean package -Dkar.finalName=nexus-casc-plugin -Daether.dependencyCollector.impl=bf -Dmaven.artifact.threads=10 --no-transfer-progress -U # -X
To build the .kar
archive and execute the (limited!) integration tests via docker-compose
:
./mvnw verify
Warning: Use the project version that matches your Nexus version. This is because the project is tied to specific version of the Nexus API and there is no guarantee the API remains consistent (although it usually does).
Deploy the .kar archive using the upstream sonatype/nexus3
image in the /opt/sonatype/nexus/deploy/
directory.
The plugin will be automatically installed on startup.
It expects a YAML configuration file to be mounted to /opt/nexus.yml
(This path can be overridden using the NEXUS_CASC_CONFIG
env var).
The format of the YAML file is documented below.
Start Nexus as usual.
nexus-casc-plugin
holds only the kar file and shell script to extract it, on top of a busybox image.
Use docker-compose.yml with shared folder/volume or kubernetes with shared volume like emptryDir.
Ensure your persistency volume is with right nexus owership (sudo chown 200:200 ./nexus-data
), or at least give full permissions: chmod 777 ./nexus-data
(Otherwise, one will get errors like: java.nio.file.AccessDeniedException: /opt/sonatype/nesus/../sonatype-work/nexus3/
)
Example of image with nexus plugin: docker.io/researchiteng/nexus-casc-plugin:3.77.2
How to start nexus:
docker network create nginx || true
if [ ! -d ./nexus-data ]; then
mkdir -p ./nexus-data
sudo chown 200:200 ./nexus-data # chmod 777 ./nexus-data
fi
if [ ! -f password_admin ]; then
tr -cd [:alpha:] < /dev/random | head -c12 >> ./password_admin
fi
docker compose up
copy the .kar archive to the folder mounted in the /opt/sonatype/nexus/deploy/
directory.
There is a docker-compose.yml
file with all the necessary to test this. The test admin user is johndoe
and its password
is located in the password_johndoe
file. The YAML configuration is located in default-nexus.yml
. It has a non-working
proxy configuration just to test its configuration. Removing httpProxy
and/or httpsProxy
entirely will also clear the relevant
proxy settings on the next boot.
./mvnw package
docker-compose run nexus
You can find an example configuration file here.
Use ${ENV_VAR}
for env var interpolation. Use ${ENV_VAR:default}
or ${ENV_VAR:"default"}
for default values.
Use ${file:/path/to/a/file}
to include the contents of a file.
The configuration file supports following options:
core:
baseUrl: "" # Nexus base URL
userAgentCustomization: ""
connectionTimeout: 0 # ignored if 0
connectionRetryAttempts: 0 # ignored if 0
httpProxy: # HTTP proxy
host: ""
port: 80 # defaults to 80
username: ""
password: ""
ntlmHost: ""
ntlmDomain: ""
httpsProxy: # HTTPs proxy
host: ""
port: 80 # still defaults to 80 because Nexus has no way to know that it needs to use TLS for the proxy itself
username: ""
password: ""
ntlmHost: ""
ntlmDomain: ""
nonProxyHosts: # list of hosts not to be queried through a proxy
- "host1"
- "hostn..."
security:
anonymousAccess: false # Enable/Disable anonymous access
pruneUsers: true # True to delete users not part of this configuration file
realms: # Authentication realms, tested for rutauth-realm only
- name: rutauth-realm
enabled: true
users:
- username: johndoe
firstName: John
lastName: Doe
password: ${file:/run/secrets/password_johndoe}
updateExistingPassword: false # True to update passwords of existing users, otherwise password is only used when creating a user
email: johndoe@example.org
roles:
- source: ""
role: nx-admin
for any repositories that require authentication it looks like this:
repository:
repositories:
- name: some-proxy
attributes:
httpclient:
connection:
blocked: false
autoBlock: true
authentication:
type: username # or ntlm
username: test
password: test
#ntlmHost: someHost
#ntlmDomain: someDomain
preemptive: false # or true
repository:
pruneBlobStores: true # True to delete blob stores not present in this configuration file
blobStores: # List of blob stores to create
- name: maven
type: File
attributes:
file:
path: maven
blobStoreQuotaConfig:
quotaLimitBytes: 10240000000
quotaType: spaceUsedQuota
- name: npm
type: File
attributes:
file:
path: npm
blobStoreQuotaConfig:
quotaLimitBytes: 10240000000
quotaType: spaceUsedQuota
- name: docker
type: File
attributes:
file:
path: docker
blobStoreQuotaConfig:
quotaLimitBytes: 10240000000
quotaType: spaceUsedQuota
- name: main
type: S3
attributes:
s3:
bucket: 'some-bucket' # (mandatory) AWS bucket
prefix: '/nexus/' # (optional) prefix for structure in bucket
# Nexus uses default S3 provider chain so options are:
# 1. Usual AWS_PROFILE, AWS_ACCESS_KEY etc. environment variables
# 2. IAM Instance Profile with appropriate IAM role and policy (see Nexus docs)
# 3. Explicit credentials (below)
accessKeyId: 'some_key' # (optional) AWS access key Id
secretAccessKey: 'some_secret_key' # (optional) AWS secret access key
sessionToken: 'some_session_token' # (optional) AWS session token
assumeRole: 'power-users' # (optional) custom IAM role to assume
region: 'eu-west-1' # (optional) AWS region
endpoint: 'https://s3.custom-endpoint.somewhere/'
expiration: '3' # (optional) days, default=3
signertype: none # (optional) 'one of none(default)|S3SignerType|AWSS3V4SignerType'
forcepathstyle: false # (optional) 'false(default)|true'
encryption_type: DEFAULT # (optional) 'one of DEFAULT(default)|s3ManagedEncryption|kmsManagedEncryption'
encryption_key: 'aws/s3' # (required kmsManagedEncryption only) AWS KMS Key Id or KMS Key Alias
pruneCleanupPolicies: true # True to delete cleanup policies not present in this configuration file
cleanupPolicies:
- name: cleanup-maven-proxy
format: maven2
notes: ''
criteria:
lastDownloaded: 864000
lastBlobUpdated: 864000
- name: cleanup-npm-proxy
format: npm
notes: ''
criteria:
lastDownloaded: 864000
- name: cleanup-docker-proxy
format: docker
notes: ''
criteria:
lastDownloaded: 864000
pruneRepositories: true # True to delete repositories not present in this configuration file
repositories:
- name: npm-proxy
online: true
recipeName: npm-proxy
attributes:
proxy:
remoteUrl: https://registry.npmjs.org
contentMaxAge: -1.0
metadataMaxAge: 1440.0
httpclient:
blocked: false
autoBlock: true
connection:
useTrustStore: false
storage:
blobStoreName: npm
strictContentTypeValidation: true
routingRules:
routingRuleId: null
negativeCache:
enabled: true
timeToLive: 1440.0
cleanup:
policyName: cleanup-npm-proxy
- name: npm-hosted
online: true
recipeName: npm-hosted
attributes:
storage:
blobStoreName: npm
strictContentTypeValidation: true
writePolicy: ALLOW_ONCE
cleanup:
policyName: None
- name: npm
online: true
recipeName: npm-group
attributes:
storage:
blobStoreName: npm
strictContentTypeValidation: true
group:
memberNames:
- "npm-proxy"
- "npm-hosted"
- name: maven-snapshots
online: true
recipeName: maven2-hosted
attributes:
maven:
versionPolicy: SNAPSHOT
layoutPolicy: STRICT
storage:
writePolicy: ALLOW
strictContentTypeValidation: false
blobStoreName: maven
- name: maven-central
online: true
recipeName: maven2-proxy
attributes:
proxy:
contentMaxAge: -1
remoteUrl: https://repo1.maven.org/maven2/
metadataMaxAge: 1440
negativeCache:
timeToLive: 1440
enabled: true
storage:
strictContentTypeValidation: false
blobStoreName: maven
httpClient:
connection:
blocked: false
autoBlock: true
maven:
versionPolicy: RELEASE
layoutPolicy: PERMISSIVE
cleanupPolicy:
name: cleanup-maven-proxy
httpclient:
maven-indexer:
- name: maven-tudelft
online: true
recipeName: maven2-proxy
attributes:
proxy:
contentMaxAge: -1
remoteUrl: https://simulation.tudelft.nl/maven/
metadataMaxAge: 1440
negativeCache:
timeToLive: 1440
enabled: true
storage:
strictContentTypeValidation: false
blobStoreName: maven
httpClient:
connection:
blocked: false
autoBlock: true
maven:
versionPolicy: RELEASE
layoutPolicy: PERMISSIVE
cleanupPolicy:
name: cleanup-maven-proxy
httpclient:
maven-indexer:
- name: maven-public
online: true
recipeName: maven2-group
attributes:
maven:
versionPolicy: MIXED
group:
memberNames:
- "maven-central"
- "maven-snapshots"
- "maven-tudelft"
storage:
blobStoreName: maven
- name: docker-hosted
online: true
recipeName: docker-hosted
attributes:
docker:
forceBasicAuth: true
v1Enabled: false
storage:
blobStoreName: docker
strictContentTypeValidation: true
writePolicy: ALLOW_ONCE
cleanup:
policyName: None
- name: docker-proxy
online: true
recipeName: docker-proxy
attributes:
docker:
forceBasicAuth: true
v1Enabled: false
proxy:
remoteUrl: https://registry-1.docker.io
contentMaxAge: -1.0
metadataMaxAge: 1440.0
dockerProxy:
indexType: REGISTRY
httpclient:
blocked: false
autoBlock: true
connection:
useTrustStore: false
storage:
blobStoreName: docker
strictContentTypeValidation: true
routingRules:
routingRuleId: null
negativeCache:
enabled: true
timeToLive: 1440.0
cleanup:
policyName: cleanup-docker-proxy
- name: docker
online: true
recipeName: docker-group
attributes:
docker:
forceBasicAuth: true
v1Enabled: false
storage:
blobStoreName: docker
strictContentTypeValidation: true
group:
memberNames:
- "docker-hosted"
- "docker-proxy"
Additional examples including apt, raw and yum are in the file default-nexus.yml