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
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Azure Functions e OpenAPI: la coppia perfetta!
Gestire tipi complessi in query string grazie a IParsable in ASP.NET Core 7.0
Health monitoring con Azure Container App
Definire una tabella come memory optimized su Sql Server tramite EF Core
Sfruttare la local cache del browser tramite gli ETag in ASP.NET Core
Real world .NET Architecture
Migrare un progetto ASP.NET Core da .NET 6 a .NET 7
Log streaming di una Azure Container App
Sfruttare l'output cache di ASP.NET Core 7 con i controller
Utilizzare la keyword with in JavaScript
Leggere i dati di configurazione di ASP.NET Core da Azure Key Vault
Creare attributi generici in C#
I più letti di oggi
- Sfruttare la local cache del browser tramite gli ETag in #aspnetcore https://aspit.co/cfc di @crad77 #webapi #aspnetmvc #blazor #cache
- ecco tutte le novità pubblicate sui nostri siti questa settimana: https://aspit.co/wkly buon week-end!
- Linting di un Dockerfile con un workflow di GitHub
- Effettuare update massivi con Entity Framework Core 7