Vendas

Assistencia Técnica

Configurando Aplicação WebApi e SignalR com NGINX e HTTPS/SSL em Ubuntu 22

Se você nunca fez isso, prepare-se para passar raiva. Mas depois passa. Você não está sozinho.

Para este tutorial foi usado .net Core 6.0 Framework e Ubuntu 22.

Tente não instalar outras versões do .net core, pois tive problemas ao instalar o 7 e o 6. A aplicação achava que o .net 6 não estava instalado. O .net ainda é meio burro pra lidar com dependencias e tb na hora da build, infelizmente.

Instalar .net framework 6

Para instalar o .net framework utilize este tutorial: https://learn.microsoft.com/pt-br/dotnet/core/install/linux-ubuntu
Atençao, use a versão especifica do seu ubuntu. Pois ja tive problemas usando o tutorial de outro ubuntu. A retrocompatibilidade do ubuntu é lamentavel, quero ver daqui a 10 anos quando precisar instalar como que vai ser.

Instalar nginx

Para instalar o nginx apenas siga o tutorial oficial: https://www.nginx.com/resources/wiki/start/topics/tutorials/install/#official-debian-ubuntu-packages

No momento deste tutorial nao existia tutorial para ubuntu 22, só para ubuntu 20. Mas mesmo assim segui o do 20 e funcionou normalmente. Diferente do .net core que faz de tudo pra bugar sua instalação. A microsoft não sabe criar instaladores descentes.

Como funciona?

Basicamente o nginx recebe a requisição e encaminha ela para o endereço ip onde está rodando a aplicação kestrel. Sim, nada magico, simples assim. Recebe a requisição na porta 80 e redireciona internamente para localhost:5000 por exemplo. Importante frizar que não é um redirect do browser, o browser nao consegue ver isso, para ele está acessando a porta 80 apenas. Aí o nginx recebe na 80 encaminha pra localhost:5000, recebe da localhost:5000 e encaminha devolta pela porta 80. Então para o browser é como se estivesse rodando na 80 mesmo. É importante entender isto, para entender o tópico que vem a seguir.

Detalhes importantes sobre as circunstâncias

Se voçê usa app.UseHttpsRedirection(); na sua aplicação, você terá problemas. Porque ao acessar o dominio, por ex seusite.com ele vai tentar te redirecionar para seusite.com:5001 achando que ta abafando, mas não, é burro. Apanhei nisto. Aí vi no browser: redirect 307 e apontando pra seusite.com:5001. Obs: a porta 5001 era onde tava rodando o kestrel em localhost no servidor, e eu fechei essa porta, por segurança. Note que aqui estamos falando de um redirect pelo browser, diferente do tópico anterior que era sobre redirect interno e mascarado.

Outra maneira de desativar o redirecionamento https é remover seusite.com:5001 da propriedade aplicationUrl em ./properties/launchSettings.json. Só que essa propriedade não existe na versão buildada. Existem ainda outras maneiras neste link, caso precise.

Headers http

Para que a aplicação .net consiga abstrair as headers encaminhadas pelo nginx, e as trate como se fosse suas, para que as políticas de segurança funcionem é preciso habilitar o firmware UseForwardedHeaders:

using Microsoft.AspNetCore.HttpOverrides;

...

app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});

É importante que este middleware esteja antes de todos os outros, para que tudo funcione corretamente.

Proxies conhecidos

Para que a aplicação aceite um proxy, ele deve ser definido como conhecido. Mas se o seu rodar em localhost, ele ja é conhecido pro default. Caso contrário, defina os proxies conhecidos:

using System.Net;

...

services.Configure<ForwardedHeadersOptions>(options =>
{
    options.KnownProxies.Add(IPAddress.Parse("10.0.0.100"));
});

Configurando NGINX

Testando o nginx

Para testar se o nginx esta funcionando tente acessar via browser pela porta 80 mesmo. Se a página abrir está funcinando. Só cuidado, que provavelmente o apache já está instalado no seu ubuntu server, e ele vai se sobrepor. Então desinstale-o. Cuidado que tem outra pegadinha nisso também. Mesmo desinstalando o apache, o arquivo index.html da pasta /var/www ainda vai continuar lá, e o nginx vai adotar como se fosse dele. Aí você vai testar, vai ver lá escrito “apache funcionando corretamente” e vai ficar igual um idiota tentando desinstalar o apache corretamente. É incrível que neste dia estava tudo me trollando, passei raiva rs.

Achando o arquivo de configuração

O caminho desse arquivo pode mudar bastante. Afinal o povo do opensource é muito indeciso. Por padrão, nos tutoriais da microsoft esse arquivo está em /etc/nginx/sites-available/default. Mas se você estiver fazendo isso no WSL Ubuntu 20, como eu fiz, não vai ter esse arquivo. Já no ubuntu server 2022 vai ter esse arquivo mas ele vai estar desabilitado. Afinal esse povo adora te trollar. Então vc ai ter que caçar o pai de todos os arquivos de configuração do nginx. Entre na pasta /etc/nginx, dê um ls ali, e veja se encontra nginx.conf. Se não estiver ali, vai caçando ele em outra pasta. Um exemplo dele aqui:

user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
        worker_connections 768;
        # multi_accept on;
}

http {

        ##
        # Basic Settings
        ##

        sendfile on;
        tcp_nopush on;
        types_hash_max_size 2048;
        # server_tokens off;

        # server_names_hash_bucket_size 64;
        # server_name_in_redirect off;

        include /etc/nginx/mime.types;
        default_type application/octet-stream;

        ##
        # SSL Settings
        ##

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
        ssl_prefer_server_ciphers on;

        ##
        # Logging Settings
        ##

        access_log /var/log/nginx/access.log;
        error_log /var/log/nginx/error.log;

        ##
        # Gzip Settings
        ##

          gzip on;

        # gzip_vary on;
        # gzip_proxied any;
        # gzip_comp_level 6;
        # gzip_buffers 16 8k;
        # gzip_http_version 1.1;
        # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

        ##
        # Virtual Host Configs
        ##

        include /etc/nginx/conf.d/*.conf;
        include /etc/nginx/sites-enabled/*;
}

Note a linha “include /etc/nginx/sites-enabled/*”, e como um include de php, mesma coisa. Entre nessa pasta, e vai ter o arquivo default

O ideal seria um arquivo para cada nome de site. Mas o objetivo aqui é que o tutorial seja rapido e fácil pra entender. Então vamos usar o default mesmo. Edite-o com sua ferramenta de preferência.

server {
        listen          80;
        server_name     seusite.com; #é o que faz o match para o nginx saber que a requisição corresponde a este servidor. Dá pra usar varias combinações aqui, usar regex e etc mas não é o foco agora. Se você nãoo tem dominio use o ip ou asterisco.
        location / {
                proxy_pass http://127.0.0.1:5000;
                proxy_http_version 1.1;
                proxy_set_header        Upgrade $http_upgrade; #header que faz upgrade na conexão, de http 1.0 para versões superiores ou websocket
                proxy_set_header        Connection keep-alive;
                proxy_set_header        Host $host;
                proxy_cache_bypass      $http_upgrade;
                proxy_set_header        X-Forwared-For $proxy_add_x_forwarded_for; #forward das headers
                proxy_set_header        X-Forwarded-Proto $scheme;#forward das headers
            #proxy_set_header serve para adicionar headers que serão passadas para o destino num redirecionamento proxy
        }
}

Não se esqueça de remover o server default que acessa a pasta /var/www/html, ou mude a porta dele para 81, como eu fiz.

Testando o proxy reverso

Para testar se a configuração está certa use: sudo nginx -t

Para aplicar a nova configuração reinicie o nginx: sudo service nginx restart

Agora, para testar, rode a aplicação .net core na porta 80. Pode ser pelo dotnet run mesmo, nem precisa compilar. (só não se esqueça que o seu arquvio appsettings.Development.json ou appsettings.json deve estar ok). Ele estando rodando na porta 5000 o nginx ja vai redirecionar pra ele. Então, de fora deste servidor, tente acessa-lo pelo browser através do seu dominio ou ip, pela porta 80. Ele deve funcionar como se estivesse rodando na 80 mesmo, só que internamente ele redirecionando para a 5000. Se funcionar, mas você estiver tendo problemas na autenticação ou nas headers deve ter configurado errado o middleware de forwarded headers ou o proxy_set_header.

HTTPS/SSL

Para configurar para ssl você precisa do arquivo .crt e o arquivo.key do seu certificado. E também o dominio configurado. O https é acessado pela porta 443. Portanto teremos que alterar a configuração anterior.

server {
        listen          443 ssl; #aqui definimos a porta 443 e que ela vai usar ssl
        server_name     seusite.com; #já explicado
        ssl_certificate /var/www/certificado.fw/certificate.crt; #o caminho do certificado
        ssl_certificate_key /var/www/certificado.fw/private.key; #o caminho da key
        ssl_session_cache builtin:1000 shared:SSL:10m; #tipos de caches que armazenam parametros de sessão. Use este mesmo.
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #os protocolos permitidos

 
        location / { #aqui continua tudo igual.
                proxy_pass http://127.0.0.1:5000;
                proxy_http_version 1.1;
                proxy_set_header        Upgrade $http_upgrade;
                proxy_set_header        Connection keep-alive;
                proxy_set_header        Host $host;
                proxy_cache_bypass      $http_upgrade;
                proxy_set_header        X-Forwared-For $proxy_add_x_forwarded_for;
                proxy_set_header        X-Forwarded-Proto $scheme;

        }

}

Agora tente acessar pelo browser via https e deve funcionar.

SIGNALR

O signal usa conexão websocket, ws. E e com ssl usa wss. Para que funcione é preciso que ele saiba evoluir a conexão de https para wss. Para o websocket vamos criar uma configuração específica para a rota do websocket, no nosso caso “/chat”.

server {
        listen          443 ssl;
        server_name     fw.batmanhub.com;
        ssl_certificate /var/www/certificado.fw/certificate.crt;
        ssl_certificate_key /var/www/certificado.fw/private.key;
        ssl_session_cache builtin:1000 shared:SSL:10m;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

        location /chat {
                proxy_pass http://127.0.0.1:5000;
                #Iguais ao anterior:
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Host $host;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
                proxy_set_header Connection "upgrade";

                #importantes:
                proxy_cache off; #desabilita o cache
                proxy_http_version 1.1; #força para http 1.1 pois ws só funciona no 1.1 em diante
                proxy_buffering off; #desabilita o buffer                
                proxy_read_timeout 100s;# habilita long pooling
        }
        location / {
                proxy_pass http://127.0.0.1:5000;
                proxy_http_version 1.1;
                proxy_set_header        Upgrade $http_upgrade;
                proxy_set_header        Connection keep-alive;
                proxy_set_header        Host $host;
                proxy_cache_bypass      $http_upgrade;
                proxy_set_header        X-Forwared-For $proxy_add_x_forwarded_for;
                proxy_set_header        X-Forwarded-Proto $scheme;
        }
}

Agora teste. Deve funcionar. Se tiver problemas comente aqui.

× WhatsApp