cloud-init is the standard tool that configures Linux cloud images on first boot. By passing cloud-init user-data when you create a VPS or VM, you can have users, keys, packages and services ready before you ever log in.
Before you start
- A platform that accepts user-data: many cloud providers, Proxmox (via custom snippets, see Proxmox cloud-init templates), or
virt-install --cloud-initon KVM. - An image with cloud-init installed (official cloud images include it).
- Your SSH public key.
A basic user-data file
User-data must start with #cloud-config:
#cloud-config
hostname: web01
timezone: Europe/Berlin
users:
- name: deploy
groups: sudo
shell: /bin/bash
sudo: "ALL=(ALL) NOPASSWD:ALL"
ssh_authorized_keys:
- ssh-ed25519 AAAA...your-key... you@laptop
ssh_pwauth: false
disable_root: true
package_update: true
package_upgrade: true
packages:
- nginx
- ufw
- fail2ban
write_files:
- path: /var/www/html/index.html
content: |
<h1>Provisioned by cloud-init</h1>
runcmd:
- ufw allow OpenSSH
- ufw allow 'Nginx Full'
- ufw --force enable
- systemctl enable --now nginxThis mirrors the manual steps in first steps on a new VPS.
Key modules
| Key | What it does |
|---|---|
users | Create accounts, groups, sudo rules and SSH keys |
packages | Install packages with the distro package manager |
write_files | Create files with content, owner and permissions |
runcmd | Run commands once at the end of first boot |
bootcmd | Run early on every boot |
power_state | Reboot or power off when finished |
Validate before use
cloud-init schema --config-file user-data.yamlOlder versions use cloud-init devel schema. YAML indentation errors are the most common cause of failure.
Check results and debug
cloud-init status --longsudo less /var/log/cloud-init-output.logDetailed module logs are in /var/log/cloud-init.log. To re-run on a test VM: sudo cloud-init clean --logs && sudo reboot.
Security tips
- User-data is often readable from inside the VM (metadata service). Do not put passwords, API keys or private keys in it; fetch secrets from a vault or inject them later.
- Prefer SSH keys and disable password login, as above.
Troubleshooting
- Nothing happened: the file does not start with
#cloud-config, or the platform did not pass it. - Packages failed: network not ready or wrong package names for that distribution.
- runcmd ran but service not running: check the output log for the failing command.
Frequently asked questions
Does cloud-init run on every boot?
Most modules run once per instance. bootcmd and some modules run every boot.
Can I use a shell script instead?
Yes, user-data starting with #!/bin/bash is executed as a script.
cloud-init or Ansible?
Use cloud-init for first-boot bootstrapping and Ansible for ongoing configuration; see Ansible for VPS setup.
