Skip to main content

Using a reverse proxy is a common practice. The following configurations are the most recommended and used ones.

Important, the headers are considered to resolve the public are X-Forwarded-Proto for the protocol and Host for the domain, please include them in your configuration.

Set trustProxy

Forwarding the headers is only half of it. Verdaccio also has to be told which upstream addresses to believe, otherwise every request looks like it comes from the proxy:

server:
trustProxy: '127.0.0.1'

Without it, rate limiting throttles all your users as if they were a single client, and the CIDR whitelist on npm tokens has nothing real to check against. See trustProxy.

Apache

A full docker example using the official httpd:2.4 image can be found in our Docker examples repository.

Apache and mod_proxy should not decode/encode slashes and leave them as they are.

Publishing large packages: Apache limits request bodies via LimitRequestBody (and front proxies may add their own limit). If npm publish of a big tarball fails with HTTP 413 Request Entity Too Large, add LimitRequestBody 0 (unlimited) inside the VirtualHost. The nginx equivalent is client_max_body_size 0;.

For installing at relative path, /npm, on the server

<VirtualHost *:80>
AllowEncodedSlashes NoDecode
ProxyPass /npm http://127.0.0.1:4873 nocanon
ProxyPassReverse /npm http://127.0.0.1:4873
</VirtualHost>

For installing at root path, /, on the server

<VirtualHost *:80>
ServerName your.domain.com
ServerAdmin hello@your.domain.com
ProxyPreserveHost On
AllowEncodedSlashes NoDecode
ProxyPass / http://127.0.0.1:4873/ nocanon
ProxyPassReverse / http://127.0.0.1:4873/
</VirtualHost>

Configuration with SSL

Apache virtual server configuration.

<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName npm.your.domain.com
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/npm.your.domain.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/npm.your.domain.com/privkey.pem
SSLProxyEngine On
ProxyRequests Off
ProxyPreserveHost On
AllowEncodedSlashes NoDecode
LimitRequestBody 0
ProxyPass / http://127.0.0.1:4873/ nocanon
ProxyPassReverse / http://127.0.0.1:4873/
RequestHeader set X-Forwarded-Proto "https"
</VirtualHost>
</IfModule>

Invalid checksum

Sometimes the gzip compression can mess with the request when running npm install and result in error messages like this:

npm WARN tar TAR_ENTRY_INVALID checksum failure
npm WARN tar zlib: incorrect data check

A possible fix for this, can be by disabling gzip compression for the virtual host, by adding this to your config:

SetEnv no-gzip 1

Resulting in a config like so:

<VirtualHost *:80>
AllowEncodedSlashes NoDecode
SetEnv no-gzip 1
ProxyPass /npm http://127.0.0.1:4873 nocanon
ProxyPassReverse /npm http://127.0.0.1:4873
</VirtualHost>

You should only add it to your virtual host config, if you are experiencing the issue.

Nginx

The following snippet is a full docker example can be tested in our Docker examples repository.

upstream verdaccio_v4 {
server verdaccio_relative_path_v4:4873;
keepalive 8;
}

upstream verdaccio_v4_root {
server verdaccio_relative_path_v4_root:8000;
keepalive 8;
}

upstream verdaccio_v3 {
server verdaccio_relative_path_latest_v3:7771;
keepalive 8;
}

server {
listen 80 default_server;
access_log /var/log/nginx/verdaccio.log;
charset utf-8;

# nginx limits request bodies to 1 MB by default, which makes `npm publish`
# of larger package tarballs fail with HTTP 413. Set 0 to disable the limit.
client_max_body_size 0;

location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
proxy_pass http://verdaccio_v4_root;
proxy_redirect off;
}

location ~ ^/verdaccio/(.*)$ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://verdaccio_v4/$1;
proxy_redirect off;
}

location ~ ^/verdacciov3/(.*)$ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_set_header X-NginX-Proxy true;

proxy_pass http://verdaccio_v3/$1;
proxy_redirect off;
}
}

SSL example

server {
listen 80;
return 302 https://$host$request_uri;
}

server {
# `listen ... ssl` enables TLS. The standalone `ssl on;` directive was
# removed in nginx 1.25.1, and the `http2` listen parameter is deprecated
# in favour of the `http2 on;` directive.
listen 443 ssl;
http2 on;
server_name localhost;

ssl_certificate /etc/nginx/cert.crt;
ssl_certificate_key /etc/nginx/cert.key;

ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
ssl_prefer_server_ciphers on;

location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://verdaccio_v4_root;
proxy_read_timeout 600;
proxy_redirect off;
}

location ~ ^/verdaccio/(.*)$ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://verdaccio_v4_root/$1;
proxy_redirect off;
}
}

Run behind reverse proxy with different domain and port

Sub-directory

If the whole URL is being used for Verdaccio, you don't need to define a url_prefix, otherwise you would need something like this in your config.yaml.

url_prefix: /sub_directory/

If you run Verdaccio behind reverse proxy, you may noticed all resource file served as relative path, like http://127.0.0.1:4873/-/static

To resolve this issue, you should send real domain and port to Verdaccio with Host header

Nginx configure should look like this:

location / {
proxy_pass http://127.0.0.1:4873/;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}

For this case, url_prefix should NOT set in Verdaccio config


or a sub-directory installation:

location ~ ^/verdaccio/(.*)$ {
proxy_pass http://127.0.0.1:4873/$1;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}

For this case, url_prefix should set to /verdaccio/

Note: There is a slash after the install path (https://your-domain:port/verdaccio/)!

Overriding the public url

The new VERDACCIO_PUBLIC_URL is intended to be used behind proxies, this variable will be used for:

  • Used as base path to serve UI resources as (js, favicon, etc)
  • Used on return metadata dist base path
  • Ignores host and X-Forwarded-Proto headers
  • If url_prefix is defined would be appened to the env variable.
VERDACCIO_PUBLIC_URL='https://somedomain.org';
url_prefix: '/my_prefix'

// url -> https://somedomain.org/my_prefix/

VERDACCIO_PUBLIC_URL='https://somedomain.org';
url_prefix: '/'

// url -> https://somedomain.org/

VERDACCIO_PUBLIC_URL='https://somedomain.org/first_prefix';
url_prefix: '/second_prefix'

// url -> https://somedomain.org/second_prefix/'

Screenshot from 2021-03-24 20-20-11