Skip to main content

Building VMs with Cloud-Init

NetActuate VMs support cloud-init and bash scripts passed at build time via the build API. Use this to bootstrap configuration, install packages, write files, and run commands automatically when a VM first boots — without requiring post-boot SSH access.

How It Works

When you include script_type and script_content in a VM build request, NetActuate passes the script to the VM via the hypervisor at first boot. The script runs before the VM is reachable via SSH.

The script_content parameter must be base64-encoded. The script_type parameter tells the platform how to interpret the content.

Supported Script Types

script_type valueFormat
cloud-initCloud-init YAML (recommended)
cloud_initAlias for cloud-init
user-dataAlias for cloud-init
user_dataAlias for cloud-init
bashBash shell script

Note: Not all OS images support cloud-init. Ubuntu 24.04 LTS and most modern Linux images do. Verify your image supports the script type before using this feature.

Cloud-Init Example

Write your cloud-init YAML, then base64-encode it before passing it to the API.

Cloud-init YAML (before encoding):

#cloud-config
packages:
- nginx
- curl

runcmd:
- systemctl enable nginx
- systemctl start nginx

write_files:
- path: /etc/app/config.env
permissions: '0600'
content: |
APP_ENV=production

Encode and build:

SCRIPT=$(base64 < cloud-init.yaml)

curl -X POST https://vapi2.netactuate.com/api/build \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"mbpkgid": 1001,
"location": 12,
"image": 203,
"fqdn": "web01.example.com",
"ssh_key_id": 88,
"script_type": "cloud-init",
"script_content": "'"$SCRIPT"'"
}'

Bash Script Example

#!/bin/bash
apt-get update -y
apt-get install -y nginx
systemctl enable nginx
systemctl start nginx

Encode and pass with "script_type": "bash".

Combining with Secrets Manager

Cloud-init content can reference secrets stored in NetActuate Secrets Manager using template syntax. Substitution happens server-side before the script reaches the VM.

#cloud-config
write_files:
- path: /etc/app/config.env
permissions: '0600'
content: |
DB_PASSWORD=${{secret.DB_PASSWORD}}
API_KEY=${{secret.API_KEY}}

runcmd:
- systemctl restart myapp

See Using Secrets Manager with Cloud-Init for the full workflow including creating secrets.

Using Cloud-Init with Ansible

Pass script_content through the netactuate.compute.node module:

- name: Provision VM with cloud-init
netactuate.compute.node:
auth_token: "{{ auth_token }}"
hostname: "{{ inventory_hostname }}"
plan: "{{ plan }}"
location: "{{ location }}"
image: "Ubuntu 24.04 LTS (20240423)"
script_type: "cloud-init"
script_content: "{{ lookup('file', 'cloud-init.yaml') | b64encode }}"
state: present

Using Cloud-Init with Terraform

resource "netactuate_server" "web" {
hostname = "web01"
plan = "VR8x4x50"
location = "LAX"
image = "5787"
ssh_keys = [var.ssh_key_id]
cloud_config = file("cloud-init.yaml")
}

Need Help?

If you need assistance, visit our support page.