# cloud-init: Automatic VPS Configuration on Creation

> cloud-init automatically configures a VPS on creation — users, SSH keys, packages, and commands via user-data with no manual server login.

## 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](https://www.zevshost.net/en/kb/podklyuchenie-vds-ssh/): 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](https://www.zevshost.net/en/kb/vds-hardening-pervye-shagi/) 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](https://www.zevshost.net/en/kb/ufw-firewall-vps/) 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.

---

Source: https://www.zevshost.net/en/kb/cloud-init-avtonastroyka-vps/
