Voltar ao blog

Serviço systemd não inicia? Como resolver

14 de setembro de 2026

Um serviço systemd que não inicia quase nunca é mistério. Rode systemctl status <unit>, depois leia as últimas 50 linhas do journal dessa unidade com journalctl -u <unit> -n 50 --no-pager — entre os dois, uma de cinco causas costuma ser nomeada com todas as letras: um caminho errado, um binário ausente, permissões erradas, uma negação do SELinux/AppArmor ou um erro de sintaxe no unit file. O motivo da falha está no log; as correções abaixo são só casamento de padrões contra ele.

Como ver por que um serviço systemd falhou?

Status primeiro, journal depois:

systemctl status myapp.service
journalctl -u myapp.service -n 50 --no-pager

O status te dá o estado (inactive (dead), failed (exit-code), activating (auto-restart)) e as últimas linhas de log. O journal te dá a história completa: stdout, stderr e as reclamações do próprio systemd sobre a unidade.

Se a unidade falhou antes e você quer o registro daquela execução, adicione -b para o boot atual ou --since today:

journalctl -u myapp.service -b --no-pager

Para o kit completo — boots, prioridades, seguir o output ao vivo — veja o journalctl cheat sheet. É a mesma memória muscular.

Mais um par que vale conhecer:

systemctl list-units --failed
systemctl reset-failed myapp.service

O primeiro lista toda unidade vermelha da máquina. O segundo limpa o estado de falha depois do conserto — cosmético, mas evita páginas de status chorando lobo.

Quais são as causas mais comuns?

Depois que o log nomeia o sintoma, a causa quase sempre é uma destas cinco:

O log dizCausa provávelCorreção
status=203/EXECCaminho errado no ExecStart= ou interpretador ausenteCaminho absoluto, chmod +x, confira o shebang
status=203/EXEC num scriptScript com line endings CRLF ou shebang erradodos2unix script.sh, conserte a primeira linha
status=1/FAILURE, sem log da appDiretório de trabalho ou env var faltandoDefina WorkingDirectory=, adicione Environment=
Permission deniedO usuário não consegue ler arquivos nem bindar a portaConserte o dono; portas abaixo de 1024 pedem AmbientCapabilities=CAP_NET_BIND_SERVICE ou root
Unit is maskedAlguém rodou systemctl masksystemctl unmask myapp.service
Edição no unit file “não faz nada”Daemon não recarregadosystemctl daemon-reload

A família 203/EXEC merece menção especial porque é a que devora tardes. O systemd não usa seu shell para lançar o ExecStart=. Isso significa:

# Errado — sem shell, ~ nunca expande, sem busca no PATH
ExecStart=~/app/run.sh

# Certo
ExecStart=/opt/app/run.sh

E o script em si precisa ser executável e começar com um shebang de verdade (#!/bin/bash ou #!/usr/bin/env bash). Um script que roda bem no seu terminal mas falha com 203 sob systemd é quase sempre um destes: não executável, line endings CRLF, shebang apontando para lugar nenhum ou caminho relativo.

Por que ele inicia na mão mas não no boot?

O bug clássico de ordenação. Se o log mostra falhas logo depois do boot mas a unidade inicia bem quando você roda systemctl start à mão, seu serviço está perdendo uma corrida — ele busca a rede, um disco montado ou um banco de dados antes disso existir.

A correção é declarar dependências em vez de torcer:

[Unit]
After=network-online.target postgresql.service
Wants=network-online.target

[Service]
ExecStartPre=/usr/bin/test -f /opt/app/config.toml

O After= ordena a inicialização; o Wants= faz o systemd de fato subir a dependência. O network-online.target só funciona se o serviço de espera de rede estiver habilitado na sua distro, então confira systemctl is-enabled NetworkManager-wait-online.service (ou o equivalente do systemd-networkd). O guarda ExecStartPre= é um jeito barato e honesto de falhar alto, com mensagem legível, em vez de um stack trace.

Uma segunda variante: o serviço inicia no boot mas morre na hora. Procure o que seu ambiente interativo tinha e o boot não tem — diferenças de PATH, um virtualenv, um HOME. Defina o que precisar explicitamente:

[Service]
Environment="PATH=/opt/app/venv/bin:/usr/bin"
User=appuser
WorkingDirectory=/opt/app

Por que meu serviço não está logando no journal?

Se o journalctl -u não mostra nada, confira três coisas em ordem:

  1. StandardOutput= e StandardError= na unidade — devem ser journal (o default) ou journal+console. Alguém pode tê-los posto em null.
  2. A app escreve num arquivo em vez do stdout. O systemd só captura stdout/stderr; quem escreve em arquivo de log passa longe do journal. Ou aponte a app para o stdout, ou leia o arquivo.
  3. Limites de armazenamento descartaram linhas antigas: journalctl --disk-usage, e SystemMaxUse= em /etc/systemd/journald.conf se o journal estiver sufocando.

Para depurar a inicialização em si, nada supera derrubar um shell dentro do contexto de boot:

[Service]
ExecStart=/bin/bash -c 'exec /opt/app/bin/server 2>&1'

Ou, para mistérios de verdade, rode o comando exato do ExecStart= como o usuário da unidade, num shell — a maioria das diferenças de ambiente aparece nos primeiros dez segundos.

Como fazer ele reiniciar sozinho depois de um crash?

A política default é Restart=no: um serviço que crasha fica morto, e você fica sabendo por um usuário. Conserte isso por serviço:

[Service]
Restart=on-failure
RestartSec=5
ConfiguraçãoReinicia quando
no (default)Nunca
on-failureSaída não zero, sinal, timeout
alwaysQualquer saída, mesmo limpa
on-watchdogSó timeout do watchdog

Pareie o Restart=on-failure com um guarda de taxa de start, para um loop de crashes não martelar a máquina: StartLimitIntervalSec= e StartLimitBurst= na seção [Unit]. Cinco falhas em sessenta segundos devem acordar um humano, não girar uma CPU.

Se você está montando isso como job agendado em vez de daemon, pese primeiro o cron vs timer do systemd — timers te dão logging no journal e ordenação de dependências de graça, que é exatamente o que este artigo passa o tempo todo buscando.

O checklist de 60 segundos

  1. systemctl status <unit> — leia o estado e as últimas linhas.
  2. journalctl -u <unit> -n 50 --no-pager — ache o erro real.
  3. 203/EXEC? Conserte caminho, shebang, permissões. Permission denied? Conserte usuário e dono dos arquivos.
  4. Falha só no boot? Adicione After=/Wants=network-online.target e um guarda ExecStartPre=.
  5. Mudou um unit file? systemctl daemon-reload && systemctl restart <unit>.
  6. Adicione Restart=on-failure para o próximo crash se anunciar em vez de se esconder.

A maioria dos momentos de “systemd é complicado” se resume a o erro esteve no journal o tempo todo. Leia-o antes de editar o unit file, não depois.

— mrsaynothing

Get the next one by email

One email per post. No spam, no algorithms.

self-hosted · no third parties · one-click unsubscribe

what is this?

Quantização GGUF: qual nível usar?

Gostou dos artigos? É assim que eu construo profissionalmente. me contrate