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:
#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.
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, andtritonctl sshsigns in asrootunless you pass--loginoruser@.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:
| Result | Cause |
|---|---|
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 stdin | With --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 bytes | The 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
- Read instance metadata from inside an instance for the rest of the metadata the guest can read.
tritonctl instance createfor every flag.- How instance metadata works for where user-data is stored and how it reaches the guest.