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.
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.
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, epoll, kqueue para FreeBSD ou poll para Windows e outras.
Como o Nginx funciona
Arquitetura do Processo do Nginx
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
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.
Ciclo de vida de uma requisição no NGINX
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) elocation
, 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. 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
# 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
sudo apk add nginx
CentOS
sudo yum install epel-release
sudo yum install nginx
Mac
1. É necessário utilizar o Homebrew, que permitirá a instalação de pacotes que o Mac não fornece. Para instalá-lo, utilize o código abaixo:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
2. Instale o Nginx:
brew install nginx
Windows
- Acesse a página http://nginx.org/en/download.html
- Escolha a versão que você deseja baixar (recomendo a stable)
- Após baixá-la, extraia o arquivo zip e mova a pasta extraída para *C:*
- 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:
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. 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.
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.
# 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
# Default server configuration | |
# | |
server { | |
listen 80; | |
listen [::]:80; | |
# Informa onde a aplicação está instalada. | |
# Utilize a pasta onde está o arquivo *index.php* | |
# | |
root /var/www/html/devto/php; | |
# Indica os arquivos que o Nginx deve pesquisar quando o usuário | |
# não informar na URL. Isso significa que se o usuário acessar "https://example.com" | |
# o Nginx deverá procurar o arquivo "https://example.com/index.php" e, caso não o | |
# encontre, ele irá buscar "https://example.com/index.html" e assim por diante | |
# | |
index index.php index.html index.htm; | |
# Define o domínio do site | |
# http://php.valdeir.dev | |
# | |
server_name php.valdeir.dev php.valdeirsantana.com.br; | |
# Informa o arquivo de log. Por padrão, ele registrará todos os acesso | |
# | |
access_log /var/www/html/devto/wordpress.log; | |
# Habilita configurações para envio de arquivos e permite o envio de arquivos com até 512MB | |
# | |
sendfile on; | |
client_max_body_size 512m; | |
# Define o bloco de configuração para site. Todo o acesse passará | |
# por este bloco. | |
# | |
location / { | |
# Verifica a existência dos arquivos acessados na ordem especificada. | |
# Usa o primeiro arquivo encontrado para o processamento da solicitação. | |
# Se o usuário acessar "http://php.valdeirpsr.com.br/wp-admin/setup-config.php", | |
# o Nginx irá verificar se ele existe ($uri); se não existe, verifica se é uma pasta | |
# ($uri/); se não for, redireciona para o arquivo "index.php" | |
# | |
try_files $uri $uri/ /index.php$is_args$args; | |
} | |
# Define o bloco de configuração para os arquivos da pasta "wp-includes" | |
# e o arquivo *xmlrpc.php* | |
# | |
location ~* /(wp-includes|xmlrpc)/.*.php$ { | |
deny all; # Bloqueia todos os acessos direto pelo navegador ou cliente | |
access_log off; # Desabilita logs de acesso | |
log_not_found off; # Desabilita logs do tipo 404 | |
} | |
# Define o bloco de configuração para os arquivos da pasta "wp-content/*" | |
# Evita que alguém envie um arquivo malicioso e acesse-o diretamente, abrindo | |
# brechas no site. | |
# | |
location ~* /wp-content/(plugins|languages|uploads|upgrade|themes)/.*.php$ { | |
deny all; | |
} | |
# Configuração do PHP | |
# | |
location ~ \.php$ { | |
# Inclui o arquivo com as configurações do fastcgi para PHP | |
include snippets/fastcgi-php.conf; | |
# Informa o PID do PHP 8.0. Isso permite ao FastCGI integrar com o PHP | |
fastcgi_pass unix:/var/run/php/php8.0-fpm.sock; | |
# Caso utilize php-cgi | |
#fastcgi_pass 127.0.0.1:9000; | |
} | |
# Define o bloco de configuração para os arquivos estáticos como imagens, css e js | |
# | |
location ~* \.(jpg|jpeg|gif|css|js|png|ico|woff|woff2|ttf|ttc|otf|eot)$ { | |
access_log off; # Desabilita log de acesso | |
expires 30d; # Informa o tempo de expiração do cache (30 dias) | |
} | |
} |
Reinicie o Nginx para ele carregar as novas configurações.
sudo nginx -s reload
NodeJS
Para começar, vamos criar um arquivo de configuração e um link simbólico para ele.
# 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
# Default server configuration | |
# | |
server { | |
# Define a porta que o Nginx deverá ouvir no IPV4 e IPV6 | |
# | |
listen 80; | |
listen [::]:80; | |
# Define o domínio do site. | |
# http://node.valdeir.dev | |
# | |
server_name node.valdeir.dev; | |
# Define o bloco de configuração para site. Todo o acesso passará | |
# por este bloco. | |
# | |
# As demais configurações de proxy estão no arquivo `/etc/nginx/proxy_params` | |
# como mostrado acima | |
# | |
location / { | |
# Inclui o arquivo com as configurações do fastcgi para PHP | |
include proxy_params; | |
# O `proxy_set_header` permite enviar "headers" para o servidor de origem | |
# | |
proxy_set_header Host $host; | |
proxy_set_header X-Real-IP $remote_addr; | |
# Servidor de origem. Toda a requisição será repassada para ele | |
# | |
proxy_pass http://127.0.0.1:3000; | |
} | |
} |
Para criação do servidor, utilizaremos a API Http do NodeJS, que retornará um "Olá, mundo".
/* filename: server.js */ | |
const http = require('http'); | |
const PORT = process.env.PORT || 3000; | |
const server = http.createServer(function(req, res) { | |
res.writeHead(200, {'Content-Type': 'text/plain'}); | |
res.write('Hello World!'); | |
res.end(); | |
}); | |
server.listen(PORT, () => { | |
console.log(`Servidor iniciado http://127.0.0.1:${PORT}`) | |
}); |
Reinicie o Nginx para ele carregar as novas configurações.
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.
Top comments (0)