Cloud-config is a feature of cloud-init, which is a package that is installed by default on most modern Linux operating systems, such as Ubuntu, Almalinux 8+, and Rocky Linux 8+.


Cloud-config is a powerful tool that allows you to configure your server during the first boot process. This is useful for setting up your server with your own default preferences, such as installing packages, configuring services like firewall and web servers, and setting up users and groups. The cloud-config data is written in YAML format, which is a human-readable data serialisation format.


We've provided some basic cloud-config examples for use with BinaryLane Ubuntu servers. These examples are designed to be used with the user-data field when creating a new Ubuntu instance. To use cloud-config, you'll need to enter the cloud-config data into the user-data field on the server creation page. You'll need to click the 'View All' button to open additional server configuration options to display the cloud-config checkbox. Checking the box enables the entry field. 



Click View All on the server creation page.




Check the Deployment script: box to enable the cloud-config user data entry field.




The cloud-config data is processed near the end of the boot process, so depending on package installations and the complexity of the script, the instance may take a few minutes to complete the boot process, all changes to be applied, and to be ready for use. You can check the status of the cloud-init service by running systemctl status cloud-init.service or journalctl -xe to see the logs.


The cloud-config data will be entered into the user-data field automatically when reinstalling a server's operating system. You'll need to delete or modify the data as necessary if you do not want the previous cloud-config user-data run during OS reinstallation. If you want to keep the cloud-config data for future use or other new servers you create, you can save it to a yaml file on your local machine with your document editor.



Combining cloud-config data with a script that is hosted somewhere else is a good way to keep the cloud-config data field short and simple. This is useful if you have a long script that you don't want to include directly in the cloud-config data. Externally hosted scripts are often used in the #include directive in the cloud-config data to add repositories, install packages, or configure services such as firewalls and web servers with your own default preferences.



Basic #cloud-config example


This is a basic #cloud-config example that uses the built-in package functionality to first ensure apt packages are up to date, upgrades any applicable base install packages, and installs a few common packages near the end of the first boot process.


#cloud-config

# This section ensures that apt packages are up to date with the first line, base packages are updated with the second line, then we define a few common packages to install.

package_update: true
package_upgrade: true
packages:
  - htop
  - nmap
  - mtr


You can enter the example above into the user-data field as shown below.




Advanced example


This example demonstrates a slightly more complex cloud-config script using the built-in functionality that includes a few different sections. It first ensures apt packages are up to date, upgrades any applicable base packages, installs a few commonly used packages, and uses the write_files and runcmd functions to write out a file and run a couple of commands, such as configuring a custom coloured prompt and 'history' output to include timestamps.


Python3 is included in default Ubuntu installations, so here we have python3-pip as an example package to install that will take a little longer to install than the other packages. This will mean the instance may take a few minutes longer than usual to be ready for use than the previous example.


#cloud-config

# This section ensures that apt packages are up to date with the first line, base packages are updated with the second line, then we define a few common packages to install. Python3 is included in default Ubuntu installations, so here we have python3-pip as an example package to install that will take a little longer to install than the other packages. This will mean the instance may take a few minutes longer than usual to be ready for use than the previous example.

package_update: true
package_upgrade: true
packages:
 - htop
 - nmap
 - mtr
 - python3-pip

# In this section of our example we use the write_files functionality to create a custom bashrc file in the root user's home directory, and then 'content' to write the contents of the file which sets a custom coloured prompt, timestamps for 'history' output, and setting the command history size.

write_files:
  - path: /root/.bashrc_custom
    content: |
      export PS1="\[\033[38;5;214m\]\u\[$(tput sgr0)\]\[\033[38;5;13m\]@\[$(tput sgr0)\]\[\033[38;5;39m\]\H\[$(tput sgr0)\]:\[$(tput sgr0)\]\[\033[38;5;10m\][\[$(tput sgr0)\]\[\033[38;5;178m\]\w\[$(tput sgr0)\]\[\033[38;5;10m\]]\[$(tput sgr0)\]: \[$(tput sgr0)\]"

    export HISTTIMEFORMAT="%d/%m/%Y %I:%M %p %Z "
    export HISTSIZE=10000

# This section uses the runcmd functionality to run two commands; the first command sources the custom bashrc file we created in the previous section, and the second command runs the 'source' command to apply the changes to the current shell. This is necessary as the 'write_files' section only writes the file to disk, and so doesn't automatically apply the changes to the current shell.

runcmd:
  - "echo '. /root/.bashrc_custom' >> /root/.bashrc"
  - 'source /root/.bashrc'

If you'd like to customise your prompt there are many sites that can help build one such as https://robotmoon.com/bash-prompt-generator/



Basic example if you have a script hosted somewhere else


If you have a script hosted somewhere else, you can use the #include directive to include the script in your cloud-config file.

This will allow you to enter the URL(or URLs, one per line) of a script or file hosted at an external repository such as Github. The #include feature supports URLs pointing to gzipped, mime-multipart, or plaintext content. This is useful if you have a long script that you don't want to include directly in the cloud-config file.


#cloud-config

include:
  - https://example.com/path/to/script.sh


Shell script example


If you prefer to use a shell script instead of a cloud-config file, you can use regular shell script syntax. Here's an example of a very simple shell script that installs a few packages:


!#/bin/bash

apt-get update
apt-get install -y htop nmap mtr


Python script example


If you prefer to use a Python script instead of a bash script, you can use regular Python syntax. Here's an example of a very simple Python script that uses basic python3 functionality that is available by default in current Ubuntu versions. The cloud-config format is recommended for basic package installs like we're doing with Python in this example, but this is how you could use a Python script if you prefer:


#!/usr/bin/python3

import os

os.system('apt-get update')
os.system('apt-get install -y htop nmap mtr')



Other languages


You can use any language that is available on the server to run your script. Just make sure that the language is installed on the server before running the script. You can use the packages section in the cloud-config file to install the necessary packages if they are not already installed as shown in the examples above.



Further reading


For more information on cloud-config and the cloud-config syntax see the official documentation:

https://cloudinit.readthedocs.io/en/latest/explanation/about-cloud-config.html


For more advanced cloud-config examples see the official documentation:

https://cloudinit.readthedocs.io/en/stable/reference/examples.html