Como Escrever Arquivos de Unidade systemd - Registrando Servicos Personalizados

Como Escrever Arquivos de Unidade systemd - Registrando Servicos Personalizados

O que e um arquivo de unidade systemd?

Um arquivo de unidade systemd e um arquivo de configuracao que registra servicos, pontos de montagem, timers e outros recursos no sistema. Colocando um arquivo .service em /etc/systemd/system/, voce pode gerenciar qualquer script ou aplicacao como um daemon com controle completo do ciclo de vida.

Resumo Rapido

  • Localizacao do arquivo de unidade: /etc/systemd/system/myapp.service
  • Tres secoes: [Unit] / [Service] / [Install]
  • Sempre execute systemctl daemon-reload apos criar ou modificar um arquivo de unidade

Estrutura do arquivo de unidade

Um arquivo de unidade tem tres secoes:

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

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

[Install]
WantedBy=multi-user.target
Secao Funcao
[Unit] Descricao, ordem de inicializacao, dependencias
[Service] Comando de inicio, politica de restart, usuario
[Install] Alvo para systemctl enable

1. Registrar um servico personalizado com um arquivo de unidade minimo

A maneira mais rapida de transformar um shell script em um servico 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 configuracao antiga ativa. Execute sempre que modificar um arquivo de unidade.

2. Secao [Unit] - Definindo ordem de inicializacao e dependencias

[Unit] controla metadados do servico e ordenacao de inicializacao.

Diretiva Significado
Description= Descricao legivel (exibida em systemctl status)
After= Iniciar este servico apos as unidades especificadas (apenas ordenacao)
Requires= Se a unidade especificada falhar, parar este servico tambem
Wants= Tentar iniciar a unidade especificada, mas continuar se falhar
ConditionPathExists= Iniciar apenas se o arquivo/diretorio especificado existir
[Unit]
Description=Web Application Backend
After=network.target postgresql.service
Wants=postgresql.service

After=network.target e o padrao para servicos que precisam de acesso a rede. Adicione After=postgresql.service para servicos dependentes de banco de dados. Note que After= controla ordenacao, nao aplicacao de dependencia - use Requires= para dependencias rigidas.

3. Secao [Service] - Comando de inicializacao e comportamento

A secao com mais configuracoes. Estas sao as diretivas principais.

Escolhendo Type=

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

Tipo Caso de uso
simple (padrao) 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 e 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 inicio (caminho absoluto obrigatorio)
ExecStop= Comando de parada (padrao SIGTERM se omitido)
ExecReload= Comando de recarga
Restart= Politica de restart: no / on-failure / always
RestartSec= Segundos de espera antes de reiniciar
User= / Group= Usuario e grupo para execucao
WorkingDirectory= Diretorio de trabalho
EnvironmentFile= Caminho para arquivo com variaveis de ambiente

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

Passando variaveis 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. Secao [Install] - Controlando o comportamento do enable

Esta secao e lida quando voce executa systemctl enable.

[Install]
WantedBy=multi-user.target

WantedBy=multi-user.target e a escolha padrao. Executar systemctl enable myapp cria um symlink em /etc/systemd/system/multi-user.target.wants/myapp.service, que aciona a inicializacao automatica no boot.

Valor Caso de uso
multi-user.target Modo multiusuario padrao (tipico para servidores)
graphical.target Servicos que requerem ambiente grafico
network-online.target Iniciar apenas apos a rede estar totalmente online

5. Comandos de gerenciamento de servicos

Operacoes comuns apos 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 nao encontrado

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

Correcao: verifique o caminho completo.

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

Esqueceu daemon-reload

Alteracoes no arquivo de unidade nao sao refletidas, ou "Unit not found" aparece.

sudo systemctl daemon-reload
sudo systemctl restart myapp

Permissao negada

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

Correcao: verifique a permissao de execucao.

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 tambem se o usuario especificado pode ler o arquivo.

EnvironmentFile nao encontrado

Se EnvironmentFile= aponta para um arquivo ausente, o servico falhara ao iniciar. Para permitir a inicializacao mesmo quando o arquivo esta 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

Proximas leituras