SSD Nodes Learn Hosting plans →
Guias Matt ConnorPor Matt Connor · Atualizado 2026-08-24

Como criar um serviço systemd para seu programa no VPS

Aprenda a criar uma unit systemd para iniciar no boot, reiniciar após falhas, registrar no journal, usar timers e aplicar hardening no VPS.

O que é um serviço systemd e por que deve usar um

Um serviço systemd é um pequeno ficheiro de texto que indica ao servidor como executar um programa: iniciá-lo no boot, reiniciá-lo se falhar e enviar a saída para o log do sistema. Essa é a sua função. Um programa iniciado manualmente numa sessão SSH termina assim que sair ou quando o servidor reinicia. Um programa associado a um serviço systemd continua em execução, porque é gerido pelo próprio servidor e não pela sua shell.

systemd é o sistema init do Ubuntu, Debian, Fedora e da maioria dos servidores Linux modernos. É o primeiro processo a iniciar e o responsável por supervisionar todos os outros. Nem sempre foi assim, e vale a pena ler como o systemd substituiu os init scripts que o precederam depois de saber o que faz um unit file. Ao escrever um service file, entrega o seu programa a esse supervisor. Este guia mostra a unit mínima funcional, as três secções presentes em todas as units, como ativá-la e consultar os seus logs, como executá-la segundo um horário com um timer e como restringi-la para que seja executada com o mínimo de privilégios possível.

O menor serviço funcional

Um ficheiro de serviço fica em /etc/systemd/system/, termina em .service e precisa apenas de algumas linhas. Crie um para um programa em /usr/local/bin/myapp:

sudo nano /etc/systemd/system/myapp.service
[Unit]
Description=My application

[Service]
ExecStart=/usr/local/bin/myapp

[Install]
WantedBy=multi-user.target

Esta é uma unidade completa e funcional. ExecStart é o comando a executar. WantedBy=multi-user.target significa iniciar o serviço quando o servidor atingir o funcionamento normal em modo multiutilizador. É isso que faz o serviço arrancar no boot. Tudo o resto é aperfeiçoamento.

As três secções e a finalidade de cada uma

Cada ficheiro de unidade está dividido em secções entre parênteses retos. Um serviço utiliza três.

[Unit] descreve o serviço e as relações deste. As duas linhas que utilizará com mais frequência:

[Unit]
Description=My application
After=network-online.target
Wants=network-online.target

Description é a designação legível que vê em systemctl status. After=network-online.target indica ao systemd que não deve iniciar o programa enquanto a rede não estiver ativa. Isto é importante para qualquer programa que escute numa porta ou estabeleça uma ligação de saída.

[Service] define a forma como o programa é executado. É aqui que coloca a maioria das definições:

[Service]
ExecStart=/usr/local/bin/myapp --config /etc/myapp/config.toml
WorkingDirectory=/opt/myapp
User=myapp
Restart=on-failure
RestartSec=5
Environment=LOG_LEVEL=info

User=myapp executa o programa com uma conta sem privilégios, em vez de root. Esta é a linha mais importante para a segurança. Não existe aqui nenhuma linha Type=, por isso o systemd recorre a simple e assume que o processo ExecStart permanece em primeiro plano. Um programa que crie um processo filho e passe para segundo plano precisa do Type= adequado à forma como é iniciado, caso contrário a unidade comunicará o estado active quando o daemon real já tiver terminado. Restart=on-failure e RestartSec=5 têm uma secção própria abaixo, porque são a razão pela qual a maioria das pessoas cria um serviço.

[Install] define o que acontece quando ativa o serviço:

[Install]
WantedBy=multi-user.target

WantedBy=multi-user.target é o que liga o serviço ao arranque do sistema quando executa systemctl enable. Sem uma secção [Install], o serviço pode ser iniciado manualmente, mas não arrancará automaticamente depois de um reboot.

Ative e monitore

Depois de escrever ou editar qualquer ficheiro de unidade, recarregue o systemd para que leia a alteração. Em seguida, ative e inicie o serviço num único passo:

sudo systemctl daemon-reload
sudo systemctl enable --now myapp.service

daemon-reload é o passo que as pessoas esquecem: o systemd mantém os ficheiros de unidade em cache, por isso uma edição não produz efeito até recarregar. enable --now ativa o serviço para o arranque e inicia-o imediatamente. Verifique:

sudo systemctl status myapp.service
* myapp.service - My application
     Loaded: loaded (/etc/systemd/system/myapp.service; enabled)
     Active: active (running) since Wed 2026-07-15 22:40:11 UTC; 3s ago
   Main PID: 4123 (myapp)

Active: active (running) e enabled são os estados pretendidos. Para ler a saída do programa, peça ao journal apenas esta unidade:

sudo journalctl -u myapp.service -f

-f acompanha as novas linhas à medida que chegam, como tail -f. Tudo o que o programa escrever na saída padrão ou na saída de erro padrão fica aqui, sem qualquer configuração de logging da sua parte.

Reinício em caso de falha, o motivo pelo qual está aqui

A principal vantagem de um serviço é que o systemd reinicia o seu programa quando ele termina de forma inesperada. Duas linhas fazem isso:

[Service]
Restart=on-failure
RestartSec=5

Restart=on-failure reinicia o programa quando ele termina com um código diferente de zero ou morre devido a um sinal de falha, como SIGKILL ou SIGSEGV. Um encerramento normal ou uma paragem causada por SIGTERM, SIGINT, SIGHUP ou SIGPIPE não desencadeia o reinício. RestartSec=5 aguarda cinco segundos entre as tentativas, para que um programa que falha imediatamente não entre num ciclo apertado. Confirme o comportamento terminando o processo e observando o systemd iniciá-lo novamente. Use SIGKILL: o SIGTERM predefinido conta como uma paragem normal, por isso on-failure não reiniciaria o serviço:

sudo systemctl kill -s SIGKILL myapp.service
sudo systemctl status myapp.service

No prazo de cinco segundos, o estado mostra um novo Main PID e active (running) novamente. Essa é toda a funcionalidade e é por isso que um serviço é melhor do que deixar um programa a correr em tmux ou screen.

Execute-o como um utilizador sem privilégios e aplique medidas de proteção

Um serviço executado como root pode fazer qualquer coisa no servidor se o programa for explorado. Execute-o com o seu próprio utilizador e adicione algumas diretivas ao systemd para restringir o ambiente. Primeiro, crie uma conta de sistema sem acesso de login e sem diretório pessoal:

sudo useradd --system --no-create-home --shell /usr/sbin/nologin myapp

Depois, defina User=myapp e adicione as linhas de proteção a [Service]:

[Service]
User=myapp
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true

Cada linha remove algo de que o programa não precisa. NoNewPrivileges=true impede que o processo obtenha novos privilégios, mesmo através de um binário setuid. PrivateTmp=true fornece um /tmp privado que nenhum outro processo pode ver. ProtectSystem=strict torna todo o sistema de ficheiros apenas de leitura, exceto alguns caminhos que indicar com ReadWritePaths=. ProtectHome=true oculta /home completamente do processo. Esta é a mesma abordagem de privilégio mínimo usada ao colocar um serviço atrás de uma firewall: conceda-lhe apenas o que precisa. Se leu o guia sobre fechar a falha da firewall IPv6 numa VPS, esta é a parte aplicada no próprio host da mesma abordagem. Para um serviço exposto à Internet, combine estas medidas com Fail2ban à frente do SSH e uma firewall com política de negação por padrão.

Em vez de escrever tudo manualmente e esquecer uma diretiva, gere uma unidade completa com medidas de proteção e copie-a:

Toolsystemd service and timer generator

Timers: o cron moderno

Um timer do systemd executa um serviço segundo um agendamento e é o substituto moderno de um cron job. Um timer é composto por dois ficheiros: um .service que executa o trabalho e um .timer que define quando o executar. Suponha que pretende fazer uma cópia de segurança todos os dias às 3am. O serviço executa a tarefa uma vez e termina:

# /etc/systemd/system/backup.service
[Unit]
Description=Nightly backup

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh

Type=oneshot informa o systemd de que o programa é executado, termina e fica concluído, em vez de permanecer residente. O timer agenda a execução:

# /etc/systemd/system/backup.timer
[Unit]
Description=Run the nightly backup

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

[Install]
WantedBy=timers.target

OnCalendar=*-*-* 03:00:00 significa 3am todos os dias. Teste qualquer expressão de calendário com systemd-analyze calendar "*-*-* 03:00:00". O comando confirma que a expressão pode ser interpretada e mostra as próximas horas em que será executada. Persistent=true executa uma tarefa em falta assim que o servidor volta a estar disponível, caso estivesse desligado às 3am. O cron não consegue fazer isto. Note que um timer é ativado através de timers.target, e não de multi-user.target. Ative o timer, não o serviço:

sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
systemctl list-timers

list-timers mostra todos os timers, com a próxima e a última execução. Assim, pode verificar rapidamente quando a tarefa será executada novamente. O gerador acima cria os .service e .timer correspondentes quando ativa o modo de timer. Em comparação com uma linha do cron, um timer fornece logs reais no journal, as mesmas diretivas de reforço de segurança disponíveis para qualquer serviço e a recuperação de execuções em falta fornecida por Persistent=true. O cron continua adequado para uma tarefa simples. Um timer é a melhor opção quando a tarefa é importante.

FAQ

Qual é a diferença entre um serviço systemd e um cron job?

Um serviço mantém um programa de longa duração em execução: inicia no boot, reinicia em caso de falha e regista informações no journal. Um cron job executa um comando curto segundo uma agenda e termina. Quando precisa de agendamento, mas também quer logs no journal, hardening e execução de tarefas cujo horário foi perdido, use um timer do systemd. Ele associa uma agenda .timer a um serviço oneshot e substitui o cron na maioria das tarefas de servidor.

Onde devo colocar o ficheiro do meu serviço systemd?

Coloque as suas próprias units em /etc/systemd/system/, com um nome terminado em .service. Esse diretório destina-se às units adicionadas pelo administrador e tem prioridade sobre as units fornecidas pelos packages em /lib/systemd/system/. Depois de criar ou editar um ficheiro nesse diretório, execute sudo systemctl daemon-reload para que o systemd detete a alteração.

Como faço um serviço reiniciar se falhar?

Adicione Restart=on-failure e RestartSec=5 à secção [Service]. Em seguida, execute sudo systemctl daemon-reload e reinicie o serviço. O systemd inicia novamente o programa quando este termina com um código diferente de zero ou morre devido a um sinal de crash. Aguarda cinco segundos entre as tentativas. Teste com sudo systemctl kill -s SIGKILL myapp.service. O SIGTERM, que é o sinal predefinido, conta como uma paragem normal e não aciona on-failure. Monitorize systemctl status e confirme que apresenta um novo PID dentro de alguns segundos.

Como executo um serviço systemd com um utilizador que não seja root?

Crie uma conta de sistema com sudo useradd --system --no-create-home --shell /usr/sbin/nologin myapp. Depois, adicione User=myapp à secção [Service]. Adicione NoNewPrivileges=true, PrivateTmp=true e ProtectSystem=strict para que o processo tenha apenas o acesso necessário. Executar um serviço com um utilizador sem privilégios é a alteração individual mais importante que pode fazer para melhorar a segurança do serviço.

Porque é que o meu serviço não iniciou?

Execute systemctl status myapp.service para ver o resumo e journalctl -u myapp.service para ver o output completo. As causas mais comuns são um caminho incorreto em ExecStart, um WorkingDirectory em falta, um erro de permissões porque User= não consegue ler um ficheiro ou a ausência de sudo systemctl daemon-reload depois de uma edição. O journal apresenta a mensagem de erro do próprio programa, que normalmente identifica diretamente o problema.