Cloud Init tutorial

Cloud-init is a powerful resource which lets you configure the OS on the first boot. This is great as it can be used to install provisioning software such as Ansible, Puppet, etc. Sometimes you would like to install just PHP on a server. This can be easily achieved.

In this post, I’m going over a few things that you would need to know about cloud-init, such as the log folder, how to use bash scripts etc.

The instance-data.json

Location: /run/cloud-init/instance-data.json

When it runs, it creates a file called “instance-data.json” which includes details about the server such as the VPC ID it belongs to, AMI details, etc. The purpose behind creating this file is to improve speed and reduce fetching the details from the provider. As any details needed for future steps can be retrieved from this file.

In this file, there are two key levels ds and v1 in the instance-data file which are important.

ds: This holds metadata of the server such as security group attached, instance-id, hostname, etc

v1: The v1 keys will exist on all cloud platforms. They hold information such as the cloud provider name, instance-id, and availability zone. For instance, on an EC2 instance, the cloud-name is “AWS”

  "base64-encoded-keys": [],
  "ds": {
    "meta-data": {
      "ami-id": "ami-09ead922c1dad67e4",
      "ami-launch-index": "0",
      "ami-manifest-path": "(unknown)",
      "block-device-mapping": {
        "ami": "/dev/xvda",
        "root": "/dev/xvda"
      "hostname": "",
      "instance-action": "none",
      "instance-id": "i-0a9aefac37b32e453",
      "instance-type": "t2.micro",
      "local-hostname": "",
      "local-ipv4": "",
      "mac": "06:df:ca:95:f5:40",
      "metrics": {
        "vhostmd": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
      "network": {
        "interfaces": {
          "macs": {
            "06:df:ca:95:f5:40": {
              "device-number": "0",
              "interface-id": "eni-0570221f577b678e3",
              "ipv4-associations": {
                "": ""
              "local-hostname": "",
              "local-ipv4s": "",
              "mac": "06:df:ca:95:f5:40",
              "owner-id": "209518873002",
              "public-hostname": "",
              "public-ipv4s": "",
              "security-group-ids": "sg-0bdacb789b33566c6",
              "security-groups": "terraform-20190331175408929800000002",
              "subnet-id": "subnet-016e51a8eead832dd",
              "subnet-ipv4-cidr-block": "",
              "vpc-id": "vpc-04f33dae1711c10c4",
              "vpc-ipv4-cidr-block": "",
              "vpc-ipv4-cidr-blocks": ""
      "placement": {
        "availability-zone": "eu-west-2a"
      "profile": "default-hvm",
      "public-hostname": "",
      "public-ipv4": "",
      "public-keys": {
      "reservation-id": "r-0699504969a655422",
      "security-groups": "terraform-20190331175408929800000002",
      "services": {
        "domain": "",
        "partition": "aws"
    "user-data": "",
    "vendor-data": null
  "v1": {
    "availability-zone": "eu-west-2a",
    "cloud-name": "aws",
    "instance-id": "i-0a9aefac37b32e453",
    "local-hostname": "ip-10-0-2-121",
    "region": "eu-west-2"

This is a great file if you would like to find everything about the instance.

On AWS AMI you cannot use the query feature of cloud-init.

Scripts folder Cloudinit userdata


This is the folder where user scripts are being saved. If you have generated the scripts using a template this is a great place to view the generated version on the actual server.


If you want to ensure that cloud-init has successfully run the script. Execute this command to verify the status

Where are cloud-init logs?

Cloud-init stores logs in /var/log/cloud-init-output.log . This file is your best friend to find out more information. The file has too many lines but if the problem is with a script not working trying search for the script name in the file.

Running Shell scripts

If you would like to run shell scripts, you will have to use the runcmd rule.

In the example, the script downloads the shell script and then runs it.

repo_update: true
repo_upgrade: security

- [ wget,"", -O, "/tmp/" ]
- [ bash, /tmp/ ]


While Cloud-init is a great resource in an ideal scenario you should provision your servers using Ansible and Packer. Cloud-init is great for quick setups.  If you can move to Docker images this is a much better approach. For example you can build a docker image using CodeBuild which can be easily achieved in few steps.