Erro 104 no NGINX com .NET na visão do Kestrel | (104: Connection reset by peer) while reading response header from upstream | Ambiente .NET
- Erro 104 no NGINX com .NET na visão do Kestrel | (104: Connection reset by peer) while reading response header from upstream | Ambiente .NET
Erro 104 no Nginx com Kestrel como Upstream
Contexto
Arquitetura comum em aplicações ASP.NET Core expostas via proxy reverso:
Cliente → Nginx → Kestrel (ASP.NET Core)
Esta documentação descreve o significado do erro 104 (Connection reset by peer) no Nginx, o comportamento do Kestrel nesse cenário e os limites de timeout e proteção aplicados pelo servidor.
O que é o erro 104 no Nginx
Exemplo de log:
recv() failed (104: Connection reset by peer) while reading response header from upstream
- Código 104 corresponde ao erro
ECONNRESET - Indica que o upstream (Kestrel) encerrou a conexão TCP abruptamente
- O reset ocorre antes do envio dos headers da resposta
O encerramento da conexão é iniciado pelo Kestrel ou pelo processo que o hospeda, não pelo Nginx.
O que aconteceu com o Kestrel
O erro 104 indica que o Kestrel tomou a iniciativa de encerrar a conexão. As causas mais comuns são:
Abort da request pela aplicação
- Exception não tratada durante o processamento
- Middleware interrompendo a pipeline
- Chamada explícita de
HttpContext.Abort() - Cancelamento interno não tratado
Nesse caso, o Kestrel envia um TCP RST, resultando no erro 104 no Nginx.
Reinício ou término do processo
- Crash do processo
dotnet - OOM Kill
- Reinício de container ou pod
- Deploy com restart
Conexões abertas são encerradas imediatamente.
Violação de limites internos do Kestrel
O Kestrel possui limites de proteção que, ao serem violados, provocam o encerramento da conexão.
Timeouts e limites definidos pelo Kestrel
O Kestrel não impõe um timeout global para a duração total do processamento de uma request. Os limites são aplicados a fases específicas da comunicação HTTP.
RequestHeadersTimeout
options.Limits.RequestHeadersTimeout = TimeSpan.FromSeconds(30);
- Valor padrão: 30 segundos
- Tempo máximo para o recebimento completo dos headers
- Ao estourar, a conexão é abortada
KeepAliveTimeout
options.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(2);
- Valor padrão: 2 minutos
- Tempo máximo de inatividade de uma conexão keep-alive
MinRequestBodyDataRate
options.Limits.MinRequestBodyDataRate =
new MinDataRate(bytesPerSecond: 240, gracePeriod: TimeSpan.FromSeconds(5));
- Valor padrão: 240 bytes por segundo após 5 segundos
- Protege contra uploads excessivamente lentos
- Violação resulta no encerramento da conexão
MinResponseDataRate
options.Limits.MinResponseDataRate =
new MinDataRate(bytesPerSecond: 240, gracePeriod: TimeSpan.FromSeconds(5));
- Valor padrão: 240 bytes por segundo
- Se a resposta não for consumida com velocidade mínima, a conexão é encerrada
- Pode afetar streaming lento ou respostas grandes
MaxRequestBodySize
options.Limits.MaxRequestBodySize = 30_000_000;
- Valor padrão aproximado: 30 MB
- Requests acima desse limite são rejeitadas
- Dependendo do estágio, pode ocorrer reset da conexão
O que o Kestrel não faz
- Não encerra requests longas com base apenas no tempo de execução
- Não aplica timeout global por controller ou action
- Não cancela automaticamente o código em execução
O processamento continua até que o código respeite o token HttpContext.RequestAborted.
Diferença entre erros comuns no Nginx
| Código | Origem | Descrição |
|---|---|---|
| 104 | Kestrel | Reset da conexão TCP |
| 504 | Nginx | Timeout de leitura do upstream |
| 499 | Cliente | Cliente encerrou a conexão |
| 502 | Nginx | Backend indisponível ou inválido |
Pontos de diagnóstico
- Logs do ASP.NET Core e do Kestrel
- Eventos de restart de container ou pod
- Métricas de memória e CPU
- Comparação entre timeouts do Nginx e limites do Kestrel
Boas práticas operacionais
- Propagar
HttpContext.RequestAbortedpara serviços internos - Ajustar limites do Kestrel conforme o perfil da aplicação
- Evitar processamento pesado síncrono em requests HTTP
- Utilizar filas ou processamento assíncrono para tarefas longas
Documentações
Configuração do Kestrel - Definição de timeouts: 🔗 Clique aqui Classe onde contém o aborto por tempo limite do envio dos headers: 🔗 Clique aqui