Todos os artigos
176 artigos · atualizado semanalmente Veja nossas Ferramentas
Todos os artigos
Tutoriais

Comandos Linux essenciais para servidor: guia de diagnóstico

systemctl, journalctl, top, df, ss e grep: os comandos para descobrir em minutos por que o serviço caiu, o disco encheu ou o servidor ficou lento.

Comandos Linux essenciais para servidor: guia de diagnóstico
COVER · Tutoriais

Você abre o terminal, conecta num servidor em produção e recebe aquela mensagem: Active: failed (Result: exit-code). O serviço caiu, mas ninguém sabe desde quando nem por quê. Ou então um colega passa o problema com um "tá lento" que não explica nada, e você precisa descobrir o que está consumindo CPU, memória ou disco sem ter um painel instalado.

É nessa hora que os comandos de administração fazem diferença. Não os de navegação, que o post sobre Linux para iniciantes já cobre, mas os que você usa para entender o que está acontecendo num servidor real, agora. Este post é um roteiro de diagnóstico: cada seção é curta e aponta para o aprofundamento quando ele existe. Rodei todos os comandos num container Debian 12 com systemd 252 como PID 1, com um nginx de pé e um serviço de teste programado para falhar.

O resumo, antes dos detalhes:

Sintoma Primeiro comando O que olhar
Serviço fora do ar systemctl --failed e systemctl status app Active: e as últimas linhas de log
Não sei por que caiu journalctl -u app -n 100 --no-pager a primeira mensagem de erro, não a última
"Tá lento" uptime, free -h, top -b -n 1 -o %CPU load average contra núcleos, memória available
Disco cheio df -h e df -i Use% e IUse% perto de 100%
Porta não responde ss -tulnp se o processo está escutando, e em qual endereço
Erro no meio do log grep -i -C 3 "erro" arquivo.log o contexto em volta da linha

systemctl: o serviço está de pé?

O systemctl é a interface do systemd, o init padrão em Debian, Ubuntu, RHEL, Fedora e derivados. Comece pela lista do que falhou:

$ systemctl --failed
  UNIT          LOAD   ACTIVE SUB    DESCRIPTION
● myapp.service loaded failed failed app que falha

Depois, o status do serviço, que já traz as últimas linhas de log e muitas vezes responde a pergunta sem precisar de mais nada:

$ systemctl status myapp --no-pager
× myapp.service - app que falha
     Active: failed (Result: exit-code) since Mon 2026-11-09 11:29:24 UTC; 8s ago
   Main PID: 47 (code=exited, status=3)
Nov 09 11:29:24 a01c07a3d3b8 sh[47]: ERROR: conexao recusada com o banco
Nov 09 11:29:24 a01c07a3d3b8 systemd[1]: myapp.service: Failed with result 'exit-code'.

(saída encurtada). Os verbos do dia a dia são start, stop, restart, reload (recarrega a configuração sem derrubar, quando o serviço suporta), enable e disable (sobe ou não no boot). Como escrever a unit de um serviço seu está no post sobre criar serviços com systemd.

journalctl: o que aconteceu antes de cair

O journalctl lê o journal do systemd, indexado por serviço, boot e prioridade:

journalctl -u myapp -n 100 --no-pager   # últimas 100 linhas, sem paginador
journalctl -u myapp -f                  # acompanha em tempo real, como tail -f
journalctl -u myapp -b                  # só o boot atual
journalctl -u myapp --since "2026-11-09 10:00" --until "2026-11-09 11:00"

Duas pegadinhas que vi no teste. A primeira: -p err não pega tudo que parece erro. Meu serviço escreveu ERROR: conexao recusada com o banco no stderr, e o journalctl -u myapp -p err voltou vazio. O -o verbose mostrou o motivo: a linha foi gravada com PRIORITY=6 (info), porque o systemd registra stdout e stderr no nível do SyslogLevel=, que por padrão é info, segundo o manual do systemd.exec. Só aplicações que mandam a prioridade (via syslog/journald, ou com prefixos como <3> na linha) aparecem no filtro. Para logs de aplicação, filtre por texto com grep.

A segunda: -b -1 (boot anterior) só funciona com journal persistente. Com Storage=auto (o valor que vem comentado no journald.conf do Debian 12), o journald.conf só grava em disco se o diretório /var/log/journal existir; sem ele, o journal fica em /run, que some no reboot, e o comando responde No such boot ID in journal. journalctl --list-boots mostra quantos boots estão guardados; se for só um, o log da queda de ontem se perdeu.

uptime, free, top e ps: o servidor está lento por quê?

Antes de caçar processo, olhe a carga:

$ uptime
 11:29:50 up 10 days, 15:47,  0 user,  load average: 2.80, 2.49, 2.25
$ nproc
20
$ free -h
               total        used        free      shared  buff/cache   available
Mem:            15Gi       1.8Gi        11Gi        29Mi       2.6Gi        13Gi

O load average é a média de processos rodando ou esperando I/O de disco em 1, 5 e 15 minutos, conforme o manual do /proc/loadavg. Compare com o número de núcleos do nproc: 2,8 em 20 núcleos é folga; 30 em 4 núcleos é fila. Na memória, leia a coluna available, não a free: o Linux usa a memória livre como cache de disco e a devolve quando alguém precisa.

Para achar o processo, eu uso o top em modo batch:

top -b -n 1 -o %CPU | head -15

O ps aux --sort=-%cpu aparece em todo tutorial, mas tem um detalhe: o %CPU do ps é o tempo de CPU dividido pelo tempo de vida do processo, ou seja, uma média desde que ele subiu, como explica o manual do ps. Um processo que travou em 100% há um minuto, depois de uma semana ocioso, aparece baixo. Para "quem está consumindo agora", top. O ps continua ótimo para o resto:

ps -eo pid,user,stat,%cpu,%mem,cmd --sort=-%mem | head   # quem segura mais memória
ps auxf                                                  # árvore: quem gerou quem
pgrep -a nginx                                           # PIDs e linha de comando

Na coluna STAT: R rodando ou na fila, S dormindo (normal), D dormindo sem poder ser interrompido (em geral esperando disco; muitos D indicam I/O saturado) e Z zumbi (o filho terminou e o pai não coletou o status com wait()).

df e du: o disco encheu?

df -h      # espaço por sistema de arquivos
df -hT     # com o tipo (ext4, xfs, overlay)
df -i      # inodes: dá para "encher" com espaço sobrando
du -h /var --max-depth=2 2>/dev/null | sort -rh | head -20

O df -i pega o caso menos óbvio: milhões de arquivos pequenos (sessões PHP, filas, cache) esgotam os inodes e nada novo pode ser criado, mesmo com gigas livres. O passo a passo completo está em investigar falta de espaço em disco, e a caça aos arquivos que mais pesam, em encontrar arquivos grandes no Linux.

ss: o que está escutando e quem está conectado

O ss substituiu o netstat; o próprio manual do netstat diz que ele está "quase obsoleto" e aponta o ss como substituto.

ss -tuln                  # portas TCP/UDP em escuta (só LISTEN)
ss -tulnp                 # idem, com o processo dono da porta (requer root para ver todos)
ss -tn state established  # conexões estabelecidas agora
ss -tlnp 'sport = :80'    # quem escuta na porta 80
ss -tan | awk 'NR>1 {print $1}' | sort | uniq -c | sort -rn   # conexões por estado

O -l é o que muita gente confunde: ele mostra só sockets em escuta. No teste, com uma conexão aberta para a porta 8080, o ss -tuln listou apenas as três linhas LISTEN; a conexão ESTAB só apareceu no ss -tan. Se a aplicação escuta em 127.0.0.1:8080 e você testa de fora, o Local Address já mostra por que não responde. No último comando, o NR>1 descarta o cabeçalho, senão "State" entra na contagem. Milhares de CLOSE_WAIT costumam indicar uma aplicação que não fecha conexões; muitos TIME_WAIT, conexões curtas demais sem keep-alive. Para revisar quais portas cada serviço usa, o post sobre portas de rede tem a lista.

grep: tirar o sinal do ruído

grep -i "error" /var/log/app/app.log                # sem diferenciar maiúsculas
grep -C 3 "Connection refused" /var/log/app/app.log # 3 linhas de contexto
grep -v "GET /health" /var/log/nginx/access.log     # tudo menos o health check
grep -rl "CRITICAL" /var/log/                       # só os nomes dos arquivos
journalctl -u postgresql --no-pager | grep -iE "fatal|error|could not"

No access log do nginx, uma expressão regular extrai os IPs que mais aparecem, e o awk conta os status HTTP (o grep -c "404" contaria também qualquer linha com "404" no tamanho ou na URL):

grep -oP '^\d+\.\d+\.\d+\.\d+' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head
awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c

Quando a regex fica mais complicada que isso, eu testo antes num testador de regex com algumas linhas reais do log, para não descobrir no meio do incidente que o padrão não casa.

O roteiro completo em dois minutos

Deploy novo, serviço respondendo lento. Em sequência:

systemctl status myapp --no-pager                     # 1. está de pé?
journalctl -u myapp -n 50 --no-pager | grep -iE "error|warn|fatal"   # 2. erro recente?
uptime && free -h                                     # 3. carga e memória
top -b -n 1 -o %CPU | head -15                        # 4. quem consome CPU agora
df -h && df -i                                        # 5. disco e inodes
ss -tan | awk 'NR>1 {print $1}' | sort | uniq -c      # 6. conexões acumulando?

Seis passos, dois minutos. Na maioria dos casos, um deles já aponta a causa e o resto vira confirmação.

Perguntas frequentes

Qual a diferença entre systemctl restart e systemctl reload?

restart para o serviço e inicia de novo, com um breve momento fora do ar. reload pede ao processo que releia a configuração sem encerrar, mas só funciona se a unit define ExecReload=. O nginx define (no teste, o status registrou Reloaded nginx.service); o PostgreSQL também recarrega a maior parte das configurações assim. Se não tiver certeza, systemctl cat servico mostra a unit.

Como ver os logs de um serviço que caiu antes do reboot?

journalctl -u nome-do-servico -b -1, que mostra o boot anterior. Isso exige journal persistente: confira com journalctl --list-boots. Se aparecer só o boot atual, crie /var/log/journal ou defina Storage=persistent no journald.conf para a próxima vez.

O ss substitui completamente o netstat?

Para diagnóstico, sim. O netstat vem do pacote net-tools, que muitas instalações mínimas nem trazem, e o próprio manual o chama de quase obsoleto. As flags básicas são parecidas (ss -tuln faz o que netstat -tuln fazia), e o ss ainda filtra por estado e porta.

Que permissões os arquivos de um servidor web precisam?

Em geral, diretórios atravessáveis pelo grupo do servidor web e arquivos só legíveis por ele. Os números estão em permissões 755, 775 e 644, e a diferença entre chmod, chown e umask, em chmod, chown e umask. Para montar o octal sem conta de cabeça, a calculadora de chmod mostra octal e simbólico lado a lado e avisa quando a combinação é insegura.

Comece pelo status, termine na causa

A diferença entre resolver em dois minutos e ficar uma hora tentando está em saber qual comando roda primeiro. systemctl status diz se o serviço está de pé, journalctl -u diz o que aconteceu, uptime, free e top dizem se o problema é carga, df diz se o disco encheu e ss diz se a porta está escutando. Lembre das duas armadilhas: o %CPU do ps é média da vida inteira do processo, e o -p err do journal não enxerga o stderr da sua aplicação. Se o servidor ainda é uma escolha em aberto, o post sobre VPS, VPC e servidor dedicado ajuda a decidir onde rodar tudo isso.

RD
Autor
Rafael Duarte
Desenvolvedor backend com passagem por fintech e SaaS B2B — trabalhou em times que escalaram APIs de zero a milhões de requisições. Carrega cicatrizes de produção suficientes para ter opiniões fortes sobre ferramentas, padrões e decisões de arquitetura. Não é acadêmico: leu a RFC do UUID quando precisou escolher entre v4 e v7 para uma tabela de alta escrita.
Ver perfil