Precisei publicar uma aplicativo web que fiz para meus estudantes e colaboradores poderem analizar alguns dados aqui na rede da universidade. Inicialmente iniciava o aplicativo apenas dessa forma na linha de comando
gunicorn --bind 0.0.0.0:5000 --workers 4 --timeout 0 wsgi:app
Essa forma é eficiente para fazer testes e ficar observando os erros, com o aplicativo aberto no navegador e de olho na saída do terminal. Na fase em que não precisamos mais olhar tantos erros (fase de produção no jargão dos desenvolvedores) é necessário que ele funcione como um serviço do servidor e seja apontado com o nginx para que fique acessível na rede, portanto vamos às etapas.
Este é o projeto que estou colocando na rede github.com/orahcio/reducao, portanto a palavra reducao sempre aparecerá quando estiver me referenciando ao projeto. A referência que mais gostei para construção desse tutorial foi essa aqui do Blog do En.
Para criar o serviço vamos criar o arquivo que constrói as especificações do que queremos executar, aqui usei o nome reducao, a localização é portanto /etc/systemd/system/reducao.service
[Unit]
Description=Serviço pra executar o gunicorn do meu aplicativo
After=network.target
[Service]
User=orahcio
Group=www-data
Environment="PATH=/home/orahcio/.pyenv/versions/reducao/bin"
WorkingDirectory=/home/orahcio/reducao
ExecStart=/home/orahcio/.pyenv/myprojectenv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/home/sammy/myproject/myproject.sock myproject.wsgi:application
[Install]
WantedBy=multi-user.target
Utilizei algumas modificaçoes em relação ao tutorial já citado, propostas aqui neste tutorial. As linhas que precismos compreender melhor são as que estão no bloco [Service].
Primeiramente o usuário e o grupo devem estar de acordo com o usuário (User=) onde a pasta do projeto do aplicativo está armazenada e o grupo (Group=) deve ser o padrão no nginx, portanto deixe inalterado como www-data.
Tive um problema de permissão nas primneiras vezes que tentei acessar o aplicativo ao final de todos os passos, dessa forma, garanta que esse projeto esteja no grupo correto e sua pasta $HOME tenha permisões de leitura e escrita, para isso vamos fazer
sudo chmod 751 /home/orahcio
para que o diretório pessoal (que é o diretório raiz do projeto) tenha as permisões para que o nginx possa acessar e escrever dados no diretório do projeo. Este por sua vez deve pertencer ao grupo padrão do nginx, www-data, para isso vamos fazer
sudo chgrp www-data ~/reducao
para que o diretório do projeto esteja no grupo correto.
Um último detalhe é que os arquivos binários do meu projeto não estão na pasta do projeto, isso aconteceu porque usei o pyenv para gerenciar o ambiente virtual do meu projeto, para saber mais é só consultar o tutorial de como gerencial ambientes virtuais usando o pyenv aqui. Por isso as linhas referente ao meu ambiente virtual (Environment=) e a execução do gunicorn (ExecStart=) estão em diretórios diferentes do diretório do projeto (WorkingDirectory).
Finalmente vamos colocar o serviço em execução, basta fazermos
sudo systemctl start reducao
sudo systemctl enable reducao
depois é só checar o estado de execução com
sudo systemctl status reducao
a saída esperada é algo do tipo
•reducao.service - myproject.service - A Flask application run with Gunicorn.
Loaded: loaded (/etc/systemd/system/reducao.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2023-10-19 17:38:56 -03; 18h ago
Main PID: 78143 (gunicorn)
Tasks: 190 (limit: 38364)
Memory: 683.1M
CPU: 2min 13.216s
CGroup: /system.slice/reducao.service
├─78143 /home/orahcio/.pyenv/versions/3.11.6/envs/reducao/bin/python3.11 /home/orahcio/.pyenv/versions/reducao/bin/gunicorn --workers 3 -->
├─78203 /home/orahcio/.pyenv/versions/3.11.6/envs/reducao/bin/python3.11 /home/orahcio/.pyenv/versions/reducao/bin/gunicorn --workers 3 -->
├─78235 /home/orahcio/.pyenv/versions/3.11.6/envs/reducao/bin/python3.11 /home/orahcio/.pyenv/versions/reducao/bin/gunicorn --workers 3 -->
└─78236 /home/orahcio/.pyenv/versions/3.11.6/envs/reducao/bin/python3.11 /home/orahcio/.pyenv/versions/reducao/bin/gunicorn --workers 3 -->
Com o serviço em funcionamento precisamos deixar ele vizível ao navegador, observe que um arquivo reducao.sock foi criado no diretório do projeto, esse arquivo é que será requisitado toda vez que o nginx precisar requisitar o serviço. Podemos agora configurar o nginx para isso.
Uma vez que temos o nginx instalado e habilitado como serviço vamos construir o arquivo de configuração do nosso aplicativo, o caminho para ele neste tutorial será /etc/nginx/sites-available/reducao.conf, o conteúdo dele deve conter
server {
listen 8001;
access_log /var/log/nginx/reducao.access.log;
error_log /var/log/nginx/reducao.error.log;
location / {
include proxy_params;
proxy_pass http://unix:/home/orahcio/reducao/reducao.sock;
}
}
Veja que o bloco server possui a primeira linha a porta na qual o nginx irá escutar para acionar o serviço (listen 8001), escolhi a porta 8001 pois a padrão 80 não estava dando certo então resolvi mudar e acabou funcionando, aconcelho fazer a aplicação flask de forma a escutar essa porta. Os demais trechos do arquivo dizem respeito a arquivos de log e no subbloco location temos o arquivo reducao.sock o qual o nginx irá ficar requisitando quando você digitar o IP do servidor na rede. Se precisa de um tutorial para publicar aplicativo para expor ao público geral, esse não é o caso aqui.
Agora vamos ativar esse novo site no servidor nginx, primeiro vamos fazer um link simbólico no diretório dos sites habilitados, para isso faça
sudo ln -s /etc/nginx/sites-available/reducao.conf /etc/nginx/sites-enabled/reducao
agora podemos testar se as configurações do _nginx estão ok com o novo site
sudo nginx -t
se a saída foi essa
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
então podemos reiniciar o servidor nginx para que as modificações tenham efeito
sudo nginx -s reload
caso o serviço não tenha sido iniciado ainda é só fazer
sudo systemctl start nginx
Pronto agora é só ir para um computador na rede que possa enxergar o _IP_ do servidor que você acaba de configurar e digitar no endereço ipdamaquina:8001 e sua aplicação estará lá rodando.
Além dos arquivos de log discriminados em acess_log e error_logo é possível ver a saída padrão do terminal desse aplicativo usando o comando
sudo journalctl -u reducao