Proxy Server via NGINX

Een reverse proxy ‘leeft’ achter de Internet router en het verkeer weet dus al hoe de reverse proxy server te bereiken is, namelijk via het publieke IP adres van die router. Deze kan opgevraagd worden middels web-sites zoals myipaddress.com e.d.

De reverse proxy ‘vertaald’ binnenkomende URL’s en stuurt deze door naar de doelserver. De URL’s worden in de http-header meegestuurd tijdens de vraag naar een URL, bijvoorbeeld http://my.domain.nl

In de DNS server van het domein domain.nl wordt een A-record gemaakt met de naam ‘my.domain.nl’ dat naar het publieke adres van de proxy-server verwijst. Vervolgens kan voor elke URL een CNAME-record (alias) gemaakt worden die dan weer verwijst naar het A-record.

De configuratie van NGINX bestaat standaard uit een bestand genaamd ‘default‘ in /etc/nginx/sites-available/ en heeft een link in /etc/nginx/sites-enabled/ Je kunt dat bestand ‘default’ vervangen door een gelijknamig bestand met de proxy-instellingen of verwijderen en maak dan nieuwe bestanden in sites-available met links in sites-enabled. Hierna wel de nginx-service restarten.

Reverse Proxy

De proxy ontvangt dit en zoekt in de configuratie of er een verwijzing voor deze URL aanwezig is en wat dan de doelserver is. Indien gevonden, wordt de aanvraag doorgestuurd. Zo’n configuratie ziet er dan bv. alsvolgt uit voor http://my.domain.nl:

server {
  listen 80;
  listen [::]:80;
  server_name my.domain.nl;
  location / {
       proxy_pass http://192.168.1.101:30123/;
   }
 }

Hier wordt de externe aanvraag via http (dus TCP/port 80) doorgestuurd naar een web-server die luistert op TCP/port 30123. Buiten het voordeel van port 80 is er tevens het voordeel dat al het verkeer dus eerst via de proxy-server binnenkomt en hier kunnen de aanvragen gecontroleerd worden op malware, aanvallen, etc…

Ook kan in de configuratie van de proxy-server het verkeer gesplitst worden naar verschillende servers als de URL verschillend is, bijvoorbeeld voor http://my.domain.nl/v1 en http://my.domain.nl/v2, inhoud van bestand /etc/nginx/sites-available/proxy.conf:

server {
   listen 80;
   server_name my.domain.nl;
   location /v1 {
       proxy_pass http://192.168.1.102:30202/;
   }
   location /v2 {
       proxy_pass http://192.168.1.103:30203/;
   }
 }

Maak de soft-link in /etc/nginx/sites-enabled alsvolgt:

$ cd /etc/nginx/sites-enabled
$ sudo ln -s /etc/nginx/sites-available/proxy.conf
$ sudo nginx -t
$ sudo nginx -s reload

SSL Certificaten

De reverse proxy kan ook gebruikt worden om https-verkeer door te sturen naar een webserver. De certificaten kunnen aangevraagd worden via Let’s Encrypt m.b.v. ’certbot’. Zie daarvoor deze post. De nginx configuratie ziet er dan bv. alsvolgt uit voor my.domain.nl website naar server met ip adres 1.2.3.4:

server {
   listen 443 ssl http2;
   server_name my.domain.nl;

   ssl_certificate /etc/letsencrypt/live/my.domain.nl/fullchain.pem;
   ssl_certificate_key /etc/letsencrypt/live/my.domain.nl/privkey.pem;

   proxy_http_version 1.1;
   proxy_set_header Upgrade $http_upgrade;
   proxy_set_header Connection "Upgrade";
   proxy_set_header Host $host;
   proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
   proxy_set_header X-Forwarded-Proto $scheme;

   location / {
     proxy_pass https://1.2.3.4;
     proxy_ssl_verify off;
   }
}

Om het http verkeer dan te ‘redirecten‘ naar https, vervangen we de ‘oude’ configuratie bij het server-gedeelte van poort 80 (http) door het volgende:

server {
   listen 80;
   server_name    my.domain.nl;
   return         301 https://$server_name$request_uri;
 }

Hierna dient de nginx proxy server gecontroleerd en herstart te worden:

$ sudo nginx -t
$ sudo nginx -s reload

Load Balancer

Met de proxy-server kan ook een load-balancer geconfigureerd worden. Hiervoor definieren we eerst een groep servers als ‘backend’. Vervolgens kan een http-aanvraag naar de backend groep gestuurd worden. Plaats het volgende blok in /etc/nginx/nginx.conf binnen het http gedeelte:

##
# Loadbalancer sets
##
upstream backend {
   server 192.168.1.101; 
   server 192.168.1.102;
   server 192.168.1.103;
} 

Vervolgens kiezen we voor deze loadbalancer set in bv. /etc/nginx/sites-available/loadbalancer.conf:

server {
   listen 80;
   server_name my.domain.nl; 
   location / {
      proxy_set_header Host $host;
      proxy_set_header X-Forwarded-For $remote_addr;
      proxy_pass http://backend;
   }
}

Voor het load-balancen zijn er een aantal methodes. Standaard wordt ‘round-robin‘ gebruikt, de aanvragen worden dan evenredig verdeelt tussen de servers in de upstream. Andere methodes zijn:

least_conn; = stuur de aanvraag naar de server met de minste connecties.

ip_hash; = stuur de aanvraag van hetzelfde bron-ip-adres naar dezelfde server

Een upstream configuratie voor least_conn zou er dan alsvolgt uitzien:

upstream backend {
      least_conn;
      server 192.168.1.101; 
      server 192.168.1.102;
      server 192.168.1.103;
   }

Tevens kunnen de aanvragen naar servers onderling gestuurd worden met een ‘weight‘. Hierdoor kunnen sommige servers meer aanvragen te verwerken krijgen dan anderen. Hoe hoger het getal, hoe meer aanvragen. De configuratie voor de upstream ziet er dan bv. zo uit:

   upstream backend {
      server 192.168.1.101 weight=4; 
      server 192.168.1.102 weight=2;
      server 192.168.1.103;
   }
$ cd /etc/nginx/sites-enabled
$ sudo ln -s /etc/nginx/sites-available/loadbalancer.conf
$ sudo nginx -t
$ sudo nginx -s reload