Systemd Timer Job Script Prompt
Convert a cron job into a robust systemd service + timer with proper logging, failure handling, sandboxing, and overlap prevention — or generate the units and accompanying script from scratch.
- Target user
- Engineers replacing crontab entries with managed systemd timers
- Difficulty
- Intermediate
- Tools
- Claude, ChatGPT
The prompt
You are a Linux platform engineer who has migrated fleets off crontab onto systemd timers and knows every footgun in the unit files. I will provide: - The job (command/script) and its schedule - Whether it's currently a cron line, and any env it depends on - Run-as user, working dir, and failure-notification needs Produce the units and a hardened wrapper script: 1. **Cron-to-timer mapping** — translate the cron expression to `OnCalendar=` (and explain `OnCalendar` syntax). Recommend `OnCalendar` for wall-clock schedules vs `OnUnitActiveSec` for "every N after last run," and add `RandomizedDelaySec=` to avoid fleet-wide thundering herd. Set `Persistent=true` so missed runs (machine off) fire on boot. 2. **Service unit** — `Type=oneshot`, explicit `ExecStart` with an absolute path, `User=`, `WorkingDirectory=`, and `Environment=`/`EnvironmentFile=` (cron's bare environment is a classic gotcha — spell out PATH). 3. **Overlap prevention** — systemd won't start a second run of a `oneshot` already running; note this replaces `flock`. Add `TimeoutStartSec=` so a hung job is killed instead of blocking forever. 4. **Sandboxing** — apply least-privilege hardening: `ProtectSystem=strict`, `ProtectHome=`, `PrivateTmp=true`, `NoNewPrivileges=true`, `ReadWritePaths=` only where the job must write. Note any that break a job writing outside its sandbox (a common cause of "works manually, fails as a unit"). 5. **Logging** — rely on the journal (`journalctl -u name`); set `SyslogIdentifier=`; show how to ship to a file if required. No need for the script to manage its own logfile. 6. **Failure handling** — `OnFailure=` to trigger a notification unit (email/webhook) and how to alert on a timer that silently stopped firing. 7. **The script** — a strict-mode Bash or Python wrapper that exits non-zero on failure so systemd records it correctly. 8. **Install + verify** — commands to enable the timer, `systemctl list-timers`, and a manual `systemctl start` to test before scheduling. Output: (a) the `.service` unit, (b) the `.timer` unit, (c) the wrapper script, (d) optional `OnFailure` notifier unit, (e) install/verify commands. Bias toward: explicit env over inherited, least privilege, fail non-zero so the journal tells the truth.