Skip to main content

cloud-init: Automatic VPS Configuration on Creation

VDS / VPS Servers · 29.09.2026

What cloud-init is and why you need it

cloud-init is the standard tool for automatically configuring a server on its first boot. It reads the configuration supplied when the VPS is created (known as user-data) and uses it to create users, install packages, add SSH keys, and run arbitrary commands — all without manually logging into the server after it is created.

The point is to avoid repeating the same steps by hand after the first SSH connection to a VDS: basic hardening, the needed users, and a system update all get applied automatically before the first login.

Where to find cloud-init on an already created VPS

Most current Ubuntu and Debian images from hosting providers already include cloud-init. You can check whether it is present and its version like this:

cloud-init --version
systemctl status cloud-init

Configuration files applied when the server was created are stored in /var/lib/cloud/instance/, and the raw data passed by the control panel is in /var/lib/cloud/instance/user-data.txt. This is useful when you need to figure out exactly what ran during the server's first boot.

User-data structure: a minimal working example

cloud-init configuration is written in YAML and must start with the line #cloud-config as the very first line of the file. A minimal example that updates packages and sets the timezone:

#cloud-config
package_update: true
package_upgrade: true
timezone: Europe/Berlin

Indentation in YAML matters: use spaces, not tabs, otherwise the configuration will not apply and the logs will show a parsing error.

Creating a user, SSH keys, and packages

A fuller example creates an unprivileged user with sudo access, adds their public SSH key, and installs the needed packages:

#cloud-config
users:
  - name: deploy
    groups: sudo
    shell: /bin/bash
    sudo: 'ALL=(ALL) NOPASSWD:ALL'
    ssh_authorized_keys:
      - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... user@laptop

packages:
  - nginx
  - fail2ban
  - unattended-upgrades

runcmd:
  - systemctl enable fail2ban
  - systemctl start fail2ban

The runcmd section runs arbitrary shell commands after packages are installed — the basic steps from the article on first steps after buying a VDS can go there too, so the server is protected right after creation.

How to pass user-data when creating a server

A hosting provider's control panel usually has a "User data" or "Cloud-init script" field at the server configuration step when ordering a VPS — the entire YAML file goes there as is. If the server is created through a cloud CLI tool, the file is passed with a separate flag, for example:

--user-data-file ./cloud-config.yaml

Important: user-data by default only applies on the instance's first boot. Passing the configuration again on an already running server requires forcibly resetting the cloud-init state with cloud-init clean and rebooting — do this deliberately, since running it again can recreate users or reinstall packages.

Debugging: if cloud-init did not work

If the expected changes did not apply after the server was created, check the execution logs:

cat /var/log/cloud-init.log
cat /var/log/cloud-init-output.log

The second file contains the actual output of the runcmd commands and package installation — you can usually spot the specific error there. Checklist:

  • Check the YAML indentation and syntax — a single stray tab breaks the whole file.
  • Make sure the first line of the file is exactly #cloud-config.
  • Check both logs: cloud-init.log for the process and cloud-init-output.log for command output.
  • If you manually opened firewall ports, check the article on configuring UFW on a VDS in case runcmd changed the filtering rules.
  • Use cloud-init clean and a reboot to reapply the configuration, rather than editing the system by hand.
← Back to Knowledge Base Ask Support