Launcher Products Bitnami Documentationimaxe CLI Blog Contact

cloud-init and user-data: configure your instances at boot like a pro

A golden AMI handles what is stable; cloud-init handles what changes. Mastering user-data and cloud-init is what lets you use one image in a thousand scenarios without rebaking it. Here is the practical guide.

Laptop showing a system update in a terminal
Laptop showing a system update in a terminal Photo: Solijon Solayev · CC BY-SA 4.0 · Wikimedia Commons

cloud-init is the de facto standard for initialising cloud instances during their first boot. When you launch an instance and pass it a user-data script, it is cloud-init that interprets and runs it: it creates users, writes files, installs packages, mounts disks or starts services.

The ideal combination is clear: the golden AMI holds what does not change —operating system, runtime, hardening— and user-data supplies what varies by environment or instance: configuration, injected secrets, role. That way you reuse a single image across many contexts.

Two ways to write user-data

user-data accepts several formats; the two most common are the shell script and cloud-config.

  • Shell script: starts with #!/bin/bash. Simple and direct for quick tasks.
  • cloud-config: starts with #cloud-config and uses declarative YAML. Cleaner, more readable and more idempotent for configuring users, packages, files and commands.

A cloud-config example

A typical #cloud-config declares sections such as packages: (packages to install), write_files: (configuration files), runcmd: (final commands) and users: (accounts and keys). Being declarative, it is easier to review and maintain than a long script.

Best practices

  • Keep user-data small: if it grows too much, that probably belongs baked into the AMI.
  • Idempotence: design the commands so that re-running them breaks nothing.
  • Never put secrets in the clear in user-data: it is readable from the instance metadata. Inject them from Secrets Manager, Parameter Store or Vault at runtime.
  • Protect metadata access: use IMDSv2 to mitigate credential theft via SSRF.
  • Log and debug: the cloud-init logs (/var/log/cloud-init-output.log) are your best friend when something fails.

Baking or booting: where each thing goes

Goes in the AMI (baking)Goes in user-data (booting)
Operating system and patchesEnvironment-specific configuration
Runtime, agents and hardeningPer-instance variables and parameters
Stable, heavy softwareCluster registration and discovery
Anything slow to installRuntime secret injection

Golden rule: what is stable and slow gets baked; what is variable and light goes at boot.

Common mistakes that cost hours

  • Putting into user-data what should be in the image, which yields slow, fragile boots.
  • Exposing secrets in plain text in the metadata.
  • Assuming user-data re-runs on every boot: by default it only runs on the first one.
  • Not checking cloud-init logs when the instance “does not do what it should”.

Frequently asked questions

Does user-data run on every reboot?

By default, only on the first boot. You can configure cloud-init to run certain parts on every boot, but do it deliberately and idempotently.

Is it safe to pass passwords in user-data?

No. user-data is readable from the instance metadata. Use a secrets manager and inject them at runtime, and protect the metadata with IMDSv2.

Does cloud-init only work on AWS?

No. cloud-init is cross-platform and works on AWS, Azure, GCP and others, which makes it ideal for automating boot in a portable way.

At imaxe.cloud we design images meant to be combined with cloud-init, so that a single AMI serves you across many scenarios.

cloud-inituser-dataec2bootstrappingimdsv2
IM

imaxe team

We build and maintain the catalog AMIs. When we publish a version, we run it in production before anyone else.

From the catalogue

AMIs related to this article

Keep reading

Related articles