domingo, 21 de maio de 2017

Nginx :: Criando um servidor de Proxy Reverso e Caching de Conteúdo



Hoje o Nginx tá rolando solto aqui. Recomendo que veja o primeiro artigo onde montamos de maneira simplista um Port Foward utilizando o Nginx com proxy reverso.

Dessa vez, vamos utilizar o Nginx para fazer o que ele faz de melhor utilizando alguns recursos mais avançados que do ultimo post: Ser um proxy reverso de alta performance para servir conteúdo estático e fazer caching dos mesmos para acelerar a navegação de sites e etc. O Nginx é uma ferramenta muito versátil que pode trabalhar em conjunto com vários outros Web Servers e ferramentas.

As estratégias de caching são quase que obrigatórias quando falamos de web hoje em dia, e viver sem isso quando sua aplicação cresce, pode causar diversos problemas de performance e até mesmo impactar nos custos de cloud, com scaling de máquinas de forma não pertinente. Uma solução pra isso é criar um proxy gateway utilizando o Nginx como primeiro contato para que ele se encarregue de cachear todo conteúdo estático como HTML, CSS, JS e imagens da nossa aplicação para diminuir ou evitar um Overhead dos nosso servidores.

Vou exemplificar esse artigo com um case parecido com o do anterior, mas dessa vez vamos trabalhar servindo uma Dashboard qualquer na porta 1234 do Apache.



Vamos seguir os passos iniciais para a instalação.


Instalação do Nginx 

Neste exemplo, como de costume, eu estarei utilizando o Debian 8 Jessie para os testes, mas o procedimento de instalação será o mesmo para todas as distribuições Debian Like.
Após a instalação vamos confirmar se o serviço está Ok.


$ sudo apt-get install nginx 
$ sudo systemctl enable nginx
$ sudo systemctl start nginx 
$ sudo systemctl status nginx

A saída deve ser parecida com essa:

● nginx.service - A high performance web server and a reverse proxy server
   Loaded: loaded (/lib/systemd/system/nginx.service; enabled)
   Active: active (running) since Sun 2017-05-21 20:12:44 GMT; 9min ago
 Main PID: 1642 (nginx)
   CGroup: /system.slice/nginx.service
           ├─1642 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
           ├─1643 nginx: worker process
           ├─1644 nginx: worker process
           ├─1645 nginx: worker process
           └─1646 nginx: worker process

May 21 20:12:44 jessie systemd[1]: Started A high performance web server and a reverse proxy server.
May 21 20:21:19 jessie systemd[1]: Started A high performance web server and a reverse proxy server.
vagrant@jessie:~/teste$


Configuração do Proxy Reverso com Cache de conteúdo estático

Edite o arquivo de configuração do Nginx e adicione a linha do proxy_cache_path

$ vim /etc/nginx/nginx.conf

user www-data;
worker_processes 4;
pid /run/nginx.pid;

events {
        worker_connections 768;
        # multi_accept on;
}

http {

        ##
        # Basic Settings
        ##
        
        # Adicione essa linha 
        proxy_cache_path  /data/nginx/cache  levels=1:2    keys_zone=STATIC:10m inactive=24h  max_size=1g;

...

Agora vamos criar a pasta de armazenamento do Cache e o arquivo que vamos utilizar para separar as configurações do nosso servidor.


$ mkdir -p /data/nginx/cache
$ touch /etc/nginx/sites-enabled/proxy-cache.conf

No arquivo que acabamos de criar, vamos adicionar as seguintes linhas:

/etc/nginx/sites-enabled/proxy-cache.conf

    server {
        listen       80;

        # Location do conteúdo estático - Aqui vamos cachear tudo
        location ~* ^.+.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|mid|midi|wav|bmp|rtf|js)$ {

            # PROXY CACHE CONFIGS
            proxy_pass             http://127.0.0.1:1234;
            proxy_set_header       Host $host;
            proxy_cache            STATIC;
            proxy_cache_valid      200  1d;
            proxy_cache_use_stale  error timeout invalid_header updating http_500 http_502 http_503 http_504;

            #CORS - Conteúdo estático libere somente o GET
            add_header 'Access-Control-Allow-Origin' *;
            add_header 'Access-Control-Allow-Credentials' 'true';
            add_header 'Access-Control-Allow-Headers' 'Content-Type,Accept';
            add_header 'Access-Control-Allow-Methods' 'GET';

            #CACHE - Informações do Cache no Header
            add_header Cache-Control "public";
            add_header X-Proxy-Cache $upstream_cache_status;

            # Tempo de expiração
            expires 30d;
        }

        # Location do Proxy reverso - Aqui rodando o Apache convencional
        location / {

            # PROXY CACHE CONFIGS
            proxy_pass             http://127.0.0.1:1234;
            proxy_set_header       Host $host;
            proxy_cache            STATIC;
            proxy_cache_valid      200  1d;
            proxy_cache_use_stale  error timeout invalid_header updating http_500 http_502 http_503 http_504;

            # CORS
            add_header 'Access-Control-Allow-Origin' *;
            add_header 'Access-Control-Allow-Credentials' 'true';
            add_header 'Access-Control-Allow-Headers' 'Content-Type,Accept';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, PATCH, DELETE, OPTIONS';

            # Status do Cache como Header no response
            add_header Cache-Control "public";
            add_header X-Proxy-Cache $upstream_cache_status;

            # Tempo de expiração do conteúdo cacheado - Aqui você pode pegar leva no cache
            expires 1d;
        }
    }

O que fizemos aqui:

Primeiramente nós criamos dois locations parecidos que vão bater na nossa configuração de proxy reverso.  As únicas diferenças são o tempo de cache, no caso 30 dias para o conteúdo estático e 1dia para o restante das solicitações.

No caso de você prover o uso de alguma API, recomendo retirar as configurações de cache do proxy_cache do location / ou diminuir o tempo de cache.

Também um pequeno detalhe do CORS que permite somente solicitações GET para o nosso conteúdo estático e liberamos os outros (mais utilizados) verbos HTTP para o restante da aplicação.

No proxy_pass, devemos informar o IP e a porta do nosso servidor original.
No exemplo eu estou provendo cache para uma aplicação que está na mesma máquina, porém rodando na porta 1234. Informe seu servidor ou load balance aqui.
Adicionamos um Header no response chamado X-Proxy-Cache, onde ele vai nos informar o status daquela solicitação mediante ao cache. No caso, as mais conhecidas vão ser HIT (veio do cache) e MISS (Não veio do cache, normalmente as primeiras solicitações após a limpeza ou vencimento do cache).

Agora vamos reiniciar o serviço e testar a aplicação:


$ rm -rf /data/nginx/cache/*
$ systemctl restart nginx

Acessando nossa Dashboard via navegador, podemos ver algo diferente das demais solicitações:

Nos conteúdos estáticos, podemos ver os Headers que adicionamos, o CORS o vencimento do cache (30 dias depois da sua solicitação) e o X-Proxy-Cache como HIT, dizendo que veio do cache (A primeira solicitação virá MISS).




Olhando mais de perto as solicitações de conteúdo fora dos assets, no caso o HTML da página podemos ver o mesmo resultado, porém com o cache para 1 dia.


Podemos testar com mais detalhes com o curl, para visualizar somente os headers com o parâmetro -I



$ curl -I http://192.168.1.53



$ curl -I http://192.168.1.53/style.css


Limpando o cache do Nginx

Para limpar o cache que o Nginx vai gerar, basta apagar o conteúdo da pasta que criamos anteriormente.

$ rm -rf /data/nginx/cache/*


Espero ter ajudado! :)

SOBRE O AUTOR

Matheus Fidelis

http://msfidelis.github.io/

Power Ranger, Piloto de Helicópteros e Astronauta da NASA. Analista DevOps e Desenvolvedor Web Backend. Apaixonado por Linux, Arquitetura, API's, Containers, Integração, Código, Testes, Escalabilidade e Cloud. :)

Postar um comentário

 
Nanoshots | Open Source Security, Linux e Tutoriais © 2015 - Designed by Templateism.com