Usare NGINX come reverse proxy di ASP.NET Core

di Marco De Sanctis, in ASP.NET Core,

Come abbiamo sottolineato in passato, da ASP.NET Core 2.0 è possibile usare il web server interno Kestrel per esporre direttamente il nostro sito su internet. Tuttavia, utilizzare un reverse proxy offre indiscutibili vantaggi che ne potrebbero consigliare la scelta in alcuni scenari.

Immaginiamo, per esempio, di aver separato la nostra applicazione in diversi moduli, ognuno dei quali è implementato come una web application a sé stante: si tratta di una strategia di decomposizione assolutamente valida e in uso, sia per siti web che per un layer di microservice Web API. In questo caso, con un proxy davanti, possiamo gestire un routing a livello applicativo, assegnando a ogni applicazione uno specifico path.


Inoltre, come si nota dall'immagine, possiamo esporre HTTPS solo sul proxy - e quindi installare il nostro certificato in un unico punto - mentre il traffico "interno" avviene in HTTP.

Se abbiamo pensato di rilasciare la nostra applicazione su Docker, e nello specifico su Linux containers, uno dei proxy più utilizzati è NGINX (https://www.nginx.com/), la cui versione open source è gratuita anche in scenari di produzione.

Grazie al supporto di Visual Studio 2017 per Docker, e al tool Docker Compose, possiamo facilmente configurare NGINX già all'interno del nostro ambiente di sviluppo.

Immaginiamo di avere un'applicazione MyApplication. Attivando il supporto a Docker, troveremo un file docker-compose.yml generato da Visual Studio come il seguente:

version: '3'

services:
  myapplication:
    image: myapplication
    build:
      context: .
      dockerfile: myapplication/Dockerfile

Quando Docker Compose esegue questo file, genera internamente una virtual network in cui al momento è presente un solo container, quello della nostra applicazione, che risponde all'url http://myapplication (attenzione, questo URL è ovviamente valido solo all'interno della virtual network e non è esposto all'esterno, per esempio alla nostra macchina host).

Per poter aggiungere NGINX è intanto necessario specificare un file di configurazione. All'interno di una sottodirectory "nginx", aggiungiamo allora il file di configurazione nginx.conf seguente:

worker_processes 4;
 
events { worker_connections 1024; }
 
http {
  sendfile on;
 
  server {
    listen 80;
 
    location / {
      proxy_pass         http://myapplication/;
      proxy_redirect     off;
      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-Host $server_name;
    }
  }
}

Anche se è la prima volta che ci affacciamo a NGINX, il contenuto in realtà è facilmente comprensibile:

  • c'è una sezione server, in cui abbiamo specificato che vogliamo metterci in ascolto sulla porta 80 (listen 80);
  • c'è una sezione location /, in cui specifichiamo alcune impostazioni per la root del sito;
  • per questa location, abbiamo indicato che vogliamo girare le richieste a http://myapplication, che è l'indirizzo della nostra vera applicazione all'interno della virtual network di Docker;
  • le restanti righe servono a definire quali header, per es. l'host e l'indirizzo del chiamante, devono essere girati alla nostra applicazione.

Il modo più semplice per sfruttare questo file è quello di creare una Docker image personalizzata di NGINX che lo includa. Pertanto, nella stessa directory nginx, creiamo un file Dockerfile come il seguente:

FROM nginx
COPY nginx/nginx.conf /etc/nginx/nginx.conf

Il codice in questo caso è davvero banale: la nostra immagine eredita da quella ufficiale di NGINX e, come secondo passo, ci limitiamo a copiare il file di configurazione nella directory /etc/nginx, che è il path dove il server si aspetta di trovarlo.

A questo punto siamo pronti per integrare NGINX nel nostro sistema. Torniamo sul file docker-compose.yml e modifichiamolo in questo modo:

version: '3'

services:
  myapplication:
    image: myapplication
    build:
      context: .
      dockerfile: myapplication/Dockerfile
  
  myserver:
    image: myserver
    build:
      context: .
      dockerfile: nginx/Dockerfile
    depends_on:
    - myapplication
    ports:
    - 8080:80

In questa versione abbiamo aggiunto un nuovo servizio, chiamato myserver, che creiamo a partire dal Dockerfile di NGINX. La clausola depends_on fa sì che docker-compose crei questo servizio solo quando myapplication è effettivamente disponibile, mentre ports indica che vogliamo esporlo sulla porta 80 e mapparlo sulla 8080 del nostro laptop.

Se vogliamo far sì che, alla pressione di F5, Visual Studio apra il browser direttamente su localhost:8080, possiamo modificare le proprietà del progetto docker-compose (aprendole con il tasto destro) come nell'immagine in basso:


Se abbiamo svolto tutti i passaggi correttamente, eseguendo l'applicazione vedremo il nostro sito web, ma analizzando gli header della risposta, noteremo che effettivamente siamo passati attraverso NGINX prima di raggiungerlo.


Nel prossimo script vedremo come esporre più applicazioni sotto lo stesso host.

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

I più letti di oggi