Skip to content

How to configure a VM with cloud-init

How-to · Updated Jul 2026

Coming from another cloud?

▸AWS·EC2 User Data

This Quake AI feature maps to AWS’s EC2 User Data.

▸Azure·Custom Data

This Quake AI feature maps to Azure’s Custom Data.

▸DigitalOcean·User Data

This Quake AI feature maps to DigitalOcean’s User Data.

▸Google Cloud·Startup Scripts

This Quake AI feature maps to Google Cloud’s Startup Scripts.

▸Hetzner·Cloud Init

This Quake AI feature maps to Hetzner’s Cloud Init.

Before this

How to configure a VM with cloud-init

Write cloud-init user data, pass it when you launch an instance, and confirm the guest applied your baseline on first boot.

For background on formats and the one-shot boot model, see cloud-init and first-boot configuration. For a full production launch workflow, see How to provision a production-ready VM.

Prerequisites

Windows: CLI examples use bash. Set up a Linux CLI environment on Windows before proceeding.

Step 1. Write a minimal cloud-config file#

Create cloud-init.yaml with a non-root sudo user, package updates, and a hostname:

YAML
#cloud-config
hostname: APP_HOSTNAME
users:
  - name: deploy
    groups: sudo
    shell: /bin/bash
    sudo: ALL=(ALL) NOPASSWD:ALL
    ssh_authorized_keys:
      - YOUR_SSH_PUBLIC_KEY
package_update: true
package_upgrade: true

Replace APP_HOSTNAME and YOUR_SSH_PUBLIC_KEY. The #cloud-config header tells cloud-init to parse the file as cloud-config YAML, not a shell script.

Step 2. Use common cloud-config modules#

Add modules as your baseline grows. Each example is self-contained; merge the keys you need into one #cloud-config file.

users (shown above): creates login accounts and injects SSH public keys.

packages:

YAML
packages:
  - nginx
  - fail2ban

package_update / package_upgrade: refresh package indexes and apply upgrades on first boot (shown in Step 1).

write_files:

YAML
write_files:
  - path: /etc/motd
    content: |
      Managed by cloud-init baseline
    owner: root:root
    permissions: "0644"

bootcmd vs runcmd: bootcmd runs early every boot (rarely needed on first-boot baselines). runcmd runs late on first boot only:

YAML
runcmd:
  - systemctl enable nginx
  - systemctl start nginx

Step 3. Pass user data at launch#

Step 4. Debug first-boot failures#

When SSH fails or packages are missing, inspect cloud-init before you rebuild the instance.

SSH in (or open the virtual machine console if SSH is not up yet) and run:

bash
cloud-init status --wait
sudo tail -n 100 /var/log/cloud-init.log
sudo tail -n 100 /var/log/cloud-init-output.log

status --wait blocks until cloud-init finishes or reports an error. The log files show module execution order and shell output from runcmd.

Validate cloud-config syntax locally:

bash
cloud-init schema --config-file cloud-init.yaml

Fix YAML errors, then launch a new instance with corrected user data. cloud-init does not re-run the full first-boot sequence on an instance that already completed it.

Step 5. Verify the baseline landed#

After cloud-init status reports done:

bash
hostname
id deploy
dpkg -l nginx 2>/dev/null || rpm -q nginx 2>/dev/null

Confirm the hostname, the deploy user, and any packages you declared are present. SSH as deploy@INSTANCE_ADDRESS with the matching private key.

See also#

Usage Guidelines

The sample code, software libraries, command line tools, proofs of concept, templates, and other related technology on this page (including any of the foregoing that is provided by Quake AI personnel) is provided to you as Quake AI Content under the Quake AI Customer Agreement, or the relevant written agreement between you and Quake AI (whichever applies). Do not use this Quake AI Content in your production accounts, or on production or other critical data. You are responsible for testing, securing, and optimizing the Quake AI Content (such as sample code) as appropriate for production grade use based on your specific quality control practices and standards. Deploying Quake AI Content may incur Quake AI charges for creating or using Quake AI chargeable resources, such as running Compute instances or storing data in Object Storage. Your use is also subject to the Acceptable Use Policy.

For the full policy, see Usage Guidelines.

Last validated: 10.07.2026

Quick answers

Was this page helpful?