# Correção: headers de performance L0 no `.htaccess` e configuração WHM (compressão/OPcache)

- **Branch:** grupo de correções `infra-update` (camada L0 — primeira camada do EPIC)
- **Stack:** Laravel 5.5.50 / PHP 7.2.34 (cPanel/AlmaLinux/Apache 2.4 + EasyApache4)
- **Arquivos alterados:**
  - `public/.htaccess` (deploy da conta — hardening H1‑H9 + performance L0.3/L0.4)
  - `_pesquisa/security/htaccess.txt` (template endurecido, mantido em sincronia)
  - `wiki/infra-update/WHM.md` (passo a passo manual no servidor)
  - `plan/2026-08-09-infra-update.epic.md` (L0.1/L0.2 reescritos para refletir escopo server-side)
- **Categoria:** performance / servidor + `.htaccess` (tarefa #23410)

---

## 1. Problema

No baseline (`2026-09-08-12-10`, 62 domínios) as métricas de performance estavam críticas:

- `compression = 0,34` → 34% das respostas nem gzip.
- `cache_policy = 16/100`, `cache_hit = 0,0` → nada servido em cache de borda.
- `origem = 1594 ms` (92% do TTFB), `transfer = 6,89 MB`.

A intenção do EPIC era resolver isso via `.htaccess` (mod_deflate/brotli) e via
`.user.ini` da conta (OPcache). Na prática, **essas duas frentes não surtiam efeito**
no servidor real, enquanto as demais melhorias de `.htaccess` funcionavam.

## 2. Causa real

Investigação empírica no cPanel/WHM (ver `_pesquisa/security/`) mostrou por que:

1. **Compressão via `.htaccess` é sobreposta.** O `AddOutputFilterByType DEFLATE`
   colocado na conta é ignorado/sobreposto pelo vhost do EasyApache4. A única via
   que funcionou (já provada no estágio‑1 com **−62,1% no transfer**) é a flag
   server-side **cPanel "Optimize Website"** (mod_deflate global). Brotli exige o
   módulo `mod_brotli` provisionado no servidor (WHM EasyApache 4).
2. **OPcache/realpath via conta é no‑op.** As chaves `opcache.*` e `realpath_cache_*`
   são **`PHP_INI_SYSTEM`**: o `.user.ini`/MultiPHP INI da conta é **ignorado
   silenciosamente**. Só o php.ini de sistema do EA4 (`/opt/cpanel/ea-php72/...`) vale.
3. **O que funciona na conta** (já validado pela pesquisa de segurança): `Header`
   cruas (sem `<IfModule mod_headers.c>`, que causa 500), `mod_expires`,
   `FilesMatch`, `FileETag` e `Rewrite*`.

Ou seja: `.htaccess` e `php.ini` da conta **funcionam para a maioria das coisas**, mas
**falham especificamente em compressão e OPcache** — exatamente o que o EPIC tentava
empurrar para a conta.

## 3. Correção real

Dividiu-se a camada L0 em **conta** (o que funciona) e **servidor/WHM** (o que exige root):

### 3.1 `public/.htaccess` (conta) — L0.3 / L0.4

- **Removido** o bloco `mod_deflate`/`mod_brotli` ineficaz.
- **Adicionado**, em `FilesMatch` (Header **crua**, sem wrapper `mod_headers`):
  ```apache
  <FilesMatch "\.(css|js|jpg|jpeg|png|webp|avif|gif|svg|woff2?|ttf|otf|ico)$">
      Header set Cache-Control "public, max-age=31536000, immutable"
  </FilesMatch>
  FileETag MTime Size
  ```
- Mantido o `mod_expires` (H9, wrapper `mod_expires` seguro) para `Expires` longo.
- O arquivo foi **reconciliado com `_pesquisa/security/htaccess.txt`** (hardening H1‑H9
  completo + canário `X-Hardening-Version`), para não regredir a segurança ao implantar.
  Ambos agora têm conteúdo ativo idêntico.

### 3.2 Servidor/WHM (root) — L0.1 / L0.2

Documentado passo a passo em `wiki/infra-update/WHM.md` (sem script automatizado no WHM):

- **gzip:** cPanel » *Optimize Website* » "Compress all content" (ou include global de deflate no WHM).
- **brotli (bônus):** WHM » *EasyApache 4* » *Customize* » Apache Modules » marcar `mod_brotli` » *Provision*.
- **OPcache (ea‑php72):** WHM » *MultiPHP INI Editor* » *System* » `ea-php72`:
  ```ini
  opcache.enable = 1
  opcache.memory_consumption = 256
  opcache.interned_strings_buffer = 32
  opcache.max_accelerated_files = 10000
  opcache.revalidate_freq = 60
  opcache.validate_timestamps = 0
  opcache.save_comments = 1
  realpath_cache_size = 4096K
  realpath_cache_ttl = 600
  ```
- **Reset de OPcache no deploy** (controlável pela conta): `php -r 'opcache_reset();'`,
  `touch public/index.php` ou restart do php-fpm — obrigatório com `validate_timestamps=0`.
- **APCu autoloader (P0‑C):** **STATUS — não aplicado neste ambiente** (a extensão
  `ea-php72-php-apcu` não está disponível no repo EA4 deste servidor; `yum --enablerepo=EA4
  install ea-php72-php-apcu` falhou com "Nenhuma correspondência"). É opcional e o
  `apcu-autoloader` do `composer.json` degrada graciosamente (warning no `dump-autoload`, sem
  quebra), então foi **pulado**. Complementar ao OPcache (cacheia o class map em memória
  compartilhada). Detalhes em `wiki/infra-update/WHM.md` (P0‑C).

## 4. Retrocompatibilidade

- Nenhuma alteração de código da aplicação; só `.htaccess` e configuração de servidor.
- Headers de segurança (H5: XFO, XCTO, Referrer-Policy, HSTS, Permissions-Policy; H7:
  SameSite=Lax; canário `X-Hardening-Version`) **preservados** — o `.htaccess` da conta é
  o template endurecido completo.
- `Cache-Control: immutable` aplica‑se só a estáticos versionados (Mix hash) → invalidação
  automática por mudança de URL; sem risco de conteúdo obsoleto em HTML.

## 5. Verificação

```bash
# Compressão (após passos WHM)
curl -sI --compressed https://infra-update.devs.maxima.inf.br/ | grep -i content-encoding
# esperado: gzip (ou br)

# Estáticos (via .htaccess da conta)
curl -sI https://infra-update.devs.maxima.inf.br/assets/css/app.css \
  | grep -iE 'cache-control|etag|x-hardening-version'
# esperado: public, max-age=31536000, immutable / ETag / 2026-08-maxima

# OPcache (no servidor, contexto ea-php72)
/opt/cpanel/ea-php72/root/usr/bin/php -i | grep -E 'opcache.memory_consumption|opcache.validate_timestamps'

# APCu autoloader (no servidor, contexto ea-php72)
/opt/cpanel/ea-php72/root/usr/bin/php -m | grep -i apcu
grep -l "apcu_fetch" vendor/composer/autoload_real.php && echo "APCu autoloader ATIVO"

# Comparativo vs baseline
python3 ../comparar/comparar.py measuring/results/2026-09-08-12-10 measuring/results/<nova-data>
# esperado: compression=1.0, cache_policy>=80, cache_hit>90% (estáticos), transfer cai
```

## 6. Notas de deploy

- Aplicar o `wiki/infra-update/WHM.md` **manualmente no WHM** (não há script executando no servidor).
- Implantar `public/.htaccess` igual ao template de segurança (já sincronizado).
- Medir no canário `infra-update.devs.maxima.inf.br` antes de liberar para os 62 domínios.
- Guardrail: manter HTTP/2, TLS 1.3, redirects=0, disponibilidade=100% e os headers de segurança.
