OpenBSD Handbook

    Theme
    • Part I. Install & Configure
      • Introduction
      • Installing OpenBSD
      • The X Window System
      • Networking
      • System Configuration
      • OpenBSD Basics
      • Managing Software: Packages and Ports
    • Part II. Daily Operations
      • Graphical Environments
      • Multimedia
      • Printing
      • Linux Compatibility
      • Windows Compatibility
      • Games
    • Part III. System Administration
      • Virtualization
      • Storage and File Systems
      • Updating and Upgrading
      • Localization
      • The OpenBSD Boot Process
      • Security
    • Part IV. Networking & Daemons
      • Services
        • Database
          • MariaDB
          • PostgreSQL
          • Redis
          • memcached
        • Directory
          • YP (NIS)
          • LDAP
        • File
          • NFS
          • Samba
        • FTP Services
          • ftpd
          • ProFTPD
          • vsftpd
          • Pure-FTPd
          • TFTP
        • Mail
          • smtpd
          • Dovecot
          • Postfix
          • Exim
          • Rspamd
        • Name
          • Unbound
          • NSD
          • BIND
        • Networking
          • OpenBGPD
          • rad
          • DHCP
          • slaacd
        • Web
          • Apache
          • nginx
          • httpd
          • relayd
        • Logging
          • syslogd
        • Monitoring
          • SNMP
        • Remote Access
          • Audit OpenSSH
          • sshd
        • File Synchronization
          • rsync
        • Messaging
          • RabbitMQ
        • Time
          • NTP
      • PF
        • pfctl cheat sheet
        • PF Anchors
        • PF Filter Rules
        • PF Forwarding
        • PF Lists and Macros
        • PF Load Balancing
        • PF Logging
        • PF NAT
        • PF Options
        • PF Policies
        • PF Shortcuts
        • PF Tables
      • Advanced Networking
        • High Availability and State Replication
        • Multi-WAN and Policy-Based Routing
        • VPN and Cryptographic Tunneling
        • Classic and Lightweight Tunnels
        • IPv6 at Scale
        • QoS and Traffic Shaping
        • MPLS and Label Distribution
        • Network Services at Scale
        • Virtualization and Host Networking
        • Large-Scale L2 and L3 Design
        • Telemetry, Logging, and Flow Export
        • Hardening and Operational Safety
        • Reference Architectures
        • Troubleshooting Playbooks
      • Serial Communication
    • Part V. Miscellaneous
      • Virtualization Cheat Sheet
      • OpenBSD Cheatsheet
      • How-to Guides
        • Complete the First 30 Minutes After Installation
        • Check Hardware Compatibility Before Installing
        • Bootstrap Wi-Fi Firmware Without Ethernet
        • Set Up OpenBSD as a Laptop or Workstation
        • Configure Laptop Power Management
        • Run OpenBSD as a Virtual Machine Guest
        • Install OpenBSD on a VPS or Cloud Server
        • Install OpenBSD with Full-Disk Encryption
        • Troubleshoot Web Browsers on OpenBSD
        • Create an Administrator Account with doas and SSH Keys
        • Establish a Conservative Security Baseline
        • Manage OpenBSD with Ansible
        • Recover Access and Reset the Root Password
        • Collect OpenBSD Diagnostic Evidence
        • Configure Secure Remote Access with OpenSSH
        • Set Up WordPress
        • Build Third-Party Software from Ports
        • Use FIDO Security Keys with OpenSSH
        • Build OpenBSD from Source
        • Configure Wi-Fi Roaming and Wired Failover
        • Dual-Boot OpenBSD on a UEFI System
        • Troubleshoot PF, NAT, and Routing
        • Automate OpenBSD Installation with Autoinstall and PXE
        • Route Multiple VLANs with PF
        • Configure a Road-Warrior WireGuard VPN
        • Troubleshoot Package Installation and Update Failures
        • Route IPv6 Networks without NAT
        • Schedule Recurring Maintenance
        • Plan a Docker Workload Migration to OpenBSD
        • Build a Mail Server with OpenSMTPD, Dovecot, and Rspamd
        • Build a Simple Router and Firewall
        • Monitor an OpenBSD System
        • Back Up and Restore an OpenBSD System
        • Configure softraid RAID1
        • Recover an OpenBSD System That Does Not Boot
        • Install Z shell (zsh)
      • OpenBSD for Linux Users
      • OpenBSD for FreeBSD Users
      • OpenBSD for macOS Users
    • OpenBSD FAQ
    • Package Search
      • Synopsis
      • Choose the Execution Account
      • Write a Non-Interactive Script
      • Test the Exact Account and Environment
      • Install a User Crontab Entry
      • Use the Daily, Weekly, and Monthly Framework
      • Direct and Test Maintenance Mail
      • Account for Systems That Sleep or Power Off
      • Remove or Recover a Job

      Schedule Recurring Maintenance

      Synopsis #

      OpenBSD uses cron(8) for scheduled commands and runs the base-system daily, weekly, and monthly maintenance scripts from root’s crontab. Local jobs should run as the least-privileged suitable account, use explicit paths, prevent unintended overlap, and report failure to a monitored mailbox.

      This guide adds one local job, verifies its non-interactive behavior, and explains when to use a user crontab or a daily.local file. It does not place credentials directly in a crontab or modify the base /etc/daily, /etc/weekly, or /etc/monthly scripts.

      Choose the Execution Account #

      A job should run as the account that already owns the files and service authority it needs. Root is appropriate only when the task genuinely requires root-owned files, devices, or system controls. A package daemon’s own account or a dedicated service account is normally safer for application work.

      Before scheduling the job, define:

      • the files and commands it may read or change;
      • its maximum expected runtime;
      • whether two instances may run concurrently;
      • where ordinary output and errors will go;
      • how a missed run will be detected;
      • how the job will be disabled and its effects reversed.

      Write a Non-Interactive Script #

      Place multi-step logic in a reviewed script instead of embedding it in one long crontab line. This example creates a read-only filesystem-capacity check:

      #!/bin/sh
      
      PATH=/bin:/usr/bin:/sbin:/usr/sbin
      export PATH
      
      exec df -h
      

      Install it with explicit ownership and mode:

      # install -o root -g wheel -m 750 check-filesystems /usr/local/libexec/check-filesystems
      

      Use absolute paths for locally installed programs because cron does not read interactive shell profiles. Load secrets from a root- or service-owned file with restrictive permissions, or use the application’s supported credentials mechanism. Do not place passwords, tokens, or private keys in the crontab command.

      Test the Exact Account and Environment #

      Run the script as its intended account before scheduling it. For a root job:

      # env -i HOME=/root LOGNAME=root USER=root PATH=/bin:/usr/bin:/sbin:/usr/sbin /usr/local/libexec/check-filesystems
      

      The minimal environment exposes hidden dependencies on a working directory, shell profile, terminal, agent, or unset variable. Confirm the exit status as well as the displayed output:

      # echo $?
      

      An exit status of zero must mean success for monitoring and cron-mail policy to work correctly.

      Install a User Crontab Entry #

      Edit the intended account’s crontab with crontab(1) . For root:

      # crontab -e
      

      OpenBSD crontab(5) supports -s before the command to prevent overlapping instances. The following entry runs at 03:17 and mails output to the local admin alias:

      SHELL=/bin/sh
      PATH=/bin:/usr/bin:/sbin:/usr/sbin
      MAILTO=admin
      
      17 3 * * * -s /usr/local/libexec/check-filesystems
      

      Cron logs command execution. By default, command output is mailed to the crontab owner or MAILTO. Do not set an empty MAILTO merely to silence an unexplained failure. The OpenBSD-specific -n command flag mails output only when a successful command is not the outcome; adopt it only after the script uses meaningful exit statuses.

      List the installed entry without editing it:

      # crontab -l
      

      System /etc/crontab entries contain an additional user field. User crontabs do not. Prefer crontab -e for a job owned by one account rather than mixing local jobs into the system file.

      Use the Daily, Weekly, and Monthly Framework #

      daily(8) documents the base maintenance scripts. Their output is mailed to root, so root mail must resolve to an account that is actually read.

      Do not edit /etc/daily, /etc/weekly, or /etc/monthly. Add site-specific work to:

      • /etc/daily.local;
      • /etc/weekly.local;
      • /etc/monthly.local.

      These local files run before the corresponding base script. They are suitable for short system-wide checks and documented variables such as ROOTBACKUP or CHECKFILESYSTEMS. A long-running application task is usually clearer in its own service-account crontab.

      For example, /etc/daily.local can enable the documented no-write filesystem check:

      CHECKFILESYSTEMS=1
      

      This causes the daily script to run fsck(8) with -n; it does not authorize repairs on mounted filesystems.

      Direct and Test Maintenance Mail #

      The periodic scripts and cron depend on local mail delivery. Map root and local operational aliases to a monitored account in /etc/mail/aliases, then rebuild the aliases with newaliases(8) .

      Send a deliberate test from the scheduled account and confirm receipt before relying on silent success. Also review /var/cron/log and local mail after the first scheduled run.

      Account for Systems That Sleep or Power Off #

      Cron does not automatically replay every job missed while a workstation was suspended or powered off. The daily(8) manual specifically warns that periodic scripts may never run on hosts that are not available at their scheduled times.

      For such a host, select a schedule during normal uptime, run a startup check that determines whether work is due, or move the task to an always-on management system. Any catch-up mechanism must record the last successful completion and remain safe when invoked more than once.

      Remove or Recover a Job #

      Disable a failing job by commenting out or removing only its crontab entry, then preserve its output and logs for diagnosis. Do not delete the script or its data before determining whether it was interrupted mid-change.

      After correction, rerun the script manually with the minimal environment, reinstall the crontab, and watch one scheduled execution. Remove obsolete scripts, credential files, lock state, and aliases only after confirming that no remaining job references them.

      Report a bug
      • Synopsis
      • Choose the Execution Account
      • Write a Non-Interactive Script
      • Test the Exact Account and Environment
      • Install a User Crontab Entry
      • Use the Daily, Weekly, and Monthly Framework
      • Direct and Test Maintenance Mail
      • Account for Systems That Sleep or Power Off
      • Remove or Recover a Job