Skip to main content

systemd timer — Time-Based Task Scheduler

systemd timers are the modern replacement for cron on systemd-based Linux distributions. Instead of editing a single cron table, you create two small text files — one that says when to run and one that says what to run — and systemd handles the rest: logging, missed-run catch-up, dependency ordering, and resource isolation.

Who This Track Is For
  • Linux administrators managing WordPress VPS, web servers, or any production workload
  • DevOps engineers replacing cron with a modern, auditable scheduler
  • Developers who need scheduled automation with structured logging and safety controls
What You Will Build
  • Calendar-based scheduled jobs (daily backups, weekly cleanups, monthly reports)
  • Monotonic interval jobs (heartbeats, health checks, cooldown retries)
  • Fleet-safe timers with jitter and randomized delays
  • Production-hardened timer units with security sandboxing and overlap prevention
How To Use This Track
  • Follow the lessons in order (1 → 9). Each lesson builds on concepts from the previous one.
  • Every lesson includes hands-on examples with expected output — run them on a test server.
  • Use systemd-analyze calendar to validate every schedule before deploying.

Learning Path

ModuleFocusWhat You Learn
1. How It WorksArchitecture and lifecycleTwo-unit model, timer types, comparison with cron
2. OnCalendar SyntaxCalendar expression masteryKeywords, operators, ranges, timezone, validation
3. Monotonic TimersInterval and boot-based schedulingOnBootSec, OnUnitActiveSec, OnUnitInactiveSec, combining
4. Unit File AnatomyComplete unit file referenceEvery directive in [Timer], [Unit], [Service], [Install]
5. Commands and ManagementCLI operationssystemctl, journalctl, list-timers, schedule validation
6. Practical Examples27 complete examplesMinutes, hours, daily, weekly, monthly, boot, advanced
7. Production PatternsHardening and reliabilitySecurity, flock overlap prevention, Persistent, jitter
8. Study CasesReal-world scenariosWordPress VPS, backup pipeline, fleet management, SaaS
9. Cheatsheet and QuizQuick referenceOne-page cheat sheet, 10-question quiz, hands-on lab

Architecture at a Glance

Why systemd Timers Over Cron

FeatureCronsystemd timer
LoggingManual (redirect to file)journald native
Missed-run catch-upNot availablePersistent=true
Overlap preventionManual (flock)flock + systemd oneshot queuing
Dependency orderingNot availableAfter=, Wants=, Requires=
Security sandboxingNot availableProtectSystem=, PrivateTmp=, etc.
Jitter / fleet load spreadingNot availableRandomizedDelaySec=
Schedule validationNot availablesystemd-analyze calendar
Per-job resource limitsNot availableRuntimeMaxSec=, CPUQuota=, etc.
Visibilitycrontab -l (per user)systemctl list-timers --all (system-wide)

System Check

systemctl --version # Expected: systemd 230+
systemctl list-timers --all --no-pager # List all active and inactive timers
systemd-analyze calendar 'Mon..Fri 06:00' # Validate a calendar expression

Quick Start

5-minute-quick-start.sh
# 1) Create a service that writes a heartbeat timestamp
sudo tee /etc/systemd/system/heartbeat.service > /dev/null <<'EOF'
[Unit]
Description=Write a heartbeat timestamp

[Service]
Type=oneshot
ExecStart=/bin/bash -c 'echo "[$(date +%%F\ %%T)] heartbeat" >> /tmp/heartbeat.log'
EOF

# 2) Create a timer that fires every 60 seconds
sudo tee /etc/systemd/system/heartbeat.timer > /dev/null <<'EOF'
[Unit]
Description=Fire heartbeat every 60 seconds

[Timer]
OnUnitActiveSec=60s

[Install]
WantedBy=timers.target
EOF

# 3) Activate
sudo systemctl daemon-reload
sudo systemctl enable --now heartbeat.timer

# 4) Verify
systemctl list-timers heartbeat.timer --no-pager

# 5) Test immediately
sudo systemctl start heartbeat.service
cat /tmp/heartbeat.log

Terminology

TermMeaning
Timer unitA .timer file that defines when to run
Service unitA .service file that defines what to run
Unit pairThe .timer + .service combination (same base name by default)
Calendar timerOnCalendar= — fires at wall-clock times (like cron)
Monotonic timerOnBootSec=, OnUnitActiveSec= — fires after elapsed time
PersistentPersistent=true — catch up missed runs after downtime
JitterRandomizedDelaySec= — random delay to spread fleet load
timers.targetThe systemd target that groups all timer units
daemon-reloadThe command that tells systemd to re-read unit files from disk
flockFile-based locking to prevent overlapping job runs

Next Step

Start with How It Works to understand the two-unit model and timer types.