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.
Curso C# (C Sharp) Avançado
Conhecer o cursoPublicando 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:
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:
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:
Mesmo se ocorrer algum erro no servidor, ela será reiniciada junto com o Nginx.
Curso Azure Virtual Machine - Fundamentos
Conhecer o cursoConfigurando 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:
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