Série Nginx #1: Instalando e Configurando
Tags: braziliandevs, nginx, wordpress, node
Published: 2021-08-26 14:38:28

## O que é o Nginx

Ele é um servidor web de código aberto, de alto desempenho e que conta com suporte a proxy reverso, sistema de cache e *load balancer*. Ele foi criado por *Igor Sysoev* por volta de 2004 para resolver o problema conhecido como [C10K](http://www.kegel.com/c10k.html).

-----------

## O problema

Parte dos servidores web utiliza o modelo de uma conexão por *thread* ou processo. Ao fazer dessa forma, quando a ação *Y* é gerada, ela esperará até uma ação *X*, criada antes, ser finalizada. Durante todo o tempo, essa ação *Y* ficará bloqueada, esperando ser liberada.

-----------

## Como o Nginx o resolveu

O *Nginx* funciona como uma *simultaneous exhibition*. Ele utiliza, normalmente, um processo mestre para cada núcleo do processador. Esse processo é responsável por ouvir os eventos e atender a todas as requisições de forma simultânea.

Diferente de outros servidores web, o Nginx não espera a ação ser realizada para prosseguir com as outras ações.

<img src="https://media1.giphy.com/media/U4A96Vl8OW7xS1COfU/giphy.gif?cid=ecf05e47kpufw5zrvruwhq0or62dqz15mlsiuhae5ww6p51u&rid=giphy.gif&ct=g" />
*simultaneous exhibition (grandmaster)*

Isso acontece porque o NGINX utiliza estratégias de I/O (Input/Output) não-bloqueantes disponibilizadas pelo sistema, que podem variar de acordo com o sistema operacional. Algumas delas são: [/dev/poll](https://github.com/nginx/nginx/blob/master/src/event/modules/ngx_devpoll_module.c), [epoll](https://github.com/nginx/nginx/blob/master/src/event/modules/ngx_epoll_module.c), [kqueue para FreeBSD](https://github.com/nginx/nginx/blob/master/src/event/modules/ngx_kqueue_module.c) ou [poll para Windows](https://github.com/nginx/nginx/blob/master/src/event/modules/ngx_win32_poll_module.c) e outras.

-----------

## Como o Nginx funciona

**Arquitetura do Processo do Nginx**

![Page Master Process](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5esnx52v43m843jyn4qj.jpg)

* O *processo mestre* executa as operações privilegiadas como configuração de leitura e vinculação de portas e então cria um pequeno número de processos filhos (os próximos três tipos).

* O processo do *cache loader* é executado na inicialização para carregar o cache baseado em disco na memória e, em seguida, é encerrado. Ele é planejado de forma moderada, portanto, suas demandas de recursos são baixas.

* O processo do *gerenciador de cache* é executado periodicamente e remove entradas dos caches de disco para mantê-las dentro dos tamanhos configurados.

* Os *services workers* fazem todo o trabalho. Eles lidam com conexões de rede, lêem e gravam conteúdo em disco e se comunicam com serviços upstream/proxy e interfaces CGI (PHP, Node, Python, Go etc).

**Processo de Trabalho**

![Detalhes do Processo de Trabalho do NGINX](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wrtktdl7is93p5uzkxql.jpg) 

* Realiza as estratégias I/O não bloqueante para a comunicação com os serviços *upstream/proxy* e interfaces *CGI*.

* Integra o servidor web com as aplicações, utilizando as interfaces FastCGI, WSGI, SCGI; o *gateway memcached*, os *streams*, as sub-requisições e o protocolo TCP.

* Lê os conteúdos estáticos (imagens, css, js etc); lê, cria e atualiza os *caches* dos arquivos ou as respostas da aplicação.

* Grava os *logs* de acesso e erro de acordo com a configuração do Nginx.

> Vale lembrar que — nativamente — a escrita de arquivo funciona de forma síncrona. O arquivo é criado e bloqueado para novos acessos até ser liberado pelo sistema. A partir do *NGINX 1.9.13*, tornou-se possível configurar a escrita de arquivos temporários de forma assíncrona com o [aio_write](https://man7.org/linux/man-pages/man3/aio_write.3.html).

**Ciclo de vida de uma requisição no NGINX**

![Ciclo de vida de uma requisição no NGINX](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nlgpga6ama3vt2uejlu2.jpg)

* Recebe a requisição e descriptografa as informações caso ela esteja utilizando HTTPS.

* Identifica a configuração das diretivas em bloco `server` (Servidor Virtual) e `location`, que é carregada conforme URI da requisição.

* Aplica limites (*Rate Limit*) para requisição (opcional).

* Executa autenticação interna e/ou externa como [*HTTP Basic Authentication*](https://datatracker.ietf.org/doc/html/rfc7617). A autenticação pode ser feita com módulos nativos ou de de terceiros (opcional).

* Acessa a aplicação através de interfaces de comunicação ou serviços *upstreams* para obter a resposta que será retornada para o cliente.

* Realiza verificações da saúde da aplicação (se ela está ativa), controle de requisições simultâneas, *load balancer*, resposta de cache etc.

* Recebe a resposta da aplicação, filtra-a utilizando compressores como *gzip*, *brotli* ou optimiza-a com filtros (por exemplo, em imagens) etc. É possível usar módulos nativos ou de terceiros para realizar o filtro (opcional).

* Registra o log de acesso e o de sessão.

* Retorna a resposta filtrada para o cliente.

-----------

## Instalação

Vamos mostrar como instalar nos sistemas operacionais mais conhecidos. Posteriormente, veremos como compilar o código fonte. Este passo é importante para configuração dos módulos de terceiro (será estudado em outra parte da série).

### Linux

No exemplo, o processo de instalação será mostrado com os sitemas *Ubuntu*, *Alpine* e *CentOs*. Posteriormente, como compilar o código no *Ubuntu*.

#### Ubuntu

```bash
# Adiciona suporte à instalação da versão mais recente
echo "deb https://nginx.org/packages/ubuntu/ $(lsb_release -cs) nginx" | sudo tee -a /etc/apt/sources.list
# Adiciona chave de assinatura
curl -sSLo- https://nginx.org/keys/nginx_signing.key | sudo apt-key add
# Instala o Nginx
sudo apt update; sudo apt install -y nginx
```

#### Alpine

```bash
sudo apk add nginx
```

#### CentOS

```bash
sudo yum install epel-release
sudo yum install nginx
```

### Mac

1\. É necessário utilizar o [Homebrew](https://brew.sh/index_pt-br), que permitirá a instalação de pacotes que o Mac não fornece. Para instalá-lo, utilize o código abaixo:

```bash
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```

2\. Instale o Nginx:

```bash
brew install nginx
```

### Windows

1. Acesse a página http://nginx.org/en/download.html
2. Escolha a versão que você deseja baixar (recomendo a *stable*)
3. Após baixá-la, extraia o arquivo *zip* e mova a pasta extraída para *C:\*
4. Inicie o executável *nginx.exe* para iniciar o serviço do servidor web.

> Dica: para encerrar o Nginx, abra o *prompt de comando* e execute o comando `tasklist /fi "imagename eq nginx.exe"`.

-----------

## Estrutura de arquivos

Após baixar e instalar o *Nginx*, é criada uma pasta com todos os arquivos de configuração.

> O local de instalação e a estrutura de arquivos podem variar conforme o método de instalação e o sistema operacional. Para esta postagem, utilizei o Nginx instalado via *apt* no Ubuntu 20.04.

Ao acessar o local de instalação (`/etc/nginx`), veremos uma estrutura parecida com esta:

```text
tree /etc/nginx

/etc/nginx
├── conf.d
├── fastcgi.conf
├── fastcgi_params
├── mime.types
├── modules-available
├── modules-enabled
├── nginx.conf
├── proxy_params
├── sites-available
│   ├── default
├── sites-enabled
│   ├── default -> /etc/nginx/sites-available/default
├── snippets
│   ├── fastcgi-php.conf
```

Vamos descobrir para que serve cada um dos arquivos/pastas:

| **Arquivo/Pasta**                | **Descrição**                                                                                                                                                                                                                                      |
|----------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **conf.d/**                      | Pasta com as configurações extras do Nginx. Nela, é possível criar um arquivo de configuração que será incluído automaticamente nas configurações gerais.                                                                                          |
| **fastcgi.conf, fastcgi_params** | Configurações do [fastcgi](https://www.ibm.com/docs/pt-br/ibm-http-server/9.0.5?topic=applications-learn-about-fastcgi). Com eles, é possível incluir, excluir ou remover parâmetros usado pela interface entre o servidor da web e os aplicativos. |
| **mime.types**                   | Funciona como um *map* para identificar o *mimetype* dos arquivos conforme a extensão dele.                                                                                                                                                        |
| **modules-available/**            | Configuração dos módulos disponíveis. (Veremos sobre os módulos mais adiante)                                                                                                                                                                      |
| **modules-enabled/**             | Através de um *symlink*, indica quais módulos o *Nginx* deverá carregar e executar.                                                                                                                                                                |
| **nginx.conf**                   | Configuração geral do *Nginx*. Nele, contém configuração básica de formatação de *log*, *SSL*, *upload*, *gzip*, *pid* (Process Identifier, no Unix), número de conexões simultâneas por processo.                                                 |
| **proxy_params**                 | Configurações usada com o recurso de *proxy* reverso. (Veremos um pouco ao configurar o *ExpressJs* com o *NodeJs*).                                                                                                                               |
| **sites-available/**             | Nesta pasta, ficam as configurações dos servidores virtuais.                                                                                                                                                                                       |
| **sites-enabled/**               | Nesta pasta, ficam os servidores virtuais ativos. Caso o arquivo de configuração esteja em *sites-available*, mas não esteja em *sites-enabled*, o Nginx não irá carregá-lo.                                                                       |
| **snippets/**                    | Configurações extras.                                                                                                                                                                                                                              |

Sabendo disso, vamos continuar.

-----------

## Configurando

Nesta etapa, configuraremos o Nginx para servir o *WordPress* e com o NodeJS (ExpressJS). Portanto, presume-se que você os conheças e os tenha instalados em seu sistema.

Removeremos os arquivos de configuração padrão. Ele não será necessário.

```bash
sudo rm /etc/nginx/sites-available/default
sudo rm /etc/nginx/sites-enabled/default
```

### PHP 8.x (WordPress)

Vamos criar um arquivo de configuração específico para esse site; dessa forma, deixaremos os arquivos mais organizados.

```bash
# Cria o arquivo de configuração
sudo touch /etc/nginx/sites-available/php.valdeir.dev.conf

# Habilita o servidor virtual
sudo ln -s /etc/nginx/sites-available/php.valdeir.dev.conf /etc/nginx/sites-enabled/php.valdeir.dev.conf
```

Agora, vamos escrever nossas regras. No arquivo `/etc/nginx/sites-available/node.valdeir.dev`, utilize o código abaixo.

 > A explicação está no arquivo para facilitar o entendimento

{% gist https://gist.github.com/valdeirpsr/152662e6df2d7f3ef775f52d4dae0367 file=php.valdeir.dev.ini %}

Reinicie o Nginx para ele carregar as novas configurações.

```bahs
sudo nginx -s reload
```

### NodeJS

Para começar, vamos criar um arquivo de configuração e um link simbólico para ele.

```bash
# Cria o arquivo de configuração
sudo touch /etc/nginx/sites-available/node.conf

# Habilita o servidor virtual
sudo ln -s /etc/nginx/sites-available/node.conf /etc/nginx/sites-enabled/node.conf
```

Agora, escreveremos nossas regras. No arquivo `/etc/nginx/sites-available/node`, utilize o código abaixo.

 > A explicação está no arquivo para facilitar o entendimento

{% gist https://gist.github.com/valdeirpsr/152662e6df2d7f3ef775f52d4dae0367 file=node.valdeir.dev.ini %}

Para criação do servidor, utilizaremos a API *Http* do *NodeJS*, que retornará um "Olá, mundo".

{% gist https://gist.github.com/valdeirpsr/152662e6df2d7f3ef775f52d4dae0367 file=server.js %}

Reinicie o Nginx para ele carregar as novas configurações.

```bahs
sudo nginx -s reload
```

Feito isso, basta iniciar o servidor com o node `node server.js`

-----------

## Finalizado

É isso, finalizamos a primeira parte. Aprendemos o que é o Nginx, como ele funciona e como configurar uma aplicação com ele.

Nas próximas partes, falaremos sobre os módulos e como usá-los para obter mais segurança e melhor performance no site. Ademais, falaremos sobre métricas e análise de *logs*.