OpenBSD Handbook

    Theme
    • Part I. Install & Configure
      • Introduction to OpenBSD
      • Installing OpenBSD
      • The X Window System
      • Networking on OpenBSD
      • System Configuration
      • OpenBSD Basics
      • Managing Software: Packages and Ports
    • Part II. Daily Operations
      • OpenBSD Desktop 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
          • OpenSMTPD Mail Server
          • Dovecot IMAP and POP3 Server
          • Postfix
          • Exim
          • Rspamd
        • Name
          • Unbound DNS Resolver
          • NSD Authoritative DNS Server
          • BIND DNS Server
        • Networking
          • OpenBGPD
          • rad
          • DHCP on OpenBSD
          • slaacd
        • Web
          • Apache HTTP Server
          • nginx Web Server
          • OpenBSD httpd Web Server
          • relayd Reverse Proxy
        • Logging
          • syslogd
        • Monitoring
          • SNMP
        • Remote Access
          • Audit OpenSSH
          • OpenSSH Server
        • File Synchronization
          • rsync
        • Messaging
          • RabbitMQ Message Broker
        • Time
          • NTP Time Synchronization
        • Load Balancing
          • Build Redundant Load-Balanced Gateways
          • Load Balance Services with NAT or DSR
          • Build an HA HTTPS Load Balancer
      • 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
        • Installation and First Boot
          • Complete the First 30 Minutes After Installation
          • Check Hardware Compatibility Before Installing
          • Bootstrap Wi-Fi Firmware Without Ethernet
          • Run OpenBSD as a Virtual Machine Guest
          • Install OpenBSD on a VPS or Cloud Server
          • Install OpenBSD with Full-Disk Encryption
          • Dual-Boot OpenBSD on a UEFI System
          • Automate OpenBSD Installation with Autoinstall and PXE
        • Desktops and Laptops
          • Set Up OpenBSD as a Laptop or Workstation
          • Configure Laptop Power Management
          • Troubleshoot Web Browsers on OpenBSD
          • Use Plan 9 Tools on OpenBSD
          • Build a Minimal Desktop with suckless Tools
          • Install Z shell (zsh)
        • Networking and Remote Access
          • Create an Administrator Account with doas and SSH Keys
          • Configure Secure Remote Access with OpenSSH
          • Use FIDO Security Keys with OpenSSH
          • Configure Wi-Fi Roaming and Wired Failover
          • Troubleshoot PF, NAT, and Routing
          • Route Multiple VLANs with PF
          • Configure a Road-Warrior WireGuard VPN
          • Route IPv6 Networks without NAT
          • Test OpenBGPD with Two Providers
          • Unlock an Internal Service with an SSH Key
          • Build a Simple Router and Firewall
        • Servers and Services
          • Set Up WordPress on OpenBSD
          • Build a Mail Server with OpenSMTPD, Dovecot, and Rspamd
        • Security, Maintenance and Recovery
          • Establish a Conservative Security Baseline
          • Recover Access and Reset the Root Password
          • Collect OpenBSD Diagnostic Evidence
          • Troubleshoot Package Installation and Update Failures
          • Schedule Recurring Maintenance
          • Monitor an OpenBSD System
          • Back Up and Restore an OpenBSD System
          • Configure softraid RAID1
          • Recover an OpenBSD System That Does Not Boot
        • Building, Automation and Virtual Machines
          • Manage OpenBSD with Ansible
          • Build Third-Party Software from Ports
          • Build OpenBSD from Source
          • Plan a Docker Workload Migration to OpenBSD
      • OpenBSD for Linux Users
      • OpenBSD for FreeBSD Users
      • OpenBSD for macOS Users
    • OpenBSD FAQ
    • OpenBSD Architectures
      • OpenBSD Package Search
        • Synopsis
        • Define the Provisioning Boundary
        • Obtain and Verify the Boot Files
        • Prepare TFTP
        • Publish the Response File through HTTP
        • Create a Host-Specific Response File
        • Configure the PXE Client Record
        • Restrict Provisioning Traffic with PF
        • Perform a Staged Installation
        • Validate and Retire Provisioning Access

        Automate OpenBSD Installation with Autoinstall and PXE

        Synopsis #

        autoinstall(8) answers installer questions from a response file. A network-booted amd64 client normally obtains an address and boot metadata through DHCP, loads pxeboot and bsd.rd through TFTP, and retrieves a host-specific or generic response file through HTTP.

        An unattended installer can erase a disk and a response file can contain authentication material. Build this workflow only on a controlled provisioning network, identify every client by verified hardware information, and retain console access until the installed system has been validated.

        Define the Provisioning Boundary #

        This example uses an OpenBSD provisioning server at 192.0.2.10 and one amd64 client with MAC address 00:11:22:33:44:55. Replace 192.0.2.10 with the server’s address on the isolated provisioning network.

        The provisioning server provides:

        • DHCP metadata that selects the client and names auto_install;
        • TFTP access to pxeboot, bsd.rd, and the auto_install link;
        • HTTP access to a response file;
        • optional access to release sets or a site80.tgz file.

        Do not expose the response service to the Internet or to an untrusted user network. Remove or disable provisioning records after the installation window.

        Obtain and Verify the Boot Files #

        Use the release directory that matches the intended architecture and obtain SHA256.sig, bsd.rd, and the architecture’s PXE boot program. Verify the signed file list with signify(1) before publishing any boot file.

        For OpenBSD 8.0, the installed release key is named openbsd-80-base.pub. Replace XX below with the two-digit release token and RELEASE with the corresponding release number:

        ftp https://cdn.openbsd.org/pub/OpenBSD/RELEASE/amd64/SHA256.sig
          # Fetch the signed file list for the selected release
        ftp https://cdn.openbsd.org/pub/OpenBSD/RELEASE/amd64/bsd.rd
          # Fetch the installer kernel
        ftp https://cdn.openbsd.org/pub/OpenBSD/RELEASE/amd64/pxeboot
          # Fetch the amd64 PXE bootstrap
        signify -C -p /etc/signify/openbsd-XX-base.pub -x SHA256.sig bsd.rd pxeboot
          # Verify both files before publishing them
        

        RELEASE and XX are placeholders. Do not combine files from different releases or architectures.

        Prepare TFTP #

        Create the TFTP root, install the verified files, and create the special link described by autoinstall(8):

        doas sh <<'ROOT'
        install -d -o root -g wheel -m 755 /tftpboot
          # Create the TFTP root
        install -o root -g wheel -m 644 bsd.rd pxeboot /tftpboot/
          # Publish the verified installer and boot program
        ln -s pxeboot /tftpboot/auto_install
          # Make the DHCP filename invoke autoinstall after PXE boot
        install -d -o root -g wheel -m 755 /tftpboot/etc
          # Create the boot-loader configuration directory
        printf '%s\n' 'boot tftp:bsd.rd' > /tftpboot/etc/boot.conf
          # Make pxeboot load the installer kernel rather than its default bsd path
        chmod 644 /tftpboot/etc/boot.conf
          # Make the configuration publicly readable through TFTP
        ROOT
        

        Current OpenBSD runs tftpd(8) as a persistent daemon. Bind it to the provisioning address and make /tftpboot its served directory:

        doas rcctl enable tftpd
          # Enable the dedicated service for the installation window
        doas rcctl set tftpd flags -l 192.0.2.10 /tftpboot
          # Restrict TFTP to the provisioning address and directory
        doas rcctl start tftpd
          # Start the configured service
        doas rcctl check tftpd
          # Confirm that it remains running
        

        TFTP has no authentication and serves publicly readable files to every reachable client. Publish only the required boot files, keep uploads disabled, and enforce the provisioning boundary with PF.

        This pxeboot path requires client firmware capable of loading the amd64 PXE bootstrap. UEFI-only network boot uses a different firmware and boot-file workflow and is outside this guide.

        Publish the Response File through HTTP #

        Create a dedicated document root within the httpd(8) chroot:

        doas install -d -o root -g www -m 750 /var/www/autoinstall
        

        Use a server block restricted to the provisioning address:

        server "autoinstall" {
            listen on 192.0.2.10 port 80
            root "/autoinstall"
            log access "autoinstall-access.log"
            log error "autoinstall-error.log"
        }
        

        Parse the complete httpd.conf(5) file before reloading it:

        doas httpd -n
          # Validate the complete configuration
        doas rcctl enable httpd
          # Enable httpd for the controlled installation window
        doas rcctl start httpd
          # Start the validated service
        

        Create a Host-Specific Response File #

        When DHCP supplies filename "auto_install", autoinstall tries the MAC-address-specific file, the hostname-specific file, and then install.conf, in that order. Use a host-specific response file to avoid applying the wrong disk layout or hostname to a client.

        For the example client, create /var/www/autoinstall/00:11:22:33:44:55-install.conf with mode 640, owned by root:www, so the www account can serve it without making it readable to unrelated local accounts. The following identity and set-source fragment is not a complete deployment response and must not be booted unmodified:

        System hostname = node1
        Password for root = *************
        Setup a user = admin
        Password for user = *************
        Public ssh key for user = ssh-ed25519 REPLACE_WITH_ADMIN_PUBLIC_KEY
        Allow root ssh login = no
        What timezone are you in = Europe/Amsterdam
        Location of sets = http
        HTTP Server = cdn.openbsd.org
        

        Thirteen asterisks disable password login for the corresponding account. Replace the public-key placeholder before deployment and verify that a separate recovery method exists. If password hashes are used instead, generate them with encrypt(1) ; never publish plaintext passwords.

        The response file uses defaults for unanswered questions. That behavior is convenient but unsafe for an unverified disk choice. Run an attended installation in the same lab first, capture the current questions, and add every answer needed to make the target disk and layout unambiguous before making the PXE record active.

        Configure the PXE Client Record #

        Add a host declaration to the provisioning server’s dhcpd.conf(5) :

        host node1 {
            hardware ethernet 00:11:22:33:44:55;
            fixed-address 192.0.2.20;
            next-server 192.0.2.10;
            filename "auto_install";
            option host-name "node1";
        }
        

        The surrounding subnet declaration must supply the correct mask, router, and resolver for the isolated network. Check the full DHCP configuration with the validation mode documented by the installed dhcpd(8) before reloading it.

        Replace PROVISIONING_INTERFACE with the verified interface name, then validate and start DHCP only on that interface:

        doas dhcpd -n
          # Parse /etc/dhcpd.conf without starting the daemon
        doas rcctl enable dhcpd
          # Enable the service for the installation window
        doas rcctl set dhcpd flags PROVISIONING_INTERFACE
          # Restrict DHCP broadcasts to the provisioning interface
        doas rcctl start dhcpd
          # Start the validated configuration
        

        If DHCP is already serving other clients, plan a maintenance window before changing its interfaces or configuration. Restart it as required by dhcpd(8) .

        On amd64, auto_install must resolve through TFTP to the expected pxeboot program. Other architectures have different network boot programs and firmware requirements. Do not reuse this amd64 recipe for another architecture.

        Restrict Provisioning Traffic with PF #

        The daemon bindings prevent wildcard listeners, but PF must also admit the required traffic only on the controlled interface. Merge an equivalent policy into the complete ruleset, replacing the example network and interface:

        provision_if = "em1"
        provision_net = "192.0.2.0/24"
        
        pass in on $provision_if inet proto udp from any port bootpc \
            to any port bootps
        pass out on $provision_if inet proto udp from ($provision_if) port bootps \
            to any port bootpc
        pass in on $provision_if inet proto udp from $provision_net \
            to ($provision_if) port tftp
        pass out on $provision_if inet proto udp from ($provision_if) \
            to $provision_net
        pass in on $provision_if inet proto tcp from $provision_net \
            to ($provision_if) port http
        

        TFTP sends its replies from a dynamically selected UDP port. The outbound UDP rule permits those server replies and creates state for subsequent acknowledgments. These rules do not authorize routing from the provisioning network to other networks. Parse the complete pf.conf(5) file with pfctl -nf /etc/pf.conf before loading it. Verify DHCP, TFTP, and HTTP from the allowed network and confirm that the services are unreachable from a denied network.

        Perform a Staged Installation #

        Keep the client console visible and boot it from the provisioning network. Confirm the following sequence before allowing the installer to write a disk:

        1. DHCP assigns the expected address and identifies the correct server.
        2. TFTP loads auto_install and bsd.rd.
        3. The installer selects autoinstall after its short timeout.
        4. HTTP requests the expected host-specific response file.
        5. The displayed hostname, interface, target disk, and set source match the plan.

        If the response file is not found, autoinstall asks for a URL or local path. Stop and diagnose DHCP, TFTP, HTTP logs, file names, permissions, and the client MAC address rather than entering secrets at an unexplained prompt.

        Validate and Retire Provisioning Access #

        After the first boot:

        • verify console and named-account SSH access;
        • verify the installed disk layout, network configuration, and hostname;
        • apply the normal first-install baseline ;
        • review the install log and server access logs;
        • remove the client’s PXE boot directive or disable network boot;
        • remove response files that are no longer required;
        • rotate any secret that was exposed beyond its intended host;
        • retain a redacted response template in configuration management.

        On the dedicated server in this example, stop and disable all three provisioning services after the installation window:

        doas rcctl stop dhcpd
          # Stop address and boot-metadata service
        doas rcctl stop tftpd
          # Stop unauthenticated boot-file service
        doas rcctl stop httpd
          # Stop the response-file service
        doas rcctl disable dhcpd tftpd httpd
          # Prevent the dedicated services from returning at boot
        

        If httpd or DHCP has another production role, remove only the provisioning listener, client records, and PF access, then validate and reload or restart the shared service.

        Use install.site(5) and reviewed, controlled site sets only for post-install customization. Keep secrets out of reusable site archives and make provisioning scripts safe to run more than once.

        Report a bug
        • Synopsis
        • Define the Provisioning Boundary
        • Obtain and Verify the Boot Files
        • Prepare TFTP
        • Publish the Response File through HTTP
        • Create a Host-Specific Response File
        • Configure the PXE Client Record
        • Restrict Provisioning Traffic with PF
        • Perform a Staged Installation
        • Validate and Retire Provisioning Access