DNS override

Make the public registry hostnames resolve to the firewall, so existing install commands are protected with no per-tool config.

With a DNS override, registry.npmjs.org, pypi.org, and files.pythonhosted.org resolve to the firewall instead of the real registries. Package managers keep their default settings. Roll it out with corporate DNS or an MDM-pushed hosts file, and prove it first on one machine with /etc/hosts.

How it differs from the base setup

The base setup uses path routing: clients call https://sfw.example.com/npm/.... A DNS override needs domain-based routing: the firewall answers for the real registry hostnames directly.

Path routingDomain routing (this page)
Client configRequiredNone
Certificate coverssfw.example.comEach registry hostname
PyPI downloadsRewritten through the firewallfiles.pythonhosted.org must also be overridden

1. Certificate with the registry hostnames

cd ~/socket-fw
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout ssl/privkey.pem \
  -out ssl/fullchain.pem \
  -subj "/CN=sfw.example.com" \
  -addext "subjectAltName=DNS:sfw.example.com,DNS:registry.npmjs.org,DNS:pypi.org,DNS:files.pythonhosted.org"
chmod 644 ssl/fullchain.pem ssl/privkey.pem

2. socket.yml with domain-based routing

This replaces the path-routing socket.yml from Block installs with Firewall, which the other pages use. Back it up first so you can restore it:

cp socket.yml socket.yml.path-routing

Running path routing and domain routing in one instance isn't covered here. Confirm with Socket before combining them.

socket:
  api_url: https://api.socket.dev
  fail_open: true

ports:
  http: 8080
  https: 8443

registries:
  npm:
    domains: [registry.npmjs.org]
    upstream: https://registry.npmjs.org
  pypi:
    domains: [pypi.org, files.pythonhosted.org]
    upstream: https://pypi.org
🚧

upstream is required

Without upstream, the firewall skips the registry (WARN: Skipping npm: missing domains or upstream) and returns 404 for everything, while /health still reports OK.

Keep the compose file from Block installs with Firewall. The firewall must be on 443, because clients connect to the registry hostnames on the standard port.

docker compose up -d --force-recreate
sleep 15
docker compose logs socket-firewall | grep "Generating .* configuration for"

You should see one line per registry (npm, pypi). If a registry is missing, check for the Skipping warning.

❗️

Don't override DNS on the firewall host

The firewall reaches the real registries by name. If the firewall host also resolves registry.npmjs.org to itself, requests loop. Leave the firewall host (and its container's DNS) on normal resolution.

3. Prove it on one machine

On a test laptop, replace 10.0.0.5 with the firewall's IP:

sudo sh -c 'cat >> /etc/hosts <<HOSTS
10.0.0.5   registry.npmjs.org
10.0.0.5   pypi.org
10.0.0.5   files.pythonhosted.org
HOSTS'

Trust the firewall certificate (see Configure registry: dev), then:

npm config get registry      # still https://registry.npmjs.org/
npm cache clean --force
npm install lodash           # succeeds, through the firewall
npm install lodahs           # 403, blocked

To undo, remove the three lines from /etc/hosts. To return the firewall to path routing, cp socket.yml.path-routing socket.yml && docker compose up -d --force-recreate.

❗️

IPv6 bypass

/etc/hosts entries only override the IPv4 lookup. On a client with IPv6, DNS can still return the real registry's IPv6 (AAAA) addresses, and installs can go straight to the registry without touching the firewall. Check with getent ahosts (below): only the firewall's address may appear. For the single-machine demo, disable IPv6 on the test machine or add IPv6 entries pointing at the firewall. For rollout, suppress AAAA records for these hostnames in corporate DNS.

4. Roll out

Pick one:

  • Corporate DNS: A records (or a resolver policy) for the three hostnames pointing at the firewall, scoped to the client networks you want covered. Suppress or override the AAAA records too.
  • MDM: push the same /etc/hosts lines plus the firewall CA as a trusted root. On macOS with Jamf, use a configuration profile for the certificate and a policy script for the hosts entries.

Track coverage by matching the client_ip in firewall decision events against your MDM, DHCP, or VPN records. See Data.

Verify

  • docker compose logs socket-firewall | grep "Generating .* configuration for" shows npm and pypi
  • getent ahosts registry.npmjs.org (Linux) or dscacheutil -q host -a name registry.npmjs.org (macOS) returns only the firewall's address, with no real IPv6 addresses
  • npm install lodahs returns 403 with no registry config on the client
  • pip install requests succeeds (proves files.pythonhosted.org is covered)
  • The firewall logs show the client's IP

Troubleshooting

SymptomFix
Certificate errorThe cert's SAN list is missing a hostname, or the client doesn't trust the CA
pip resolves but wheels failfiles.pythonhosted.org is missing from DNS, the SAN, or domains
Everything hangs or loopsThe firewall host is resolving the registries to itself
Every request returns the "Error 404 - Socket Firewall" pageA registry is missing upstream, so no routes loaded
Some installs skip the firewallThe client is using IPv6. See the IPv6 bypass callout

Reference


Did this page help you?