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 calendarto validate every schedule before deploying.
Learning Path
| Module | Focus | What You Learn |
|---|---|---|
| 1. How It Works | Architecture and lifecycle | Two-unit model, timer types, comparison with cron |
| 2. OnCalendar Syntax | Calendar expression mastery | Keywords, operators, ranges, timezone, validation |
| 3. Monotonic Timers | Interval and boot-based scheduling | OnBootSec, OnUnitActiveSec, OnUnitInactiveSec, combining |
| 4. Unit File Anatomy | Complete unit file reference | Every directive in [Timer], [Unit], [Service], [Install] |
| 5. Commands and Management | CLI operations | systemctl, journalctl, list-timers, schedule validation |
| 6. Practical Examples | 27 complete examples | Minutes, hours, daily, weekly, monthly, boot, advanced |
| 7. Production Patterns | Hardening and reliability | Security, flock overlap prevention, Persistent, jitter |
| 8. Study Cases | Real-world scenarios | WordPress VPS, backup pipeline, fleet management, SaaS |
| 9. Cheatsheet and Quiz | Quick reference | One-page cheat sheet, 10-question quiz, hands-on lab |
Architecture at a Glance
Why systemd Timers Over Cron
| Feature | Cron | systemd timer |
|---|---|---|
| Logging | Manual (redirect to file) | journald native |
| Missed-run catch-up | Not available | Persistent=true |
| Overlap prevention | Manual (flock) | flock + systemd oneshot queuing |
| Dependency ordering | Not available | After=, Wants=, Requires= |
| Security sandboxing | Not available | ProtectSystem=, PrivateTmp=, etc. |
| Jitter / fleet load spreading | Not available | RandomizedDelaySec= |
| Schedule validation | Not available | systemd-analyze calendar |
| Per-job resource limits | Not available | RuntimeMaxSec=, CPUQuota=, etc. |
| Visibility | crontab -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
| Term | Meaning |
|---|---|
| Timer unit | A .timer file that defines when to run |
| Service unit | A .service file that defines what to run |
| Unit pair | The .timer + .service combination (same base name by default) |
| Calendar timer | OnCalendar= — fires at wall-clock times (like cron) |
| Monotonic timer | OnBootSec=, OnUnitActiveSec= — fires after elapsed time |
| Persistent | Persistent=true — catch up missed runs after downtime |
| Jitter | RandomizedDelaySec= — random delay to spread fleet load |
timers.target | The systemd target that groups all timer units |
daemon-reload | The command that tells systemd to re-read unit files from disk |
flock | File-based locking to prevent overlapping job runs |
Next Step
Start with How It Works to understand the two-unit model and timer types.