Nexus Configuration
Complete guide for integrating Socket Registry Firewall with Sonatype Nexus Repository Manager. Covers all three deployment topologies, plus auto-discovery of proxy and hosted repositories for the Downstream topology.
Overview
Socket Registry Firewall integrates with Nexus Repository Manager to protect package ingestion and distribution.
Pick your topology first. It determines how you configure both sides:
- Upstream (most common): Nexus proxy repos point their Remote storage URL at the firewall's manual per-ecosystem routes (
/npm,/maven,/pypi, ...). One URL per format, shared by every repo of that format. - Downstream: developers point package managers at the firewall, which forwards to Nexus. Auto-discovery fits here: it polls the Nexus API and generates one route per repository (
/repository/<repo-name>), each forwarding to your Nexus.
⚠️ Auto-discovery generates routes that forward to Nexus, so it cannot produce the Nexus-to-firewall routes the Upstream topology needs. Configure Upstream with manual routes as shown in Upstream Deployment Setup.
Supported Nexus repository formats:
| Nexus Format | Firewall Registry | Notes |
|---|---|---|
| npm | npm | Full support |
| pypi | pypi | Full support |
| maven2 | maven | Full support |
| cargo | cargo | Full support |
| rubygems | rubygems | Full support |
| nuget | nuget | Full support |
| go | go | Full support |
| conda | conda | Experimental - treated as PyPI |
Discovered repositories are routed at the standard Nexus path, /repository/<repo>.
📝 OpenVSX is not auto-discovered from Nexus or Artifactory. Define an OpenVSX route manually under
path_routing.routes.
📝 HuggingFace repositories are discovered from Artifactory only. Nexus auto-discovery does not route HuggingFace repositories.
Formats Socket does not scan natively (docker, helm, raw, yum, and others) can still be protected with External Registry Cooldown, which blocks recently published packages based on their publish date.
Deployment Topologies
1. Upstream Deployment (Most Common)
Nexus proxy repositories pull packages through the firewall. Developers and CI use Nexus directly.
Developer / CI ---> Nexus ---> Socket Firewall ---> Public Registry
(caching) (npmjs.org, pypi.org)
Benefits:
- Single enforcement point
- No developer config changes needed
- Nexus caches packages (most installs don't hit firewall)
- Centralized security for entire organization
Use when:
- You already have Nexus Repository Manager deployed
- Developers are already configured to use Nexus
- You want to protect package ingestion from public registries
See Upstream Deployment Setup →
2. Downstream Deployment
Developers and CI point at the firewall, which proxies to Nexus (which may host internal packages or proxy to public registries).
Developer / CI ---> Socket Firewall ---> Nexus ---> Public/Internal Registry
Benefits:
- Protect developer workstations directly
- Works with Nexus proxy, group, or hosted repos
- Can layer on top of existing Nexus setup
Use when:
- You want to protect specific teams or projects
- You have Nexus hosting internal packages
- You want an additional security layer beyond Nexus
See Downstream Deployment Setup →
3. Middle Deployment (Multi-Tier)
Firewall sits between two Nexus instances (e.g., Development → Production, Regional → Central).
Nexus Dev ---> Socket Firewall ---> Nexus Production
(Proxy) (Hosted/Proxy)
Benefits:
- Scan packages flowing between internal registries
- Supports multi-tier Nexus deployments
- Protects internal package distribution
Use when:
- You have multiple Nexus instances (Dev/Prod, Regional/Central)
- Packages flow between Nexus instances
- You need to scan internal package distribution
Auto-Discovery Configuration
Socket Firewall can automatically discover Nexus proxy and hosted repositories and create firewall routes without manual configuration.
📝 Every auto-discovered route has the form
/repository/<repo-name>and forwards to that repository on your Nexus instance. This builds the Downstream topology (client → firewall → Nexus). For the Upstream topology, use manual routes instead.
Basic Auto-Discovery
path_routing:
enabled: true
domain: socket-firewall.company.com
mode: nexus
private_registry:
api_url: https://nexus.company.com
api_key: your-nexus-api-token # or set the PRIVATE_REGISTRY_KEY env var
interval: 5m # Auto-sync every 5 minutesRoutes are discovered from Nexus and updated automatically on the sync interval. Repositories added or removed in Nexus appear and disappear without a firewall config change.
⚠️
socket.ymldoes not expand${VAR}placeholders. Credential fields must contain a literal value; to keep credentials out of the file, omitapi_keyand set thePRIVATE_REGISTRY_KEYenvironment variable instead.
Advanced Auto-Discovery
path_routing:
enabled: true
domain: socket-firewall.company.com
private_registry:
api_url: https://nexus.company.com
api_key: your-nexus-api-token # Token auth (takes precedence)
mode: nexus
# OR use basic auth with separate fields:
username: admin # Basic auth username
password: secret # Basic auth password
interval: 5m # Sync interval (30s, 5m, 1h, etc.)
ignore_ssl_errors: true # Disable verification of SSL when connecting to the Private Registry
include_pattern: "^(npm|pypi|maven)-.*" # Only npm/pypi/maven repos
exclude_pattern: "(tmp|test|snapshot)-.*" # Exclude temp/test repos
supported_ecosystems_only: true # Skip unsupported package types (default: true)
include_virtual: false # Include group repos (default: false)Leave include_virtual at false unless clients route through a group repository directly — the member repositories behind a group are discovered individually, and each keeps its own host allowlist and cooldown checks. See include_virtual and supported_ecosystems_only in the Configuration Reference.
How Auto-Discovery Works
- Firewall calls Nexus REST API:
GET /service/rest/v1/repositories - Filters for the repository types it routes:
proxyandhosted.grouprepositories are included only wheninclude_virtual: true - Parses repository list and extracts:
- Repository name
- Format (npm, pypi, maven2, etc.)
- Remote URL
- For
proxyrepositories, checks the remote URL against the known public registry hosts for that ecosystem. A repository proxying any other host gets a cooldown route when External Registry Cooldown is enabled, and no route otherwise - Creates firewall routes:
- Path:
/repository/{repo-name}/(Nexus-compatible path) - Upstream: Remote URL from repository config
- Registry: Inferred from format
- Path:
- Generates nginx configuration with discovered routes
- Repeats on interval, adding/removing routes as repositories change
Configuration Options for Auto-Discovery
private_registry:
api_url: https://nexus.company.com # Nexus base URL (required)
api_key: your-api-token # API token (takes precedence)
mode: nexus
# OR use basic auth with separate fields:
username: admin # Basic auth username
password: secret # Basic auth password
interval: 5m # Sync interval (default: 5m)
ignore_ssl_errors: true # Disable verification of SSL when connecting to the Private Registry (default: false)
include_pattern: ".*" # Regex to include repos (default: all)
exclude_pattern: "(tmp|test)-.*" # Regex to exclude repos (default: none)
supported_ecosystems_only: true # Skip unsupported package types (default: true)
include_virtual: false # Include group repos (default: false)The api_key can also be provided via the PRIVATE_REGISTRY_KEY environment variable.
Authentication priority: api_key (or PRIVATE_REGISTRY_KEY env var) takes precedence. If api_key is not set, username and password are combined as username:password for basic auth.
Service Account Permissions for Auto-Discovery
Auto-discovery calls the Nexus REST API to list repositories. The service account used for authentication needs read-only access to the repository listing endpoint.
API endpoint used: GET /service/rest/v1/repositories
This endpoint returns the name, format, type, and URL of every repository the authenticated user can see. No write operations are performed — the firewall only reads repository metadata to generate routes.
Minimum-Privilege Setup (Recommended)
Create a dedicated service account with the minimum permissions required:
-
Create a role in Nexus:
- Go to Administration → Security → Roles → Create Role → Nexus Role
- Role ID:
socket-firewall-discovery - Role Name: Socket Firewall Discovery
- Privileges: Add
nx-repository-view-*-*-browseandnx-repository-view-*-*-read - These privileges grant read-only visibility into all repositories. To restrict to specific formats, replace the first wildcard (e.g.,
nx-repository-view-npm-*-browsefor npm only) - Save
-
Create a local user:
- Go to Administration → Security → Users → Create Local User
- ID:
socket-firewall - Status: Active
- Roles: Assign only
socket-firewall-discovery - Save
-
Generate an API token (preferred over password):
- Log in as the new user
- Go to Profile → User Token → Access user token
- Use the
nameCode:passCodeasapi_keyinsocket.yml
Nexus Privilege Reference
| Privilege | Purpose | Required? |
|---|---|---|
nx-repository-view-*-*-browse | Browse repository contents in the UI and API | Yes |
nx-repository-view-*-*-read | Read repository metadata via REST API | Yes |
nx-repository-view-*-*-edit | Modify repository contents | No — not needed |
nx-repository-admin-*-*-* | Repository administration | No — not needed |
nx-apikey-all | Manage API keys | No — not needed |
Verifying Permissions
Test that the service account can list repositories:
# Using token auth (nameCode:passCode)
curl -u "nameCode:passCode" \
https://nexus.company.com/service/rest/v1/repositories
# Using API token (Bearer)
curl -H "Authorization: Bearer your-token" \
https://nexus.company.com/service/rest/v1/repositories
# Expected: JSON array of repository objects
# [{"name": "npm-proxy", "format": "npm", "type": "proxy", "url": "..."}, ...]If the response is 403 Forbidden, the account is missing the nx-repository-view privileges. If it returns an empty list, the account may have browse privileges scoped to specific repositories — widen the scope or use wildcard privileges.
Upstream Deployment Setup
Protect package ingestion by pointing Nexus proxy repos at the firewall. This walkthrough is self-contained: each step ends with a command that proves the step worked, so a failure always points at the layer you just touched.
📝 Using the Socket-hosted firewall? Your tenant already serves the per-ecosystem routes with a publicly trusted certificate, so you only need Steps 1 (token already provisioned with your tenant), 5, 6, and 7.
Before You Start
You'll need:
- A host for the firewall with Docker and Docker Compose, reachable from your Nexus server. Upstream deployments only see cache misses, so 2 CPU / 2 GB is usually enough to start.
- A DNS name for the firewall (e.g.,
socket-firewall.internal.company.com) that resolves from the Nexus host. - A Socket organization with Firewall enabled. If it isn't, the firewall logs an entitlement error at startup (Step 3 shows the check). Contact your Socket account team.
- Admin access to Nexus (repository settings, SSL certificates, and the SSRF protection setting if your firewall resolves to a private IP).
Step 1: Create the Socket API Token
- In the Socket dashboard, open your organization's settings and create an API token.
- Grant it exactly two scopes:
packages:listandentitlements:list. Nothing else is required. Prefer a dedicated least-privilege token over reusing a broader one. - Export it where you'll run the firewall:
export SOCKET_SECURITY_API_TOKEN=your-token-hereThe token is validated when the firewall starts (Step 3). Never put it in socket.yml: the file doesn't expand environment variables, and the container reads SOCKET_SECURITY_API_TOKEN directly.
Step 2: Create the TLS Certificate
Nexus fetches from the firewall over HTTPS, so the firewall needs a certificate for its DNS name. Pick one path:
-
Certificate from your internal CA (recommended): request a certificate whose SAN includes the firewall's DNS name. Save the full chain as
ssl/fullchain.pemand the key asssl/privkey.pem. -
Self-signed (labs and PoCs):
mkdir -p ssl openssl req -x509 -newkey rsa:2048 -nodes -keyout ssl/privkey.pem -out ssl/fullchain.pem -days 365 \ -subj "/CN=socket-firewall.internal.company.com" \ -addext "subjectAltName=DNS:socket-firewall.internal.company.com"
The SAN entry is not optional: Nexus runs on the JVM, and modern Java rejects certificates that only have a matching CN. The failure looks identical to a missing-trust error, which makes it miserable to debug after the fact.
Verify the certificate has the SAN before moving on:
openssl x509 -in ssl/fullchain.pem -noout -subject -ext subjectAltName
# expect: subjectAltName says DNS:socket-firewall.internal.company.comStep 3: Deploy the Firewall
Upstream uses manual per-ecosystem routes. One route per ecosystem; every Nexus repo of that format shares it. Auto-discovery does not apply here, because it generates routes that forward back to Nexus (see Auto-Discovery Configuration).
socket.yml:
socket:
api_url: https://api.socket.dev
fail_open: false # block installs if the Socket API is unreachable; set true to prefer availability
ports:
http: 8080
https: 8443
ssl:
cert: /etc/nginx/ssl/fullchain.pem
key: /etc/nginx/ssl/privkey.pem
# Upstream topology - Nexus -> firewall -> public registry
path_routing:
enabled: true
domain: socket-firewall.internal.company.com
client_rewrite_scheme: https # scheme for URLs rewritten in responses; upstream connections use path_routing.rewrite_scheme (default https)
routes:
- path: /npm
upstream: https://registry.npmjs.org
registry: npm
- path: /pypi
upstream: https://pypi.org
registry: pypi
- path: /maven
upstream: https://repo1.maven.org/maven2
registry: maven
- path: /cargo
upstream: https://index.crates.io
registry: cargo
- path: /rubygems
upstream: https://rubygems.org
registry: rubygems
- path: /nuget
upstream: https://api.nuget.org
registry: nuget
- path: /go
upstream: https://proxy.golang.org
registry: go
- path: /conda
upstream: https://repo.anaconda.com/pkgs/main
registry: conda
metadata_filtering:
enabled: true
include_unchecked_versions: true
max_versions: 100 # newest 100 versions are security-checked; older ones are served unchecked
nginx:
worker_processes: 4
worker_connections: 8192⚠️ Use
client_rewrite_scheme(not the olderrewrite_scheme) to control the scheme of rewritten URLs. Setting barerewrite_scheme: httpalso switches upstream connections to plain HTTP, and public registries answer those with redirects that break Nexus fetches.
docker-compose.yml:
services:
socket-firewall:
image: socketdev/socket-registry-firewall:latest
ports:
- "8080:8080"
- "8443:8443"
environment:
- SOCKET_SECURITY_API_TOKEN=${SOCKET_SECURITY_API_TOKEN}
volumes:
- ./socket.yml:/app/socket.yml:ro
- ./ssl:/etc/nginx/ssl
restart: unless-stoppedStart and verify:
docker compose up -d
# 1. Token and entitlement check. The firewall validates your API token at startup.
# The success line logs at INFO, which the default log_level suppresses, so check
# for the FAILURE line instead: no output means validation passed.
docker compose logs socket-firewall | grep -i "firewall access validation failed"
# expect: no output
# any hit means the token, its scopes, or the org's Firewall entitlement is wrong.
# Fix before continuing. For positive confirmation instead, set
# socket.log_level: debug and grep for "Firewall access validated at startup".
# 2. Route checks (drop -k once you're on a CA-signed certificate)
curl -k -o /dev/null -w "%{http_code}\n" \
https://socket-firewall.internal.company.com:8443/health # expect 200
curl -k -o /dev/null -w "%{http_code}\n" \
https://socket-firewall.internal.company.com:8443/npm/lodash # expect 200 (route works)
curl -k -o /dev/null -w "%{http_code}\n" \
https://socket-firewall.internal.company.com:8443/lodash # expect 404 (no route without the ecosystem path)Step 4: Make Nexus Trust the Firewall
Nexus must trust the firewall's certificate. Trust matters beyond the Remote storage URL itself: package metadata returned through the firewall has its download URLs rewritten to the firewall's hostname, and Nexus fetches those URLs directly.
Socket-hosted tenants and public-CA certificates: nothing to do. Keep TLS verification on and go to Step 5.
Internal CA or self-signed certificates:
-
Import the certificate into the Nexus truststore (survives Nexus upgrades, unlike editing the JVM
cacerts):-
UI: Administration → Security → SSL Certificates → Load certificate, paste the PEM or load from the firewall host
-
REST: the request body is the raw PEM, not JSON-wrapped:
curl -u admin:PASS -X POST https://nexus.company.com/service/rest/v1/security/ssl/truststore \ -H 'Content-Type: application/json' --data-binary @fullchain.pem
-
-
In Step 5, enable Use the Nexus truststore under HTTP on each proxy repository (
httpClient.connection.useTrustStore: truevia the repositories API).
Corporate egress with TLS inspection: if traffic from Nexus to the firewall passes through a proxy that re-signs TLS, import the inspecting proxy's CA into the Nexus truststore the same way.
Verify from the Nexus host that the hostname, certificate, and network path line up:
curl -s -o /dev/null -w "%{http_code}\n" --cacert fullchain.pem \
https://socket-firewall.internal.company.com:8443/health
# expect 200: proves DNS, the network path, and that the cert matches the hostnameTesting only: you can uncheck Verify TLS/SSL certificate on a repo to rule TLS in or out while debugging. Turn it back on before production.
Step 5: Configure Nexus Proxy Repositories
Point each Nexus proxy repository to the firewall instead of the public registry. Hosted and group repositories don't change. Groups aggregate the proxy members, which are already protected once the proxies point at the firewall.
The Remote storage URL is per format, not per repo: every npm-format proxy repo uses the same /npm URL, every maven2 repo the same /maven URL, and so on. A repo created later just reuses its format's URL, so new-repo automation is a fixed lookup by format. The ecosystem path is required: a remote URL without it returns 404 for every request, which presents as "no traffic" on both sides.
Leave the repository's Authentication section empty; the firewall routes don't take credentials on this hop.
⚠️ SSRF protection (Nexus 3.7x+): Nexus rejects proxy remote URLs whose host resolves to a private IP (
Proxy URL blocked: Host resolves to private/local IP address(es)). Self-hosted firewalls on internal networks hit this. Allow the firewall's hostname first:curl -u admin:PASS -X PUT https://nexus.company.com/service/rest/v1/security/ssrf-protection \ -H 'Content-Type: application/json' \ -d '{"enabled": true, "allowedIPs": [], "allowedDomains": ["socket-firewall.internal.company.com"]}'
npm Proxy Repository
- Go to Administration → Repository → Repositories
- Click on your npm proxy repository (e.g.,
npm-proxy) - Under Proxy, change Remote storage URL from
https://registry.npmjs.orgto:https://socket-firewall.internal.company.com:8443/npm - If you imported a certificate in Step 4, check Use the Nexus truststore under HTTP
- Save
Verify immediately with one metadata fetch through the repo you just saved:
curl -s -o /dev/null -w "%{http_code}\n" https://nexus.company.com/repository/npm-proxy/lodash
# expect 200; a 404 means the Remote storage URL is missing the /npm path,
# and Nexus's own log shows TLS errors if trust isn't set up (Step 4)PyPI Proxy Repository
- Click on your PyPI proxy repository (e.g.,
pypi-proxy) - Change Remote storage URL to:
https://socket-firewall.internal.company.com:8443/pypi - Save
Maven Proxy Repository
- Click on your Maven proxy repository (e.g.,
maven-central) - Change Remote storage URL to:
https://socket-firewall.internal.company.com:8443/maven - Under Storage:
- Version policy: Release (or Mixed if needed)
- Layout policy: Permissive (recommended)
- Save
All Formats: Remote Storage URL Reference
| Nexus repo format | Remote storage URL |
|---|---|
| npm | https://socket-firewall.internal.company.com:8443/npm |
| pypi | https://socket-firewall.internal.company.com:8443/pypi |
| maven2 | https://socket-firewall.internal.company.com:8443/maven |
| cargo | https://socket-firewall.internal.company.com:8443/cargo |
| rubygems | https://socket-firewall.internal.company.com:8443/rubygems |
| nuget | https://socket-firewall.internal.company.com:8443/nuget |
| go | https://socket-firewall.internal.company.com:8443/go |
| conda | https://socket-firewall.internal.company.com:8443/conda |
Step 6: Validate
Run these in order. Each one isolates a different layer, so a failure tells you where to look.
6a. From the Nexus host (network, DNS, and TLS in one shot):
curl -s -o /dev/null -w "%{http_code}\n" https://socket-firewall.internal.company.com:8443/health # expect 200
curl -s -o /dev/null -w "%{http_code}\n" https://socket-firewall.internal.company.com:8443/npm/lodash # expect 200A failure here is network path, DNS, or TLS between Nexus and the firewall. Fix that before touching repo config.
6b. Through Nexus (safe package):
curl -s -o /dev/null -w "%{http_code}\n" https://nexus.company.com/repository/npm-proxy/lodash # expect 200 (metadata)
curl -s -o /dev/null -w "%{http_code}\n" https://nexus.company.com/repository/npm-proxy/lodash/-/lodash-4.17.21.tgz # expect 200 (download)The first fetch of any package is a cache miss and traverses the firewall; repeats are served from Nexus's cache without reaching the firewall. That's the design, not a bypass. To force a re-check of something already cached, invalidate the repo cache in Nexus.
6c. Through Nexus (blocked package):
⚠️ Never validate with live malware. If anything in the chain fails open, that download lands in your Nexus blob store. Use
[email protected]: it's the typosquat oflodash, flagged as known malware by Socket so the firewall blocks it, but the0.0.1-securityartifact itself is npm's empty security-holding placeholder, harmless by construction.
curl -s -o /dev/null -w "%{http_code}\n" https://nexus.company.com/repository/npm-proxy/lodahs/-/lodahs-0.0.1-security.tgz # expect 404The firewall answers Nexus with 403 plus x-socket-decision: blocked and x-socket-block-reason: Known malware; Nexus reports the failed remote fetch to its client as a 404 ({"success":false,"error":"Package 'lodahs' not found"}). See it unwrapped by hitting the firewall directly:
curl -skI https://socket-firewall.internal.company.com:8443/npm/lodahs/-/lodahs-0.0.1-security.tgz | grep -i x-socketMetadata filtering usually shows the same block. When every version of the typosquat has a malware verdict, the version list comes back empty and npm install lodahs fails with No matching version found:
curl -s https://nexus.company.com/repository/npm-proxy/lodahs | python3 -c \
'import json,sys; print("versions served:", list(json.load(sys.stdin).get("versions", {})))'
# expect: versions served: []If the list still includes 0.0.1-security, the metadata filter got no malware verdict for that version, and default settings keep versions without a verdict in listings. Check the direct firewall request above: x-socket-decision: blocked there means downloads are still blocked and only the listing differs.
6d. Firewall logs (proof the traffic traversed and the block fired):
📝 Self-hosted only. A Socket-hosted tenant has no container to read, so skip to the dashboard check below.
docker compose logs socket-firewall | grep lodash # allowed traffic
docker compose logs socket-firewall | grep "Known malware" # the blockEvents also appear in the Socket dashboard under Firewall, per package, with the decision and reason.
📝 What a block looks like to developers: blocked versions are filtered out of the version metadata the firewall serves (newest versions checked first), so
npm installof a blocked version typically fails withETARGET / No matching version found, and a direct tarball fetch surfaces as 404 through Nexus. Developers see "version not found", not a security error. When a version "disappears" through Nexus, check the Firewall events before debugging the package manager.
Step 7: Move to Production
Cut over in stages rather than all repos at once:
- Flip one proxy repo (npm is the easiest to validate) in a lower environment. Run 6a–6d.
- Flip the remaining formats in the lower environment; validate each with a safe fetch.
- Production window: repeat per format. Rollback is reverting the Remote storage URL. It takes effect immediately with no restart, and Nexus keeps serving everything it already cached in the meantime.
Operational notes for the runbook:
- Negative cache: if the firewall blocks a version and policy later allows it, Nexus's not-found cache keeps answering 404 until the TTL expires. Invalidate the repo cache (Administration → Repository → Repositories → Invalidate cache) to clear it immediately after policy changes.
- Auto-blocking: Nexus can auto-block a proxy repo ("Remote Unavailable") after repeated remote errors. During the cutover window, watch repository status; if a repo auto-blocks while you're iterating on config, fix the cause and un-block it rather than waiting out the backoff.
- Metadata freshness: the repo's metadata max age controls how quickly policy changes show up in version lists served by Nexus. The default (1440 minutes) is fine steady-state; a lower value during initial rollout makes validation faster.
- Nexus Community Edition: fresh CE installs must accept the EULA (onboarding wizard or
POST /service/rest/v1/system/eula) before Nexus serves proxied content. Until then, binary fetches return 403 from Nexus itself.
Downstream Deployment Setup
Developers point at the firewall, which proxies to Nexus.
Step 1: Define Routes
Every Nexus repository is served at https://nexus.company.com/repository/<repo>, so each route's upstream follows the same shape regardless of ecosystem.
socket.yml:
socket:
api_url: https://api.socket.dev
ports:
http: 8080
https: 8443
# Downstream topology (default) - client -> firewall -> Nexus
path_routing:
enabled: true
domain: firewall.company.com
config_mode: downstream
routes:
# Point to Nexus group or proxy repos
- path: /npm
upstream: https://nexus.company.com/repository/npm-group
registry: npm
- path: /pypi
upstream: https://nexus.company.com/repository/pypi-group
registry: pypi
- path: /maven
upstream: https://nexus.company.com/repository/maven-public
registry: maven
- path: /cargo
upstream: https://nexus.company.com/repository/cargo-group
registry: cargo
- path: /rubygems
upstream: https://nexus.company.com/repository/rubygems-group
registry: rubygems
- path: /nuget
upstream: https://nexus.company.com/repository/nuget-group
registry: nuget
- path: /go
upstream: https://nexus.company.com/repository/go-group
registry: go
- path: /conda
upstream: https://nexus.company.com/repository/conda-proxy
registry: condaStep 2: Client Configuration
Developers point at the firewall instead of Nexus:
# npm
npm config set registry https://firewall.company.com/npm/
# PyPI
pip config set global.index-url https://firewall.company.com/pypi/simple
# Maven (settings.xml)
# <mirror>
# <id>firewall</id>
# <url>https://firewall.company.com/maven/</url>
# <mirrorOf>central</mirrorOf>
# </mirror>
# Cargo (.cargo/config.toml)
# [registries.firewall]
# index = "https://firewall.company.com/cargo/"
# Go
export GOPROXY=https://firewall.company.com/go/,direct
# RubyGems
gem sources --add https://firewall.company.com/rubygems/ --remove https://rubygems.org/
# NuGet
dotnet nuget add source https://firewall.company.com/nuget/ -n firewall
# Conda
conda config --set custom_channels.main https://firewall.company.com/conda/Middle Deployment Setup
Firewall sits between two Nexus instances.
config_mode does not change how Nexus routes are generated: every discovered Nexus route uses the default mode: rewrite. For a middle topology, set mode: proxy explicitly on each route, as the example below does.
socket.yml:
socket:
api_url: https://api.socket.dev
ports:
http: 8080
https: 8443
# Middle topology - Nexus -> firewall -> Nexus
path_routing:
enabled: true
domain: socket-firewall.internal.company.com
config_mode: middle
routes:
# Dev Nexus proxy → Prod Nexus proxy
- path: /pypi
upstream: https://nexus-prod.company.com/repository/pypi-proxy
registry: pypi
mode: proxy # IMPORTANT - passes URLs unchanged
- path: /npm
upstream: https://nexus-prod.company.com/repository/npm-proxy
registry: npm
mode: proxyDev Nexus Configuration:
- Create proxy repository in Dev Nexus
- Set Remote storage URL to firewall:
- Remote URL:
https://socket-firewall.internal.company.com:8443/pypi
- Remote URL:
- Developers use Dev Nexus
Why mode: proxy is required:
- Production Nexus returns relative URLs like
../../packages/xyz/file.tar.gz mode: proxypasses these URLs through unchanged- Dev Nexus resolves relative URLs against its own base path
mode: rewritewould break this by rewriting URLs to firewall paths
Nexus Authentication
Generate API Token
- Log in to Nexus web UI as admin
- Click profile icon (top right) → User Token
- Click Access user token
- Enter admin password
- Copy the Name Code (username) and Pass Code (password)
- Use as API key:
Name Code:Pass Code(base64 encoded)
Or use the REST API:
# Get user token
curl -u admin:admin123 -X GET \
https://nexus.company.com/service/rest/v1/security/user-token
# Returns:
# {
# "nameCode": "abc123",
# "passCode": "xyz789"
# }
# Use in firewall config as: abc123:xyz789Using Basic Auth
You can authenticate with basic auth using separate username and password fields:
private_registry:
api_url: https://nexus.company.com
username: admin
password: admin123Alternatively, you can combine them in the api_key field:
private_registry:
api_url: https://nexus.company.com
api_key: admin:admin123 # username:password formatAuthentication priority: api_key (or PRIVATE_REGISTRY_KEY env var) takes precedence over username/password.
Security recommendation: Use API token instead of password for automation.
Troubleshooting
Every Request Through a Repo Returns 404
Symptom: the proxy repo saves fine, but all fetches fail and neither side shows meaningful traffic.
Cause: the Remote storage URL is missing its ecosystem path. https://firewall-host:8443 matches no route; requests hit the catch-all and return 404. Use https://firewall-host:8443/npm (or /maven, /pypi, ...) per the repo's format.
Nexus Rejects the Remote URL (SSRF Protection)
Symptom: saving the repo fails with Proxy URL blocked: Host resolves to private/local IP address(es).
Cause: Nexus 3.7x+ blocks proxy remotes that resolve to private IPs, which self-hosted firewalls on internal networks do. Allowlist the firewall hostname:
curl -u admin:PASS -X PUT https://nexus.company.com/service/rest/v1/security/ssrf-protection \
-H 'Content-Type: application/json' \
-d '{"enabled": true, "allowedIPs": [], "allowedDomains": ["socket-firewall.internal.company.com"]}'Truststore Import Fails with "Invalid PEM formatted certificate"
The /service/rest/v1/security/ssl/truststore endpoint takes the raw PEM as the request body. Wrapping it in JSON ({"pem": "..."}) produces this error. Use --data-binary @fullchain.pem.
Metadata Works but Downloads Fail
Symptom: version listings come through Nexus, but tarball/artifact downloads fail.
Cause: download URLs in metadata are rewritten to the firewall's hostname, and Nexus fetches them directly. If Nexus doesn't trust the firewall's certificate, those fetches fail even though the remote URL check passed. Import the cert into the Nexus truststore and enable Use the Nexus truststore on the repo (Step 4).
Nexus Can't Reach Firewall
Symptom: Nexus shows "Remote Unavailable" errors in repository health checks
Check:
# From Nexus server, test connectivity
curl -k https://socket-firewall.internal.company.com:8443/health
# Check DNS resolution
nslookup socket-firewall.internal.company.com
# Test HTTP connectivity
curl -v -k https://socket-firewall.internal.company.com:8443/npm/lodashSolution:
- Verify DNS record points to firewall host
- Ensure firewall ports (8080/8443) are accessible from Nexus
- Check firewall rules/security groups
- Verify no corporate proxy is interfering
SSL Certificate Errors
Symptom: Nexus logs show SSL handshake failures or certificate errors
Check first: the firewall's certificate must have a SAN entry matching the hostname Nexus uses. Java rejects CN-only certificates, and the error looks identical to a missing-trust error:
openssl s_client -connect socket-firewall.internal.company.com:8443 </dev/null 2>/dev/null \
| openssl x509 -noout -subject -ext subjectAltNameFix: import the certificate into the Nexus truststore and enable Use the Nexus truststore on each proxy repo (see Step 4). Prefer this over keytool edits to the JVM cacerts, which don't survive Nexus upgrades.
Testing only: uncheck "Verify TLS/SSL certificate" in the proxy repository settings to isolate TLS as the cause, then re-enable it.
Auto-Discovery Not Finding Repositories
Check Nexus API access:
# Test API connectivity
curl -u admin:admin123 \
https://nexus.company.com/service/rest/v1/repositories
# Should return JSON list of repositoriesCheck firewall logs:
docker compose logs socket-firewall | grep -i discovery
docker compose logs socket-firewall | grep -i nexusCommon issues:
- API token/credentials incorrect
- User lacks permissions (needs admin or role with repository read access)
api_urlincorrect (should be base Nexus URL, not including/service/rest)- Network connectivity from firewall to Nexus
- The repository is a
groupandinclude_virtualisfalse(the default) — its member repositories are discovered instead - A
proxyrepository points at a host that is not a known public registry for its format (a private registry or an internal mirror). Such repositories get a cooldown route when External Registry Cooldown is enabled and no route otherwise - Set
log_level: debugto confirm — skipped repositories are reported only at debug level
See the supported_ecosystems_only and include_virtual sections of the Configuration Reference for the full matrix of what gets a route.
Empty Package Lists
Symptom: npm search or pip search returns empty results through Nexus
Cause: Nexus metadata cache not populated yet
Solution:
- Trigger initial metadata download in Nexus:
- Go to Administration → Repository → Repositories → (your proxy repo)
- Click Rebuild Index or wait for scheduled task
- Wait for Nexus to fetch and cache metadata (can take several minutes for npm/pypi)
- Retry search
Maven Artifacts Not Found
Symptom: Maven builds fail to find artifacts from Nexus proxy
Check Nexus maven proxy settings:
- Version policy: Set to "Mixed" (or "Release" for central)
- Layout policy: Set to "Permissive"
- Content Disposition: Set to "Inline"
Check firewall logs:
docker compose logs socket-firewall | grep maven
docker compose logs socket-firewall | grep -i errorPackage Downloads Slow
Symptom: Package installs through Nexus → Firewall are slower than expected
Optimization steps:
- Check Nexus blob store - Ensure adequate disk space for caching
- Tune Nexus cache - Increase negative cache TTL in proxy repo settings
- Enable firewall Redis cache:
redis: enabled: true host: redis ttl: 86400 - Increase firewall workers:
nginx: worker_processes: 8 worker_connections: 16384
Best Practices
Repository Naming
Use consistent naming in Nexus to simplify filtering:
npm-proxy- Proxy to public npm registrynpm-hosted- Internal npm packagesnpm-group- Group combining proxy + hostedpypi-proxy- Proxy to public PyPIpypi-hosted- Internal Python packages
Then use filters in firewall:
include_pattern: ".*-proxy" # Only protect proxy repos
exclude_pattern: ".*-hosted" # Don't scan internal packagesCaching Strategy
Nexus caching + Firewall caching = Maximum efficiency:
- Nexus caches packages after first fetch
- Firewall caches verdicts, refreshing every 10 minutes for downloads and every hour for metadata checks by default; a stale verdict can still be served for up to 24 hours if the Socket API is unreachable
- Subsequent installs hit Nexus cache (never reach firewall)
- New packages hit firewall once, then cached by both
Result: Minimal latency overhead after initial fetch
📝 See Configuration Reference for the full set of cache TTL options.
Configure Nexus cache:
- Negative cache TTL: 1440 minutes (1 day)
- Metadata max age: 1440 minutes
- Enable "Not found cache"
Monitoring
Monitor both Nexus and Firewall:
Nexus:
- Repository health checks (green = healthy)
- Blob store usage
- Component download counts
- Failed proxy requests
Firewall:
- Block events (malicious packages blocked)
- API error rates
- Cache hit rates
- Request latency
Splunk integration (recommended):
splunk:
enabled: true
hec_url: https://splunk.company.com:8088/services/collector/event
hec_token: ${SPLUNK_HEC_TOKEN}
index: security
source: socket-firewall-nexusWebhook integration (any HTTP endpoint):
webhook:
enabled: true
url: https://siem.company.com/api/events
auth_header: "Bearer ${WEBHOOK_TOKEN}"
on_block: true
on_warn: true
# Optional: batch events as NDJSON instead of one POST per event
batch_enabled: true
batch_size: 524288 # flush at 512KB
batch_period: 5 # or every 5 secondsSee Delivery Modes for how batching affects delivery guarantees.
Prometheus metrics:
The firewall always serves GET /metrics on a dedicated port (metrics_port, default 9145). This listener is exempt from the bearer_token client auth gate, so restrict access to it at the network layer with nginx allow/deny rules or a Kubernetes NetworkPolicy. For these topologies the most useful families are the upstream-latency and firewall-overhead histograms, the circuit-breaker state gauges, socket_redis_available, and the cache hit and stale-serve counters.
The
/metricsexemption from the client auth gate requires version 2.0.7 or higher.
High Availability
For production deployments:
-
Multiple firewall instances with shared Redis cache:
services: socket-firewall-1: # ... firewall config socket-firewall-2: # ... firewall config redis: # ... shared Redis -
Load balancer in front of firewall instances
-
Nexus proxy repos point to load balancer VIP
-
Nexus HA (if using Nexus 3 Pro):
- Deploy Nexus in HA configuration
- All nodes point proxy repos to firewall load balancer
Security Hardening
- Use proper TLS certificates (not self-signed in production)
- Rotate API tokens regularly (Nexus → Security → User Tokens)
- Limit Nexus API user permissions to read-only repositories
- Use
fail_open: falsein production for maximum security - Monitor and alert on block events
- Enable Nexus audit logging for compliance
External Registry Cooldown for Unsupported Repos
Nexus often hosts repositories whose formats Socket does not scan natively (docker, helm, raw, yum, and others). External registry cooldown covers these repositories by blocking packages published more recently than a configurable window.
Cooldown in local mode requires Redis. In API mode Redis is used for caching when available. See External Registry Cooldown for the mode options.
How it works with auto-discovery:
- Auto-discovery detects all Nexus repositories, including unsupported formats
- Supported repositories get Socket API-checked routes as normal
- Unsupported repositories are matched against the configured cooldown registries
- Matched repositories get
cooldown-checked routes - Unmatched unsupported repositories are skipped — no route is generated
Matching runs by Nexus repository name first, then by remote URL (normalized, trailing slashes stripped).
Configuration
redis:
enabled: true
host: redis
port: 6379
path_routing:
enabled: true
domain: socket-firewall.company.com
private_registry:
api_url: https://nexus.company.com
api_key: ${NEXUS_API_KEY}
mode: nexus
interval: 5m
supported_ecosystems_only: true # Supported repos get Socket API checks
external_registry_cooldown:
enabled: true
cooldown_period: 7d # Block packages published within 7 days
# Match by repository name or remote URL
registries:
- name: helm-proxy
url: https://charts.helm.sh
ecosystem: npm # Ecosystem used for the publish-date lookup
# Or auto-discover the unsupported repos from Nexus
private_registry:
enabled: true
source: auto # Detect from path_routing.mode
include_unsupported_only: true # Only repos skipped by supported_ecosystems_onlyDocker Repositories Are Not Covered on Nexus
Cooldown routes are not generated for Docker-format Nexus repositories. Nexus serves Docker repositories on per-repository HTTP connector ports (or via subdomain routing), which the firewall's path-prefix routing cannot reach; auto-discovery logs a skip notice for these repositories.
Publish-Date Fallback
When the ecosystem lookup cannot determine a publish date, the firewall can query your Nexus instance directly with GET /service/rest/v1/search?repository=<repo>&name=<package>&version=<version> and use the earliest blobCreated timestamp across the matching assets, falling back to lastModified.
external_registry_cooldown:
enabled: true
cooldown_period: 7d
fallback: nexus # Or 'auto' when path_routing.mode is nexusThe fallback reuses the path_routing.private_registry credentials, so there is no extra authentication to configure. See Publish-Date Fallback for all fallback modes.
Reference
Nexus Proxy Repository Configuration
| Setting | Value |
|---|---|
| Name | npm-proxy, pypi-proxy, etc. |
| Format | npm, pypi, maven2, etc. |
| Remote storage | https://socket-firewall.company.com:8443/{ecosystem} |
| TLS/SSL verification | Disabled (if self-signed) or add cert to trust store |
| Negative cache TTL | 1440 minutes (recommended) |
Firewall Configuration Summary
| Topology | config_mode | route mode | URL Rewriting |
|---|---|---|---|
| Upstream | upstream | rewrite | Yes |
| Downstream | (default) | rewrite | Yes |
| Middle | middle | proxy (set per route) | No |
config_mode does not affect Nexus auto-discovery: discovered routes always use rewrite. In a middle topology, set mode: proxy on each route explicitly.
Supported Repository Formats
| Nexus Format | Firewall Registry | Notes |
|---|---|---|
| npm | npm | Full support |
| pypi | pypi | Full support |
| maven2 | maven | Full support |
| cargo | cargo | Full support |
| rubygems | rubygems | Full support |
| nuget | nuget | Full support |
| go | go | Full support |
| conda | conda | Experimental - treated as PyPI |
| helm | cooldown | Via external registry cooldown |
| raw | cooldown | Via external registry cooldown |
| yum | cooldown | Via external registry cooldown |
| (other) | cooldown | Via external registry cooldown |
| docker | — | Cooldown routes are not generated for Nexus Docker repositories |
Nexus REST API Endpoints
| Endpoint | Purpose |
|---|---|
/service/rest/v1/repositories | List all repositories |
/service/rest/v1/security/user-token | Generate API token |
/service/rest/v1/repositories/{name} | Get specific repository |
/service/rest/v1/status | Nexus health status |
Updated 20 days ago