Chapter Objective: Control who may schedule jobs, configure system-wide cron and systemd timer units for administrator-managed automation, and monitor whether scheduled tasks actually succeeded.

Key files/commands: /etc/cron.allow, /etc/cron.d/, OnCalendar=, logrotate

User Tasks vs. System Tasks

The previous chapter covered scheduling jobs as an individual user with crontab -e and at. This chapter shifts to the administrator's perspective: managing scheduling infrastructure for the whole system — deciding who's allowed to schedule jobs at all, and configuring automation that isn't tied to any one user's account.

🔵 Why It Matters A system task like log rotation or a nightly security scan needs to run reliably regardless of which users exist or are logged in — it belongs to the system itself, not to any individual's crontab.

Controlling Who Can Schedule Jobs

By default, most users can schedule their own cron and at jobs. Administrators can restrict this with allow/deny files.

FileEffect
/etc/cron.allowIf present, ONLY listed users may use cron — everyone else is blocked
/etc/cron.denyIf cron.allow doesn't exist, listed users are blocked; everyone else is allowed
/etc/at.allowSame logic as cron.allow, but for at
/etc/at.denySame logic as cron.deny, but for at
# Only sarah and miguel may use cron; everyone else is denied
echo -e "sarah\nmiguel" | sudo tee /etc/cron.allow

# Block a specific user from using cron, allow everyone else
echo "guestuser" | sudo tee -a /etc/cron.deny
⚠️ Warning — allow Always Wins If cron.allow exists at all, cron.deny is ignored completely — access is restricted to exactly the users listed in cron.allow, regardless of what's in the deny file. Don't create an allow file expecting the deny file to still add exceptions.

System Cron Directories in Depth

# /etc/crontab format includes a USER field the per-user crontab doesn't have
# minute hour day month weekday user  command
0 3 * * * root /usr/local/bin/full-backup.sh
LocationTypical Use
/etc/crontabSystem jobs edited directly by the administrator
/etc/cron.d/*.confPackages drop their own scheduled jobs here, separate from the main file
/etc/cron.daily/, .hourly/, .weekly/, .monthly/Executable scripts, run as a batch by run-parts at the matching interval
# Drop a script into the daily directory to run it once a day
sudo cp cleanup-tmp.sh /etc/cron.daily/
sudo chmod +x /etc/cron.daily/cleanup-tmp.sh
✅ Tip — Package-Friendly Automation /etc/cron.d/ exists so a package's installer can drop in its own scheduled job without needing to parse and modify the shared /etc/crontab file — cleaner for both upgrades and uninstalls.

Writing a Custom systemd Timer

A systemd timer is a pair of unit files: a .service defining what to run, and a .timer defining when.

# /etc/systemd/system/backup.service
[Unit]
Description=Nightly backup job

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh

# /etc/systemd/system/backup.timer
[Unit]
Description=Run backup.service nightly

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

[Install]
WantedBy=timers.target
DirectiveMeaning
OnCalendar=A calendar-style schedule, similar in spirit to cron but more expressive
Persistent=trueIf the system was off when the timer should have fired, run it as soon as possible after boot
RandomizedDelaySec=Adds a random delay up to N seconds, to avoid many timers firing at the exact same instant
OnBootSec=Alternative to OnCalendar — fire a set time after boot instead of at a wall-clock time
# After creating both files, reload systemd's unit definitions
sudo systemctl daemon-reload

# Enable and start the TIMER, not the service directly
sudo systemctl enable --now backup.timer

# Confirm it's scheduled and see the next run time
systemctl list-timers backup.timer
⚠️ Warning — Enable the Timer, Not the Service Running systemctl enable backup.service by mistake just makes the service start at boot — it won't schedule anything. The .timer unit is what needs to be enabled for scheduling to actually happen.

logrotate: A Real System Task

logrotate is a practical, concrete example of scheduled system automation already running on every RHEL system — it periodically rotates, compresses, and eventually discards old log files so /var/log doesn't grow without bound.

# Global logrotate configuration
cat /etc/logrotate.conf

# Per-application configuration, one file per service
ls /etc/logrotate.d/

# Example snippet for a hypothetical application log
/var/log/myapp/*.log {
    weekly
    rotate 4
    compress
    missingok
    notifempty
}

# Manually trigger a run (useful for testing a config)
sudo logrotate -f /etc/logrotate.conf
🔵 Note On current RHEL, logrotate itself is typically triggered by a systemd timer (logrotate.timer) rather than a classic cron.daily script — a good real-world example of the two scheduling mechanisms working together.

Monitoring Scheduled Job Results

A scheduled job that fails silently is worse than one that fails loudly — always plan for how you'll know something went wrong.

# Cron mails job output to the owning user by default, if mail is configured
mail

# Check systemd timer / service run history and output
journalctl -u backup.service

# Confirm the last and next run times for a timer
systemctl list-timers --all
✅ Tip — Redirect Cron Output Deliberately Cron jobs frequently run with no interactive terminal and no configured mail system, silently dropping their output. Redirect a cron job's output to a log file explicitly (>> /var/log/myjob.log 2>&1) so you have somewhere reliable to check.

Key Terms for Chapter 4

cron.allow / cron.deny
Files controlling which users may schedule cron jobs
run-parts
Utility that executes every script in a directory, used by the cron.daily/weekly/monthly mechanism
OnCalendar
The systemd timer directive specifying a calendar-based schedule
Persistent
Timer directive ensuring a missed run still fires after the system comes back up
RandomizedDelaySec
Timer directive adding a random delay to avoid many jobs firing simultaneously
logrotate
Utility that rotates, compresses, and eventually removes old log files on a schedule

Review Questions

  1. If both /etc/cron.allow and /etc/cron.deny exist, which one takes effect?
  2. What extra field does /etc/crontab have that a per-user crontab (edited with crontab -e) does not?
  3. What is the purpose of /etc/cron.d/, and why might a package prefer it over editing /etc/crontab directly?
  4. When setting up a systemd timer, what unit do you actually enable — the .service or the .timer?
  5. What does Persistent=true do for a systemd timer?
  6. What real, already-running system task rotates and compresses log files on a schedule?
  7. Why is it good practice to explicitly redirect a cron job's output to a log file?