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 FormatFirewall RegistryNotes
npmnpmFull support
pypipypiFull support
maven2mavenFull support
cargocargoFull support
rubygemsrubygemsFull support
nugetnugetFull support
gogoFull support
condacondaExperimental - 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

See Middle Deployment Setup →


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 minutes

Routes 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.yml does not expand ${VAR} placeholders. Credential fields must contain a literal value; to keep credentials out of the file, omit api_key and set the PRIVATE_REGISTRY_KEY environment 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

  1. Firewall calls Nexus REST API: GET /service/rest/v1/repositories
  2. Filters for the repository types it routes: proxy and hosted. group repositories are included only when include_virtual: true
  3. Parses repository list and extracts:
    • Repository name
    • Format (npm, pypi, maven2, etc.)
    • Remote URL
  4. For proxy repositories, 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
  5. Creates firewall routes:
    • Path: /repository/{repo-name}/ (Nexus-compatible path)
    • Upstream: Remote URL from repository config
    • Registry: Inferred from format
  6. Generates nginx configuration with discovered routes
  7. 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:

  1. 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-*-*-browse and nx-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-*-browse for npm only)
    • Save
  2. Create a local user:

    • Go to Administration → Security → Users → Create Local User
    • ID: socket-firewall
    • Status: Active
    • Roles: Assign only socket-firewall-discovery
    • Save
  3. Generate an API token (preferred over password):

    • Log in as the new user
    • Go to Profile → User Token → Access user token
    • Use the nameCode:passCode as api_key in socket.yml

Nexus Privilege Reference

PrivilegePurposeRequired?
nx-repository-view-*-*-browseBrowse repository contents in the UI and APIYes
nx-repository-view-*-*-readRead repository metadata via REST APIYes
nx-repository-view-*-*-editModify repository contentsNo — not needed
nx-repository-admin-*-*-*Repository administrationNo — not needed
nx-apikey-allManage API keysNo — 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

  1. In the Socket dashboard, open your organization's settings and create an API token.
  2. Grant it exactly two scopes: packages:list and entitlements:list. Nothing else is required. Prefer a dedicated least-privilege token over reusing a broader one.
  3. Export it where you'll run the firewall:
export SOCKET_SECURITY_API_TOKEN=your-token-here

The 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.pem and the key as ssl/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.com

Step 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 older rewrite_scheme) to control the scheme of rewritten URLs. Setting bare rewrite_scheme: http also 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-stopped

Start 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:

  1. 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
  2. In Step 5, enable Use the Nexus truststore under HTTP on each proxy repository (httpClient.connection.useTrustStore: true via 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 hostname

Testing 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

  1. Go to Administration → Repository → Repositories
  2. Click on your npm proxy repository (e.g., npm-proxy)
  3. Under Proxy, change Remote storage URL from https://registry.npmjs.org to:
    https://socket-firewall.internal.company.com:8443/npm
  4. If you imported a certificate in Step 4, check Use the Nexus truststore under HTTP
  5. 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

  1. Click on your PyPI proxy repository (e.g., pypi-proxy)
  2. Change Remote storage URL to:
    https://socket-firewall.internal.company.com:8443/pypi
  3. Save

Maven Proxy Repository

  1. Click on your Maven proxy repository (e.g., maven-central)
  2. Change Remote storage URL to:
    https://socket-firewall.internal.company.com:8443/maven
  3. Under Storage:
    • Version policy: Release (or Mixed if needed)
    • Layout policy: Permissive (recommended)
  4. Save

All Formats: Remote Storage URL Reference

Nexus repo formatRemote storage URL
npmhttps://socket-firewall.internal.company.com:8443/npm
pypihttps://socket-firewall.internal.company.com:8443/pypi
maven2https://socket-firewall.internal.company.com:8443/maven
cargohttps://socket-firewall.internal.company.com:8443/cargo
rubygemshttps://socket-firewall.internal.company.com:8443/rubygems
nugethttps://socket-firewall.internal.company.com:8443/nuget
gohttps://socket-firewall.internal.company.com:8443/go
condahttps://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 200

A 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 of lodash, flagged as known malware by Socket so the firewall blocks it, but the 0.0.1-security artifact 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 404

The 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-socket

Metadata 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 block

Events 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 install of a blocked version typically fails with ETARGET / 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:

  1. Flip one proxy repo (npm is the easiest to validate) in a lower environment. Run 6a–6d.
  2. Flip the remaining formats in the lower environment; validate each with a safe fetch.
  3. 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: conda

Step 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: proxy

Dev Nexus Configuration:

  1. Create proxy repository in Dev Nexus
  2. Set Remote storage URL to firewall:
    • Remote URL: https://socket-firewall.internal.company.com:8443/pypi
  3. Developers use Dev Nexus

Why mode: proxy is required:

  • Production Nexus returns relative URLs like ../../packages/xyz/file.tar.gz
  • mode: proxy passes these URLs through unchanged
  • Dev Nexus resolves relative URLs against its own base path
  • mode: rewrite would break this by rewriting URLs to firewall paths

Nexus Authentication

Generate API Token

  1. Log in to Nexus web UI as admin
  2. Click profile icon (top right) → User Token
  3. Click Access user token
  4. Enter admin password
  5. Copy the Name Code (username) and Pass Code (password)
  6. 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:xyz789

Using 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: admin123

Alternatively, you can combine them in the api_key field:

private_registry:
  api_url: https://nexus.company.com
  api_key: admin:admin123 # username:password format

Authentication 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/lodash

Solution:

  • 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 subjectAltName

Fix: 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 repositories

Check firewall logs:

docker compose logs socket-firewall | grep -i discovery
docker compose logs socket-firewall | grep -i nexus

Common issues:

  • API token/credentials incorrect
  • User lacks permissions (needs admin or role with repository read access)
  • api_url incorrect (should be base Nexus URL, not including /service/rest)
  • Network connectivity from firewall to Nexus
  • The repository is a group and include_virtual is false (the default) — its member repositories are discovered instead
  • A proxy repository 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: debug to 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:

  1. Trigger initial metadata download in Nexus:
    • Go to Administration → Repository → Repositories → (your proxy repo)
    • Click Rebuild Index or wait for scheduled task
  2. Wait for Nexus to fetch and cache metadata (can take several minutes for npm/pypi)
  3. Retry search

Maven Artifacts Not Found

Symptom: Maven builds fail to find artifacts from Nexus proxy

Check Nexus maven proxy settings:

  1. Version policy: Set to "Mixed" (or "Release" for central)
  2. Layout policy: Set to "Permissive"
  3. Content Disposition: Set to "Inline"

Check firewall logs:

docker compose logs socket-firewall | grep maven
docker compose logs socket-firewall | grep -i error

Package Downloads Slow

Symptom: Package installs through Nexus → Firewall are slower than expected

Optimization steps:

  1. Check Nexus blob store - Ensure adequate disk space for caching
  2. Tune Nexus cache - Increase negative cache TTL in proxy repo settings
  3. Enable firewall Redis cache:
    redis:
      enabled: true
      host: redis
      ttl: 86400
  4. 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 registry
  • npm-hosted - Internal npm packages
  • npm-group - Group combining proxy + hosted
  • pypi-proxy - Proxy to public PyPI
  • pypi-hosted - Internal Python packages

Then use filters in firewall:

include_pattern: ".*-proxy" # Only protect proxy repos
exclude_pattern: ".*-hosted" # Don't scan internal packages

Caching Strategy

Nexus caching + Firewall caching = Maximum efficiency:

  1. Nexus caches packages after first fetch
  2. 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
  3. Subsequent installs hit Nexus cache (never reach firewall)
  4. 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-nexus

Webhook 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 seconds

See 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 /metrics exemption from the client auth gate requires version 2.0.7 or higher.

High Availability

For production deployments:

  1. Multiple firewall instances with shared Redis cache:

    services:
      socket-firewall-1:
        # ... firewall config
      socket-firewall-2:
        # ... firewall config
      redis:
        # ... shared Redis
  2. Load balancer in front of firewall instances

  3. Nexus proxy repos point to load balancer VIP

  4. Nexus HA (if using Nexus 3 Pro):

    • Deploy Nexus in HA configuration
    • All nodes point proxy repos to firewall load balancer

Security Hardening

  1. Use proper TLS certificates (not self-signed in production)
  2. Rotate API tokens regularly (Nexus → Security → User Tokens)
  3. Limit Nexus API user permissions to read-only repositories
  4. Use fail_open: false in production for maximum security
  5. Monitor and alert on block events
  6. 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:

  1. Auto-discovery detects all Nexus repositories, including unsupported formats
  2. Supported repositories get Socket API-checked routes as normal
  3. Unsupported repositories are matched against the configured cooldown registries
  4. Matched repositories get cooldown-checked routes
  5. 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_only

Docker 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 nexus

The 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

SettingValue
Namenpm-proxy, pypi-proxy, etc.
Formatnpm, pypi, maven2, etc.
Remote storagehttps://socket-firewall.company.com:8443/{ecosystem}
TLS/SSL verificationDisabled (if self-signed) or add cert to trust store
Negative cache TTL1440 minutes (recommended)

Firewall Configuration Summary

Topologyconfig_moderoute modeURL Rewriting
UpstreamupstreamrewriteYes
Downstream(default)rewriteYes
Middlemiddleproxy (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 FormatFirewall RegistryNotes
npmnpmFull support
pypipypiFull support
maven2mavenFull support
cargocargoFull support
rubygemsrubygemsFull support
nugetnugetFull support
gogoFull support
condacondaExperimental - treated as PyPI
helmcooldownVia external registry cooldown
rawcooldownVia external registry cooldown
yumcooldownVia external registry cooldown
(other)cooldownVia external registry cooldown
docker—Cooldown routes are not generated for Nexus Docker repositories

Nexus REST API Endpoints

EndpointPurpose
/service/rest/v1/repositoriesList all repositories
/service/rest/v1/security/user-tokenGenerate API token
/service/rest/v1/repositories/{name}Get specific repository
/service/rest/v1/statusNexus health status


Did this page help you?