---
updatedAt: 2026-08-05T21:10:05.000Z
agentTools:
  projectIndex: https://docs.socket.dev/llms.txt
---

# Artifactory Configuration

# Artifactory Integration Guide

Complete guide for integrating Socket Registry Firewall with JFrog Artifactory. Supports auto-discovery of repositories and four deployment topologies.

## Overview

Socket Registry Firewall integrates with Artifactory to protect package ingestion and distribution. The firewall can automatically discover and sync repository configurations from Artifactory, eliminating manual route configuration.

**Supported Artifactory repository types:**

| Artifactory Package Type | Firewall Registry | Firewall URL Path                       | Notes                                                                                                       |
| ------------------------ | ----------------- | --------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| npm                      | `npm`             | `/artifactory/api/npm/<repo>`           |                                                                                                             |
| pypi                     | `pypi`            | `/artifactory/api/pypi/<repo>`          |                                                                                                             |
| maven                    | `maven`           | `/artifactory/<repo>`                   | Direct path — no `/api/` prefix                                                                             |
| gradle                   | `maven`           | `/artifactory/<repo>`                   | Maven layout; see [cooldown](#external-registry-cooldown-for-unsupported-repos) for non-Maven-Central hosts |
| cargo                    | `cargo`           | `/artifactory/<repo>`                   | Direct path                                                                                                 |
| gems                     | `rubygems`        | `/artifactory/api/gems/<repo>`          |                                                                                                             |
| nuget (v2)               | `nuget`           | `/artifactory/api/nuget/<repo>`         |                                                                                                             |
| nuget (v3)               | `nuget`           | `/artifactory/api/nuget/v3/<repo>`      | Used for repository keys containing `v3`                                                                    |
| go                       | `go`              | `/artifactory/api/go/<repo>`            | Requires a virtual repository in front                                                                      |
| conda                    | `conda`           | `/artifactory/<repo>`                   | Direct path; experimental — scanned as PyPI                                                                 |
| huggingfaceml            | `huggingface`     | `/artifactory/api/huggingfaceml/<repo>` | Requires version 2.0.9 or higher                                                                            |

> **Important:** Artifactory smart remotes require the per-ecosystem path shown above. Using a different path triggers Artifactory's warning: *"Smart repository detected. URL format missing /api/\<package\_name>/"*

> :memo: **HuggingFace repositories are discovered from Artifactory only.** Nexus auto-discovery does not route HuggingFace repositories.

> :memo: **OpenVSX is not auto-discovered** from Artifactory or Nexus. Define an OpenVSX route manually under `path_routing.routes`.

Package types Socket does not scan natively (Docker, Helm, generic, and others) can still be protected with [External Registry Cooldown](#external-registry-cooldown-for-unsupported-repos), which blocks recently published packages based on their publish date.

***

## Deployment Topologies

### 1. Direct Deployment (Baseline — No Firewall)

Standard Artifactory setup with no security scanning. Remote repositories connect straight to the public registries. Use it as the "before" picture when comparing against the topologies below.

```
Developer / CI  --->  Artifactory  --->  Public Registry
                      (caching)          (npmjs.org, pypi.org)
```

| Ecosystem | Artifactory Remote URL                 | Notes                                            |
| --------- | -------------------------------------- | ------------------------------------------------ |
| npm       | `https://registry.npmjs.org`           |                                                  |
| PyPI      | `https://files.pythonhosted.org`       | **PyPI Registry URL**: `https://pypi.org`        |
| Maven     | `https://repo1.maven.org/maven2/`      |                                                  |
| Gradle    | `https://plugins.gradle.org/m2/`       |                                                  |
| Cargo     | `https://index.crates.io/`             | **Git Registry URL**: `https://index.crates.io/` |
| RubyGems  | `https://rubygems.org/`                |                                                  |
| NuGet v3  | `https://api.nuget.org/v3/index.json`  | **V3 Feed URL**: same value                      |
| NuGet v2  | `https://www.nuget.org/`               |                                                  |
| Go        | `https://proxy.golang.org/`            | Needs a virtual repository in front              |
| Conda     | `https://repo.anaconda.com/pkgs/main/` |                                                  |

***

### 2. Upstream Deployment (Most Common)

Artifactory remote repositories pull packages through the firewall. Developers and CI use Artifactory directly.

```
Developer / CI  --->  Artifactory  --->  Socket Firewall  --->  Public Registry
                      (caching)                                   (npmjs.org, pypi.org)
```

**Benefits:**

* Single enforcement point
* No developer config changes needed
* Artifactory caches packages (most installs don't hit firewall)
* Centralized security for entire organization

**Use when:**

* You already have Artifactory deployed
* Developers are already configured to use Artifactory
* You want to protect package ingestion from public registries

[See Upstream Deployment Setup →](#upstream-deployment-setup)

***

### 3. Downstream Deployment

Developers and CI point at the firewall, which proxies to Artifactory (which may or may not have its own upstream).

```
Developer / CI  --->  Socket Firewall  --->  Artifactory  --->  Public/Internal Registry
```

**Benefits:**

* Protect developer workstations directly
* Works with Artifactory virtual repos or local repos
* Can layer on top of existing Artifactory setup

**Use when:**

* You want to protect specific teams or projects
* You have Artifactory hosting internal packages
* You want an additional security layer beyond Artifactory

[See Downstream Deployment Setup →](#downstream-deployment-setup)

***

### 4. Middle Deployment (Multi-Tier)

Firewall sits between two Artifactory instances (e.g., On-Premise → Production, Regional → Central).

```
On-Premise Artifactory  --->  Socket Firewall  --->  Artifactory Production
(Virtual Repo)                                       (Remote Repo)
```

**Benefits:**

* Scan packages flowing between internal registries
* Supports Artifactory virtual repos aggregating remote repos
* Protects multi-tier Artifactory topologies

**Use when:**

* You have multiple Artifactory instances (On-Premise/Prod, Regional/Central)
* Packages flow between Artifactory instances
* You need to scan internal package distribution

[See Middle Deployment Setup →](#middle-deployment-setup)

***

## Auto-Discovery Configuration

Socket Firewall can automatically discover all Artifactory remote repositories and create firewall routes without manual configuration.

### Basic Auto-Discovery

```yaml
path_routing:
  enabled: true
  domain: socket-firewall.company.com
  
  private_registry:
    api_url: https://artifactory.company.com/artifactory
    api_key: your-artifactory-api-key  # Or use env var ARTIFACTORY_API_KEY
    mode: artifactory
    interval: 5m  # Auto-sync every 5 minutes
```

Routes are discovered from Artifactory and updated automatically. No need to manually define each route!

### Advanced Auto-Discovery

```yaml
path_routing:
  enabled: true
  domain: socket-firewall.company.com
  
  private_registry:
    api_url: https://artifactory.company.com/artifactory
    api_key: your-artifactory-api-key    # Token auth (takes precedence)
    mode: artifactory
    # 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 VIRTUAL repos (default: false)
```

Leave `include_virtual` at `false` unless clients route through a virtual repository directly — the member repositories behind a virtual aggregator are discovered individually, and each keeps its own host allowlist and cooldown checks. See `include_virtual` and `supported_ecosystems_only` in the [Configuration Reference](https://docs.socket.dev/docs/socket-firewall-enterprise-registry-mode-configuration-reference).

### How Auto-Discovery Works

1. Firewall calls Artifactory REST API: `GET /api/repositories`
2. Filters for the repository types it routes: `REMOTE`, `LOCAL`, `FEDERATED`, and `DISTRIBUTION`. `VIRTUAL` repositories are included only when `include_virtual: true`
3. Parses repository list and extracts:
   * Repository key (name)
   * Package type (npm, pypi, maven, etc.)
   * Repository type (`REMOTE`, `LOCAL`, `FEDERATED`, `DISTRIBUTION`, or `VIRTUAL`)
4. For `REMOTE` 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](#external-registry-cooldown-for-unsupported-repos) is enabled, and no route otherwise
5. Creates firewall routes for each discovered repository — both the ecosystem API path (`/artifactory/api/{package-type}/{repo-key}`) and the direct path (`/artifactory/{repo-key}`), so Artifactory smart remotes work with either URL form
6. Generates nginx configuration with discovered routes
7. Repeats on interval, adding/removing routes as repositories change

### Service Account Permissions for Auto-Discovery

Auto-discovery calls the Artifactory REST API to list repositories. The service account used for authentication needs **read-only** access to the repository listing endpoint.

**API endpoint used:** `GET /api/repositories`

This endpoint returns the key, package type, repository 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 group** in Artifactory:
   * Go to **Administration → Identity & Access → Groups → New Group**
   * **Group Name**: `socket-firewall-discovery`
   * **Auto Join**: No

2. **Create a permission target**:
   * Go to **Administration → Identity & Access → Permissions → New Permission**
   * **Name**: `socket-firewall-read`
   * **Resources → Repositories**: Select **Any Repository** (or only the repositories you want the firewall to discover)
   * **Groups**: Add `socket-firewall-discovery` with **Read** permission only
   * Do **not** grant Deploy, Annotate, Delete, or Manage
   * **Save**

3. **Create a local user**:
   * Go to **Administration → Identity & Access → Users → New User**
   * **Username**: `socket-firewall`
   * **Status**: Enabled
   * **Groups**: Add to `socket-firewall-discovery`
   * **Save**

4. **Generate an API key** (preferred over password):

   * Log in as the new user
   * Go to **Edit Profile → API Key → Generate**
   * Use this key as `api_key` in `socket.yml`

   Alternatively, generate an **Access Token** (Artifactory 7.x+):

   * Go to **Administration → Identity & Access → Access Tokens → Generate Token**
   * **Token Scope**: User `socket-firewall`
   * Use the token as `api_key` in `socket.yml`

#### Artifactory Permission Reference

| Permission | Purpose                                   | Required?       |
| ---------- | ----------------------------------------- | --------------- |
| Read       | Read/list repositories and their metadata | **Yes**         |
| Deploy     | Upload artifacts                          | No — not needed |
| Annotate   | Add/modify properties on artifacts        | No — not needed |
| Delete     | Delete artifacts or repositories          | No — not needed |
| Manage     | Administer permissions and settings       | No — not needed |

> **Note (Artifactory Cloud / SaaS):** If you use Artifactory Cloud (JFrog Platform), the same permissions apply. Use a scoped **Access Token** with read-only permissions. Navigate to **Administration → Identity & Access → Access Tokens** to generate one.

#### Verifying Permissions

Test that the service account can list repositories:

```bash
# Using API key
curl -H "X-JFrog-Art-Api: your-api-key" \
  https://artifactory.company.com/artifactory/api/repositories

# Using basic auth (username:password)
curl -u "socket-firewall:password" \
  https://artifactory.company.com/artifactory/api/repositories

# Using Access Token (Artifactory 7.x+)
curl -H "Authorization: Bearer your-access-token" \
  https://artifactory.company.com/artifactory/api/repositories

# Expected: JSON array of repository objects
# [{"key": "npm-remote", "type": "REMOTE", "packageType": "npm", "url": "..."}, ...]
```

If the response is `401 Unauthorized`, the API key or token is invalid. If it returns `403 Forbidden`, the user lacks the Read permission on repositories. If it returns an empty list, the permission target may be scoped too narrowly — ensure it includes the repositories you want to discover.

***

## Upstream Deployment Setup

Protect package ingestion by pointing Artifactory remote repos at the firewall.

### Step 1: Deploy Socket Firewall

**socket.yml:**

```yaml
socket:
  api_url: https://api.socket.dev

ports:
  http: 8080
  https: 8443

# Upstream topology - Artifactory -> firewall -> public registry

path_routing:
  enabled: true
  domain: socket-firewall.internal.company.com
  config_mode: upstream
  
  private_registry:
    api_url: https://artifactory.company.com/artifactory
    api_key: ${ARTIFACTORY_API_KEY}
    mode: artifactory  # Auto-discovery
    interval: 5m
    exclude_pattern: "(tmp|test)-.*"

nginx:
  worker_processes: 4
  worker_connections: 8192
```

**docker-compose.yml:**

```yaml
services:
  socket-firewall:
    image: socketdev/socket-registry-firewall:latest
    ports:
      - "8080:8080"
      - "8443:8443"
    environment:
      - SOCKET_SECURITY_API_TOKEN=${SOCKET_SECURITY_API_TOKEN}
      - ARTIFACTORY_API_KEY=${ARTIFACTORY_API_KEY}
    volumes:
      - ./socket.yml:/app/socket.yml:ro
      - ./ssl:/etc/nginx/ssl
    restart: unless-stopped
```

**Start:**

```bash
docker compose up -d
curl -k https://socket-firewall.internal.company.com:8443/health
```

### Step 2: Configure Artifactory Remote Repositories

In **Administration → Repositories → Remote**, edit each remote repository and replace the public registry URL with the firewall URL for that ecosystem. Substitute your own repository key for the example keys.

> **Important:** Each ecosystem has its own path form. Artifactory reports *"Smart repository detected. URL format missing /api/\<package\_name>/"* when the URL uses the wrong form, and several ecosystems fail outright.

| Ecosystem   | Firewall URL                                                            | Other settings that matter                                                                                                                                   |
| ----------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| npm         | `https://socket-firewall:8443/artifactory/api/npm/npm-remote`           | **Repository Layout**: `npm-default`                                                                                                                         |
| PyPI        | `https://socket-firewall:8443/artifactory/api/pypi/pypi-remote`         | **PyPI Registry URL**: the same firewall URL; **Repository Suffix**: `simple`; **Repository Layout**: `simple-default`                                       |
| Maven       | `https://socket-firewall:8443/artifactory/maven-central-remote`         | **Repository Layout**: `maven-2-default`; **Handle Releases**: Yes; **Handle Snapshots**: Yes; **Suppress POM Consistency Checks**: Yes                      |
| Gradle      | `https://socket-firewall:8443/artifactory/gradle-plugins-remote`        | **Repository Layout**: `maven-2-default`; **Handle Releases**: Yes; **Handle Snapshots**: Yes                                                                |
| Cargo       | `https://socket-firewall:8443/artifactory/cargo-remote`                 | **Git Registry URL**: the same firewall URL; **Repository Layout**: `cargo-default`; **Anonymous Access**: Yes                                               |
| RubyGems    | `https://socket-firewall:8443/artifactory/api/gems/gems-remote`         | **Repository Layout**: `simple-default`                                                                                                                      |
| NuGet v3    | `https://socket-firewall:8443/artifactory/api/nuget/v3/nuget-v3-remote` | **V3 Feed URL**: the same firewall URL; **Feed Context Path**: `api/v2`; **Download Context Path**: `api/v2/package`; **Repository Layout**: `nuget-default` |
| NuGet v2    | `https://socket-firewall:8443/artifactory/api/nuget/nuget-v2-remote`    | **Feed Context Path**: `api/v2`; **Download Context Path**: `api/v2/package`; **Repository Layout**: `nuget-default`                                         |
| Go          | `https://socket-firewall:8443/artifactory/api/go/go-remote`             | **VCS Git Provider**: `GITHUB`; **Repository Layout**: `go-default`; requires a virtual repository wrapping the remote                                       |
| Conda       | `https://socket-firewall:8443/artifactory/conda-main-remote`            | **Repository Layout**: `simple-default`                                                                                                                      |
| HuggingFace | `https://socket-firewall:8443/artifactory/api/huggingfaceml/hf-remote`  | Requires firewall version 2.0.9 or higher                                                                                                                    |

> **Note:** Maven, Gradle, Cargo, and Conda use the direct path (`/artifactory/<repo>`). Every other ecosystem uses the `/api/<type>/` prefix.

### Step 3: Common Settings for All Remotes

Apply these to every remote repository that points at the firewall:

| Setting                     | Value                | Reason                                                                                              |
| --------------------------- | -------------------- | --------------------------------------------------------------------------------------------------- |
| **Allow Any Host Auth**     | Yes                  | Required for Artifactory smart remote authentication                                                |
| **Store Artifacts Locally** | Yes                  | Caches scanned packages so repeat installs skip the firewall                                        |
| **Verify SSL Certificate**  | Yes (No for testing) | Add the firewall's CA to Artifactory's trust store in production rather than disabling verification |

### Step 4: Test

**Test npm:**

```bash
# Developers use Artifactory as normal
npm config set registry https://artifactory.company.com/artifactory/api/npm/npm-remote/
npm install lodash

# Check firewall logs
docker compose logs socket-firewall | grep lodash
```

**Test PyPI:**

```bash
pip config set global.index-url https://artifactory.company.com/artifactory/api/pypi/pypi-remote/simple
pip install requests

docker compose logs socket-firewall | grep requests
```

### Step 5: Verify Auto-Discovery

Check that the firewall discovered your Artifactory repositories:

```bash
# View discovered routes
docker compose exec socket-firewall cat /app/discovered-routes.yml

# Check logs for discovery events
docker compose logs socket-firewall | grep "Discovered.*repositories"
```

***

## Downstream Deployment Setup

Developers point at the firewall, which proxies to Artifactory.

### Step 1: Define Routes

**socket.yml:**

```yaml
socket:
  api_url: https://api.socket.dev

ports:
  http: 8080
  https: 8443

# Downstream topology (default) - client -> firewall -> Artifactory

path_routing:
  enabled: true
  domain: firewall.company.com
  config_mode: downstream
  
  routes:
    # Point to Artifactory virtual or remote repos
    - path: /npm
      upstream: https://artifactory.company.com/artifactory/api/npm/npm-virtual
      registry: npm
      
    - path: /pypi
      upstream: https://artifactory.company.com/artifactory/api/pypi/pypi-virtual
      registry: pypi
      
    - path: /maven
      upstream: https://artifactory.company.com/artifactory/maven-central-virtual
      registry: maven
      
    - path: /gradle
      upstream: https://artifactory.company.com/artifactory/gradle-plugins-virtual
      registry: maven
      
    - path: /cargo
      upstream: https://artifactory.company.com/artifactory/cargo-virtual
      registry: cargo
      
    - path: /rubygems
      upstream: https://artifactory.company.com/artifactory/api/gems/gems-virtual
      registry: rubygems
      
    - path: /nuget
      upstream: https://artifactory.company.com/artifactory/api/nuget/v3/nuget-v3-virtual
      registry: nuget
      
    - path: /go
      upstream: https://artifactory.company.com/artifactory/api/go/go-virtual
      registry: go
      
    - path: /conda
      upstream: https://artifactory.company.com/artifactory/conda-virtual
      registry: conda
```

### Step 2: Upstream URL Patterns

Each route's `upstream` must use the Artifactory path form for its ecosystem:

| Ecosystem | Route `upstream` Format            | Example                                      |
| --------- | ---------------------------------- | -------------------------------------------- |
| npm       | `/artifactory/api/npm/<repo>`      | `/artifactory/api/npm/npm-virtual`           |
| PyPI      | `/artifactory/api/pypi/<repo>`     | `/artifactory/api/pypi/pypi-virtual`         |
| Maven     | `/artifactory/<repo>`              | `/artifactory/maven-central-virtual`         |
| Gradle    | `/artifactory/<repo>`              | `/artifactory/gradle-plugins-virtual`        |
| Cargo     | `/artifactory/<repo>`              | `/artifactory/cargo-virtual`                 |
| RubyGems  | `/artifactory/api/gems/<repo>`     | `/artifactory/api/gems/gems-virtual`         |
| NuGet v3  | `/artifactory/api/nuget/v3/<repo>` | `/artifactory/api/nuget/v3/nuget-v3-virtual` |
| NuGet v2  | `/artifactory/api/nuget/<repo>`    | `/artifactory/api/nuget/nuget-v2-virtual`    |
| Go        | `/artifactory/api/go/<repo>`       | `/artifactory/api/go/go-virtual`             |
| Conda     | `/artifactory/<repo>`              | `/artifactory/conda-virtual`                 |

> **Note:** Maven, Gradle, Cargo, and Conda use direct paths. Every other ecosystem needs the `/api/<type>/` prefix.

### Step 3: Client Configuration

Developers point at the firewall instead of Artifactory:

```bash
# 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 Artifactory instances: the on-premise instance's remote repositories point through the firewall at the upstream (cloud) instance, which connects to the public registries.

```
On-Prem Artifactory  --->  Socket Firewall  --->  Cloud Artifactory  --->  Public Registry
```

### Step 1: Configure the Firewall for Middle Topology

Point auto-discovery at the **upstream** (cloud) Artifactory instance.

**socket.yml:**

```yaml
socket:
  api_url: https://api.socket.dev

ports:
  http: 8080
  https: 8443

# Middle topology - Artifactory -> firewall -> Artifactory

path_routing:
  enabled: true
  domain: socket-firewall.internal.company.com
  config_mode: middle
  
  private_registry:
    api_url: https://artifactory-prod.company.com/artifactory
    api_key: ${ARTIFACTORY_API_KEY}
    mode: artifactory  # Auto-discovery from the upstream Artifactory
    interval: 5m

nginx:
  worker_processes: 4
  worker_connections: 8192
```

With `config_mode: middle`, auto-discovery applies `mode: proxy` to the ecosystems that rewrite URLs inside package metadata — pypi, conda, npm, and nuget. Every other discovered ecosystem uses `mode: rewrite`. To define routes by hand instead, set `mode: proxy` per route:

```yaml
path_routing:
  routes:
    - path: /pypi
      upstream: https://artifactory-prod.company.com/artifactory/api/pypi/pypi-remote
      registry: pypi
      mode: proxy
```

**Why `mode: proxy` matters:**

* The upstream Artifactory returns relative URLs like `../../packages/xyz/file.tar.gz`
* `mode: proxy` passes these URLs through unchanged
* The on-premise Artifactory resolves relative URLs against its own base path
* `mode: rewrite` would rewrite them to firewall paths, which the on-premise instance cannot resolve

### Step 2: Configure On-Premise Remote Repositories

Point each on-premise remote repository at the firewall, using the same per-ecosystem URL forms and common settings as [Step 2](#step-2-configure-artifactory-remote-repositories) and [Step 3](#step-3-common-settings-for-all-remotes) of the upstream setup. The repository key in the URL is the key of the matching repository on the **upstream** instance.

Go additionally requires a virtual repository wrapping the remote on **both** Artifactory instances.

### Step 3: Create Virtual Repositories On-Premise

For each ecosystem, create an on-premise virtual repository that aggregates the firewall-facing remote (external packages, scanned) plus any local repositories (internal packages). Developers point at these virtual repositories.

| Ecosystem | Virtual Repo    | Includes Remote        | Includes Local |
| --------- | --------------- | ---------------------- | -------------- |
| npm       | `npm-virtual`   | `npm-remote`           | `npm-local`    |
| PyPI      | `pypi-virtual`  | `pypi-remote`          | `pypi-local`   |
| Maven     | `maven-virtual` | `maven-central-remote` | `maven-local`  |
| Go        | `go-virtual`    | `go-remote`            | `go-local`     |

### Step 4: Test the Chain

```bash
# From the on-premise Artifactory, check firewall connectivity
curl -k https://socket-firewall.internal.company.com:8443/health

# Install through the on-premise virtual repo
npm config set registry https://artifactory.company.com/artifactory/api/npm/npm-virtual/
npm install lodash

# Confirm the firewall scanned it
docker compose logs socket-firewall | grep lodash
```

***

## Troubleshooting

### Artifactory Can't Reach Firewall

**Symptom:** Artifactory shows connection errors when fetching packages

**Check:**

```bash
# From Artifactory server, test connectivity
curl -k https://socket-firewall.internal.company.com:8443/health

# Check DNS resolution
nslookup socket-firewall.internal.company.com

# Check firewall from Artifactory
ping socket-firewall.internal.company.com
```

**Solution:**

* Verify DNS record points to firewall host
* Ensure firewall ports (8080/8443) are accessible from Artifactory
* Check firewall rules/security groups

### SSL Certificate Errors

**Symptom:** Artifactory logs show SSL verification errors

**Option 1 - Trust firewall cert in Artifactory:**

```bash
# Copy firewall cert to Artifactory server
scp ssl/fullchain.pem artifactory-server:/tmp/socket-firewall.crt

# Add to Artifactory's Java trust store
keytool -import -alias socket-firewall \
  -keystore $JAVA_HOME/lib/security/cacerts \
  -file /tmp/socket-firewall.crt \
  -storepass changeit

# Restart Artifactory
```

**Option 2 - Disable SSL verification (testing only):**

* In Artifactory remote repo settings, uncheck "Verify SSL Certificate"

### Auto-Discovery Not Finding Repositories

**Check Artifactory API access:**

```bash
# Test API connectivity
curl -H "X-JFrog-Art-Api: your-api-key" \
  https://artifactory.company.com/artifactory/api/repositories

# Should return JSON list of repositories
```

**Check firewall logs:**

```bash
docker compose logs socket-firewall | grep -i discovery
docker compose logs socket-firewall | grep -i artifactory
```

**Common issues:**

* API key lacks permissions (needs "Read" on repositories)
* `api_url` incorrect (should end with `/artifactory`, not include `/api`)
* Network connectivity from firewall to Artifactory
* The repository is `VIRTUAL` and `include_virtual` is `false` (the default) — its member repositories are discovered instead
* A `REMOTE` repository proxies a host that is not a known public registry for its ecosystem (a private Artifactory, an internal mirror, or a service such as Google AOSS). Such repositories get a cooldown route when [External Registry Cooldown](#external-registry-cooldown-for-unsupported-repos) is enabled and no route otherwise. Gradle repositories are checked against the Maven hosts, so a Gradle remote proxying `plugins.gradle.org` needs a cooldown entry
* 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](https://docs.socket.dev/docs/socket-firewall-enterprise-registry-mode-configuration-reference) for the full matrix of what gets a route.

### Virtual Repo Doubled URLs

**Symptom:** Artifactory virtual repos return URLs like `/artifactory/api/pypi/pypi-virtual/artifactory/api/pypi/pypi-remote/packages/...`

**Solution:** Use `config_mode: middle` and `mode: proxy`:

```yaml
path_routing:
  config_mode: middle
  routes:
    - path: /pypi
      upstream: https://artifactory.company.com/artifactory/api/pypi/pypi-remote
      registry: pypi
      mode: proxy  # Critical - prevents URL rewriting
```

### Package Downloads Failing

**Check firewall is blocking correctly:**

```bash
# Try to install known malicious package
npm install some-malicious-package

# Check firewall logs for block
docker compose logs socket-firewall | grep -i block
```

**Check firewall is allowing correct packages:**

```bash
# Install known safe package
npm install lodash

# Should succeed - check logs
docker compose logs socket-firewall | grep lodash
```

### Private npm Packages Return 404 While Public Packages Install

**Symptom:** the client reports a 404 against the public registry, such as `GET https://registry.npmjs.org/@scope/private-pkg/-/private-pkg-1.0.0.tgz: Not Found`, together with "No authorization header was set for the request".

**Cause:** the download URL reached the client without being rewritten, so the client contacted the public registry directly instead of the firewall — and without your credentials.

**Check** that the metadata the firewall returns points back at the firewall:

```bash
curl -s -H "Authorization: Basic $SOCKET_AUTH_B64" \
  'https://firewall.company.com/npm/@scope%2fprivate-pkg' \
  | grep -o '"tarball":"[^"]*"' | head -3
```

Every `tarball` URL should name your firewall host. Public packages mask this condition: their un-rewritten downloads still succeed, but they reach the client unscanned — so treat a public-registry URL here as a problem even when installs appear to work.

> **Tarball URL rewriting across all npm metadata content types and encodings requires version 2.0.12 or higher.**

***

## Best Practices

### Repository Naming

Use consistent naming in Artifactory to simplify filtering:

* `npm-public` - Public npm registry
* `npm-internal` - Internal npm packages
* `pypi-public` - Public PyPI registry
* `pypi-internal` - Internal Python packages

Then use filters:

```yaml
include_pattern: ".*-public"  # Only protect public-facing repos
exclude_pattern: ".*-internal"  # Don't scan internal packages
```

### Caching Strategy

**Artifactory caching + Firewall caching = Maximum efficiency:**

1. Artifactory 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 Artifactory cache (never reach firewall)
4. New packages hit firewall once, then cached by both

**Result:** Minimal latency overhead after initial fetch

> :memo: See [Configuration Reference](https://docs.socket.dev/docs/socket-firewall-enterprise-registry-mode-configuration-reference) for the full set of cache TTL options.

### Monitoring

**Monitor both Artifactory and Firewall:**

Artifactory:

* Monitor remote repository health
* Check artifact download counts
* Review failed download requests

Firewall:

* Monitor block events (malicious packages)
* Check API error rates
* Review cache hit rates

**Splunk integration (recommended):**

```yaml
splunk:
  enabled: true
  hec_url: https://splunk.company.com:8088/services/collector/event
  hec_token: ${SPLUNK_HEC_TOKEN}
  index: security
  source: socket-firewall-artifactory
```

**Webhook integration (any HTTP endpoint):**

```yaml
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](https://docs.socket.dev/docs/socket-firewall-enterprise-registry-mode-configuration-reference#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:
   ```yaml
   services:
     socket-firewall-1:
       # ... firewall config
     socket-firewall-2:
       # ... firewall config
     redis:
       # ... shared Redis
   ```

2. **Load balancer** in front of firewall instances

3. **Artifactory remote repo** points to load balancer VIP

### Security Hardening

1. **Use proper TLS certificates** (not self-signed in production)
2. **Rotate API keys** regularly
3. **Limit Artifactory API key permissions** to read-only repositories
4. **Use `fail_open: false`** in production for maximum security
5. **Monitor and alert** on block events

***

## External Registry Cooldown for Unsupported Repos

Artifactory often hosts repositories whose package types Socket does not scan natively (Docker, Helm, generic, 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](https://docs.socket.dev/docs/socket-firewall-enterprise-registry-mode-configuration-reference#external-registry-cooldown) for the mode options.

**How it works with auto-discovery:**

1. Auto-discovery detects all Artifactory repositories, including unsupported package types
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 Artifactory repository key first, then by remote URL (normalized, trailing slashes stripped).

### Configuration

```yaml
redis:
  enabled: true
  host: redis
  port: 6379

path_routing:
  enabled: true
  domain: socket-firewall.company.com
  
  private_registry:
    api_url: https://artifactory.company.com/artifactory
    api_key: ${ARTIFACTORY_API_KEY}
    mode: artifactory
    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 key or remote URL
  registries:
    - name: gradle-plugins-remote
      url: https://plugins.gradle.org/m2/
      ecosystem: maven
    - name: docker-hub-remote
      url: https://registry-1.docker.io
      ecosystem: docker
  
  # Or auto-discover the unsupported repos from Artifactory
  private_registry:
    enabled: true
    source: auto                      # Detect from path_routing.mode
    include_unsupported_only: true    # Only repos skipped by supported_ecosystems_only
```

A Gradle remote proxying `https://plugins.gradle.org/m2/` is checked against the Maven registry hosts, so it needs an entry like the one above to be routed.

### Docker and OCI Repositories

> **Docker/OCI cooldown requires version 2.0.9 or higher.**

Docker repositories get cooldown-checked routes on both path forms Artifactory serves: `/artifactory/api/docker/<repo>` (used by Docker clients and smart remotes) and `/artifactory/<repo>`. Configure them like any other cooldown registry with `ecosystem: docker` — `oci` is accepted as an alias and behaves identically, and PURLs are always emitted as `pkg:docker/...`.

| Request                                                    | Behavior                                                                                     |
| ---------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| Tag-referenced manifest (`.../v2/<image>/manifests/<tag>`) | Gated — a tag pull inside the cooldown window is blocked with 403 before any layer downloads |
| Digest-referenced manifest (`manifests/sha256:...`)        | Passes through                                                                               |
| Blobs and layers                                           | Passes through                                                                               |
| `/v2/` ping, `_catalog`, `tags/list`                       | Passes through                                                                               |

Image names with multiple path segments (`myorg/team/app`) are supported.

### Publish-Date Fallback

When the ecosystem lookup cannot determine a publish date, the firewall can read the artifact's `created` timestamp from Artifactory instead. It searches both the repository and its `<repo>-cache` variant and takes the earliest match, and it works on Artifactory OSS — no Pro license needed.

```yaml
external_registry_cooldown:
  enabled: true
  fallback: external      # Query Artifactory first, ecosystem lookup second
  # Or: fallback: artifactory  # Ecosystem lookup first, Artifactory second
```

The fallback reuses the `path_routing.private_registry` credentials, so there is no extra authentication to configure. See [Publish-Date Fallback](https://docs.socket.dev/docs/socket-firewall-enterprise-registry-mode-configuration-reference#publish-date-fallback) for all fallback modes.

***

## Reference

### Artifactory Remote Repository Configuration

| Setting                 | Value                                                                                                |
| ----------------------- | ---------------------------------------------------------------------------------------------------- |
| Repository Key          | `npm-remote`, `pypi-remote`, etc.                                                                    |
| Package Type            | npm, pypi, maven, etc.                                                                               |
| URL                     | The firewall URL for the ecosystem — see [Step 2](#step-2-configure-artifactory-remote-repositories) |
| Allow Any Host Auth     | Yes                                                                                                  |
| Verify SSL Certificate  | Yes (No only when using self-signed certificates in testing)                                         |
| Store Artifacts Locally | Yes (recommended)                                                                                    |

### Firewall Configuration Summary

| Topology   | config\_mode | route mode | URL Rewriting | Auto-Discovery |
| ---------- | ------------ | ---------- | ------------- | -------------- |
| Direct     | N/A          | N/A        | N/A           | N/A            |
| Upstream   | `upstream`   | `rewrite`  | Yes           | Yes            |
| Downstream | (default)    | `rewrite`  | Yes           | Optional       |
| Middle     | `middle`     | `proxy`\*  | No\*          | Yes            |

\* In `middle`, auto-discovery applies `proxy` to pypi, conda, npm, and nuget routes; other ecosystems use `rewrite`. Both the API path and the direct path are generated in every `config_mode`.

### Supported Package Types

| Artifactory Package Type | Firewall Registry | Notes                            |
| ------------------------ | ----------------- | -------------------------------- |
| npm                      | `npm`             | Full support                     |
| pypi                     | `pypi`            | Full support                     |
| maven                    | `maven`           | Full support                     |
| gradle                   | `maven`           | Maven layout                     |
| cargo                    | `cargo`           | Full support                     |
| gems                     | `rubygems`        | Full support                     |
| nuget                    | `nuget`           | Full support (v2 and v3 paths)   |
| go                       | `go`              | Full support                     |
| conda                    | `conda`           | Experimental - treated as PyPI   |
| huggingfaceml            | `huggingface`     | Requires version 2.0.9 or higher |
| docker                   | `cooldown`        | Via external registry cooldown   |
| helm                     | `cooldown`        | Via external registry cooldown   |
| generic                  | `cooldown`        | Via external registry cooldown   |
| (other)                  | `cooldown`        | Via external registry cooldown   |

<br />