Linux: Automação de Tarefas — cron / systemd / journalctl

Tudo num servidor tem que ser automatizado — backups agendados, limpeza de logs, health checks. O Linux oferece soluções de automação que vão do simples (cron) ao moderno (systemd timers).

📋 Pré-requisitos: Você já deve conhecer

1. O Que Você Vai Aprender


2. A História do "Nunca Mais Acordar às 2 da Manhã Pra Rodar Script"

(1) O Problema: Backup Manual Todo Dia

O script de backup do Xiaoming precisava ser rodado manualmente todo dia. Ele colocava despertador — acordava às 2 da manhã pra rodar ./backup.sh. Depois de uma semana, estava exausto.

(2) O cron Trouxe a Liberdade

O Bob ensinou o crontab pra ele:

BASH
crontab -e
# Adicione:
0 2 * * * /home/alice/scripts/backup.sh > /dev/null 2>&1

A partir daí, o sistema rodava o backup automaticamente todo dia às 2 da manhã. O Xiaoming só precisava olhar os logs de vez em quando.

(3) O Benefício: Deixe a Máquina Fazer o que a Máquina Tem que Fazer

Depois de aprender cron, o Xiaoming automatizou tudo de uma vez: backup diário, relatórios semanais, limpeza de logs, health checks. O tempo gasto com operação caiu de 2 horas pra 10 minutos por dia.


3. Pontos-Chave

(1) crontab — Tarefas Agendadas

Sintaxe do cron: minute hour day month weekday command

TEXT
  min  hora  dia  mes  weekday  comando
(0-59)(0-23)(1-31)(1-12)(0-7)
                       (0=Domingo 7=Domingo)
TEXT
# Sintaxe especial
@reboot     # Roda na inicialização
@daily      # Todo dia às 0:00 (igual a 0 0 * * *)
@hourly     # A cada hora (igual a 0 * * * *)
@weekly     # Toda segunda às 0:00
@monthly    # Dia 1 de cada mês às 0:00

Exemplos Comuns:

TEXT
# Ver o cron do usuário atual
crontab -l

# Editar o crontab
crontab -e

# Apagar todas as tarefas agendadas
crontab -r

# Exemplos comuns
0 2 * * * /scripts/backup.sh              # Todo dia às 2:00
*/5 * * * * /scripts/health-check.sh      # A cada 5 minutos
0 0 * * 0 /scripts/weekly-report.sh       # Todo domingo às 0:00
0 0 1 * * /scripts/monthly-cleanup.sh     # Dia 1 de cada mês
0 9-17 * * 1-5 /scripts/business-hours.sh # Dias úteis 9-17, a cada hora
⚠️ Atenção: crontab -r apaga todas as tarefas do usuário atual sem pedir confirmação! A recuperação só é possível a partir de um backup. Sempre faça backup com crontab -l antes de apagar, ou crie o hábito de editar com crontab -e em vez de apagar com crontab -r.

💡 Dica: O ambiente de execução do cron é diferente de um shell interativo — ele não carrega ~/.bashrc, ~/.profile etc., e o PATH normalmente só tem /usr/bin:/bin. Se o seu script depende de variáveis de ambiente customizadas, faça source dos arquivos de configuração no topo, ou use caminhos absolutos pros comandos no crontab.

(2) Serviço do systemd

BASH
# Caminho da unit de serviço
/etc/systemd/system/meuapp.service

# Estrutura básica
[Unit]
Description=Minha Aplicação Web
After=network.target

[Service]
Type=simple
User=alice
WorkingDirectory=/opt/meuapp
ExecStart=/usr/bin/node server.js
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

# Como usar
sudo systemctl daemon-reload     # Recarregar a configuração
sudo systemctl start meuapp      # Iniciar
sudo systemctl enable meuapp     # Habilitar no boot
sudo systemctl status meuapp     # Ver o status
sudo journalctl -u meuapp -f     # Ver os logs

(3) Timer do systemd

💡 Dica: systemd timer ou cron? Se a sua tarefa depende de outros serviços, precisa de logs, ou pode ser perdida durante uma parada do sistema (precisa compensar), escolha o systemd timer (Persistent=true). Pra scripts periódicos simples sem essas necessidades, o cron é mais leve e intuitivo. Projetos novos deveriam começar pelo systemd timer.

BASH
# Unit de timer (substitui o cron)
/etc/systemd/system/backup.timer

[Unit]
Description=Timer do Backup Diário

[Timer]
OnCalendar=daily
Persistent=true

[Install]
WantedBy=timers.target

# Serviço correspondente
/etc/systemd/system/backup.service

[Unit]
Description=Serviço de Backup Diário

[Service]
Type=oneshot
ExecStart=/opt/scripts/backup.sh

# Como usar
sudo systemctl enable --now backup.timer
sudo systemctl list-timers --all

Sintaxe do OnCalendar:

TEXT
OnCalendar=daily                    # Todo dia às 0:00
OnCalendar=hourly                   # A cada hora
OnCalendar=*-*-* 02:00:00           # Todo dia às 2:00
OnCalendar=Mon *-*-* 03:00:00       # Toda segunda às 3:00
OnCalendar=*-*-1 00:00:00           # Dia 1 de cada mês
OnCalendar=*:0/5                    # A cada 5 minutos

(4) journalctl — Visualizador de Logs

BASH
# Básico
journalctl                           # Todos os logs
journalctl -u nginx                  # Serviço específico
journalctl -u nginx -f               # Acompanhar em tempo real
journalctl -u nginx --since "1 hour ago"
journalctl -u nginx --until "2026-07-07 10:00"
journalctl -p err                    # Só nível de erro ou acima
journalctl -p err -u nginx           # Logs de erro do nginx

# Gerenciamento
journalctl --disk-usage              # Conferir o uso de disco dos logs
sudo journalctl --vacuum-size=500M   # Limitar o tamanho dos logs
sudo journalctl --vacuum-time=7d     # Manter só 7 dias

(5) logrotate — Rotação de Logs

💡 Dica: O logrotate é executado diariamente pelo cron do sistema (script em /etc/cron.daily/logrotate). Você só precisa escrever a configuração em /etc/logrotate.d/. Depois de alterar uma config, use logrotate -d /etc/logrotate.d/sua-config em modo debug pra previsualizar, e depois entre em vigor automaticamente.

BASH
# Locais de configuração
/etc/logrotate.conf                  # Config global
/etc/logrotate.d/                    # Configs por aplicação

# Exemplo: rotação de logs do Nginx
/var/log/nginx/*.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
    create 640 www-data adm
    postrotate
        [ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
    endscript
}

Diretivas Comuns:

Diretiva Significado
daily/weekly/monthly Frequência da rotação
rotate N Mantém N cópias arquivadas
compress Compacta os arquivos (gzip)
delaycompress Atrasa a compactação em um ciclo
missingok Não dá erro se o arquivo estiver faltando
notifempty Não rotaciona arquivos vazios
size 100M Só rotaciona quando o arquivo atinge o tamanho definido
maxage 30 Apaga arquivos com mais de 30 dias

(6) ▶ Exemplo: Configuração do crontab

TEXT
# Editar o crontab
crontab -e

# Escreva o conteúdo abaixo
# ┌───── minuto (0-59)
# │ ┌───── hora (0-23)
# │ │ ┌───── dia do mês (1-31)
# │ │ │ ┌───── mês (1-12)
# │ │ │ │ ┌───── dia da semana (0-7, 0=Domingo)
# * * * * * comando

# Backup automático todo dia às 2:00
0 2 * * * /home/alice/scripts/backup.sh

# Health check a cada 5 minutos
*/5 * * * * /home/alice/scripts/health-check.sh

# Relatório semanal toda segunda às 3:00
0 3 * * 1 /home/alice/scripts/weekly-report.sh

# Limpeza de arquivos no dia 1 de cada mês
0 0 1 * * /home/alice/scripts/cleanup.sh

(7) ▶ Exemplo: Criando um Serviço systemd

BASH
# Criar um serviço systemd pra uma aplicação Node.js
sudo tee /etc/systemd/system/webapp.service << 'EOF'
[Unit]
Description=Aplicação Web Node.js
Documentation=https://example.com/docs
After=network.target

[Service]
Type=simple
User=alice
Group=alice
WorkingDirectory=/opt/webapp
Environment=NODE_ENV=production
Environment=PORT=3000
ExecStart=/usr/bin/node /opt/webapp/server.js
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=10

# Opções de segurança
ProtectSystem=full
NoNewPrivileges=true
PrivateTmp=true

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now webapp
sudo systemctl status webapp

Saída:

TEXT
● webapp.service - Aplicação Web Node.js
     Loaded: loaded (/etc/systemd/system/webapp.service; enabled)
     Active: active (running) since Tue 2026-07-07 10:23:45 UTC
   Main PID: 5678 (node)
      Tasks: 12 (limit: 4915)
      Memory: 45.2M
        CPU: 1.234s

(8) ▶ Exemplo: systemd Timer Substituindo o cron

BASH
# Serviço de backup
sudo tee /etc/systemd/system/backup.service << 'EOF'
[Unit]
Description=Backup Diário

[Service]
Type=oneshot
ExecStart=/opt/scripts/backup.sh
User=alice
EOF

# Timer de backup
sudo tee /etc/systemd/system/backup.timer << 'EOF'
[Unit]
Description=Roda o backup todo dia às 2h
Requires=backup.service

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

[Install]
WantedBy=timers.target
EOF

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

Saída:

TEXT
NEXT                        LEFT          LAST                        PASSED
Tue 2026-07-07 02:00:00 UTC 15h left      Mon 2026-07-06 02:00:00 UTC 9h ago
n/a                         n/a           n/a                         n/a

1 timers listed.

(9) ▶ Exemplo: Consultas de Log com journalctl

BASH
# Ver os erros do nginx na última hora
journalctl -u nginx -p err --since "1 hour ago"

# Ver todos os logs de ontem
journalctl --since yesterday --until today

# Ver os logs de um PID específico
journalctl _PID=1234

# Acompanhar vários serviços em tempo real
journalctl -u nginx -u webapp -f

# Exportar logs pra um arquivo
journalctl -u webapp --since "2026-07-06" > webapp-logs.txt

# Conferir o uso de disco dos logs
journalctl --disk-usage
# Archived and active journals take up 512.0M

# Limpar
sudo journalctl --vacuum-size=200M

Saída:

TEXT
Jul 07 10:23:45 server nginx[1234]: GET /api/users 200 1234
Jul 07 10:23:50 server nginx[1234]: POST /api/data 500 0
Jul 07 10:24:01 server webapp[5678]: Error: ECONNREFUSED
-- Logs begin at Mon 2026-07-06 00:00:01 --
Jul 07 09:00:00 server sshd[890]: Accepted publickey for alice
Archived and active journals take up 512.0M
Deleted archived journals: 23
Vacuuming done, freed 312.0M of archived journals

(10) ▶ Exemplo: Configuração do logrotate

BASH
# Configurar a rotação de logs pra uma aplicação customizada
sudo tee /etc/logrotate.d/custom-app << 'EOF'
/var/log/custom-app/*.log {
    daily
    rotate 14
    compress
    delaycompress
    missingok
    notifempty
    create 640 www-data www-data
    sharedscripts
    postrotate
        systemctl reload custom-app > /dev/null 2>&1 || true
    endscript
}
EOF

# Testar a configuração
sudo logrotate -d /etc/logrotate.d/custom-app

# Forçar a execução manualmente
sudo logrotate -f /etc/logrotate.d/custom-app

Saída:

TEXT
reading config file /etc/logrotate.d/custom-app
Handling 1 logs

rotating pattern: /var/log/custom-app/*.log
rotating 14 kept versions
considering log /var/log/custom-app/app.log
  log needs rotating
renaming /var/log/custom-app/app.log to /var/log/custom-app/app.log.1
creating new /var/log/custom-app/app.log mode=0640 user=www-data group=www-data

(11) ▶ Exemplo Abrangente: Sistema de Operações Automatizadas

BASH
#!/bin/bash
# setup-automation.sh - Configura o sistema de operações automatizadas

set -euo pipefail

echo "=== Configurando o Sistema de Operacoes Automatizadas ==="

# 1. Criar diretório de scripts
mkdir -p /opt/scripts

# 2. Script de backup
cat > /opt/scripts/backup.sh << 'BACKUPEOF'
#!/bin/bash
# Backup automático - disparado todo dia às 2h pelo cron ou systemd timer

SOURCE="/var/www"
DEST="/backup"
RETENTION=30

mkdir -p "$DEST"
BACKUP_FILE="${DEST}/backup_$(date +%Y%m%d).tar.gz"

tar -czf "$BACKUP_FILE" \
    --exclude=node_modules \
    --exclude=.git \
    "$SOURCE" 2>/dev/null

# Limpar backups expirados
find "$DEST" -name "backup_*.tar.gz" -mtime +$RETENTION -delete

# Log
echo "[$(date)] Backup: $BACKUP_FILE ($(du -h "$BACKUP_FILE" | cut -f1))" >> /var/log/backup.log
BACKUPEOF
chmod +x /opt/scripts/backup.sh

# 3. Script de health check
cat > /opt/scripts/health-check.sh << 'HEALTHEOF'
#!/bin/bash
# Health check - roda a cada 5 minutos

WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
SERVICES=("nginx" "postgresql" "webapp")

for svc in "${SERVICES[@]}"; do
    if ! systemctl is-active --quiet "$svc"; then
        MESSAGE="❌ Servico $svc com problema $(date)"
        echo "$MESSAGE" | mail -s "Alerta de Servico" admin@example.com
        # curl -X POST -d "text=$MESSAGE" "$WEBHOOK_URL"
    fi
done

# Verificação de disco
DISK_USAGE=$(df -h / | tail -1 | awk '{print $5}' | tr -d '%')
if [ "$DISK_USAGE" -gt 85 ]; then
    echo "⚠️ Uso de disco: ${DISK_USAGE}%" >> /var/log/disk-alert.log
fi
HEALTHEOF
chmod +x /opt/scripts/health-check.sh

# 4. Configurar o cron
(crontab -l 2>/dev/null; echo "") | crontab -
(crontab -l 2>/dev/null; echo "# Backup automático - todo dia às 2:00") | crontab -
(crontab -l 2>/dev/null; echo "0 2 * * * /opt/scripts/backup.sh > /dev/null 2>&1") | crontab -
(crontab -l 2>/dev/null; echo "# Health check - a cada 5 minutos") | crontab -
(crontab -l 2>/dev/null; echo "*/5 * * * * /opt/scripts/health-check.sh > /dev/null 2>&1") | crontab -
(crontab -l 2>/dev/null; echo "# Limpeza de logs - todo domingo") | crontab -
(crontab -l 2>/dev/null; echo "0 0 * * 0 journalctl --vacuum-size=200M > /dev/null 2>&1") | crontab -

echo ""
echo "=== Sistema de Operacoes Automatizadas Configurado ==="
echo "Tarefas configuradas:"
crontab -l | grep -v "^#"
echo ""
echo "Verificacao manual: crontab -l"

❓ Perguntas Frequentes

P: As variáveis de ambiente do crontab são as mesmas do terminal? R: Não! O PATH no ambiente de execução do cron é bem mínimo (geralmente /usr/bin:/bin). Se o seu script depende do PATH definido em ~/.bashrc, defina o PATH no topo do script ou use caminhos absolutos no comando do cron.

P: Que vantagens o systemd timer tem sobre o cron? R: 1) Gerenciamento de dependências: timers podem depender de outros serviços. 2) Integração com logs: journalctl automático. 3) Execução perdida: Persistent=true compensa na próxima inicialização. 4) Mais preciso: aceita precisão de milissegundos. 5) Gerenciamento unificado: systemctl list-timers.

P: Os logs do journalctl podem encher o disco? R: O padrão é no máximo 10% do disco (mas limitado a 4 GB). Use journalctl --vacuum-size=500M ou configure SystemMaxUse=500M no /etc/systemd/journald.conf pra limitar.

P: O logrotate roda sozinho ou preciso configurar no cron? R: O logrotate é executado diariamente pelo cron nativo do sistema (em /etc/cron.daily/logrotate). Você só precisa configurar as regras em /etc/logrotate.d/ — não precisa de configuração adicional no cron.

P: Como debugar quando o crontab não executa? R: Troubleshooting em três passos: 1) Verifique se o serviço de cron está rodando: systemctl status cron. 2) Confira os logs do cron: grep CRON /var/log/syslog. 3) Rode o script manualmente pra confirmar que funciona: bash /caminho/do/script.sh.


📖 Resumo


📝 Exercícios

  1. Básico (⭐): Configure o crontab pra rodar date a cada hora e anexar a saída em /tmp/cron-test.log, depois use journalctl pra ver os logs de inicialização do nginx ou do sshd
  2. Intermediário (⭐⭐): Crie um hello.service simples e inicie-o (Type=simple), depois crie uma config do logrotate pra /var/log/test-app/*.log com rotação diária mantendo 7 dias
  3. Desafio (⭐⭐⭐): Escreva um timer do systemd que limpa arquivos expirados em /tmp todo dia às 3:00 da manhã, com o arquivo de serviço correspondente, e configure o journalctl pra ver os logs de execução
Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%