Ubuntu Criar um Serviço

Você tem um script ou programa que precisa rodar o tempo todo: ligar sozinho no boot, voltar se cair e guardar o que acontece num log. Em vez de deixá-lo aberto num terminal, você o transforma num serviço do systemd. Nesta aula você vai fazer isso do zero e testar o reinício automático matando o processo de propósito.

Você vai aprender
  • Escrever um arquivo .service e entender cada linha.
  • Ativar, conferir e acompanhar o log do serviço.
  • Provar que o Restart=on-failure funciona.
  • Criar serviços de usuário (sem sudo) e timers (agendamentos).
  • Resolver os erros mais comuns: 203/EXEC, 217/USER e "start request repeated too quickly".

Antes, leia systemctl: aqui usamos status, enable e daemon-reload.


Antes do comando: como o systemd lê um serviço

Um serviço é um arquivo de texto com seções entre colchetes. Cada seção responde uma pergunta:

SeçãoPergunta
[Unit]O que é este serviço e do que ele depende?
[Service]Que programa rodar, como qual usuário, e o que fazer se ele cair?
[Install]Em que momento do boot ele deve ligar (quando você der enable)?

Serviços que você cria ficam em /etc/systemd/system/. Os que vêm com pacotes ficam em /usr/lib/systemd/system/; não mexa neles.


Passo a passo: o serviço "relógio"

Nosso exemplo é um script simples que anota a hora a cada 10 segundos. Ele é inofensivo, então você pode reproduzir tudo numa VM ou no seu Ubuntu.

  1. Escreva o script.

    #!/usr/bin/env bash
    # Anota a hora a cada 10 segundos.
    while true; do
        echo "tic-tac: $(date +%T)"
        sleep 10
    done

    Crie com sudo nano /usr/local/bin/relogio.sh. A pasta /usr/local/bin é o lugar padrão para programas que você mesmo instala.

    O echo escreve na saída padrão. Num serviço, tudo o que o programa escreve vai automaticamente para o log do systemd: você não precisa criar arquivo de log.

  2. Dê permissão de execução e teste à mão.

    $ sudo chmod +x /usr/local/bin/relogio.sh
    $ /usr/local/bin/relogio.sh
    tic-tac: 10:30:00
    tic-tac: 10:30:10
    ^C                                          « Ctrl+C para parar o teste

    Sempre teste o script antes de virar serviço. Se ele não funciona no terminal, também não vai funcionar como serviço.

  3. Escreva o arquivo do serviço.

    [Unit]
    Description=Relógio de teste do Guia Ubuntu
    After=network.target
    
    [Service]
    Type=simple
    ExecStart=/usr/local/bin/relogio.sh
    User=ana
    Restart=on-failure
    RestartSec=5
    
    [Install]
    WantedBy=multi-user.target

    Crie com sudo nano /etc/systemd/system/relogio.service. O nome do arquivo é o nome do serviço. Linha por linha:

    LinhaO que significa
    Description=Texto que aparece no status e nos logs.
    After=network.targetSó inicie depois que a rede estiver configurada. É só ordem: não obriga a rede a existir.
    Type=simpleO programa fica rodando em primeiro plano (o normal para scripts). É o padrão; está aqui para ficar explícito.
    ExecStart=O comando a rodar. Sempre com caminho completo.
    User=anaRoda como a usuária ana. Sem essa linha, o serviço roda como root.
    Restart=on-failureSe o programa cair com erro ou for morto, inicie de novo.
    RestartSec=5Espere 5 segundos antes de reiniciar.
    WantedBy=multi-user.targetNo enable, ligue junto com o estágio normal do boot (sistema pronto para uso, com ou sem interface gráfica).
  4. Avise o systemd e ligue o serviço.

    sudo systemctl daemon-reload
    Relê os arquivos: o systemd ainda não sabe que o novo arquivo existe.
    sudo systemctl enable --now relogio
    Liga agora e em todo boot.
    $ sudo systemctl daemon-reload
    $ sudo systemctl enable --now relogio
    Created symlink '/etc/systemd/system/multi-user.target.wants/relogio.service' → '/etc/systemd/system/relogio.service'.
  5. Confira o estado.

    $ systemctl status relogio
    ● relogio.service - Relógio de teste do Guia Ubuntu
         Loaded: loaded (/etc/systemd/system/relogio.service; enabled; preset: enabled)   « enabled: liga no boot
         Active: active (running) since Thu 2026-10-15 10:31:02 -03; 25s ago
       Main PID: 5337 (relogio.sh)                                                        « anote este número
          Tasks: 2 (limit: 18339)
         Memory: 1.4M (peak: 1.7M)
            CPU: 11ms
         CGroup: /system.slice/relogio.service
                 ├─5337 /bin/bash /usr/local/bin/relogio.sh
                 └─5344 sleep 10
    
    out 15 10:31:02 notebook systemd[1]: Started relogio.service - Relógio de teste do Guia Ubuntu.
    out 15 10:31:02 notebook relogio.sh[5337]: tic-tac: 10:31:02
    out 15 10:31:12 notebook relogio.sh[5337]: tic-tac: 10:31:12

    O CGroup mostra dois processos: o bash rodando o script e o sleep que ele chamou. Os echo do script já aparecem no log.

  6. Acompanhe o log ao vivo.

    $ journalctl -u relogio -f
    out 15 10:31:22 notebook relogio.sh[5337]: tic-tac: 10:31:22
    out 15 10:31:32 notebook relogio.sh[5337]: tic-tac: 10:31:32

    O -f (de follow) fica mostrando linhas novas. Ctrl+C sai.


Teste: mate o processo e veja o systemd reiniciar

Agora a prova de que o Restart=on-failure funciona. Vamos simular uma queda matando o processo principal com o sinal 9 (KILL), que não pode ser ignorado (veja kill).

systemctl show
Mostra propriedades internas de uma unit.
-p MainPID
Só a propriedade MainPID (o processo principal).
--value
Só o valor, sem o nome. Perfeito para usar dentro de outro comando.
relogio
O serviço.
$ systemctl show -p MainPID --value relogio
5337
$ sudo kill -9 5337                         « simula uma queda
$ sleep 6
$ systemctl status relogio
● relogio.service - Relógio de teste do Guia Ubuntu
     Loaded: loaded (/etc/systemd/system/relogio.service; enabled; preset: enabled)
     Active: active (running) since Thu 2026-10-15 10:33:08 -03; 1s ago       « voltou, há 1 segundo
   Main PID: 5502 (relogio.sh)                                               « PID novo: é outro processo

O log conta exatamente o que aconteceu:

$ journalctl -u relogio -n 5
out 15 10:33:03 notebook systemd[1]: relogio.service: Main process exited, code=killed, status=9/KILL   « morreu
out 15 10:33:03 notebook systemd[1]: relogio.service: Failed with result 'signal'.
out 15 10:33:08 notebook systemd[1]: relogio.service: Scheduled restart job, restart counter is at 1.  « 5 s depois
out 15 10:33:08 notebook systemd[1]: Started relogio.service - Relógio de teste do Guia Ubuntu.
out 15 10:33:08 notebook relogio.sh[5502]: tic-tac: 10:33:08
E se eu der systemctl stop?

Aí ele não volta. Um stop é uma parada pedida por você, não uma falha. O Restart=on-failure só age quando o programa cai sozinho ou é morto por fora.

Por que kill -9 e não só kill?

O kill sem número manda o sinal TERM, um pedido educado de encerramento. O systemd considera esse fim "limpo" e, com on-failure, não reinicia. O sinal 9 (KILL) é uma morte forçada, igual a uma queda de verdade. Se quiser que o serviço volte em qualquer caso, use Restart=always.

Opções de Restart=

ValorReinicia quando…Use para…
noNunca (padrão)Tarefas que rodam uma vez
on-failureSai com erro, é morto por sinal ou travaA maioria dos serviços
on-abnormalÉ morto por sinal ou trava (não por código de erro)Programas que saem com erro de propósito
alwaysSempre que terminar, até com sucessoProgramas que nunca deveriam parar

Parar e remover o serviço

$ sudo systemctl disable --now relogio      # para e tira do boot
Removed '/etc/systemd/system/multi-user.target.wants/relogio.service'.
$ sudo rm /etc/systemd/system/relogio.service
$ sudo systemctl daemon-reload

Outras formas de fazer

Serviço de usuário (sem sudo)

Para algo que só importa para você, como sincronizar uma pasta, crie um serviço de usuário. Ele roda como você, enquanto você estiver logado.

  1. Crie a pasta e o arquivo em ~/.config/systemd/user/:
    $ mkdir -p ~/.config/systemd/user
    $ nano ~/.config/systemd/user/relogio.service
    [Unit]
    Description=Relógio do usuário
    
    [Service]
    ExecStart=%h/bin/relogio.sh
    Restart=on-failure
    
    [Install]
    WantedBy=default.target

    %h é trocado pela sua pasta pessoal. Não há User=: ele já roda como você. O alvo é default.target, o "boot" da sua sessão.

  2. Use --user em tudo, sem sudo:
    $ systemctl --user daemon-reload
    $ systemctl --user enable --now relogio
    $ journalctl --user -u relogio -f

Para o serviço de usuário rodar mesmo quando você não está logado (num servidor, por exemplo), rode uma vez sudo loginctl enable-linger ana.

Timer: rodar de tempos em tempos

Para "rodar todo dia às 2h", em vez de um serviço que fica em loop, use um timer. São dois arquivos com o mesmo nome:

[Unit]
Description=Backup da pasta pessoal

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
[Unit]
Description=Backup diário às 2h

[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true

[Install]
WantedBy=timers.target
LinhaSignificado
Type=oneshotO programa roda, termina, e isso é o normal.
OnCalendar=*-*-* 02:00:00Todo ano-mês-dia, às 02:00. Também aceita daily, weekly, Mon *-*-* 08:00.
Persistent=trueSe o computador estava desligado às 2h, roda assim que ligar.
$ sudo systemctl daemon-reload
$ sudo systemctl enable --now backup.timer      « habilite o .timer, não o .service
$ systemctl list-timers backup.timer

Para testar a regra de horário antes: systemd-analyze calendar "*-*-* 02:00:00" mostra a próxima execução. Compare com o cron em Agendar Tarefas.

Qual usar?

SituaçãoUse
Programa que fica rodando sempre, para o sistema todoServiço em /etc/systemd/system/
Programa só seu, enquanto você está logadoServiço de usuário (--user)
Tarefa que roda de tempos em tempos.timer + .service com Type=oneshot, ou cron
Testar algo rápido, sem criar arquivosystemd-run --user comando (cria um serviço temporário)
Rodar uma vez, depois de fechar o terminalnohup ou tmux (veja Jobs)

Opções úteis do [Service]

OpçãoPara que serveExemplo
WorkingDirectory=Pasta onde o programa roda (importa se ele usa caminhos relativos)WorkingDirectory=/opt/meuapp
Environment=Define uma variável de ambienteEnvironment=PORTA=8080
EnvironmentFile=Lê variáveis de um arquivo (bom para senhas fora do .service)EnvironmentFile=/etc/meuapp.env
User= / Group=Com qual usuário e grupo rodarUser=www-data
ExecStartPre=Comando antes de iniciar (ex.: testar a configuração)ExecStartPre=/usr/sbin/nginx -t
ExecReload=O que fazer no systemctl reloadExecReload=/bin/kill -HUP $MAINPID
StartLimitBurst= / StartLimitIntervalSec=Quantas tentativas de reinício, em quanto tempo, antes de desistir (vão na seção [Unit])StartLimitBurst=5

Quando não funciona

status=203/EXEC
$ systemctl status relogio
× relogio.service - Relógio de teste do Guia Ubuntu
     Active: failed (Result: exit-code) since Thu 2026-10-15 10:40:11 -03; 3s ago
    Process: 5610 ExecStart=/usr/local/bin/relogio.sh (code=exited, status=203/EXEC)

O que aconteceu: o systemd não conseguiu executar o programa. As causas, em ordem de frequência: falta permissão de execução, o caminho no ExecStart está errado, ou falta a primeira linha #!/usr/bin/env bash no script.

Como confirmar e resolver:

$ ls -l /usr/local/bin/relogio.sh
-rw-r--r-- 1 root root 98 Oct 15 10:39 /usr/local/bin/relogio.sh     « sem "x": não é executável
$ sudo chmod +x /usr/local/bin/relogio.sh
$ head -1 /usr/local/bin/relogio.sh
#!/usr/bin/env bash
$ sudo systemctl restart relogio
status=217/USER

O que aconteceu: o usuário de User= não existe (erro de digitação, por exemplo).

Como resolver: confira com id nome-do-usuario, corrija o arquivo, rode sudo systemctl daemon-reload e reinicie.

"start request repeated too quickly"
$ journalctl -u relogio -n 3
out 15 10:45:20 notebook systemd[1]: relogio.service: Start request repeated too quickly.
out 15 10:45:20 notebook systemd[1]: relogio.service: Failed with result 'exit-code'.
out 15 10:45:20 notebook systemd[1]: Failed to start relogio.service - Relógio de teste do Guia Ubuntu.

O que aconteceu: o programa cai logo ao iniciar, o systemd reinicia, ele cai de novo… Depois de várias tentativas seguidas, o systemd desiste para não ficar em loop.

Como resolver: leia as linhas anteriores do log para achar o erro real (journalctl -u relogio -n 50), corrija, e então libere o serviço:

$ sudo systemctl reset-failed relogio
$ sudo systemctl start relogio
No terminal funciona, como serviço não

O que aconteceu: o serviço roda num ambiente "limpo": sem os seus apelidos, sem o seu PATH completo, em outra pasta e às vezes como outro usuário.

Como resolver:

  • Use caminhos completos no script (/usr/bin/python3, /home/ana/dados/arquivo.txt).
  • Defina WorkingDirectory= se o programa usa caminhos relativos.
  • Passe variáveis com Environment= ou EnvironmentFile=.
  • Confira se o User= tem permissão nas pastas que o programa usa.
Atenção: sem User=, o serviço é root

Um serviço sem User= roda com poder total. Se o programa tiver uma falha, o invasor ganha o sistema inteiro. Sempre que possível, rode como um usuário comum ou um usuário próprio do serviço.


Referência

ComandoO que faz
sudo systemctl daemon-reloadRelê os arquivos depois de criar ou editar
sudo systemctl enable --now nomeLiga agora e no boot
systemctl status nomeEstado e log recente
journalctl -u nome -fLog ao vivo
systemctl show -p MainPID --value nomePID do processo principal
sudo systemctl reset-failed nomeZera o estado de falha e o limite de tentativas
systemd-analyze verify arquivo.serviceProcura erros no arquivo
systemd-analyze calendar "expressão"Testa uma regra de OnCalendar
systemctl --user …Mesmos comandos, para serviços de usuário

Exercícios

1. O comando do serviço

Complete a linha que diz qual programa o serviço roda:

=/usr/local/bin/relogio.sh

2. Voltar se cair

Complete para o serviço reiniciar quando falhar ou for morto:

Restart=

3. Depois de criar o arquivo

Você acabou de criar /etc/systemd/system/meuapp.service. Complete o primeiro comando a rodar:

sudo systemctl

4. O status mostra status=203/EXEC. Qual é a causa mais provável?

5. Se o arquivo .service não tem a linha User=, com qual usuário o programa roda?


Resumo

  • Script testado no terminal → arquivo em /etc/systemd/system/nome.service → daemon-reload → enable --now.
  • [Unit] descreve, [Service] diz o que rodar e como, [Install] diz quando ligar no boot.
  • Restart=on-failure + RestartSec fazem o serviço voltar sozinho; o log mostra "Scheduled restart job".
  • Use User= para não rodar como root; caminhos sempre completos.
  • 203/EXEC = não conseguiu executar; "repeated too quickly" = leia o erro anterior e use reset-failed.