Cloud-init: automating first-boot setup for your VPS
Quick answer
Cloud-init is the standard tool most Linux cloud images use to run first-boot configuration: setting the hostname, injecting SSH keys, installing packages, and running your own scripts, all before you ever log in. It's an industry-standard, open-source tool, not something specific to any one provider.
What cloud-init actually is
Cloud-init runs automatically the first time a cloud image boots, before you get a login prompt. It reads configuration supplied at creation time and applies it: setting the hostname, creating user accounts, injecting SSH public keys, installing packages, writing files, and running arbitrary commands. Nearly every mainstream Linux cloud image (Ubuntu, Debian, Rocky Linux, AlmaLinux, and others) ships with cloud-init pre-installed, which is why it's become the de facto standard for first-boot automation across cloud providers generally, rather than something tied to any one platform.
What a typical user-data file contains
Cloud-init is driven by a file usually called user-data, written in YAML. The directives you will meet first:
| Directive | What it does |
|---|---|
packages: | A list of packages to install on first boot |
write_files: | Files to create, with their content and target path, before the machine finishes booting |
runcmd: | Shell commands to run once, near the end of the first-boot process |
ssh_authorized_keys: | Public keys to add to the default user's authorized_keys so key-based login works immediately |
The file starts with #cloud-config on its own first line, which is how cloud-init recognises it as a config directive file rather than a raw shell script (a plain #!/bin/bash script is also valid user-data, and runs directly, if you'd rather script the whole thing yourself).
Why it matters for repeatable infrastructure
Without cloud-init, first-boot setup means logging in after creation and running the same setup steps by hand, every time. That's slow, and it's easy to get inconsistent results between machines. Cloud-init moves that setup into a declarative file that runs unattended, which means:
- New servers come up already configured, rather than needing a manual pass after creation.
- The same user-data file produces the same result every time, which is exactly what infrastructure-as-code workflows depend on.
- Provisioning tools (Terraform, Ansible, and similar) can generate or template the user-data file per server, so first-boot configuration becomes part of your version-controlled infrastructure rather than a manual runbook.
For the full range of what a user-data file can do beyond the directives above, see the official cloud-init documentation.