Série Nginx #2: Compilando o Nginx
Tags: braziliandevs, nginx, devops, webdev
Published: 2021-09-02 19:21:15

Opa!! Chegamos em mais uma parte da série sobre Nginx.

Neste capítulo, aprenderemos como compilar o código fonte do Nginx no Ubuntu.

Quais as vantagens? 😎

 - Flexibilidade;
 - Utilização de módulos de terceiros;
 - Aplicar as correções de segurança mais recentes.

E as desvantagens? 😢

 - É mais complexo;
 - Demanda mais tempo.

Do que preciso para compilar o código?? 👷

Precisamos instalar algumas ferramentas para "buildar" e adicionar suporte a determinadas funcionalidades do Nginx. São elas:

```bash
apt update;
apt install -y curl \
    vim \              # Será nosso editor <3
    build-essential \  # Serve para "buildar"
    gcc \              # " para compilar o código escrito em C
    systemd \          # " para gerenciar o serviço do servidor
    libgd-dev \        # " para o uso do módulo de otimização de imagem (será mostrado em outro capítulo)
    libpcre3-dev \     # " para funções do Core e da diretiva Rewrite, Location (RegExp em geral)
    libssl-dev \       # " para utilizar SSL
    libmaxminddb-dev \ # " para usar um módulo de terceiro para GeoIP2
    zlib1g-dev         # " para otimização com GZIP
```

Ferramentas instaladas, vamos baixar nosso Nginx. Neste capítulo, utilizaremos a versão 1.21.

Baixá-la é simples, basta executar o comando abaixo em seu terminal.

```bash
# Baixa e extrai
curl -sSLo- http://nginx.org/download/nginx-1.21.2.tar.gz | \
tar -xzvf -

# Acessa a pasta criada
cd nginx-1.21.2
```

Ótimo! Baixamos! Agora é hora de usar as ferramentas baixadas para compilar o Nginx. 🎉🎉

Irei deixar o código completo e depois explicarei cada uma das *flags*.

```bash
# Configura os diretórios e
# quais módulos o Nginx deverá instalar
./configure \
    \
    --prefix=/etc/nginx \
    --sbin-path=/usr/sbin/nginx \
    --conf-path=/etc/nginx/nginx.conf \
    --http-log-path=/var/log/nginx/access.log \
    --error-log-path=/var/log/nginx/error.log \
    --pid-path=/run/nginx.pid \
    --modules-path=/etc/nginx/modules-available \
    \
    --http-client-body-temp-path=/usr/local/nginx/client_body_temp \
    --http-proxy-temp-path=/usr/local/nginx/proxy_temp \
    --http-fastcgi-temp-path=/usr/local/nginx/fastcgi_temp \
    --http-uwsgi-temp-path=/usr/local/nginx/uwsgi_temp \
    --http-scgi-temp-path=/usr/local/nginx/scgi_temp \
    \
    --with-debug \
    --with-compat \
    --with-pcre-jit \
    --with-pcre \
    --user=www-data \
    --group=www-data \
    --with-threads \
    \
    --with-http_ssl_module \
    --with-http_stub_status_module \
    --with-http_realip_module \
    --with-http_auth_request_module \
    --with-http_v2_module \
    --with-http_dav_module \
    --with-http_slice_module \
    --with-http_addition_module \
    --with-http_gunzip_module \
    --with-http_gzip_static_module \
    --with-http_image_filter_module=dynamic \
    --with-http_sub_module \
    --with-stream=dynamic \
    --with-stream_ssl_module \
    \
    --without-mail_pop3_module \
    --without-mail_imap_module \
    --without-mail_smtp_module

# Compila o Nginx já configurado
make

# Instala o Nginx no sistema
make install
```

Apareceu algum erro? Não? 🎉🎉
Ótimo! Finalizamos a instalação do servidor. Para testar, basta iniciar o serviço do Nginx e abrir o navegador http://localhost 🖥

```bash
/usr/sbin/nginx
```

> Nos próximos capítulos, ao indicar um módulo irei informar qual *flag* deverá ser utilizada para instalá-lo com o Nginx. Ela deverá ser utilizada no momento da compilação.

-----------

## Explicação das Flags 🚩

Não é obrigatório saber todas, mas é importante saber o que você está instalando e para que cada *flag* serve.

**Configurações de Caminhos**

O *script* `configure` permite definir caminhos para arquivos binários e de configuração NGINX e para bibliotecas dependentes como PCRE ou SSL, a fim de vinculá-los ao binário NGINX.

<dl>
  <dt><code>--prefix=<em>&lt;path&gt;</em></code></dt>
  <dd>Define o diretório principal das configurações do Nginx. Padrão: <em>/usr/local/nginx</em></dd>

  <dt><code>-sbin-path=<em>&lt;path&gt;</em></code></dt>
  <dd>Define o nome e o caminho do arquivo executável. Padrão: <em>&lt;prefix&gt;/sbin/nginx</em></dd>

  <dt><code>--conf-path=<em>&lt;path&gt;</em></code></dt>
  <dd>Define o arquivo principal de configuração do Nginx. É possível carregar o Nginx com um arquivo de configuração diferente, basta usar a <i>flag</i> <code>-c &lt;file&gt;</code>. Padrão: <em>&lt;prefix&gt;/nginx.conf</em></dd>

  <dt><code>--http-log-path=<em>&lt;path&gt;</em></code></dt>
  <dd>Define o arquivo principal do log de acesso geral. É possível configurar um arquivo diferente para cada servidor virtual usando a diretiva <a href="https://nginx.org/r/access_log">access_log</a>. Padrão: <em>&lt;prefix&gt;/logs/access.log</em></dd>

  <dt><code>--error-log-path=<em>&lt;path&gt;</em></code></dt>
  <dd>Define o arquivo principal do log de erro geral. É possível configurar um arquivo diferente para cada servidor virtual usando a diretiva <a href="https://nginx.org/r/access_log">error_log</a>. Padrão: <em>&lt;prefix&gt;/logs/error.log</em></dd>

  <dt><code>--pid-path=<em>&lt;path&gt;</em></code></dt>
  <dd>Define o nome do arquivo que conterá o PID (ID do processo mestre). Você pode alterar o local no arquivo <code>nginx.conf</code>. Padrão: <em>&lt;prefix&gt;/logs/nginx.pid</em></dd>

  <dt><code>--modules-path=<em>&lt;path&gt;</em></code></dt>
  <dd>Define o diretório onde os módulos dinâmicos serão instalados. Padrão: <em>&lt;prefix&gt;/modules/</em></dd>
</dl>

**Configurações de diretórios de dados temporários**

<dl>
  <dt><code>--http-client-body-temp-path=<em>&lt;path&gt;</em></code></dt>
  <dd>Define o diretório em que será armazenados temporariamente o corpo das requisições. Padrão: <em>&lt;prefix&gt;/client_body_temp</em></dd>
  
  <dt><code>--http-proxy-temp-path=<em>&lt;path&gt;</em></code></dt>
  <dd>Define o diretório em que serão armazenados temporariamente os dados recebidos ao utilizar proxy reverso. Padrão: <em>&lt;prefix&gt;/proxy_temp</em></dd>

  <dt><code>--http-fastcgi-temp-path=<em>&lt;path&gt;</em></code></dt>
  <dd>Define o diretório em que serão armazenados temporariamente os dados recebidos ao utilizar por servidores FastCGI. Padrão: <em>&lt;prefix&gt;/fastcgi_temp</em></dd>

  <dt><code>--http-uwsgi-temp-path=<em>&lt;path&gt;</em></code></dt>
  <dd>Define o diretório em que serão armazenados temporariamente os dados recebidos ao utilizar por servidores UWSGI. Padrão: <em>&lt;prefix&gt;/uwsgi_temp</em></dd>

  <dt><code>--http-scgi-temp-path=<em>&lt;path&gt;</em></code></dt>
  <dd>Define o diretório em que serão armazenados temporariamente os dados recebidos ao utilizar por servidores SCGI. Padrão: <em>&lt;prefix&gt;/scgi_temp</em></dd>
</dl>

**Configurações gerais do Nginx**

<dl>
  <dt><code>--with-debug</code></dt>
  <dd>Habilita os logs de debug.</dd>

  <dt><code>--with-compat</code></dt>
  <dd>Habilita a compatibilidade com módulos dinâmicos.</dd>

  <dt><code>--with-pcre-jit</code></dt>
  <dd>Habilita a biblioteca PCRE com suporte a “just-in-time compilation”. Requer a biblioteca PCRE instalada.</dd>

  <dt><code>--with-pcre</code></dt>
  <dd>Força o uso da biblioteca PCRE. Requer a biblioteca PCRE instalada.</dd>

  <dt><code>--user=<em>user-name</em></code></dt>
  <dd>Define o usuário sem privilégios cujas credentiais serão usadas nos processos de trabalho (Services Worker). Padrão: <em>nobody</em></dd>

  <dt><code>--group=<em>group-name</em></code></dt>
  <dd>Define o nome do grupo sem privilégios cujas credentiais serão usadas nos processos de trabalho (Services Worker). Padrão: O mesmo que <em>--user</em></dd>

  <dt><code>--with-threads</code></dt>
  <dd>Habilita a thread pools. Elas são usadas para leitura e envio de arquivos sem bloquear os processos de trabalho.</dd>
</dl>

**Ativando módulos**

O NGINX consiste em um conjunto de módulos específicos de função, que são compilados com o *script* `configure` junto com outras opções de construção.

Se você quiser ativar um módulo que não é "buildado" por padrão, utilize o prefixo `--with-<nome_do_modulo>`.

<dl>
  <dt><code>--with-http_ssl_module</code></dt>
  <dd>Habilita suporte ao protocolo HTTPS para um servidor virtual. Requer a biblioteca <a href="https://www.openssl.org/">openssl</a></dd>
  
  <dt><code>--with-http_stub_status_module</code></dt>
  <dd>Habilita o módulo <em>ngx_http_stub_status_module</em>. Ele é usado por plataformas de métrica ou gerenciamento de *logs*.</dd>

  <dt><code>--with-http_realip_module</code></dt>
  <dd>Habilita o módulo <em>ngx_http_realip_module</em>. Ele é usado para alterar o endereço do cliente. Com o Cloudflare, por exemplo, permite identificar o IP real do usuário.</dd>

  <dt><code>--with-http_auth_request_module</code></dt>
  <dd>Habilita o módulo <em>ngx_http_auth_request_module</em>. Ele é utilizado para implementação de subrequisições para autenticação.</dd>

  <dt><code>--with-http_v2_module</code></dt>
  <dd>Habilita suporte ao protocolo HTTP/2</i>.</dd>

  <dt><code>--with-http_dav_module</code></dt>
  <dd>Habilita o módulo <em>ngx_http_dav_module</em>. Ele é utilizado para gerenciamento de arquivos com o protocolo WebDAV.</dd>

  <dt><code>--with-http_slice_module</code></dt>
  <dd>Habilita o módulo <em>ngx_http_slice_module</em>. Ele é usado para dividir uma requisição. Isso permite retornar partes de um arquivo de acordo com o cabeçalho <i>Range</i>, por exemplo.</dd>

  <dt><code>--with-http_addition_module</code></dt>
  <dd>Habilita o módulo <em>ngx_http_addition_module</em>. Ele é usado para modificar uma resposta adicionando um conteúdo antes ou depois dela.</dd>

  <dt><code>--with-http_gunzip_module</code></dt>
  <dd>Habilita o módulo <em>ngx_http_gunzip_module</em>. Ele é utilizado para compactação com <em>gzip</em></dd>

  <dt><code>--with-http_gzip_static_module</code></dt>
  <dd>Habilita o módulo <em>ngx_http_gzip_static_module</em>. Ele é utilizado para transferência de arquivos compactados com <em>gzip</em>.</dd>

  <dt><code>--with-http_image_filter_module=<em>dynamic</em></code></dt>
  <dd>Habilita o módulo <em>ngx_http_image_filter_module</em>. Ele serve para modificar/alterar arquivos de imagens (JPEG, GIF, PNG, WEBP).</dd>

  <dt><code>--with-http_sub_module</code></dt>
  <dd>Habilita o módulo <em>ngx_http_sub_module</em>. Ele permite substituir trechos da resposta.</dd>

  <dt><code>--with-stream=<em>dynamic</em></code></dt>
  <dd>Habilita o módulo <em>ngx_stream_core_module</em> para proxy TCP/UDP e balanço de carga genérico.</dd>

  <dt><code>--with-stream_ssl_module</code></dt>
  <dd>Habilita o suporte ao procotolo SSL/TLS para módulo <em>ngx_stream_core_module</em>.</dd>
</dl>

**Desativando módulos**

Alguns módulos como Rewrite e HTTP são "buildados" por padrão. Para desativá-los, basta usar o prefixo `--without-<nome-do-modulo>`.

<dl>
  <dt><code>--without-mail_pop3_module</code></dt>
  <dd>Desabilita o protocolo <em>POP3</em> para o proxy de email</dd>

  <dt><code>--without-mail_imap_module</code></dt>
  <dd>Desabilita o protocolo <em>IMAP</em> para o proxy de email</dd>

  <dt><code>--without-mail_smtp_module</code></dt>
  <dd>Desabilita o protocolo <em>SMTP</em> para o proxy de email</dd>
</dl>

Ufa!! Terminamos. 🥱🥱
Para saber outras *flags*, basta acessar o link http://nginx.org/en/docs/configure.html

-----------

## Organizando nossa estrutura 📝

Se você abrir o arquivo `/etc/nginx/nginx.conf`, verá que o Nginx já deixou uma configuração pronta. Eu não curto muito essa estrutura e essa configuração, então mudá-la-ei, mas este passo é totalmente opcional e fica de acordo com o gosto de cada dev.

```bash
# Cria as pastas necessárias
mkdir -p /etc/nginx/{modules-enabled,config_default,sites-available,sites-enabled,log_formats,snippets} /var/www/html

# Move os arquivos de exemplo
mv /etc/nginx/*.default /etc/nginx/config_default
```

Agora vamos reescrever o arquivo de configuração `/etc/nginx/nginx.conf` com o conteúdo abaixo:

{% gist https://gist.github.com/valdeirpsr/152662e6df2d7f3ef775f52d4dae0367 file=nginx.conf %}

Falta pouco! Como removemos o código padrão, nosso servidor parou de funcionar. Precisamos criar um novo servidor virtual, beleza? 👍

```bash
vim /etc/nginx/sites-available/valdeir.dev.conf
```

No *vim*, digite a configuração abaixo:

```conf
server {
    server_name _;

    index index.html index.htm;
    autoindex on;

    location / {
        try_files $uri $uri/ =404;
    }
}
```

Ótimo! Agora é necessário criar um link simbólico no diretório *sites-enabled* para ativar o site. Ainda no vim, aperte <kbd>ESC</kbd> duas vezes e digite:

```bash
:w <enter>
:! ln -s %:p /etc/nginx/sites-enabled <enter>
:q
```

Após cada modificação nos arquivos de configuração, é necessário recarregar o *Nginx*.

```bash
/usr/sbin/nginx -s reload
```

-------

## Criando serviço no Ubuntu

Este passo também é opcional. Ele permitirá gerenciar o Nginx através do `systemd` (auto iniciar, parar, recarregar etc).

É simples! Basta criar o arquivo `/lib/systemd/system/nginx.service` com o código abaixo:

```
[Unit]
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target

[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/usr/sbin/nginx -s reload
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true

[Install]
WantedBy=multi-user.target
```

> O valor de `PIDFile` deverá ser igual ao da *flag* `--pid-path`, que usamos durante a compilação.

> O valor de `ExecStartPre`, `ExecStart` e `ExecReload` deverá ser igual ao da *flag* `--sbin-path`.

-------

## Conclusão

Chegamos ao final de mais um capítulo. Nos próximos, aprenderemos o que e como funcionam as princiais diretivas do Nginx; aprenderemos também como melhorar e segurança e performance de nossos sites.