User-data Scripts
Custom AMI
Amazon Linux
Troubleshooting
Cloud Computing

User-data scripts is not running on my custom AMI, but working in standard Amazon linux

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

When user-data works on a standard Amazon Linux AMI but not on your custom AMI, the most likely issue is not the script text itself. The custom image often differs in one of three critical ways: cloud-init is missing or disabled, first-boot state was baked into the AMI, or the script is failing silently at boot. The fix is to verify the boot pipeline, not just the shell commands inside the script.

User Data Usually Runs Through cloud-init

On Amazon Linux images, user-data processing is typically handled by cloud-init. When an EC2 instance starts, cloud-init reads instance metadata, parses user data, and executes supported directives during the boot process.

That means a custom AMI can break user-data execution even if the script is valid, simply by changing the boot-time services or by preserving stale instance state from the machine that was used to create the image.

First Check Whether cloud-init Exists and Is Enabled

Start by confirming that the derived instance actually has the service installed and enabled.

bash
sudo systemctl status cloud-init
sudo systemctl status cloud-final
rpm -q cloud-init

If those services are missing, disabled, or failing at boot, user data will not run the way it did on the stock image.

Also inspect the configuration files.

bash
sudo ls /etc/cloud
sudo grep -R "user-data" /etc/cloud /etc/cloud/cloud.cfg.d

A custom AMI may include modified cloud-init settings that skip expected modules.

The Most Common Custom-AMI Mistake: Baking Old Instance State Into the Image

A very common failure happens when you create an AMI from an instance that has already completed its first-boot initialization. cloud-init stores state under /var/lib/cloud/. If that state is left in place when the image is created, new instances launched from the AMI may believe first-boot tasks have already run.

Before creating the AMI, clean that state on the source instance.

bash
sudo cloud-init clean
sudo rm -rf /var/lib/cloud/*

Then stop the instance and create the AMI. This is often the difference between a reusable image and an image that silently skips user data.

Read the Right Logs

Do not debug this blind. The boot logs usually tell you exactly where the failure occurred.

bash
sudo tail -n 200 /var/log/cloud-init.log
sudo tail -n 200 /var/log/cloud-init-output.log
sudo journalctl -u cloud-init -u cloud-final --no-pager

Look for:

  • syntax errors in the script
  • a missing interpreter in the shebang line
  • package manager failures
  • metadata access errors
  • a message showing that cloud-init considered initialization already complete

If the logs are empty, that is itself a clue that the service did not run.

Make the Script Self-Diagnosing

A short user-data script with explicit logging is much easier to debug than a large bootstrap file with no output redirection.

bash
1#!/bin/bash
2set -euxo pipefail
3exec > /var/log/user-data-debug.log 2>&1
4
5echo "user-data started"
6date
7id
8hostnamectl

If this minimal script does not produce /var/log/user-data-debug.log, the problem is the boot mechanism, not your application setup.

Confirm the AMI Still Matches the Expected Runtime

A custom AMI can diverge from standard Amazon Linux in subtle ways.

Examples include:

  • replacing the default shell or removing /bin/bash
  • disabling networking too early in boot
  • changing systemd targets or service ordering
  • hardening metadata access in a way that blocks instance initialization

That is why comparing packages and enabled services between the stock AMI and the custom AMI is often worthwhile.

Retest With a Minimal Launch Template

If the custom image still fails, reduce the launch configuration complexity.

Use:

  • a minimal user-data script
  • default networking
  • no extra bootstrap tooling
  • no dependency on external package repositories

Once the minimal case works, add your real setup back one piece at a time. This isolates whether the problem is in the AMI, the user data, or the surrounding infrastructure.

Common Pitfalls

  • Assuming the script text is wrong when cloud-init never ran at all.
  • Creating the AMI without cleaning /var/lib/cloud/ first.
  • Checking only the EC2 console output and ignoring cloud-init logs on the instance.
  • Using a user-data script without a shebang line or without explicit logging.
  • Making custom OS changes that disable or reorder the services responsible for first-boot initialization.

Summary

  • User-data on Amazon Linux usually depends on cloud-init.
  • Custom AMIs often fail because cloud-init is disabled, misconfigured, or carrying old first-boot state.
  • Clean cloud-init state before creating a reusable AMI.
  • Debug with /var/log/cloud-init.log, /var/log/cloud-init-output.log, and a minimal logged script.
  • If a stock AMI works and the custom one does not, inspect the image boot pipeline before rewriting the user-data script.

Course illustration
Course illustration

All Rights Reserved.