← Voltar ao blog

Configuração do nginx para Magento 2: setup de produção

Rodrigo Biazzi

O Magento 2 vem com uma configuração de exemplo do nginx, e a maioria dos setups de produção é construída em cima dela. Isso é bom, porque o sample trata corretamente o fallback de arquivos estáticos, a media, as regras de segurança e os pontos de entrada do PHP. Os problemas vêm das partes ao redor: o server block, o TLS, o Varnish no meio, timeouts e buffers. Este artigo percorre um setup de nginx para o Magento Open Source e o Adobe Commerce 2.4.8 e explica as partes que as pessoas costumam errar.

Comece pelo nginx.conf.sample

Na raiz do Magento existe um arquivo chamado nginx.conf.sample. Ele não é um server block completo. Foi feito para ser incluído dentro de um, e espera uma variável chamada $MAGE_ROOT e um upstream chamado fastcgi_backend.

upstream fastcgi_backend {
    server unix:/run/php/php8.3-fpm-magento.sock;
}

server {
    listen 8080;
    server_name shop.example.com;

    set $MAGE_ROOT /var/www/magento/current;
    include /etc/nginx/magento/magento.conf;
}

Repare que o include aponta para uma cópia, não para o arquivo dentro da raiz do Magento. Copie o nginx.conf.sample para a pasta de configuração do nginx e inclua a cópia. Os updates do Composer substituem o sample na raiz do projeto, e você não quer que um upgrade mude a config do seu web server sem revisão. Depois de cada upgrade do Magento, compare o sample novo com a sua cópia e traga o que mudou.

O que o sample faz

Ajuda saber o que você está incluindo antes de mudar:

  • Define o document root como $MAGE_ROOT/pub. Desde o 2.4, pub é o único document root suportado. Servir a raiz do projeto expõe arquivos que nunca deveriam ser públicos.
  • Manda arquivos ausentes em /static/ para o static.php, que pode gerá-los na hora no modo developer. Também remove o segmento de versão de URLs como /static/version1712345678/frontend/..., que é como funciona a assinatura de conteúdo estático.
  • Manda arquivos ausentes em /media/ para o get.php, que serve arquivos guardados no media storage do banco de dados e redimensiona imagens de catálogo sob demanda.
  • Bloqueia o acesso a /media/customer/, /media/downloadable/, /media/import/, e a arquivos ocultos e pastas sensíveis.
  • Permite execução de PHP só para uma lista fixa de pontos de entrada como index.php, get.php, static.php e as páginas de erro, e nega qualquer outro arquivo .php. Essa é uma regra de segurança importante. Um arquivo PHP enviado para a media não consegue rodar.
  • Define headers de cache longos em arquivos estáticos e de media e habilita gzip para tipos de texto.

Se você escrever sua própria config do zero, mantenha todos esses comportamentos. A lista de PHP permitido em particular já impediu muito upload de malware de virar execução remota de código.

Um layout típico com Varnish

Em uma loja com Varnish, o nginx costuma aparecer duas vezes no caminho do request:

  1. O nginx na porta 443 termina o TLS e faz proxy para o Varnish.
  2. O Varnish na porta 6081 serve páginas em cache ou encaminha os misses para o backend.
  3. O nginx na porta 8080 roda a config do Magento e passa os requests PHP para o PHP-FPM.

A frente TLS fica mais ou menos assim:

server {
    listen 443 ssl;
    http2 on;
    server_name shop.example.com;

    ssl_certificate     /etc/letsencrypt/live/shop.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/shop.example.com/privkey.pem;

    client_max_body_size 64m;

    location / {
        proxy_pass http://127.0.0.1:6081;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Forwarded-Port 443;
        proxy_buffer_size 128k;
        proxy_buffers 4 256k;
        proxy_busy_buffers_size 256k;
        proxy_read_timeout 300s;
    }
}

server {
    listen 80;
    server_name shop.example.com;
    return 301 https://$host$request_uri;
}

A diretiva http2 on é a sintaxe do nginx 1.25.1 em diante. Em versões mais antigas do nginx você adiciona http2 na linha do listen.

Avisando o Magento que o request era HTTPS

Atrás de um proxy, o Magento enxerga HTTP puro vindo do Varnish. Ele usa o header X-Forwarded-Proto para saber que o request original era seguro. Se esse header faltar, você tem loops de redirect quando URLs seguras são obrigatórias, ou mixed content quando o Magento monta links http em uma página https. Garanta que o Varnish repasse o header ao backend.

Headers grandes

O Magento manda um header X-Magento-Tags grande em páginas de categoria com muitos produtos. O Varnish o remove antes de a resposta sair, mas entre o backend e o Varnish ele pode ser grande. Se você vê erros 502 só em páginas de categoria grandes, confira os parâmetros http_resp_hdr_len e http_resp_size do Varnish e os tamanhos de buffer do fastcgi no nginx. O guia do Varnish cobre o lado do Varnish.

Buffers e timeouts do FastCGI

A config do sample define buffers do FastCGI e timeouts longos para o location do PHP. Ela também passa memory_limit e max_execution_time ao PHP por meio de fastcgi_param PHP_VALUE. Esses valores sobrescrevem o seu php.ini nos requests web. Se você muda o memory limit no php.ini e nada acontece, geralmente é por isso.

Decida se quer os limites do PHP definidos no nginx ou no pool do FPM. Deixá-los na config do pool com php_admin_value é mais claro, porque um único lugar os controla. Se você os mover, remova a linha PHP_VALUE da sua cópia do sample.

Timeouts longos são úteis para exportações e importações do admin feitas pelo navegador, mas também deixam requests travados segurando um worker por minutos. Um request de storefront que leva 600 segundos é um bug, não algo para esperar. Considere um timeout menor no server block do storefront e um maior para os paths do admin, se você separá-los.

Compressão

O sample habilita gzip para tipos de conteúdo de texto. O Brotli comprime melhor JavaScript e CSS, mas precisa do módulo brotli do nginx, que não faz parte do build padrão do nginx na maioria das distribuições. Se estiver disponível:

brotli on;
brotli_comp_level 5;
brotli_types text/plain text/css application/javascript application/json image/svg+xml;

Se uma CDN fica na frente da loja, ela costuma comprimir as respostas por conta própria, e a compressão do nginx importa menos para os visitantes. Ainda assim, reduz o tráfego entre a sua origem e a CDN.

IP real do cliente

Quando um load balancer, o Varnish ou uma CDN fica na frente, o nginx enxerga o IP do proxy como se fosse o cliente. Logs, rate limits e recursos do Magento que olham o endereço remoto passam a usar o IP errado. O módulo realip resolve isso:

set_real_ip_from 127.0.0.1;
set_real_ip_from 10.0.0.0/8;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

Liste só proxies que você controla. Confiar no X-Forwarded-For vindo de qualquer lugar deixa qualquer visitante falsificar o próprio IP.

Protegendo o admin

A URL do admin não deve ser o /admin padrão. Além disso, o nginx pode restringi-la por IP quando sua equipe trabalha de endereços fixos:

location ~* ^/(index\.php/)?backoffice_x7k2 {
    allow 203.0.113.10;
    deny all;
    try_files $uri $uri/ /index.php$is_args$args;
}

Troque o path pelo front name do seu admin. Teste com cuidado, porque o admin também carrega assets estáticos e faz chamadas AJAX sob esse path. Funciona melhor combinado com as medidas do guia de hardening de segurança do admin.

Rate limiting de bots

Crawlers agressivos batendo na navegação em camadas e na busca podem gerar milhares de requests sem cache por minuto. O limit_req do nginx pode desacelerá-los:

limit_req_zone $binary_remote_addr zone=search:10m rate=2r/s;

location /catalogsearch/ {
    limit_req zone=search burst=10 nodelay;
    try_files $uri $uri/ /index.php$is_args$args;
}

Aplique no server block do backend, não na frente TLS, se o Varnish cacheia algumas dessas URLs. Garanta antes que a configuração de IP real acima esteja no lugar, senão todo visitante compartilha o IP do proxy e é limitado junto.

Testando as mudanças

Rode sempre nginx -t antes de um reload, e faça reload em vez de restart para as conexões abertas terminarem. Depois de qualquer mudança nas regras de location do Magento, confira uma página de produto, uma página de categoria, um arquivo estático com o segmento de versão na URL, uma imagem de produto redimensionada que ainda não existe, o login do admin e o checkout. Isso cobre os caminhos de código que mais quebram.

FAQ

Devo editar o nginx.conf.sample diretamente?

Não. Copie para a pasta de configuração do nginx e inclua a cópia. Os upgrades substituem o sample, e você deve revisar as mudanças antes de elas chegarem ao seu servidor.

Por que o Magento mostra loops de redirect atrás do nginx e do Varnish?

Geralmente o header X-Forwarded-Proto está faltando, então o Magento acha que o request é HTTP puro e redireciona para HTTPS de novo. Repasse o header do proxy TLS pelo Varnish até o backend.

Por que o memory_limit do meu php.ini não vale para requests web?

A config de nginx do sample passa o memory_limit por fastcgi_param PHP_VALUE, que sobrescreve o php.ini. Mude lá ou mova a configuração para o pool do FPM.

pub é o document root correto para o Magento 2.4.8?

Sim. Desde o 2.4 a pasta pub é o document root suportado. Servir a raiz do projeto expõe arquivos que não podem ser públicos.

Atendo como freelancer em Magento e Adobe Commerce, incluindo setup de servidor e hospedagem. Se precisar de ajuda com isso, fale comigo.

Artigos relacionados