Load balancing with NGiNX & Varnish

If you are using npm Enterprise and want to apply Varnish as a solution for load balancing then follow the steps below.

Preferred Topology

The recommended topology is to provide a dedicated host for NGiNX and Varnish to run on. In environments where a secondary instance is warranted to support the load, running NGiNX and Varnish on the primary will only introduce competition for resources and could destabilize your environment.


IMPORTANT

The configuration files provided assume that NGiNX and Varnish are each running on the same dedicated host, separate from the hosts for the primary and secondary npmE instances.


Install and Configure NGiNX

For directions on how to install NGiNX, see their tutorial here.

Edit the NGiNX Configuration

Change the NGiNX configuration to match the configuration specified below using the command:

sudo nano /etc/nginx/nginx.conf

nginx.conf contents

# -----------------------------------------------------------------------------
# 1. replace `your-domain.com` with your public-facing domain
# 2. replace `1.1.1.1` with your primary server's IP
# 3. replace worker_processes with 1 if host only has 1 core
# 4. add `fs.file-max = 4096` to `/etc/sysctl.conf`
# 5. copy your SSL pem file to `/etc/nginx/wildcard.pem`
# -----------------------------------------------------------------------------

user root;
worker_processes 2;
pid /var/run/nginx.pid;
worker_rlimit_nofile 30000;

events {
    worker_connections  4096;
}

http {
    upstream website {
      # primary server website.
      server 1.1.1.1:8081;
    }

    upstream registry {
        server 127.0.0.1:6081;
    }

    client_max_body_size  200M;
    keepalive_timeout     65;

    sendfile      on;
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    access_log    /var/log/nginx/access.log  main;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    # HTTPS - npmE website
    server {
        listen       443;
        server_name  your-domain.com;

        ssl                   on;
        ssl_certificate       /etc/nginx/wildcard.pem;
        ssl_certificate_key   /etc/nginx/wildcard.pem;
        ssl_session_timeout   5m;
        ssl_protocols         TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers           "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS";
        ssl_prefer_server_ciphers on;

        location / {
            proxy_pass       http://website;
              proxy_pass_request_headers on;
        }
    }

    # HTTPS - npmE Registry
    server {
        listen       443;
        server_name  registry.your-domain.com;

        ssl                   on;
        ssl_certificate       /etc/nginx/wildcard.pem;
        ssl_certificate_key   /etc/nginx/wildcard.pem;
        ssl_session_timeout   5m;
        ssl_protocols         TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers           "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS";
        ssl_prefer_server_ciphers on;

        location / {
            proxy_pass       http://registry;
            proxy_pass_request_headers on;
        }
    }

    # npm Enterprise on HTTPS.
    server {
        listen       4443;
        server_name  npm.your-domain.com;

        ssl                   on;
        ssl_certificate       /etc/nginx/wildcard.pem;
        ssl_certificate_key   /etc/nginx/wildcard.pem;
        ssl_session_timeout   5m;
        ssl_protocols         TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers           "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS";
        ssl_prefer_server_ciphers on;

        location / {
            proxy_pass       http://registry;
            proxy_pass_request_headers on;
        }
    }

    # HTTP -
    server {
        listen        80;
        server_name   npm.your-domain.com;
        rewrite       ^ https://$server_name$request_uri? permanent;
    }
}

Copy SSL Certificate

  • copy your SSL .pem fileto/etc/nginx/wildcard.pem`
  • reload the NGiNX configuration with sudo nginx -s reload

Increase File Handles

Edit your system control configuration with the following command and add the line shown:

sudo nano /etc/sysctl.conf

add line:

fs.file-max = 4096

Install and Configure Varnish

For directions on how to install Varnish, see their documentation here.

Edit the Varnish Configuration

Change the Varnish configuration to match the configuration specified below using the command:

sudo nano /etc/varnish/default.vcl

default.vcl contents

# -----------------------------------------------------------------------------
# 1. replace `1.1.1.1` with your primary server's IP
# 2. replace `2.2.2.2` with your secondary server's IP
# 3. duplicate `replica1` block for each secondary server
# 4. add additional replicas in `vcl_init` via `pkgread.add_backend()`
# -----------------------------------------------------------------------------

vcl 4.0;
import directors;
backend primary {
  .host = "1.1.1.1";
  .port = "8080";
  .probe = {
    .url = "/";
    .timeout = 2s;
    .interval = 30s;
    .window = 5;
    .threshold = 3;
  }
}

backend replica1 {
  .host = "2.2.2.2";
  .port = "8080";
  .probe = {
    .url = "/";
    .timeout = 2s;
    .interval = 30s;
    .window = 5;
    .threshold = 3;
  }
}

sub vcl_init {
  new pkgread = directors.round_robin();
  pkgread.add_backend(primary);
  pkgread.add_backend(replica1);
}

sub vcl_backend_response {
  unset beresp.http.Etag;
  if (bereq.url ~ "@" || bereq.url ~ "/-/whoami" || beresp.status >= 300 || bereq.method != "GET") {
    # DON'T CACHE SCOPED MODULES.
    set beresp.ttl = 0s;
  } else if (bereq.url ~ "\.tgz$") {
    # CACHE TARBALLS FOR A LONG TIME.
    set beresp.ttl = 21600s;
  } else if (bereq.url ~ "^/[^/]+$") {
    # DON'T CACHE JSON FOR LONG.
    set beresp.ttl = 300s;
  } else {
    # DON'T CACHE SPECIAL ROUTES
    set beresp.ttl = 0s;
  }
}

sub vcl_hash {
  hash_data(req.url);
  return (lookup);
}

sub vcl_recv {
  set req.http.X-Authorization = req.http.Authorization;
  unset req.http.Authorization;
  unset req.http.If-Modified-Since;
  # we can correct for specific package collisions here.
  if (req.method == "GET") {
    set req.backend_hint = pkgread.backend();
  } else {
    set req.backend_hint = primary;
  }
}

sub vcl_backend_response {
    if (beresp.status >= 300 && bereq.retries == 0 && bereq.method == "GET") {
        return(retry);
    }
}

sub vcl_backend_fetch {
  set bereq.http.Authorization = bereq.http.X-Authorization;
  if (bereq.retries > 0) {
      set bereq.backend = primary;
  }
}

Restart Varnish

On Debian systems

sudo service varnish restart

On CentOS/RHEL systems

sudo systemctl restart varnish

results matching ""

    No results matching ""