Implantando Tornado com proxy reverso Nginx no CentOS 5

Este é o penúltimo da sequência de posts sobre uma implantação Tornado com proxy reverso Nginx no CentOS 5. O objetivo é ter um servidor que receba as conexões por uma única porta e distribua para as várias instâncias de Tornado, cada uma em porta diferente, no fim teremos algo como a figura abaixo:

Tornado atrás de um proxy reverso

O Nginx por padrão distribui as requisições no estilo round-robin, tu podes alterar isto estudando um pouco sobre a opção HTTPUpstreamModule do Nginx.

Para seguir as instruções e obter sucesso nos procedimentos tu precisas de um ambiente CentOS 5 com Python e Tornado instalados, se tu não tem isto pronto, leia estes outros posts antes de prosseguir:

Instalei o servidor web Nginx pelo yum, para que isto fosse possível tive que adicionar o repositório do Nginx nas configurações do yum.

Assim criei um arquivo em /etc/yum.repos.d/, como o exemplo abaixo:

vi /etc/yum.repos.d/nginx.repo

Adicionei ao arquivo nginx.repo recém criado as linhas que seguem:

[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=0
enabled=1

Pronto, mandei instalar assim:

yum install nginx

Após terminar fiz um teste bobo como este:

service nginx start

E tudo correu bem, sem erros.

Fui para a configuração, mudei pouca coisa do arquivo padrão da instalação, apenas o parâmetro worker_processes que define o número de processos de trabalho, o valor ideal deste parâmetro depende de vários fatores, inclusive, mas não limitado, ao número de cores do processador. Se você não souber como quantificar, colocar a quantidade de cores do processador é um bom começo.

Adicionei também o parâmetro use epoll em events para “forçar” o uso deste modelo de notificação de eventos.

Então abri e editei o arquivo das configurações do Nginx com o comando que segue:

vi /etc/nginx/nginx.conf

Meu arquivo ficou assim:

user  nginx;
worker_processes  5;
 
error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;
 
events {
    worker_connections  1024;
    use epoll;
}
 
http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  /var/log/nginx/access.log  main;
    sendfile        on;
    keepalive_timeout  65;
    include /etc/nginx/conf.d/*.conf;
}

Belezas, este ai acima é o arquivo das configurações “comuns” do Nginx, abaixo criei um arquivo para as configurações do proxy reverso da minha implantação Tornado.

Inicialmente:

vi /etc/nginx/conf.d/bapi.conf

Tu podes escolher outro nome de arquivo, desde que terminado com “.conf”. O bapi.conf daqui é em homenagem ao nome de batismo do meu aplicativo Tornado.

Legal, mas aqui não vou entrar em detalhe sobre cada um dos parâmetros – ficaria muito extenso nosso papo e este não é o meu objetivo -, quero apenas dizer que adicionaremos no parâmetro de grupo de servidores upstream as instancias Tornado na qual este Nginx fará proxy reverso e no proxy_pass a referencia para o grupo de servidores upstream.

Para saber mais sobre cada um destes parâmetros, acesse a wiki oficial do Nginx pelo link: http://wiki.nginx.org/DirectiveIndex.

Meu arquivo ficou assim:

 
proxy_next_upstream error;
 
upstream bapis {
    server 127.0.0.1:8080;
    server 127.0.0.1:8081;
}
 
server {
    listen       8888;
    server_name  bapih.bis.com.br;
 
    location /static/ {
        root /var/www/static;
        if ($query_string) {
            expires max;
        }
    }
 
    location / {
        proxy_pass_header Server;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Scheme $scheme;
        proxy_pass http://bapis;
    }
}

Neste momento, se tu seguiu tudo direitinho e for um cara de sorte, já tens o que querias – quer dizer, o que eu queria – um proxy reverso para meu Tornado.

Eu fiz um teste bobão, assim:

Iniciei duas instancias Tornado:

python26 /var/www/bapi/main.py --port=8080
python26 /var/www/bapi/main.py --port=8081

reIniciei o nginx:

service nginx restart

E voila, acessei minha aplicação Tornado de um browser qualquer pela porta 8888 e lá estava ela funcionando belezinha!

Eu quis complicar um pouquinho e adicionei suporte ao https (SSL), se não tiver afim disto seu trabalho terminou por aqui.

Ops, o teu pode ter terminado aqui, mas o meu não, pois para terminar a implantação deste servidor vou configurar o Supervisor para gerenciar as instancias Tornado, quando terminar faço referência da continuação aqui.

==========> A parte do SSL começa aqui <==========

Como confio em mim, me escolhi como certificador de mim mesmo e gerei meu próprio certificado, assim sem detalhes porque está fora do escopo desta postagen:

openssl genrsa -out cert.key 1024
openssl req -new -key cert.key -out req.pem
openssl x509 -req -days 364 -in req.pem -signkey cert.key -out cert.pem

Alterei meu /etc/nginx/conf.d/bapi.conf para SSL, veja como ficou:

proxy_next_upstream error;
 
upstream bapis {
    server 127.0.0.1:8080;
    server 127.0.0.1:8081;
}
 
server {
    listen       443;
    ssl on;
    ssl_certificate /var/www/ssl/cert.pem;
    ssl_certificate_key /var/www/ssl/cert.key;
 
    default_type application/octet-stream;
 
    location /static/ {
        root /var/www/static;
        if ($query_string) {
            expires max;
        }
    }
 
    location / {
        proxy_pass_header Server;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Scheme $scheme;
        proxy_pass http://bapis;
    }
}

Reiniciei as coisas novamente e tudo certo, lá estava meu aplicativo Tornado rodando sobre HTTPS.

==========> SSL termina aqui <==========

Valeu