User data is a script that runs once on an instance’s first boot, before SSH is available. Use it to install packages, add users, drop config files, or kick off your provisioning tool of choice.

All Atlas Linux templates (Ubuntu, Debian, AlmaLinux, Rocky) ship with cloud-init — the de facto standard for this. Pass YAML in the #cloud-config format and cloud-init handles the rest.

Example: bootstrap a sudo user and install packages

#cloud-config
users:
  - name: deploy
    groups: sudo
    shell: /bin/bash
    ssh-authorized-keys:
      - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI...
 
package_update: true
package_upgrade: true
 
packages:
  - curl
  - vim
  - jq
 
runcmd:
  - echo "Welcome to Atlas Cloud!" > /etc/motd

This creates a deploy user with sudo, drops the SSH key, installs three packages, and writes a motd. The whole thing runs unattended on first boot.

How to pass user data

Console

In the New Instance wizard, expand User Data and paste the YAML.

CLI

cmk expects base64-encoded user data:

cmk deploy virtualmachine \
  serviceofferingid=$SO templateid=$TMPL networkids=$NET zoneid=$ZONE \
  keypair=mykey name=hello-atlas \
  userdata=$(base64 -w0 < user-data.yaml)

Terraform

resource "cloudstack_instance" "web" {
  name             = "web"
  service_offering = "Atlas.a5"
  template         = "Ubuntu 24.04 LTS"
  network_id       = cloudstack_network.default.id
  zone             = "is1"
  keypair          = "mykey"
  user_data        = file("${path.module}/user-data.yaml")
}

The provider base64-encodes for you.

User Data Library

If you reuse the same script across many instances, save it once via Compute → User Data Library and reference it by ID on deploy. This avoids duplicating the script in every Terraform module or cmk call.

USERDATA_ID=$(cmk register userdata name=bootstrap-deploy userdata=$(base64 -w0 < user-data.yaml) | jq -r '.userdata.id')
cmk deploy virtualmachine ... userdataid=$USERDATA_ID

What runs when

Cloud-init runs once at first boot, before SSH is available. Subsequent boots skip it. Logs go to:

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

tail -f that file while a VM is starting — it’s the canonical place to see what broke.

Common failures

  • My user data didn’t run. Confirm the first line is #cloud-config (literal text, no <!-- etc.). Re-launch the VM after fixing — cloud-init only runs on first boot.
  • My SSH key wasn’t injected. You probably mixed up the userdata= and keypair= parameters. The keypair= argument on deploy virtualmachine is what attaches a registered SSH key from your SSH Key Pairs library; user data is for everything else.
  • apt update hangs inside cloud-init. Your network’s egress rules likely block outbound TCP 80/443/53 and UDP 53. See Guest networks and allow them.