Cloud-Init: Servers That Configure Themselves
Every cloud provider runs cloud-init on first boot. Most people never use it, and then configure each server by hand.
Cloud-init reads a configuration you supply when creating an instance and applies it on first boot. Every provider in this catalogue supports it. It turns “log in and set up the server” into a text file you can version and reuse.
What it can do on first boot
- Create users, add SSH keys, configure sudo.
- Set the hostname and timezone.
- Update package lists and install packages.
- Write arbitrary files with specific permissions.
- Configure the firewall.
- Mount and format additional volumes.
- Run shell commands in a defined order.
- Reboot when finished, if needed.
That covers the entire manual checklist most people run after creating a server, which is the point.
A sensible starting configuration
A useful cloud-config typically does the following, in this order:
- Create a non-root user with your public key and passwordless sudo.
- Disable SSH password authentication and root login.
- Update all packages.
- Install the essentials: a firewall, fail2ban, unattended-upgrades, and your runtime.
- Enable and configure the firewall with a default-deny inbound policy.
- Enable automatic security updates.
- Write any configuration files the services need.
- Start services.
Written once, this produces an identically configured server every time, in about ninety seconds, with no opportunity to forget a step.
The rules that avoid frustration
- It runs once, on first boot. Changing user data later does nothing to an existing instance.
- Validate the YAML before creating the instance. A syntax error means a server that boots and does nothing you asked for.
- Check the logs at
/var/log/cloud-init-output.logwhen something did not happen. - Order matters —
runcmdexecutes after packages are installed, which is usually what you want. - Never put secrets in user data. It is readable from instance metadata by anything on the machine.
- Keep it idempotent where possible, so re-running by hand is safe.
The secrets rule is important. User data is not a secure channel; fetch secrets at runtime from a secret manager using the instance identity instead.
When to move beyond cloud-init
| Situation | Better tool |
|---|---|
| Configuration changes after boot | Ansible, or a configuration management tool |
| Long install times on every boot | A pre-baked image |
| Complex conditional logic | A configuration management tool |
| Many servers with drifting state | Ansible run on a schedule |
| Fast autoscaling | A pre-baked image; boot time matters |
The common progression: cloud-init for the base, then a baked image once boot time matters, with cloud-init handling only per-instance specifics such as hostname and role.
Baked images
Building a custom image with everything pre-installed — using Packer or the provider’s snapshot feature — cuts boot time from minutes to seconds and removes dependency on package repositories being available at boot.
- Start from the provider’s base image.
- Apply your cloud-init configuration and install everything.
- Remove machine-specific identifiers such as SSH host keys and machine-id.
- Snapshot it, versioned with a date or commit.
- Use cloud-init at launch only for the small per-instance differences.
- Rebuild the image on a schedule so security patches are included.
That last step matters. A baked image that is never rebuilt becomes a security liability the moment the base has patches.
Common questions
Do all providers support it?
All the major ones, including every provider in this catalogue, though the field may be labelled “user data”, “cloud-config” or “startup script”. The format is the same.
Can I re-run cloud-init?
You can force it with cloud-init clean followed by a reboot, but it is intended for first boot. For ongoing configuration use a configuration management tool.
Why did my script not run?
Usually a YAML error, a missing #cloud-config first line, or the script assuming a package that was not yet installed. The output log names the failure.
Is it a replacement for Ansible?
No. Cloud-init sets up a server once at creation. Ansible manages configuration over a server’s lifetime. They complement each other.
Where to go next
See the first hour on a new cloud server and infrastructure as code.