This article introduces cloud-init, explains how it works, and highlights the key benefits of using it to automate and standardize operating system provisioning at scale.
Cloud-init has become the de facto standard for automating the initial configuration of Linux systems across cloud, virtualized, and edge environments. By enabling operating system instances to be customized at first boot, cloud-init simplifies provisioning, reduces manual configuration effort, and helps ensure consistency at scale. This article explores what cloud-init is, how it works, and the key benefits it provides for infrastructure teams, including automated user and network configuration, software installation, system customization, and repeatable deployments. Whether you're building cloud-native platforms, managing virtual machines, or creating custom operating system images, understanding cloud-init is essential for modern infrastructure automation.
cloud-init is the industry-standard, open-source tool for automating the initial configuration of Linux instances at first boot. Originally designed for cloud virtual machines, it has evolved into a powerful general-purpose provisioning framework that works equally well on bare metal hardware.
At its core, cloud-init reads configuration data from a variety of sources — called "data sources" — and uses that data to configure a system before it is handed off to users or automation pipelines. On a bare metal RHEL system, this means everything from setting the hostname, creating users, injecting SSH keys, configuring networking, mounting disks, and running arbitrary scripts can happen automatically, without a human touching a keyboard.
The tool is deeply integrated into Red Hat Enterprise Linux. It ships in the default RHEL repositories, is supported across RHEL 8 and RHEL 9, and is a first-class citizen in environments managed by Red Hat tools like Satellite, Insights, and Image Builder.
Anyone who has racked and stacked physical servers knows the pain. You image the machine, then spend the next 20–60 minutes repeating the same steps: set the hostname, configure network interfaces, create service accounts, copy SSH keys, harden SSH config, register with Satellite or Subscription Manager, join the monitoring system, run your configuration management agent for the first time. Multiply this by dozens or hundreds of servers and the operational cost — and risk of human error — becomes significant.
Kickstart helps with the OS installation phase, but it has limitations for post-install configuration, particularly when you need dynamic values (IP addresses, hostnames, certificates) or want to separate concerns between the OS image and the instance-specific configuration.
cloud-init sits at the intersection of OS installation and configuration management. It handles the "Day 0" and "Day 1" configuration that happens between "the OS is installed" and "the server is ready for its workload." This makes it complementary to tools like Ansible or Puppet, not a replacement — it gets the node to a state where those tools can take over cleanly.
For bare metal RHEL specifically, cloud-init solves several real problems:
cloud-init works with RHEL deployments on bare metal instancescloud-init runs as a set of systemd services during the early boot process, broken into four stages:
This staged approach means cloud-init can safely configure networking before needing the network, and can defer tasks that require connectivity until after the network is confirmed available.
In cloud environments, data sources are obvious: AWS metadata service, Azure IMDS, GCP metadata server. On bare metal, you have several options:
NoCloud is the most common for bare metal. It reads configuration from a local filesystem (an ISO image, a USB drive, or a directory) or from a URL. You can pass the URL via kernel command line parameters (`ds=nocloud-net;seedfrom=http://your-server/`), making this very amenable to PXE-booted environments.
HTTP/URL-based data sources work well when you have a provisioning service — such as a Foreman/Satellite instance or a custom metadata service — that can serve per-host configuration dynamically based on MAC address or other identifiers.
Kickstart integration is a natural fit for RHEL. You can use Kickstart to handle disk partitioning and OS installation, then hand off to cloud-init for post-install configuration by embedding a NoCloud seed or URL reference in the `%post` section.
When using NoCloud datasource in cloud-init, the meta-data file is one of the core components that provides instance identity and basic configuration to the VM during first boot. The meta-data file defines instance-level identity information. It is required for NoCloud datasource.
It typically lives alongside:
All are placed in an ISO labeled cidata or a directory mounted as seed data or passed via kernel parameters. At a minimum following values are required for meta-data
instance-id: "<unique identifier for instance>"
local-hostname: vpac-rhel-node01The primary configuration format is YAML, beginning with the `#cloud-config` header. Here is an example showing common bare metal provisioning tasks:
#cloud-config
# Set the hostname
hostname: vpac-rhel-node01
fqdn: vpac-rhel-node01.example.com
manage_etc_hosts: true
# Create users and inject SSH keys
users:
- name: admin
groups: wheel
sudo: ALL=(ALL) NOPASSWD:ALL
ssh_authorized_keys:
- ssh-ed25519 AAAA...your-public-key
# Write configuration files
write_files:
- path: /etc/sysconfig/network-scripts/ifcfg-eth1
content: |
TYPE=Ethernet
BOOTPROTO=static
IPADDR=10.0.1.100
NETMASK=255.255.255.0
GATEWAY=10.0.1.1
ONBOOT=yes
# Install or remove packages
packages:
- insights-client
- rhc
- firewalld
package_update: true
# Run commands at first boot
runcmd:
- rhc connect --organization <your-org-id> --activation-key <your-activation-key>
- insights-client --register
- systemctl enable --now firewalld
- firewall-cmd --permanent --add-service=ssh
- firewall-cmd --reloadThe most powerful bare metal workflow pairs PXE boot with cloud-init. The sequence looks like this:
This entire sequence, from PXE boot to a fully configured, registered, and monitored server, can complete in under 15 minutes with no human interaction.
Red Hat Satellite 6.x and later have native cloud-init integration. Satellite can serve as a cloud-init data source, delivering host-specific configuration including subscription registration, content view assignment, and activation keys. When combined with Satellite's discovery and provisioning workflows, you get a fully automated bare metal provisioning pipeline that is also connected to your subscription management and patch lifecycle.
cloud-initInstalling cloud-init on RHEL is straightforward:
dnf install cloud-init
systemctl enable cloud-init-local cloud-init cloud-config cloud-finalFor a bare metal test, create a NoCloud seed directory with your `user-data` and `meta-data` files, package it as an ISO, and attach it to your server. On the next boot, cloud-init will read and apply your configuration.
From there, the path to a fully automated provisioning pipeline is incremental: integrate with your PXE environment, connect your provisioning service as a dynamic data source, layer in Satellite for subscription and content management, and add your configuration management tooling as a `runcmd` step.
cloud-init is not just a cloud technology that has been bolted onto bare metal as an afterthought. For RHEL environments, it is the right tool for the gap between OS installation and application readiness — consistent, auditable, fast, and deeply integrated with the Red Hat ecosystem. If you are still configuring bare metal servers by hand, cloud-init is worth evaluating. The investment in your initial configuration templates pays back quickly, and the operational consistency it brings has compounding value as your environment grows.
Author
Ram Gopinathan
Reading time
5 min read
Tags
Rate this article