Skip to main content

Firstboot script

For customizations that cannot be performed during buildtime, a firstboot script is a widely known solution. It is an executable, typically a shell or python script, which is executed during first boot of an image. Note, it is not executed in subsequent reboots of a system.

There are several ways how to achieve this behavior, on Fedora or Red Hat compatible systems the most common way is to utilize systemd.

When creating systemd units, please avoid the following unit names:

  • osbuild-first-boot.service
  • systemd-firstboot.service
  • ignition-firstboot.service

Firstboot systemd unit

To execute a single command, create a oneshot systemd service unit:

name = "firsboot-single"

[[customizations.files]]
path = "/etc/systemd/system/firstboot-single.service"
data = """
[Service]
Type=oneshot
ExecStart=/usr/bin/echo "This message will be logged into system journal"
ExecStart=/usr/bin/echo "Multiple ExecStart statements are allowed"

[Install]
WantedBy=default.target
"""

[customizations.services]
enabled = ["firstboot-single"]

Firstboot systemd unit with Ansible

To execute a shell script or, in this case Ansible, create a helper file together with a systemd service unit:

name = "firsboot-ansible"

[[packages]]
name = "ansible-core"

[[packages]]
name = "linux-system-roles"

[[customizations.files]]
path = "/usr/local/sbin/custom-first-boot"
mode = 0774
data = """
#!/usr/bin/ansible-playbook -i localhost,

- name: Deploy cockpit
hosts: localhost
connection: local

tasks:
- name: Cockpit
import_role:
name: linux-system-roles.cockpit
vars:
cockpit_packages: minimal

- name: Firewall
import_role:
name: linux-system-roles.firewall
vars:
firewall:
service: cockpit
state: enabled
"""

[[customizations.files]]
path = "/etc/systemd/system/custom-first-boot.service
data = """
[Unit]
ConditionPathExists=/usr/local/sbin/custom-first-boot
Wants=network-online.target
After=network-online.target
After=osbuild-first-boot.service

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/custom-first-boot
ExecStartPost=mv /usr/local/sbin/custom-first-boot /usr/local/sbin/custom-first-boot-done

[Install]
WantedBy=multi-user.target
"""

[customizations.services]
enabled = ["custom-first-boot"]