En este video veremos como publicar una aplicación web creada con el framework de .NET Core 5, en la que primeramente dejaremos nuestra aplicación configurada desde Visual Studio 2019 para que funcione correctamente detrás de un proxy reverso.
En este caso utilizaremos nginx como servidor web para configurar este proxy, la idea de usar nginx es que la aplicación de .NET Core 5 no este expuesta directamente a internet ya que el servidor web Kestrel en el cual corren estas aplicaciones no es muy robusto.
En este diagrama podemos visualizar la configuración que vamos a realizar, en la que en un servidor tendremos la aplicación de .NET Core 5 y en el otro tendremos el proxy reverso con nginx, las peticiones web del exterior deberán ser recibas en nuestro firewall o gateway y deberán ser redireccionadas a nuestro servidor con el proxy reverso y este a su vez redireccionará a nuestro servidor con nuestra aplicación de .NET Core, en ambos servidores utilizo Ubuntu Server 20.04 LTS.
El proxy reverso también actuará como terminación SSL es decir que se encargará de manejar el tráfico encriptado a través del protocolo HTTPS y quitarle esta carga a nuestra aplicación de .NET.
A continuación dejare los comandos y referencias utilizadas en el video para que sea mas sencillo copiarlas y utilizarlas.
Primeramente configuraremos nuestra aplicación para que funcione correctamente detrás de un proxy reverso, siguiendo las instrucciones que indico en el video, para mayor información dejo los enlaces de la documentación de Microsoft en los que me he basado para realizar este tutorial.
Una vez configurada nuestra aplicación pasamos a la siguiente parte en la que montaremos nuestra aplicación .NET en uno de los servidores, ejecutaremos los siguientes comandos por SSH.
Descargamos paquete oficial de Microsoft.
wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
Instalamos el paquete.
sudo dpkg -i packages-microsoft-prod.deb
Actualizamos los repositorios del sistema.
sudo apt-get update
Actualizamos paquetes necesarios así como los runtimes de .NET Core 5.
sudo apt-get install -y apt-transport-https
sudo apt-get install dotnet-runtime-5.0
sudo apt-get install -y aspnetcore-runtime-5.0
Subimos el proyecto publicado al servidor y le ponemos permisos a la carpeta con el usuario que vaya ejecutar al aplicación de .NET, en este ejemplo pongo mi aplicación en una carpeta llamada App y le doy permisos al usuario www-data.
sudo chown -R www-data:www-data /var/www/App
Pruebo que si funcione mi aplicación.
dotnet WebApp.dll
Indico que el host de mi aplicación sea accesible en una dirección IP especifica.
dotnet WebApp.dll --urls "http://192.168.0.106:5000"
Creo una configuración para que mi aplicación de .NET Core se ejecute como servicio en el servidor de Ubuntu.
sudo nano /etc/systemd/system/aspnet.service
Dentro del archivo pongo la siguiente configuración.
[Unit]
Description=Ejemplo .NET Core 5.0
[Service]
WorkingDirectory=/var/www/App
ExecStart=/usr/bin/dotnet /var/www/App/WebApp.dll --urls 'http://192.168.0.106:5000'
Restart=always
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=dotnet-core
User=www-data
Environment=ASPNETCORE_ENVIRONMENT=Development
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false
[Install]
WantedBy=multi-user.target
Habilito el servicio en el servidor, lo enciendo y reviso su estatus.
sudo systemctl enable aspnet.service
sudo systemctl start aspnet.service
sudo systemctl status aspnet.service
Ahora que todo esta listo en el servidor de .NET Core nos pasamos a la parte 3 y última que es configurar el proxy reverso, estos son los comandos que utilizó durante la configuración.
Instalar el servidor wen nginx.
sudo apt-get install nginx
Ingresamos a la ruta donde esta la configuración de nginx
cd /etc/nginx/
Editamos el archivo nginx.conf con el editar nano.
sudo nano nginx.conf
Añadimos esta línea el bloque de http y guardamos el archivo.
limit_req_zone $binary_remote_addr zone=one:10m rate=5r/s;
Ahora nos metemos a la carpeta de los sitios disponibles de nginx.
cd /etc/nginx/sites-available/
Creamos un archivo de configuración para nuestro sitio con el editor nano con el nombre de nuestro dominio.
sudo nano aspnet.bioxor.net
Utilizamos la siguiente configuración dentro del archivo, se debe sustituir la dirección IP 192.168.0.106 por la IP local de tu servidor o contenedor donde esta tu aplicación de .NET Core y el nombre de dominio aspnet.bioxor.net por el propio y la ruta de los certificados ssl por la ruta real en lo que se encuentren almacenados los tuyos.
upstream app{
server 192.168.0.106:5000;
}
server {
server_name aspnet.bioxor.net
listen 80;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name aspnet.bioxor.net;
ssl_certificate /etc/nginx/certs/server.crt;
ssl_certificate_key /etc/nginx/certs/server.key;
ssl_protocols TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on; #ensure your cert is capable
ssl_stapling_verify on; #ensure your cert is capable
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
#Redirects all traffic
location / {
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-Proto $scheme;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffers 32 4k;
proxy_pass http://app;
limit_req zone=one burst=10 nodelay;
}
}
Guardamos el archivo y ahora nos metemos a la carpeta de sitios habilitados de nginx para crear un enlace simbólico a nuestra configuración del sitio.
cd /etc/nginx/sites-enabled/
Creamos el enlace simbólico.
sudo ln -s ../sites-available/aspnet.bioxor.net
Ahora revisamos que no hay ningún error de sintaxis en nuestro archivos de configuración de nginx.
sudo nginx -t
Y por último reinciamos el servicio de nginx para que nos tome los cambios.
sudo service nginx restart
En este punto ya debe estar funcionando nuestra aplicación .NET Correctamente detrás del proxy reverso.
Que tal, excelente aporte, sólo como observación en la parte “Ahora nos metemos a la carpeta de los sitios habilitado de nginx.” la ruta creo que esta mal, por que más adelante el enlace simbólico lo realiza a la misma ruta. Viendo el video de dónde llegue acá creo que la ruta correcta es “cd /etc/nginx/sites-available/”
Gracias por la observación en la redacción César, ahora mismo lo corrijo, es correcto primero debes entrar a sites-available para crear el archivo de configuración y no a sites-enabled, saludos.
Muy agradecido por tan funcional y excelente aporte, he lanzado mi aplicación .NETCORE con sql server a producción, utilizando un vps, he tenido que estudiar mucho el contenido que aportas Borja, sin embargo puedo decir que es genial ser parte de tu canal y tus tutoriales.
Quiero comentarte adicionalmente que por alguna razón el servicio o tarea automática me da conflicto solamente en el punto cuando hago login en mi aplicación, al parecer algo no se recibe correctamente al construir o loguearse en la base de datos .
Es decir logro ingresar normal con https, pero al dar click en mi botón de autenticar en mi aplicación aparece este mensaje de error, quiero mencionar que al ejecutar desde una terminal a demanda o manualmente logro ingresar sin problemas.
¿Podrías compartirme alguna idea de cómo solucionarlo?.
ExtendedSocketException: Resource temporarily unavailable
Exception: Cannot connect to SQL Server Browser. Ensure SQL Server Browser has been started.
Microsoft.Data.SqlClient.SNI.SSRP.GetPortByInstanceName(string browserHostName, string instanceName)
System.Net.Dns.InternalGetHostByName(string hostName)
System.Net.Dns.InternalGetHostByName(string hostName)
System.Net.Dns.GetHostAddresses(string hostNameOrAddress)
System.Net.Sockets.UdpClient.BeginSend(byte[] datagram, int bytes, string hostname, int port, AsyncCallback requestCallback, object state)