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
Creazione di componenti personalizzati in React.js con Tailwind CSS
Usare i servizi di Azure OpenAI e ChatGPT in ASP.NET Core con Semantic Kernel
Hosting di componenti WebAssembly in un'applicazione Blazor static
Sostituire la GitHub Action di login su private registry
Generare un hash con SHA-3 in .NET
C# 12: Cosa c'è di nuovo e interessante
Estrarre dati randomici da una lista di oggetti in C#
Persistere la ChatHistory di Semantic Kernel in ASP.NET Core Web API per GPT
Rinnovare il token di una GitHub App durante l'esecuzione di un workflow
Referenziare un @layer più alto in CSS
Disabilitare automaticamente un workflow di GitHub (parte 2)
Testare l'invio dei messaggi con Event Hubs Data Explorer