Many people use Puppet, Chef or Ansible (or indeed their own custom scripts) to configure instances after booting, to make them part of their application or a cluster. Wouldn't it be better if you could launch an instance, have it configure itself, and install software? Well, actually you can!

Creating templates

You can only create, amend and delete custom templates via the API at the moment, so the first step in creating a template will be to find out your API token. You can do this by visiting our API documentation and you'll see your API key automatically inserted just after the part saying "Because you have an account on Civo, you already have an API key".

While you're there, you may want to have a read of the Templates API documentation. We're about to be using that a lot!

Using the API to create a new template

First we're going to make a curl request to the create template API call to create our new template. Let's say we're going to create a web server that serves our website (and we can then quickly launch more of them later).

As described on that page, the command to create a template looks like this:

curl -H "Authorization: bearer {TOKEN}" \
  -F id=my-webserver-1.0 -F name="My Webserver 1.0" -F image_id=123456

The image_id is a really key part. We need to use an existing Glance Image ID from Civo's OpenStack or use the ID of an existing template (and then we'll always use the same ID as they use). So, if we wanted to use Ubuntu 16.04 as our base OS, we could call:

curl -H "Authorization: bearer {TOKEN}"

To get the list (a little pro-tip for you) install the jq tool and pipe the command output above into it for a nice pretty printed output. For more information on jq or to download it see

At the time of writing, the Ubuntu 16.04 template has the image_id of d5d43ba0-82e9-43de-8883-5ebaf07bf3e3. We could use that as the image_id of our template, but if a new Ubuntu 16.04 image is released by us, you'd be stuck using the old version (if it's still around). So a better way would be to use the id of ubuntu-16.04.

So now we're ready to create our template. You can go ahead and run:

curl -H "Authorization: bearer {TOKEN}" \
  -F id=my-webserver-1.0 -F name="My Webserver 1.0" -F image_id=ubuntu-16.04

Using the API to update a template

In a very similar way to how we created a template, we can update one by using an HTTP PUT and appending the ID to the URL. For example:

curl -H "Authorization: bearer {TOKEN}" \ \
  -F name="My Webserver 1.1"

Using the API to delete a template

And finally if you've been just playing with templates, please clean up after yourself and delete them.

curl -H "Authorization: bearer {TOKEN}" \

Using Cloud-config

So far this is all very interesting, but doesn't really offer much in the way of benefits. If you use it like this it won't even offer you a functional instance. The reason is that by default the cloud images supplied by Civo (which are the same ones supplied by the OS distributors) don't create a user with an accessible password.

So we come to the all important "run this special file to configure yourself when you first boot" file, a.k.a. cloud-config which is run by cloud-init. There is lots of documentation on all the things you can do with cloud-init at that site, so we'd really recommend you give it a thorough read.

Creating an initial cloud-config

A barebones cloud-config file might look something like this:


timezone: Europe/London
manage_etc_hosts: true

  - name: ubuntu
    sudo: ['ALL=(ALL) NOPASSWD:ALL']
    shell: /bin/bash

  list: |
  expire: False

  - sed -i -e 's/^PasswordAuthentication no.*$/PasswordAuthentication yes/' /etc/ssh/sshd_config
  - sed -i '/PermitRootLogin/ s/.*/PermitRootLogin yes/g' /etc/ssh/sshd_config
  - service sshd restart

That will configure the hostname on the instance, set the timezone, and create a root user with the testpasswordhere password. It then uses the runcmd section to enable logging in over SSH using a password, rather than just a public key. So, if you create a file somewhere on your filesystem (we'll use the current directory ./ and cloud-config for our purposes here), you can update your template with it:

curl -v -X PUT -H "Authorization: bearer {TOKEN}" \
  -F cloud_config=@./cloud-config \

Notice that we use @ before the ./cloud-config filename - without that it will send the name of your local file, not its actual contents to the API.

At this point you can launch an instance using your template and login to it:

curl -H "Authorization: bearer {TOKEN}" \
  -d ""

curl -H "Authorization: bearer {TOKEN}"
# Wait for status to be ACTIVE and public_ip to have a value

ssh ubuntu@{public_ip} # and testpasswordhere
The authenticity of host '{public_ip}' can't be established.
ECDSA key fingerprint is SHA256:....
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '{public_ip}' (ECDSA) to the list of known hosts.
ubuntu@{public_ip}'s password: 
Welcome to Ubuntu 16.04.1 LTS (GNU/Linux 4.4.0-53-generic x86_64)

There'll be some other warnings that we work around in our cloud inits there, but you now have a box configured that you can log into.

You can see from here that you can now launch database servers or webservers, clone code, whatever you want. You can use write_files within your Cloud-config to upload config files, etc, git clone repositories after that, etc. The world is your oyster.

Playing nicely with Civo

However, at this point the hostname is hardcoded to be and the initial user is ubuntu, etc. So to make it play a little nicer with, there are some tweaks we should make.

Hopefully it'll be clear that if the same key exists in our sample, you add to it in YAML format rather than duplicate the whole section.


To dynamically insert the hostname from Civo, you should add in some sections to the top of:

hostname: $HOSTNAME


The hardcoded timezone of Europe/London in our example works perfectly for us, but you may want to change it. automatically uses the configured timezone for the user (you can change this in your Profile settings if you want to).

timezone: $TIMEZONE

SSH authentication

Using a password is a bit old-school these days, key-based authentication is much nicer. We already allow you to upload your SSH keys into Civo, so rather than hardcode authentication details in the template, you can change it so it uses your choice of key and the random password created by Civo:

  - name: $INITIAL_USER
      - $SSH_KEY
    sudo: ['ALL=(ALL) NOPASSWD:ALL']
    shell: /bin/bash
  list: |

That takes care of an SSH Key if you chose one and the random password we assign when building your instance.

Civo statistics reporting

Enabling Civostatsd can be a little tricky, it's really operating system dependent. To give you an example of how we do it on our Ubuntu 16.04 templates:

  - name: civostatsd
    shell: /bin/false

  - content: |
      Description=Civo Statistics Reporting Daemon


    path: /etc/systemd/system/civostatsd.service

  - echo 'server=""' > /etc/civostatsd
  - echo 'token="$CIVOSTATSD_TOKEN"' >> /etc/civostatsd
  - chown civostatsd:civostatsd /etc/civostatsd
  - curl -s | /bin/bash

Creating templated instances via the web interface

If you've created custom templates, then a new option will appear alongside the Operating systems selector:

Screen Shot 2017-11-03 at 11.51.32.png

If you click on the Templates tab you can now choose your newly created template.

Screen Shot 2017-11-03 at 11.51.37.png

We hope this has covered the basics of getting started with custom templates, please tweet us and tell us how you're using custom templates.