Guia Completo do Spool do Exim: Mensagens Congeladas (Frozen), Travas de Kernel e Diagnóstico no CloudLinux
Voltar para blog

Guia Completo do Spool do Exim: Mensagens Congeladas (Frozen), Travas de Kernel e Diagnóstico no CloudLinux

08/10/2026 · 11 min · Infraestrutura

Quem gerencia servidores de e-mail com cPanel e Exim já deve ter presenciado um acúmulo repentino na fila com centenas ou milhares de mensagens com status frozen (congeladas). Quando isso acontece, o disco começa a sofrer com excesso de operações de leitura e escrita (I/O wait), e os e-mails legítimos acabam demorando muito mais para serem despachados.

O estado congelado não é uma pane no software: ele funciona como um disjuntor de segurança do próprio Exim para evitar que o servidor desperdice processador e rede tentando entregar repetidamente mensagens que violaram regras rígidas ou sofreram erros irrecuperáveis.

Neste artigo, vamos entender como o Exim estrutura os arquivos no diretório de spool, o que significa um bloqueio por frozen by ACL, por que anexos grandes causam falhas silenciosas e como diagnosticar e limpar o ambiente com comandos rápidos no terminal.


1. A Estrutura Física do Spool do Exim e Interações com o Kernel#

Para entender por que as mensagens congelam, vale a pena olhar como o Exim grava dados em /var/spool/exim/input/.

Como o Exim divide uma mensagem no disco#

Cada mensagem que entra na fila é separada em pelo menos dois arquivos distintos:

  1. Arquivo de cabeçalho (-H): guarda os metadados do envelope (remetente real, destinatários, carimbos de tempo, cifras TLS e identificador de status). É aqui que fica gravada a flag lógica de congelamento.
  2. Arquivo de dados (-D): contém o corpo do e-mail e os anexos codificados (normalmente em Base64).

Essa separação permite que o Exim leia apenas os arquivos -H durante a inspeção de fila (exim -bp), economizando memória e evitando ler corpos pesados de e-mails desnecessariamente.

O mecanismo de travas e a flag frozen#

Quando o serviço inicia uma tentativa de entrega:


O ciclo de vida e impacto de uma mensagem congelada#

Uma mensagem entra em estado congelado (frozen) quando o servidor não consegue entregar a mensagem original e também falha ao tentar notificar o remetente:

  1. Tentativa inicial e falha: o Exim tenta entregar um e-mail (por exemplo, um relatório de cron disparado por root para um endereço externo). O servidor de destino rejeita a entrega com um erro permanente (código 5xx) ou atinge o limite de tentativas temporárias (código 4xx).
  2. Geração da mensagem de retorno (bounce): conforme o padrão SMTP, o servidor cria uma notificação de falha. Para evitar loops infinitos de notificações entre servidores, o remetente desse aviso é gravado como nulo: <>.
  3. Falha na entrega do bounce: o Exim tenta devolver a notificação para quem gerou o e-mail ([email protected]). Se o alias em /etc/aliases não existir, a caixa postal local estiver lotada ou o domínio não resolver internamente, o aviso também não pode ser entregue.
  4. Congelamento: como a mensagem original não pôde ser entregue e o aviso de erro também falhou, o Exim ativa a função interna deliver_freeze(). O arquivo de cabeçalho da mensagem no disco ganha a marca de congelado, e o daemon para de tentar enviá-la nas varreduras normais de fila (exim -q).

Quando milhares de mensagens congeladas se acumulam por semanas, o diretório /var/spool/exim/input/ fica sobrecarregado. O número de inodes diminui e comandos comuns de checagem começam a demorar segundos ou minutos, elevando o uso de CPU em modo de espera de disco (I/O wait).

2. Rastreamento e Análise Forense da Fila pelo Terminal#

Identificando domínios com maior retenção#

Para ter um resumo estatístico rápido de quais destinos estão acumulando volume:

exim -bp | exiqsumm | sort -n | tail -n 20

O comando exim -bp lista o estado atual de todas as mensagens no spool, o exiqsumm agrupa os totais por domínio e o tail destaca os 20 maiores acumuladores.

Isolando identificadores de mensagens#

Quando você identifica um domínio suspeito (domain.com), use o exiqgrep para listar apenas os IDs das mensagens retidas:

exiqgrep -r "@domain\.com$" -i

A flag -i emite apenas o identificador da mensagem (por exemplo, 1wF7Aa-00000009iej-1s3H), facilitando o envio para outros comandos via pipe ou xargs.

Lendo metadados e histórico completo#

Com o ID em mãos, consulte o histórico de eventos e os cabeçalhos salvos no spool:

# Ver a linha do tempo completa da mensagem
exim -Mvl 1wF7Aa-00000009iej-1s3H

# Inspecionar os cabeçalhos brutos salvos no arquivo -H
exim -Mvh 1wF7Aa-00000009iej-1s3H

Estudo de caso 1: falhas de autenticação e ataques de dicionário: ataques de backscatter e a flag frozen by ACL#

Um dos logs mais comuns em servidores com mensagens congeladas é este:

2026-04-21 06:13:30 Received from [email protected] H=(noreply.spamdome.com) [34.82.177.3] P=esmtps X=TLS1.3:TLS_AES_256_GCM_SHA384:256 S=3207 [email protected] T="\351\205\215\351\200\201\347\212\266\346\263\201\343\201\256\343\201\224\346\241\210\345\206\205"
2026-04-21 06:13:30 frozen by ACL

O que está acontecendo aqui#

  1. Remetente forjado: o remetente utiliza uma estrutura que simula retorno de erro para tentar forçar o seu servidor a enviar um aviso de falha (bounce) para uma vítima externa.
  2. Assunto codificado: a sequência de escape octal \351\205\215... no campo T= representa caracteres orientais (neste exemplo, uma notificação falsa de entrega de mercadoria em japonês).
  3. Decisão da ACL: a mensagem passou pela checagem de conexão inicial, mas atingiu a pontuação máxima nas regras de antispam durante a fase de dados (acl_smtp_data). Quando a diretiva no Exim está configurada para congelar em vez de rejeitar imediatamente (deny), o arquivo é retido no spool para conferência manual.
Dica operacional: se o seu servidor recebe muito spam com essa característica, vale a pena alterar a política das ACLs de antispam no cPanel de Freeze para Deny (550), evitando que lixo eletrônico consuma inodes em disco.

Estudo de caso 2: mensagens volumosas e esgotamento de storage: mensagens volumosas e esgotamento de storage#

Quando uma única mensagem aparece retendo 15 MB ou mais no spool e permanece presa por horas, dois fatores costumam estar em jogo:

Limites de tamanho no destino (message_size_limit)#

No /etc/exim.conf, existe a diretiva message_size_limit. Se o seu servidor permite envios de até 50 MB, mas o servidor do destinatário aceita no máximo 10 MB, o diálogo SMTP falha:

A expansão do base64 e cotas locais#

Arquivos anexados a e-mails precisam ser codificados em texto ASCII de 7 bits via Base64. Essa conversão adiciona um acréscimo fixo de aproximadamente 33% ao tamanho original:


Inspecionando o conteúdo antes de purgar#

Antes de deletar itens da fila, inspecione algumas mensagens para identificar se o disparo veio de scripts legítimos ou de invasões em sites hospedados:

# Ver os cabecalhos completos da mensagem
exim -Mvh 1wG0DU-00000004C5t-42tQ

# Ver o corpo do e-mail
exim -Mvb 1wG0DU-00000004C5t-42tQ

# Ver o log individual de tentativas dessa mensagem
exim -Mvl 1wG0DU-00000004C5t-42tQ

Nos cabeçalhos (exim -Mvh), procure pela linha injetada pelo PHP:

X-PHP-Originating-Script: 1001:envio.php

O número antes dos dois pontos é o UID do usuário no Linux. Com esse identificador, você descobre em qual pasta /home/usuario/public_html o script disparador reside.

3. Depuração de Baixo Nível com strace e Gargalos de I/O#

Se o log do Exim não deixar claro por que uma mensagem não avança, você pode acompanhar as chamadas de sistema forçando a entrega monitorada:

strace -f -s 256 -e trace=network,openat,write,flock exim -M 1wF7Aa-00000009iej-1s3H

Dois gargalos comuns revelados pelo strace#

  1. Black hole de MTU (Path MTU Discovery): se o Exim conclui o handshake TCP, envia o comando DATA, mas congela indefinidamente em chamadas write() com blocos grandes de Base64 sem nunca receber retorno em read(), algum roteador no caminho está descartando pacotes grandes com o bit Don't Fragment (DF) ativo.
  2. Esgotamento de inodes no disco: se o comando df -h mostra espaço livre, mas o df -i acusa 100% de uso de inodes na partição /var, chamadas openat() para criar novos cabeçalhos falham com ENOSPC. O Exim entra em colapso e congela mensagens em cascata.

Rastreando falhas de entrega de mensagem específica com strace#

Se uma mensagem específica insiste em travar e você precisa ver onde a conexão morre (seja em consulta DNS ou falha de socket):

strace -f -tt -s 512 -e trace=openat,write,connect,unlink exim -M 1wG0DU-00000004C5t-42tQ

A flag -f acompanha processos filhos e -e trace=connect mostra o IP e a porta de rede exatos onde o Exim tentou se conectar antes de falhar.

4. Procedimentos Cirúrgicos: Descongelamento, Retentativas e Purga em Massa#

Purgando mensagens congeladas de um domínio específico (SPAM)#

Para remover do spool todas as mensagens congeladas associadas a um domínio fraudulento:

exiqgrep -r "@domain\.com$" -i | xargs -I {} exim -Mrm {}

O comando exim -Mrm remove fisicamente os arquivos -H e -D do disco e limpa os registros correspondentes no banco de retentativas (retry.db).

Descongelando e forçando entrega de e-mails legítimos#

Se a causa da retenção (como uma falha de DNS externa) foi resolvida e as mensagens legítimas precisam ser entregues:

# 1. Descongelar as mensagens (Thaw)
exiqgrep -r "@domain\.com$" -i | xargs -I {} exim -Mt {}

# 2. Forçar a tentativa imediata de entrega
exiqgrep -r "@domain\.com$" -i | xargs -I {} exim -M {}

Purgando mensagens congeladas em massa#

Se você já conferiu a fila e precisa remover todas as mensagens congeladas de uma só vez sem derrubar o serviço do Exim:

exiqgrep -z -i | xargs exim -Mrm

Entendendo a cadeia de comandos:

5. Conectividade remota do MySQL sob CloudLinux e CageFS#

Liberar o MySQL para conexões externas em servidores cPanel com CloudLinux exige ajustes tanto na escuta de rede quanto na camada de isolamento do CageFS.

1. Liberando a escuta do MySQL na rede#

Por padrão, o MySQL atende apenas em 127.0.0.1. Para permitir conexões vindas da rede externa, edite o /etc/my.cnf:

[mysqld]
bind-address = 0.0.0.0
skip-name-resolve = 1

Reinicie o banco de dados e confirme a porta aberta:

/scripts/restartsrv_mysql
ss -tulpn | grep 3306

2. Mapeamento de sockets e esqueleto no CageFS#

O CloudLinux isola cada usuário cPanel dentro de um ambiente virtualizado (o CageFS). Quando usuários locais rodam scripts no terminal ou em cron jobs que conversam com o MySQL, eles precisam acessar o socket do banco dentro de suas jaulas.

Verifique se o socket do MySQL está listado nos pontos de montagem do CageFS em /etc/cagefs/cagefs.mp:

/var/lib/mysql/mysql.sock
/var/run/mysqld/mysqld.sock

Se bibliotecas de cliente ou binários do banco tiverem sido atualizados recentemente no sistema principal, force a sincronização das jaulas dos usuários:

cagefsctl --addrpm MariaDB-client
cagefsctl --force-update

A flag --force-update remonta o esqueleto do CageFS em /usr/share/cagefs-skeleton/, garantindo que todas as contas tenham acesso às bibliotecas compartilhadas corretas.

3. Monitoramento de limites com o MySQL governor#

O CloudLinux possui um módulo chamado MySQL Governor que monitora o consumo de CPU e I/O de disco de cada conta em tempo real.

Se uma aplicação externa começar a rodar consultas lentas sem índices, o MySQL Governor reduz a prioridade do usuário para evitar que ele derrube o servidor.

Para checar se um usuário está sofrendo restrições:

dbctl list | grep usuario

Se o usuário estiver marcado como throttled, suas consultas remotas vão demorar para responder, dando a impressão de falha de conexão.


6. Problemas comuns e armadilhas de rede (CSF/LFD)#

Bloqueio por excesso de conexões no CSF (PORTFLOOD)#

Se a porta 3306 estiver liberada no firewall, mas o cliente externo relatar quedas constantes, verifique a diretiva PORTFLOOD no /etc/csf/csf.conf:

PORTFLOOD = "3306;tcp;5;10"

Se essa regra estiver ativa, qualquer aplicativo que abrir mais de 5 conexões em 10 segundos terá o IP bloqueado temporariamente.

Para evitar isso em integrações legítimas, adicione o IP do cliente diretamente na lista de permissões permanentes:

csf -a IP_DO_CLIENTE "Acesso remoto ao banco"
csf -r

Erro de plugin de autenticação (caching_sha2_password)#

Se clientes antigos ou bibliotecas legadas de PHP tentarem conectar no MySQL 8 e devolverem o erro Authentication plugin 'caching_sha2_password' cannot be loaded, ajuste o método de autenticação do usuário para o padrão anterior:

ALTER USER 'usuario'@'IP_DO_CLIENTE' IDENTIFIED WITH mysql_native_password BY 'SuaSenhaForte';
FLUSH PRIVILEGES;

Limite de descritores de arquivo no kernel (limitnofile)#

Quando muitas conexões remotas simultâneas são abertas, o MySQL pode acusar erro de Too many open files ou Can't create a new thread.

Confira o limite atual do processo:

cat /proc/$(pgrep mysqld)/limits | grep "Max open files"

Se o limite for baixo, aumente nas configurações do systemd criando /etc/systemd/system/mysqld.service.d/override.conf:

[Service]
LimitNOFILE=65535

Depois aplique e reinicie:

systemctl daemon-reload
/scripts/restartsrv_mysql

7. Checklist de Validação e Matriz Operacional#

Matriz rápida de diagnóstico para problemas de spool#

| Sintoma | Causa mais provável | Verificação rápida | Resolução | |

Para ter certeza de que ambos os serviços estão operando em harmonia:

  1. Fila do Exim limpa: rode exim -bpc e confirme que a contagem total de mensagens caiu para níveis saudáveis (geralmente abaixo de algumas dezenas).
  2. Porta 3306 acessível externamente: teste a partir de uma máquina remota usando nc -zv IP_DO_SERVIDOR 3306.
  3. CageFS atualizado: rode cagefsctl --validate para certificar que nenhum ponto de montagem do MySQL ficou quebrado.
  4. Logs limpos: monitore /var/log/exim_mainlog e /var/log/messages por alguns minutos para garantir que nenhuma mensagem volte a congelar sem motivo.

Este artigo foi útil?

Deixe uma reação rápida para apoiar o conteúdo:

CC BY-NC

Este post está licenciado sob CC BY-NC.

Comentários

Participe da discussão abaixo.

0 comentários