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.
- Escrever um arquivo
.servicee entender cada linha. - Ativar, conferir e acompanhar o log do serviço.
- Provar que o
Restart=on-failurefunciona. - Criar serviços de usuário (sem sudo) e timers (agendamentos).
- Resolver os erros mais comuns:
203/EXEC,217/USERe "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ção | Pergunta |
|---|---|
[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.
-
Escreva o script.
#!/usr/bin/env bash # Anota a hora a cada 10 segundos. while true; do echo "tic-tac: $(date +%T)" sleep 10 doneCrie com
sudo nano /usr/local/bin/relogio.sh. A pasta/usr/local/biné o lugar padrão para programas que você mesmo instala.O
echoescreve 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. -
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.
-
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:Linha O que significa Description=Texto que aparece no statuse 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). -
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'.
-
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:12O
CGroupmostra dois processos: o bash rodando o script e osleepque ele chamou. Osechodo script já aparecem no log. -
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
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.
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=
| Valor | Reinicia quando… | Use para… |
|---|---|---|
no | Nunca (padrão) | Tarefas que rodam uma vez |
on-failure | Sai com erro, é morto por sinal ou trava | A 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 |
always | Sempre que terminar, até com sucesso | Programas 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.
- 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. - Use
--userem 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
| Linha | Significado |
|---|---|
Type=oneshot | O programa roda, termina, e isso é o normal. |
OnCalendar=*-*-* 02:00:00 | Todo ano-mês-dia, às 02:00. Também aceita daily, weekly, Mon *-*-* 08:00. |
Persistent=true | Se 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ção | Use |
|---|---|
| Programa que fica rodando sempre, para o sistema todo | Serviço em /etc/systemd/system/ |
| Programa só seu, enquanto você está logado | Serviç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 arquivo | systemd-run --user comando (cria um serviço temporário) |
| Rodar uma vez, depois de fechar o terminal | nohup ou tmux (veja Jobs) |
Opções úteis do [Service]
| Opção | Para que serve | Exemplo |
|---|---|---|
WorkingDirectory= | Pasta onde o programa roda (importa se ele usa caminhos relativos) | WorkingDirectory=/opt/meuapp |
Environment= | Define uma variável de ambiente | Environment=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 rodar | User=www-data |
ExecStartPre= | Comando antes de iniciar (ex.: testar a configuração) | ExecStartPre=/usr/sbin/nginx -t |
ExecReload= | O que fazer no systemctl reload | ExecReload=/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.
$ 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
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=ouEnvironmentFile=. - Confira se o
User=tem permissão nas pastas que o programa usa.
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
| Comando | O que faz |
|---|---|
sudo systemctl daemon-reload | Relê os arquivos depois de criar ou editar |
sudo systemctl enable --now nome | Liga agora e no boot |
systemctl status nome | Estado e log recente |
journalctl -u nome -f | Log ao vivo |
systemctl show -p MainPID --value nome | PID do processo principal |
sudo systemctl reset-failed nome | Zera o estado de falha e o limite de tentativas |
systemd-analyze verify arquivo.service | Procura 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:
2. Voltar se cair
Complete para o serviço reiniciar quando falhar ou for morto:
3. Depois de criar o arquivo
Você acabou de criar /etc/systemd/system/meuapp.service. Complete o primeiro comando a rodar:
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+RestartSecfazem 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 usereset-failed.