How to use cloud-init
Description: cloud-init is a tool for automatically initializing and customizing an instance of a Linux distribution. By adding cloud-init configuration to your instance, you can instruct cloud-init to execute ...

Hide navigation sidebar
Hide table of contents sidebar
Skip to content
Back to top
View this page
Toggle table of contents sidebar

# How to use `cloud-init`

▶ Watch on YouTube

`cloud-init` is a tool for automatically initializing and customizing an instance of a Linux distribution.

By adding `cloud-init` configuration to your instance, you can instruct `cloud-init` to execute specific actions at the first start of an instance. Possible actions include, for example:

- Updating and installing packages

- Applying certain configurations

- Adding users

- Enabling services

- Running commands or scripts

- Automatically growing the file system of a VM to the size of the disk

See the Cloud-init documentation for detailed information.

Note

The `cloud-init` actions are run only once on the first start of the instance. Rebooting the instance does not re-trigger the actions.

## `cloud-init` support in images

To use `cloud-init`, you must base your instance on an image that has `cloud-init` installed:

- All images from the `ubuntu` and `ubuntu-daily` image servers have `cloud-init` support. However, images for Ubuntu releases prior to 20.04 LTS require special handling to integrate properly with `cloud-init`, so that `lxc exec` works correctly with virtual machines that use those images. Refer to VM `cloud-init`.

- Images from the `images` remote have `cloud-init`-enabled variants, which are usually bigger in size than the default variant. The cloud variants use the `/cloud` suffix, for example, `images:alpine/edge/cloud`.

## Configuration options

LXD supports two different sets of configuration options for configuring `cloud-init`: `cloud-init.*` and `user.*`. Which of these sets you must use depends on the `cloud-init` support in the image that you use. As a rule of thumb, newer images support the `cloud-init.*` configuration options, while older images support `user.*`. However, there might be exceptions to that rule.

The following configuration options are supported:

- `cloud-init.vendor-data` or `user.vendor-data` (see Vendor data)

- `cloud-init.user-data` or `user.user-data` (see User data formats)

- `cloud-init.network-config` or `user.network-config` (see Network configuration)

For more information about the configuration options, see the `cloud-init` instance options, and the documentation for the LXD data source in the `cloud-init` documentation.

### Vendor data and user data

Both `vendor-data` and `user-data` are used to provide cloud configuration data to `cloud-init`.

The main idea is that `vendor-data` is used for the general default configuration, while `user-data` is used for instance-specific configuration. This means that you should specify `vendor-data` in a profile and `user-data` in the instance configuration. LXD does not enforce this method, but allows using both `vendor-data` and `user-data` in profiles and in the instance configuration.

If both `vendor-data` and `user-data` are supplied for an instance, `cloud-init` merges the two configurations. However, if you use the same keys in both configurations, merging might not be possible. In this case, configure how `cloud-init` should merge the provided data. See Merging user data sections for instructions.

## How to configure `cloud-init`

To configure `cloud-init` for an instance, add the corresponding configuration options to a profile that the instance uses or directly to the instance configuration.

When configuring `cloud-init` directly for an instance, keep in mind that `cloud-init` runs only on the first start of the instance. That means that you must configure `cloud-init` before you start the instance. If you are using the CLI client, create the instance with `lxc init` instead of `lxc launch`, and then start it after completing the configuration.

To add your configuration:

Write the configuration to a file and pass that file to the `lxc config` command. For example, create `cloud-init.yml` with the following content:

    #cloud-config
    package_upgrade: true
    packages:
      - package1
      - package2

Then run the following command:

    lxc config set <instance_name> cloud-init.user-data - < cloud-init.yml

Provide the `cloud-init` configuration as a string with escaped newline characters.

For example:

    lxc query --request PATCH /1.0/instances/<instance_name> --data '{
      "config": {
        "cloud-init.user-data": "#cloud-config\npackage_upgrade: true\npackages:\n  - package1\n  - package2"
      }
    }'

Alternatively, to avoid mistakes, write the configuration to a file and include that in your request. For example, create `cloud-init.txt` with the following content:

    #cloud-config
    package_upgrade: true
    packages:
      - package1
      - package2

Then send the following request:

    lxc query --request PATCH /1.0/instances/<instance_name> --data '{
    "config": {
      "cloud-init.user-data": "'"$(awk -v ORS='\\n' '1' cloud-init.txt)"'"
      }
    }'

Go to the Configuration tab of the instance detail page and select Advanced > Cloud init. Then click Edit instance and override the configuration for one or more of the `cloud-init` configuration options.

### YAML format for `cloud-init` configuration

The `cloud-init` options require YAML’s literal style format. You use a pipe symbol (`|`) to indicate that all indented text after the pipe should be passed to `cloud-init` as a single string, with new lines and indentation preserved.

The `vendor-data` and `user-data` options usually start with `#cloud-config`.

For example:

    config:
      cloud-init.user-data: |
        #cloud-config
        package_upgrade: true
        packages:
          - package1
          - package2

Tip

See How to validate user data for information on how to check whether the syntax is correct.

## How to check the `cloud-init` status

`cloud-init` runs automatically on the first start of an instance. Depending on the configured actions, it might take a while until it finishes.

To check the `cloud-init` status, log on to the instance and enter the following command:

    cloud-init status

If the result is `status: running`, `cloud-init` is still working. If the result is `status: done`, it has finished.

Alternatively, use the `--wait` flag to be notified only when `cloud-init` is finished:

`root@instance:~#` `cloud-init status --wait`
`.....................................``status: done`

## How to specify user or vendor data

The `user-data` and `vendor-data` configuration can be used to, for example, upgrade or install packages, add users, or run commands.

The provided values must have a first line that indicates what type of user data format is being passed to `cloud-init`. For activities like upgrading packages or setting up a user, `#cloud-config` is the data format to use.

The configuration data is stored in the following files in the instance’s root file system:

- `/var/lib/cloud/instance/cloud-config.txt`

- `/var/lib/cloud/instance/user-data.txt`

### Examples

See the following sections for the user data (or vendor data) configuration for different example use cases.

You can find more advanced examples in the `cloud-init` documentation.

#### Upgrade packages

To trigger a package upgrade from the repositories for the instance right after the instance is created, use the `package_upgrade` key:

    config:
      cloud-init.user-data: |
        #cloud-config
        package_upgrade: true

#### Install packages

To install specific packages when the instance is set up, use the `packages` key and specify the package names as a list:

    config:
      cloud-init.user-data: |
        #cloud-config
        packages:
          - git
          - openssh-server

#### Set the time zone

To set the time zone for the instance on instance creation, use the `timezone` key:

    config:
      cloud-init.user-data: |
        #cloud-config
        timezone: Europe/Rome

#### Run commands

To run a command (such as writing a marker file), use the `runcmd` key and specify the commands as a list:

    config:
      cloud-init.user-data: |
        #cloud-config
        runcmd:
          - [touch, /run/cloud.init.ran]

#### Add a user account

To add a user account, use the `user` key. See the Including users and groups example in the `cloud-init` documentation for details about default users and which keys are supported.

    config:
      cloud-init.user-data: |
        #cloud-config
        user:
          - name: documentation_example

## How to specify network configuration data

By default, `cloud-init` configures a DHCP client on an instance’s `eth0` interface. You can define your own network configuration using the `network-config` option to override the default configuration (this is due to how the template is structured).

`cloud-init` then renders the relevant network configuration on the system using either `ifupdown` or `netplan`, depending on the Ubuntu release.

The configuration data is stored in the following files in the instance’s root file system:

- `/var/lib/cloud/seed/nocloud-net/network-config`

- `/etc/network/interfaces.d/50-cloud-init.cfg` (if using `ifupdown`)

- `/etc/netplan/50-cloud-init.yaml` (if using `netplan`)

### Example

To configure a specific network interface with a static IPv4 address and also use a custom name server, use the following configuration:

    config:
      cloud-init.network-config: |
        version: 1
        config:
          - type: physical
            name: eth1
            subnets:
              - type: static
                ipv4: true
                address: 10.10.101.20
                netmask: 255.255.255.0
                gateway: 10.10.101.1
                control: auto
          - type: nameserver
            address: 10.10.10.254