Publicando uma aplicação ASP.NET Core no Linux com o Nginx

Ao concluir uma aplicação ASP.NET Core é chegado o momento de compartilhá-la com o mundo. Há várias formas de fazer isso, pode ser com Docker no Heroku ou mesmo uma função AWS Lambda. Mas devido a versatilidade, atualmente a forma mais comum de realizar o deploy de uma aplicação ASP.NET Core é em uma instância Linux de máquina virtual adquirida em um serviço de cloud computing, onde todo o processo é realizado pelo desenvolvedor. E neste artigo veremos este processo passo a passo.

Ubuntu Server

Para este artigo estou utilizando a versão 20.04 LTS do Ubuntu Server. Caso esteja utilizando outra distribuição, pode haver algumas diferenças, mas no geral os códigos e comandos apresentados aqui devem funcionar nela.

Amazon Web Services (AWS) - RDS - Fundamentos
Curso de Amazon Web Services (AWS) - RDS - Fundamentos
CONHEÇA O CURSO

Publicando a aplicação

Por não ser o foco do artigo, não mostrarei a criação da aplicação, farei uso da API criada com o framework Carter apresentada anteriormente. E como esta aplicação já está pronta, então vamos partir deste ponto.

No momento que a aplicação é concluída, podemos realizar o seu deploy, através do comando abaixo:

dotnet publish -c Release -r linux-x64

Como não desejo instalar o .NET Core no servidor, note que estou publicando a aplicação como self-contained.

Para verificar se tudo está correto, copie a aplicação para o servidor (todo o conteúdo da pasta “publish“) e execute o comando abaixo:

./aplicacao

Se não for gerado nenhum erro:

Aplicação funcionando no terminal

Significa que está tudo certo com a aplicação. Então podemos dar continuidade ao nosso processo.

Instalando o Nginx

O Kestrel é um ótimo servidor e mesmo que seja estável para ser utilizado em produção, ele não possui tantos recursos como um servidor mais robusto, tipo o Apache, IIS ou Nginx. Assim, uma forma de mitigar isso é utilizando um proxy reverso.

O proxy reverso funciona como um intermediário das requisições. Toda requisição passará por ele, que se encarrega de redirecioná-la para a aplicação. Com isso, a aplicação poderá fazer uso de recursos não disponíveis no Kestrel, como balanceamento de carga, compressão de requisição, entre outros.

Existem algumas opções de proxy reverso, sendo que o mais usado é o Nginx.

Geralmente uma máquina virtual de um serviço de Cloud já contém esta aplicação, caso não contenha, é necessário instalá-la:

sudo apt-get install nginx

Ao final da instalação, o serviço do Nginx já estará funcionando. Podemos verificar se deu tudo certo analisando-o:

sudo systemctl status nginx

Configurando o Nginx

Para configurar o Nginx como proxy reverso de uma aplicação ASP.NET Core, vamos criar dentro de /etc/nginx/sites-available/ um arquivo chamado exemploapi.com. Aqui é importante frisar que as boas práticas recomendam que este arquivo seja nomeado de acordo com o domínio da aplicação configurada nele. Assim, caso haja mais de uma aplicação, será mais fácil localizar a sua configuração.

Adicione neste arquivo o conteúdo abaixo:

server {
    listen        80;
    server_name   exemploapi.com *.exemploapi.com;
    location / {
        proxy_pass         http://localhost: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-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
    }
}

Nele estamos definindo que toda requisição recebida na porta 80, pelo domínio exemploapi.com, deve ser redirecionada para http://localhost:5000. As demais opções são atributos que dão mais segurança para a aplicação, mas não faz parte do escopo deste artigo explicá-las.

Para evitar qualquer problema, defina o usuário do Nginx como proprietário do arquivo:

sudo chown -R www-data: /etc/nginx/sites-available/exemploapi.com

E dê permissão de escrita para ele:

sudo chmod -R 775 /etc/nginx/sites-available/exemploapi.com

Para garantir que o servidor não aceite requisições de outros domínios, é necessário alterar o conteúdo do arquivo /etc/nginx/sites-available/default para o abaixo:

server {
    listen   80 default_server;
    listen [::]:80 default_server deferred;
    return   444;
}

Assim, para qualquer requisição na porta 80 que não seja do domínio que definimos para a nossa aplicação, o servidor retornará o código 444.

Por fim, crie um link simbólico do arquivo em sites-available para o sites-enabled, o qual é lido pelo Nginx quando iniciado:

sudo ln -sfn /etc/nginx/sites-available/exemploapi.com /etc/nginx/sites-enabled/

Para verificar que não há nenhum erro nestes arquivos, é possível analisar a sintaxe deles com o comando abaixo:

sudo nginx -t

Estando tudo certo, o Nginx pode ser reiniciado:

sudo systemctl restart nginx

Com isso, caso a aplicação esteja iniciada, ao acessar o domínio http://exemploapi.com, já teremos acesso à ela:

Aplicação acessada no navegador, pela url http://exemploapi.com

Lembrando que o domínio só funcionará caso esteja definido em algum serviço de DNS, o redirecionamento dele para o servidor. Localmente isso pode ser configurado no arquivo hosts, com a adição da linha:

127.0.0.0 exemploapi.com

Configurando a aplicação como serviço

No estado atual, se ocorrer qualquer problema no servidor, o serviço do Nginx é reiniciado, mas isso não ocorre com a nossa a aplicação, pois ela está sendo iniciada manualmente. Para evitar isso, podemos defini-la como um serviço, algo que já abordei no meu artigo de Worker Service.

Desta forma, crie o arquivo /etc/systemd/system/kestrel-exemploapi.service, com o conteúdo abaixo:

[Unit]
Description=Serviço da aplicação do ExemploApi

[Service]
WorkingDirectory=/caminho/aplicacao
ExecStart=/caminho/aplicacao
Restart=always
# Restart service after 10 seconds if service crashes:
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=dotnet-example
User=www-data
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false
StandardOutput=/var/log/aplicacao-output.log
StandardError=/var/log/aplicacao-error.log

[Install]
WantedBy=multi-user.target

Registre este serviço:

sudo systemctl enable kestrel-exemploapi.service

O inicie:

sudo systemctl start kestrel-exemploapi.service

E verifique se está tudo certo:

sudo systemctl status kestrel-exemploapi.service

Agora a nossa aplicação sempre estará acessível:

Aplicação acessada no navegador, pela url http://exemploapi.com

Mesmo se ocorrer algum erro no servidor, ela será reiniciada junto com o Nginx.

Django - Tópicos de segurança
Curso de Django - Tópicos de segurança
CONHEÇA O CURSO

Configurando conexão segura

Caso possua um certificado SSL, que pode ser criado gratuitamente com o Certbot, este pode ser definido na configuração da aplicação no Nginx, no arquivo exemploapi.com:

server {
     listen       80;
     listen       [::]:80;
     server_name   exemploapi.com *.exemploapi.com;

     return 301 https://$host$request_uri;
}

server {
     listen       443 ssl http2;
     listen       [::]:443 ssl http2;
     server_name  exemploapi.com *.exemploapi.com;

     ssl_certificate /etc/letsencrypt/live/exemploapi.com/cert.pem;
     ssl_certificate_key /etc/letsencrypt/live/exemploapi.com/privkey.pem;
     ssl_session_cache shared:SSL:1m;
     ssl_session_timeout  10m;
     ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
     ssl_ciphers HIGH:SEED:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!RSAPSK:!aDH:!aECDH:!EDH-DSS-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:!SRP;
     ssl_prefer_server_ciphers on;

     location / {
        proxy_pass         http://localhost: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-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
    }
}

Nesta configuração é definido que todas as requisições via HTTP, sejam redirecionadas para a versão HTTPS do site. E dentro da configuração HTTPS, os certificados são indicados:

ssl_certificate /etc/letsencrypt/live/exemploapi.com/cert.pem;
ssl_certificate_key /etc/letsencrypt/live/exemploapi.com/privkey.pem;

Reinicie o Nginx para que a versão segura da aplicação seja disponibilizada:

Aplicação acessada no navegador, por url seguraça, mas com aviso no navegador

Acima o Chrome indica que o site não é seguro, porque o certificado utilizado não foi criado por uma autoridade válida. Criei ele localmente XD

Deixe seu comentário

Instrutor, nerd, cinéfilo e desenvolvedor nas horas vagas. Graduado em Ciências da Computação pela Universidade Metodista de São Paulo.

© 2004 - 2019 TreinaWeb Tecnologia LTDA - CNPJ: 06.156.637/0001-58 Av. Paulista, 1765, Conj 71 e 72 - Bela Vista - São Paulo - SP - 01311-200