You can provision a brand new DigitalOcean Droplet to be fully configured and running your application the moment it boots, without any manual intervention, by leveraging cloud-init.

Let’s see cloud-init in action. Imagine we want to launch a Droplet that immediately installs Nginx, pulls a simple index.html from a remote URL, and starts the Nginx service.

First, we need to create a cloud-init configuration file. This is typically written in YAML.

#cloud-config
package_update: true
packages:
  - nginx
runcmd:
  - wget -O /var/www/html/index.html https://gist.githubusercontent.com/yourusername/yourgistid/raw/index.html
  - systemctl enable nginx
  - systemctl start nginx

In this cloud-config file:

  • package_update: true tells cloud-init to run apt update (or equivalent for the OS) before installing any packages.
  • packages: - nginx specifies that the nginx package should be installed.
  • runcmd: is a list of commands to execute in order after the packages are installed. Here, we download a custom index.html file and then ensure Nginx is enabled to start on boot and is started immediately.

Now, when you create a new Droplet in DigitalOcean, you can select the "Custom image" option or use the API/CLI to pass this cloud-init data. For example, using the doctl command-line tool:

doctl compute droplet create my-nginx-droplet \
  --image ubuntu-22-04-x64 \
  --size s-1vcpu-1gb \
  --region nyc3 \
  --user-data-file ./my-nginx-config.yaml

The moment this Droplet spins up, cloud-init will execute the directives in my-nginx-config.yaml. Within a minute or two, you should be able to access http://<your-droplet-ip> and see the index.html you specified.

The problem cloud-init solves is the repetitive, manual configuration of new servers. Instead of logging in, running apt update, apt install nginx, downloading files, and starting services, you define this entire process declaratively. cloud-init is an industry standard for this, present in most major Linux distributions and cloud providers. It runs very early in the boot process, before most other services are initialized, ensuring your base configuration is in place.

The core components of cloud-init are datasources and modules. Datasources detect the cloud environment (like DigitalOcean) and fetch the user-provided data (your cloud-config file). Modules then act on this data, performing tasks like package installation, file writing, user creation, and script execution. The runcmd module is particularly powerful for ad-hoc scripting.

You can also use cloud-init for more complex tasks:

  • User Management: Create users, set passwords or SSH keys.
  • File Manipulation: Write arbitrary files, manage permissions.
  • Network Configuration: Set static IPs, configure DNS.
  • Mounting Volumes: Attach and mount block storage devices.

For instance, to add an SSH key for a user named deploy:

#cloud-config
users:
  - name: deploy
    ssh_authorized_keys:
      - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC... user@example.com
    sudo: ALL=(ALL) NOPASSWD:ALL
    groups:
      - sudo

This ensures that the deploy user can immediately SSH into the Droplet with the specified key and has sudo privileges.

A common pitfall is assuming cloud-init waits for the entire OS to be ready. It runs during the initial boot sequence. Commands in runcmd execute sequentially, but if a command depends on a service that hasn’t fully started yet (e.g., a database connection), it might fail. You often need to add sleep commands or use systemd units that depend on other services to ensure proper ordering for complex setups.

The cloud-init logs are your best friend for debugging. They are typically located at /var/log/cloud-init.log and /var/log/cloud-init-output.log. The output log captures the stdout and stderr of the commands executed by cloud-init.

You’ve now provisioned a server that’s ready to serve. The next logical step is to manage multiple such servers as a cohesive unit, perhaps by integrating them into a load balancer or a configuration management system.

Want structured learning?

Take the full Digitalocean course →