Nginx
Tags: nginx, distributedsystems, devops
Published: 2023-05-24 21:31:42

O **NGINX** é um servidor web/proxy reverso rápido, de alto rendimento e um proxy para correio eletrônico (IMAP/POP3), é um software livre e de código-aberto. Ele é um serviço, é um programa que roda e que serve para responder requisições web.
  
Ele não usa somente aquela ideia de processos do servidor Apache, threads e programação paralela, ele usa um outro conceito de **programação assíncrona** muito interessante:
  
<img src="https://user-images.githubusercontent.com/61624336/204335254-c050775b-5e13-43a7-a2e4-ece2064d05df.png" height="177" align="right">
  
Então, temos aqui uma base do funcionamento do NGINX. Quando você inicia um serviço do NGINX, ele cria um processo principal como se fosse o patrão desses colaboradores aqui. No qual esse patrão vai criar alguns processos colaboradores, alguns **worker process**. Esses worker process são criados baseado no número de núcleos (cores) que o seu processador tem. Suponha que eu tenho um servidor que tem **um processador com quatro núcleos**. Então eu poderia criar, por exemplo, **4 processos worker process** para tratar requisições. Porque assim eu tenho um maior número de processos tratando cada número de requisições, então eu consigo tratar mais requisições.
  
> Só que a sacada é: Não é como se cada processo tratasse uma requisição. Não é isso! Cada um desses processos trata um número grande de requisições, várias requisições, e para que ele consiga tratar mais de uma requisição, ele usa um conceito de **Multiplexing I/O**. Ou seja, ele faz mais de uma coisa de forma **assíncrona**.
  
Então, imagine que chegou uma requisição nesse worker aqui e depois chega uma nova requisição que caiu nesse mesmo worker. O que ele vai fazer? Ele vai colocar para executar o primeiro. Enquanto esse processo está esperando essa tarefa ser executada - por exemplo: o servidor de aplicação responder e o arquivo ser carregado - ele já trata outra requisição, coloca para carregar imagem e manda requisição para servidor de imagem. Depois ele pega a resposta da primeira requisição e devolve, continua tratando a segunda e devolve. Por isso o NGINX veio com a proposta de ser o servidor web mais rápido.
  
> Existem benchmarks que colocam realmente o NGINX lá no topo, ou seja, é um servidor muito performático. Mas obviamente não existe bala de prata e ele tem seus cenários onde ele trabalha muito bem e não é ferramenta ideal.
  
> **Funcionamento do NGINX**: Ele inicia um servidor, um processo. Esse processo cria outros processos colaboradores, e cada um desses processos consegue tratar várias requisições utilizando o conceito de programação assíncrona, garantindo assim uma grande performance.  

<a href="https://hub.docker.com/_/nginx"><img src="https://cdn.worldvectorlogo.com/logos/nginx-1.svg" height="177" align="right"></a>

Difere-se muito do servidor Apache, porque ele transfere a responsabilidade de um servidor web para um servidor de aplicação além de ser:

- Tolerante a falhas;
- Compatível com o IPv6;
  
> **Exemplo**: Com Java você pode ter um Tomcat rodando, ou com PHP você vai ter um PHP FPM rodando. Enfim, você vai ter algum servidor de aplicação aqui, e o NGINX consegue se conectar à ele. Mas nós vamos focar só na parte do NGINX, sem nos conectarmos a algum servidor de aplicação.

## Instalação do NGINX
Como baixar e configurar o NGINX server.

**Windows**
- http://nginx.org/en/download.html

**macOS**
```sh
brew install nginx 
```

**Linux**
```sh
sudo apt install nginx
```

Para iniciar o nginx é simples, basta escrever o nome dele na linha de comando no terminal:
  
```sh
nginx
```
  
Basta somente executa-lo e acessar o http://localhost:8080

<img width="529" alt="welcome-screen-e1450116630667" src="https://user-images.githubusercontent.com/61624336/204398044-71e2ced9-7789-4abc-bc17-8dd682c5f6a2.png">
  
## [NGINX] Servidor HTTP
<div align="center"><img src="https://www.svgrepo.com/show/373315/nginx-opened.svg" height="177"></div>

#### Exibe ajuda e lá podemos ver os caminhos do arquivo de configuração
```
nginx -h
```

### Arquivos de configuração do servidor (`nginx.conf`)
  
Essa é a área que configuramos o nosso servidor Nginx:
  
[![NGINX](https://img.shields.io/badge/-nginx.conf-000000?style=social&logo=Nginx&logoColor=#009639)](#)

```python
#user  nobody;
worker_processes  1; # auto

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024; # limite de processos em um sistema operacional de arquivos assíncronos (file descriptors = sockets, connections, etc...)
}


http { # Servidor HTTP
    include       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  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    server { # Servidor Web
        listen       8080;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }


    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}


    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;

    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;

    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}
    include servers/*;
}
```
  
Você pode usar o comando abaixo para retirar os comentários e visualizar somente o necessário, funciona como um filtro:
  
```sh
cat /opt/homebrew/etc/nginx/nginx.conf | grep -ve '^.\s*#' | grep -ve '^#' | sed '/^$/d' 
```
  
Dessa forma, o arquivo de configuração fica assim:
  
[![NGINX](https://img.shields.io/badge/-nginx.conf-000000?style=social&logo=Nginx&logoColor=#009639)](#)

```python
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       8080;
        server_name  localhost;
        location / {
            root   html;
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
    include servers/*;
}
```
  
Vamos editar nosso arquivo principal da página do Nginx. Para isso, acesse o comando abaixo:
  
```sh
nano /opt/homebrew/Cellar/nginx/1.23.2/html/index.html
```
  
Se definirmos `location /`, significa `/` literalmente tudo, ou seja, podemos definir qual o diretório raiz do projeto, qual o arquivo padrão, regras de redirecionamento, etc. Percebe-se que o arquivo não mostra o preview dele no localhost. 

#### Recarrega o arquivo nginx
```sh
nginx -s reload
```

#### Testar o arquivo de configuração
```sh
nginx -t 
```

### Páginas de erro HTTP
Os códigos de erro de protocolo HTTP começam na faixa dos `400`:

```python
server {
    listen 80;
    server_name localhost;
    
    location / {
        root C:/Users/isaac/Dev/nginx;
        index index.html
    }
    error_page 404 400 401 402 /erro.html;
}
```

## [NGINX] Proxy Reverso
<img src="https://linuxhandbook.com/content/images/2020/09/deploy-multiple-services-with-nginx-reverse-proxy-container.png" align="right" height="177">

Um **proxy** de rede funciona basicamente como se fosse um "túnel" ou "filtro", quando acessamos uma determinada área, o proxy . Então é assim que funciona um proxy, ele literalmente pega as requisições e dispara na internet para um servidor web acessar as informações, ou sejam um **proxy reverso** ele pega as requisições feitas e redireciona ainda para outro servidor (Como se acrescentasse mais uma etapa no processo de proxy).

<blockquote>Então, o <b>proxy reverso</b> é um servidor web que recebe as requisições e distribui para outros servidores.</blockquote>

Porque normalmente um proxy fica no lado do cliente. O conceito padrão de proxy é algo que fica no lado do cliente interceptando os pacotes de rede. Como nesse caso o proxy está no lado do servidor, chamamos de *proxy reverso*.

```python
location / {
    proxy_pass http://localhost;
}
```

Com esse simples código, eu tenho o conceito de proxy reverso.
  
> Por que realizar um proxy reverso e não apenas deixar o servidor de aplicação lidar com todas as requisições? Com nginx na frente podemos responder arquivos estáticos muito mais rapidamente. Esse é um dos principais motivos. O nginx é um servidor incrivelmente performático, então nós ganhamos muito ao não enviar todas as requisições para o servidor de aplicação. O nginx pode enviar diretamente os arquivos estáticos sem processar nada, além de poder definir cache, compressão, etc.
  
### Servidor 2 em 1
Com o proxy reverso podemos receber uma requisição e devolver muito rápido se for um arquivo estático, fazer cash e etc. Já para fazer uma rota ou uma URL que precisa de lógica, que precisa ser processada, eu mando para o servidor de aplicação.

Exemplo (default.conf):
```python
server {
    listen 80;
    server_name localhost;
    
    location / {
        root /Users/isaac/Dev/nginx;
        index index.html
    }
    
    location ~ \.php$ {
        proxy_pass http://localhost:8000;
    }
    
    error_page 404 400 401 402 /erro.html
}
```

```sh
php -S localhost:8000
```
  
Com nginx na frente podemos responder arquivos estáticos muito mais rapidamente. Esse é um dos principais motivos. O nginx é um servidor incrivelmente performático, então nós ganhamos muito ao não enviar todas as requisições para o servidor de aplicação. O nginx pode enviar diretamente os arquivos estáticos sem processar nada, além de poder definir cache, compressão, etc.

## [NGINX] API Gateway
	
<div align="center"><img src="https://user-images.githubusercontent.com/61624336/205203395-dab2e0ee-13b6-4499-a75d-015942262517.svg" height="177"></div>

### Monolítica, Microserviços e Múltiplos serviços
<img src="https://www.redhat.com/cms/managed-files/monolithic-vs-microservices.png" height="177" align="right">

Resumidamente:

- **Monolithic** (Monolítica): é nada mais e nada menos do que uma arquitetura para uma aplicação rodando em somente **um serviço** contendo uma estrutura com poucas seções de maneira estruturada para o servidor;

- **Microserviços** (Microservices): é nada mais é do que uma arquitetura com **muitos micro (pequenos) serviços** rodando em uma ou várias aplicações, ideal para projetos de grande porte e com diversas áreas diferentes. 

Vamos criar dois serviços dentro de (microserviços.conf):

```python
server {
    listen 8001;
    server_name localhost;
    
    location / {
        root /Users/isaac/Dev/nginx/servico1;
        index index.html
    }
    
    error_page 404 400 401 /erro.html;
}

server {
    listen 8002;
    server_name localhost;
    
    location / {
        root /Users/isaac/Dev/nginx/servico2;
        index index.html
    }
    
    error_page 404 400 401 /erro.html;
}
```

Agora vamos criar a index.html:

```sh
mkdir Dev/nginx/servico1 Dev/nginx/servico2
echo "Servico 1" > Dev/nginx/servico1/index.html
echo "Servico 2" > Dev/nginx/servico1/index.html
```

Configurando um servidor web que faz o redirecionamento para outros múltiplos servidores baseados na URL recebida (ponto de entrada para centralizar o acesso a múltiplos serviços em um único host):

```python
location /servico1 {
    proxy_pass http://localhost:8001/;
  }
  
location /servico2 {
    proxy_pass http://localhost:8002/;
  }
```

Dessa forma, todas as requisições podem ser feitas para o mesmo servidor, facilitando a vida do cliente, dentre outras vantagens.
  
> Um servidor web que faz o redirecionamento para outros múltiplos servidores baseado na URL recebida. Dessa forma, todas as requisições podem ser feitas para o mesmo servidor, facilitando a vida do cliente, dentre outras vantagens.

A partir do API Gateway é decidido onde essa requisição será direcionada.

- Problema: Clientes acessando livremente os serviços geram caos
- Gateway fornece um proxy, uma fachada, para as necessidades reais
- **Desvantagem: Esse portão de entrada pode se tornar um pouco central de falha**

O comportamento do Gateway

- Simplesmente autorizar e redirecionar os requests
- Uso de Decorator para adicionar informações necessárias aos requests
- Limitar o acesso ou conteúdo trafegado
- Impedir que determinadas URLs sejam acessadas por completo

Agora que conhecemos o conceito de um API Gateway, temos uma base melhor para esse artigo fenomenal do próprio Nginx: https://www.nginx.com/blog/deploying-nginx-plus-as-an-api-gateway-part-1/

## [NGINX] Load Balancing (Balanceamento de carga)
	
<div align="center"><img src="https://user-images.githubusercontent.com/61624336/205202929-3a9cacc2-221f-4e8f-9cb5-9ba501a2e491.svg" height="177"></div>

É um balanceador de carga (como um switch para serviços).

```sh
mv Dev/nginx/servico2/servico.html Dev/nginx/servico2/index.html
```

Podemos configura-lo de forma muito simples, com o `upstream`:
```python
upstream servicos {
     server localhost:8001;
     server localhost:8002;
}

server {
    listen 8003;
    server_name localhost;
    
    location / {
        proxy_pass http://servicos;
    }
}
```
Na prática, através do nome definido em upstream, podemos acessar algum dos servidores deste grupo dependendo de algumas regras definidas.

### Configuração de logs
`access_log` é qualquer log de acesso, já o `error_log` é um log somente de erros. Vamos ver um exemplo no (nginx.conf):

```python
#user nobody;
worker_processes 1;

#error_log  logs/error.log;
#error_log  logs/error.log notice;
#error_log  logs/error.log info;

#pid        logs/nginx.pid


events {
    worker_connections  1024;
}


http {
    include        mime.types;
    default_type   application/octet-stream;
    
    logs_format main  '$remote_addr - $remote_user [$time_local] "$request"'
                      '$status $body_bytes_sent "$http_referer"
                      '"$http_user_agent" "$http_x_fowarded_for"';
                      
   #access_log  logs/access.log  main;
}
```

Logo:

```sh
mkdir Dev/nginx/logs
nginx -t
nginx -s reload
tail -f Dev/nginx/logs/servico1
tail -f Dev/nginx/logs/servico2
```

### Formato de logs (nginx.conf)
```python
#user nobody;
worker_processes 1;

#error_log  logs/error.log;
#error_log  logs/error.log notice;
#error_log  logs/error.log info;

#pid        logs/nginx.pid


events {
    worker_connections  1024;
}


http {
    include        mime.types;
    default_type   application/octet-stream;
    
    logs_format main  'Remote Addr: $remote_addr - Time: [$time_local] "$request"'
                      'Status: $status, Referer: "$http_referer"
                        
   #access_log  logs/access.log  main;
}

     sendfile          on;
``` 

### Formato de logs (microservicos.conf) 
```python
server {
    listen 8001;
    server_name localhost;
    access_log /Users/isaac/Dev/nginx/logs/servico1.log main;
    
    location / {
      root /Users/isaac/Dev/nginx/logs/servico1.log;
      index index.html;
    }
}

server {
    listen 8002;
    server_name localhost;
    access_log /Users/isaac/Dev/nginx/logs/servico2.log main;

    location / {
      root /Users/isaac/Dev/nginx/logs/servico2.log;
      index index.html;
    }
}
```

## Adicionando informações
Dentro do `load-balancer.conf`:

```python
upstream servicos {
     server localhost:8001;
     server localhost:8002;
}

server {
    listen 8003;
    server_name localhost;
    
    location / {
        proxy_pass http://servicos;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
```

No `nginx.conf`:


```vim
#user nobody;
worker_processes 1;

#error_log  logs/error.log;
#error_log  logs/error.log notice;
#error_log  logs/error.log info;

#pid        logs/nginx.pid


events {
    worker_connections  1024;
}


http {
    include        mime.types;
    default_type   application/octet-stream;
    
    logs_format main  'Remote Addr: $http_x_real_ip, Time: [$time_local] "$request"'
                      'Status: $status, Referer: "$http_referer"
                        
   #access_log  logs/access.log  main;
}

     sendfile          on;
``` 

### Definindo pesos (load-balancer.conf)
Se não distriuimos corretamente o peso para cada um servidor, deixaremos um desses servidores sobrecarregados.

```vim
upstream servicos {
     server localhost:8001 weight=2;
     server localhost:8002;
}

server {
    listen 8003;
    server_name localhost;
    
    location / {
        proxy_pass http://servicos;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
```

Aplicamos o cenário de quando temos servidores com capacidades diferentes.

### Servidores de backup
- https://nginx.org/en/docs/http/ngx_http_upstream_module.html

Vamos fazer o seguinte, vamos utilizar o servidor1 como o servidor principal e o servidor2 como o nosso servidor de backup.

```vim
upstream servicos {
     server localhost:8001 fail_timeout=120s;
     server localhost:8002 backup;
}

server {
    listen 8003;
    server_name localhost;
    
    location / {
        proxy_pass http://servicos;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
```

Utilizaremos o servidor backup somente para casos extremos, ou seja, se o servidor principal falhar e estiver em instabilidade, o servidor backup o substitue.

## [NGINX] Fast CGI
<div align="center"><img src="https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2013/09/nginx-fcgi-1a.png"></div><br \>

Lógicas do lado do servidor, e para isso foi criado o **CGI**. Com a mesma ideia do CGI, surgiu então o **FastCGI** cujo você não precisa criar outro processo por cada requisição, o que melhora muito na performance. 

<img src="https://fastcgi-archives.github.io/images/litespeed-screenshot.jpg" height="177" align="right">

A principal diferença entre o **CGI** e o **FastCGI** está no processo, o **FastCGI** permanece vivo após o encerramento de uma requisição. Ao iniciar um processo FastCGO, ele ouvirá novas conexões e não morrerá mais, ou seja, o mesmo processo continua gerenciando os recursos da aplicação. Usando CGI, a cada requisição um processo é criado e depois morre.

### Configurando o proxy
```sh
touch index.php
echo '<?php phpinfo();' > index.php
docker run --rm -it -p 9000:9000 -v $(pwd):/caminho/projeto php:fpm
```

Quero um serviço para rodar no `localhost:8004`, vamos criar um novo documento (fpm.conf):

```vim
server {
   listen 8004;
   
   location / {
       fastcgi_pass localhost:9000;
   }
}
```

### Parâmetros adicionais
Ainda dentro do (fpm.conf):

```vim
server {
    listen 8004;
    root /caminho/projeto;
    
    location / {
        include fastcgi.conf;
        fastcgi_pass localhost:9000;
    }
}
```

É um protocolo mais enxuto com fendas comprimidas e dessa forma a requisição do app não precisa receber todo o protocolo HTTP

## Performance

### Cache HTTP
O navegador (browser) pode ignorar os cabeçalhos de cache e não cachear o recurso. Tanto isso é verdade que temos a opção de desabilitar o cache do nosso navegador. Os cabeçalhos de cache instruem o navegador sobre o quanto tempo ele pode/deve manter o recurso em cache, mas cabe a ele aceitar essa instrução ou não. Todos os navegadores modernos tendem a seguir a instrução a menos que configuremos de forma diferente.

```vim
server {
    listen 8005;
    root /Users/isaac/Dev/performance;
    index index.html;
    
    location ~ \.jpg$ {
       expires 30d;
       add_header Cache-Control public;
    }
}
```

## Compreensão
Modo de compreensão instalado no próprio NGINX:

```python
server {
    listen 8005;
    root /Users/isaac/Dev/performance;
    index index.html
    gzip on;
    gzip_types image/jpg text/css;
    
    location ~ \.jpg$ {
         expires 30d;
         add_header Cache-Control public;
    }
}
```

Os tipos de recursos que são mais beneficiados pela compressão com gzip na web são os arquivos de texto (estáticos): html, css, js, svg, etc...

Os arquivos de texto podem ser facilmente comprimidos e são os que mais levam vantagem desta técnica. Arquivos binários ou arquivos de imagem, por exemplo, naturalmente já são comprimidos, por isso o efeito seria bem menor (ou inexistente).

## Conexões

```python
server {
    listen 8005;
    root /Users/isaac/Dev/performance;
    index index.html;
    gzip on;
    gzip_types text/css;
    add_header Keep-Alive "timeout=5, max=1000";
    
    location ~ \.jpg$ {
         expires 30d;
         add_header Cache-Control public;
    }
}
```

## Cache
### Caminho do Cache

É possível tranformar nosso servidor em um servidor cache, armazenando dados de resposta para não reprocessar determinadas requisições. Em um cenário em que URLs precisam de processamento e não mudam de usuário para usuário.

```python
fastcgi_cache_path level=1.2 /tmp/cache keys_zone=fpm:10m;
proxy_cache_path /tmp/cache levels=1:2 keys_zone=proxy:1m;

server {
    listen 8004;
    root /caminho/projeto;
    
    location / {
        include fastcgi.conf;
        fastcgi_pass localhost:9000;
    }
}
```

Com uma simples página web por exemplo, nós não precisamos realizar todas as queries de cursos, formações, etc o tempo todo. Podemos executar uma vez só e armazenar o html montado em cache.

### Usando o cache

```python
fastcgi_cache_path /tmp/cache level=1:2 keys_zone=fpm:10m;

server {
    listen 8004;
    root /caminho/projeto;
    
    location / {
        fastcgi_pass localhost:9000;
        include fastcgi.conf;
        fastcgi_cache_key $request_method$request_uri;
        fastcgi_cache fpm;
        fastcgi_cache_valid 1m;
    }
}
```

### Verificando o status
Para podermos depurar quando necessário, se precisarmos saber se um cache está sendo encontrado ou não, ter um cabeçalho na resposta é uma forma bem fácil de obter essa informação.

```python
fastcgi_cache_path /tmp/cache level=1:2 keys_zone=fpm:10m;

server {
    listen 8004;
    root /caminho/projeto;
    
    location / {
        fastcgi_pass localhost:9000;
        include fastcgi.conf;
        fastcgi_cache_key $request_method$request_uri;
        fastcgi_cache fpm;
        fastcgi_cache_valid 1m;
        add_header X-Cache-Status $upstream_cache_status;
    }
}
```

## HTTPS
<div align="center"><img src="https://user-images.githubusercontent.com/61624336/130708015-a80f3f14-3d5b-42a7-877c-fe19a2966d3c.png"></div><br \>

Um protocolo de Hipertexto seguro criptografado. Quanto utilizamos o HTTP os dados são transportados em texto puro para o servidor, visível para qualquer um. Nossos dados são enviados em um texto puro, ficando visível para qualquer um que consiga interceptar nossa conexão!

### Gerando nosso próprio certificado

```sh
openssl req -x509 -nodes -days 30 -newkey rsa:2048 -keyout /tmp/localhost.key -out /tmp/localhost.crt
```
```sh
security add-certificate /tmp/localhost.crt
security add-trusted-cert /tmp/localhost.crt
```

### Configurando o NGINX

```python
server {
    listen 443 ssl;
    root /Users/isaac/Dev/performance;
    index index.html
    gzip on;
    gzip_types text/css;
    add_header Keep-Alive "timeout=5, max=1000";
    ssl_certificate /tmp/localhost.crt;
    ssl_certificate_key /tmp/localhost.key;
    
    location ~ \.jpg$ {
         expires 30d;
         add_header Cache-Control public;
    }
}

server {
    listen 8005;
    root /Users/isaac/Dev/performance;
    index index.html;
    gzip on;
    gzip_types text/css;
    add_header Keep-Alive "timeout=5, max=1000"
    
    location ~ \.jpg$ {
         expires 30d;
         add_header Cache-Control public;
    }
}
```