Como Escrever Arquivos de Unidade systemd - Registrando Serviços Personalizados

Como Escrever Arquivos de Unidade systemd - Registrando Serviços Personalizados

O que é um arquivo de unidade systemd?

Um arquivo de unidade systemd é um arquivo de configuração que registra serviços, pontos de montagem, timers e outros recursos no sistema. Colocando um arquivo .service em /etc/systemd/system/, você pode gerenciar qualquer script ou aplicação como um daemon com controle completo do ciclo de vida.

Resumo Rápido

  • Localização do arquivo de unidade: /etc/systemd/system/myapp.service
  • Três seções: [Unit] / [Service] / [Install]
  • Sempre execute systemctl daemon-reload após criar ou modificar um arquivo de unidade

Estrutura do arquivo de unidade

Um arquivo de unidade tem três seções:

[Unit]
Description=My Custom Service
After=network.target

[Service]
ExecStart=/usr/local/bin/myapp
Restart=on-failure
User=myuser

[Install]
WantedBy=multi-user.target
Seção Função
[Unit] Descrição, ordem de inicialização, dependências
[Service] Comando de início, política de restart, usuário
[Install] Alvo para systemctl enable

1. Registrar um serviço personalizado com um arquivo de unidade mínimo

A maneira mais rápida de transformar um shell script em um serviço gerenciado.

1-1. Criar o script

sudo tee /usr/local/bin/myapp.sh > /dev/null << 'EOF'
#!/bin/bash
while true; do
    echo "$(date) running" >> /var/log/myapp.log
    sleep 10
done
EOF
sudo chmod +x /usr/local/bin/myapp.sh

1-2. Criar o arquivo de unidade

sudo tee /etc/systemd/system/myapp.service > /dev/null << 'EOF'
[Unit]
Description=My Application
After=network.target

[Service]
ExecStart=/usr/local/bin/myapp.sh
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

1-3. Recarregar, habilitar e iniciar

sudo systemctl daemon-reload
sudo systemctl enable --now myapp
sudo systemctl status myapp
● myapp.service - My Application
     Loaded: loaded (/etc/systemd/system/myapp.service; enabled)
     Active: active (running) since Sun 2026-05-31 12:00:00 UTC; 3s ago
   Main PID: 12345 (myapp.sh)

Esquecer daemon-reload causa erros "Unit not found" ou deixa a configuração antiga ativa. Execute sempre que modificar um arquivo de unidade.

2. Seção [Unit] - Definindo ordem de inicialização e dependências

[Unit] controla metadados do serviço e ordenação de inicialização.

Diretiva Significado
Description= Descrição legível (exibida em systemctl status)
After= Iniciar este serviço após as unidades especificadas (apenas ordenação)
Requires= Se a unidade especificada falhar, parar este serviço também
Wants= Tentar iniciar a unidade especificada, mas continuar se falhar
ConditionPathExists= Iniciar apenas se o arquivo/diretório especificado existir
[Unit]
Description=Web Application Backend
After=network.target postgresql.service
Wants=postgresql.service

After=network.target é o padrão para serviços que precisam de acesso à rede. Adicione After=postgresql.service para serviços dependentes de banco de dados. Note que After= controla ordenação, não aplicação de dependência - use Requires= para dependências rigidas.

3. Seção [Service] - Comando de inicialização e comportamento

A seção com mais configurações. Estas são as diretivas principais.

Escolhendo Type=

Type= define como o systemd rastreia o estado do processo.

Tipo Caso de uso
simple (padrão) Um processo que permanece em primeiro plano
forking Um processo que se daemoniza (faz fork)
oneshot Um script que executa uma vez e termina
notify Um processo que sinaliza prontidao com READY=1

Para a maioria dos casos, simple ou oneshot é a escolha certa.

Diretivas principais

[Service]
Type=simple
ExecStart=/usr/local/bin/myapp --config /etc/myapp/config.yml
ExecStop=/bin/kill -TERM $MAINPID
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5
User=www-data
Group=www-data
WorkingDirectory=/var/lib/myapp
EnvironmentFile=/etc/myapp/env
Diretiva Significado
ExecStart= Comando de início (caminho absoluto obrigatório)
ExecStop= Comando de parada (padrão SIGTERM se omitido)
ExecReload= Comando de recarga
Restart= Política de restart: no / on-failure / always
RestartSec= Segundos de espera antes de reiniciar
User= / Group= Usuário e grupo para execução
WorkingDirectory= Diretório de trabalho
EnvironmentFile= Caminho para arquivo com variáveis de ambiente

ExecStart= requer um caminho absoluto - seja o binário diretamente ou um shell com caminho absoluto: /bin/bash /path/to/script.sh. Caminhos relativos como ./script.sh não funcionam.

Passando variáveis de ambiente

[Service]
Environment="NODE_ENV=production"
Environment="PORT=3000"
EnvironmentFile=/etc/myapp/env

Exemplo /etc/myapp/env:

DB_HOST=localhost
DB_PORT=5432
SECRET_KEY=changeme

4. Seção [Install] - Controlando o comportamento do enable

Esta seção é lida quando você executa systemctl enable.

[Install]
WantedBy=multi-user.target

WantedBy=multi-user.target é a escolha padrão. Executar systemctl enable myapp cria um symlink em /etc/systemd/system/multi-user.target.wants/myapp.service, que aciona a inicialização automática no boot.

Valor Caso de uso
multi-user.target Modo multiusuário padrão (típico para servidores)
graphical.target Serviços que requerem ambiente gráfico
network-online.target Iniciar apenas após a rede estar totalmente online

5. Comandos de gerenciamento de serviços

Operações comuns após criar um arquivo de unidade:

# Recarregar arquivos de unidade (obrigatorio apos qualquer alteracao)
sudo systemctl daemon-reload

# Habilitar (inicio automatico no boot) + iniciar imediatamente
sudo systemctl enable --now myapp

# Verificar status
sudo systemctl status myapp

# Reiniciar
sudo systemctl restart myapp

# Recarregar configuracao (requer ExecReload)
sudo systemctl reload myapp

# Parar
sudo systemctl stop myapp

# Desabilitar inicio automatico
sudo systemctl disable myapp

# Ver logs recentes (ultimas 50 linhas)
journalctl -u myapp -n 50 --no-pager

6. Falhas comuns e como corrigi-las

Caminho do ExecStart não encontrado

myapp.service: control process exited with error code
ExecStart=/usr/local/bin/myapp (code=exited, status=203/EXEC)

Correção: verifique o caminho completo.

which myapp
ls -la /usr/local/bin/myapp

Esqueceu daemon-reload

Alterações no arquivo de unidade não são refletidas, ou "Unit not found" aparece.

sudo systemctl daemon-reload
sudo systemctl restart myapp

Permissão negada

journalctl -u myapp -n 20
# myapp.sh: Permission denied

Correção: verifique a permissão de execução.

ls -la /usr/local/bin/myapp.sh
# Se falta permissao de execucao:
sudo chmod +x /usr/local/bin/myapp.sh

Se User= estiver definido, verifique também se o usuário especificado pode ler o arquivo.

EnvironmentFile não encontrado

Se EnvironmentFile= aponta para um arquivo ausente, o serviço falhará ao iniciar. Para permitir a inicialização mesmo quando o arquivo está ausente, prefixe o caminho com -:

EnvironmentFile=-/etc/myapp/env

Cheatsheet do fluxo completo

# 1. Criar o script
sudo vim /usr/local/bin/myapp.sh
sudo chmod +x /usr/local/bin/myapp.sh

# 2. Criar o arquivo de unidade
sudo vim /etc/systemd/system/myapp.service

# 3. Registrar e iniciar
sudo systemctl daemon-reload
sudo systemctl enable --now myapp

# 4. Verificar
sudo systemctl status myapp
journalctl -u myapp -f

Próximas leituras