Skip to main content

Pass user-data when you create an instance

This guide creates an instance with user-data, the blob cloud-init reads at first boot, and confirms the guest can read it. It extends Create an instance, so you need everything that guide lists: tritonctl signed in, a project, a subnet, and an image.

Step 1: Write the user-data file​

On your workstation, write the file. This example is a cloud-config that adds an SSH key and installs a package, and keeps the two settings from the platform's default cloud-config that the instance needs to boot reachable:

user-data.yaml
#cloud-config
disable_root: false
ssh_authorized_keys:
- <SSH_PUBLIC_KEY>
packages:
- nginx
updates:
network:
when:
- boot

<SSH_PUBLIC_KEY> is the full line of your public key, for example the contents of ~/.ssh/id_ed25519.pub.

The file must be UTF-8 text, at most 65536 bytes once encoded as a JSON string. That encoding adds two bytes for the surrounding quotes, one byte for each double quote, backslash, newline, carriage return, tab, backspace, or form feed, and five bytes for each other control character.

warning

On a bhyve instance whose image uses cloud-init's NoCloud datasource, your user-data replaces the default cloud-config the platform writes. Nothing from the default is merged in. Keep these parts of it in your own file:

  • disable_root: false. Without it, cloud-init blocks root sign-in, and tritonctl ssh signs in as root unless you pass --login or user@.
  • ssh_authorized_keys. The default is what installs the keys you pass with --ssh-key.
  • updates: network: when: [boot]. This works around a cloud-init bug on some images, such as Ubuntu 26.04, that leaves the static IP address unapplied on first boot, so the instance is unreachable.

The default also sets the generated root password for console sign-in. Your file replaces that too.

Step 2: Create the instance with the file​

On your workstation:

tritonctl instance create \
--name web-1 \
--image <IMAGE_NAME> \
--subnet <SUBNET_NAME> \
--ssh-key workstation \
--cpu 2 \
--memory 4G \
--user-data user-data.yaml \
--wait

To read the user-data from standard input, pass --user-data -:

generate-cloud-config | tritonctl instance create \
--name web-1 \
--image <IMAGE_NAME> \
--subnet <SUBNET_NAME> \
--cpu 2 \
--memory 4G \
--user-data - \
--wait

generate-cloud-config stands for any command that prints your user-data.

If the create fails on the user-data:

ResultCause
read user data from <PATH>The CLI could not read the file, or the file is not UTF-8. Nothing was sent.
read user data from stdinWith --user-data -, the CLI could not read standard input, or it is not UTF-8. Nothing was sent.
400, user_data: metadata value exceeds 65536 bytesThe file is over the size limit.

Any other failure is covered in Create an instance.

Step 3: Confirm the instance has it​

From your workstation, read the stored value:

tritonctl meta get --scope instance --id web-1 --key user-data

From inside the instance, read what the guest sees:

TOKEN=$(curl -sS -X PUT http://169.254.169.254/latest/api/token \
-H "X-aws-ec2-metadata-token-ttl-seconds: 300")
curl -sS -H "X-aws-ec2-metadata-token: $TOKEN" \
http://169.254.169.254/latest/user-data

The second command prints the file exactly as you passed it.

See also​