User data runs once at boot — the script that turns a bare instance into a running web server, wired in one property.
An instance boots from a machine image, but a stock Ubuntu image doesn't know it's supposed to be a web server. User data is a script AWS runs once, automatically, the first time an instance boots — the mechanism for turning a bare machine into whatever you actually needed it to be. The script itself is ordinary bash: install packages, query the instance metadata service for the instance's own ID/type/AZ (a real, live HTTP endpoint every instance can reach at 169.254.169.254, no credentials needed), and write out a status page.
Instance takes a userData prop directly. UserData.custom(script) wraps any raw script string exactly as-is — CDK handles the base64-encoding CloudFormation requires, so the script itself stays ordinary bash, not something CDK-specific.
On the right, BOOTSTRAP_SCRIPT is given — a script that installs Apache and reports the instance's own metadata. Wire it into the instance with userData: UserData.custom(BOOTSTRAP_SCRIPT), then run the synthesizer. UserData is a new name the starter doesn't import yet — add it to the existing multi-line import list from aws-cdk-lib/aws-ec2, alongside SecurityGroup, Peer, and Port.
Try this yourself: the scenario this whole concept opened with was two instances, in two separate Availability Zones, for redundancy. Nothing here stops you from constructing a second
Instancealongside the first, in the same VPC — CloudSynth's sandbox doesn't grade this (there's no second-instance assertion), but it's worth trying: it's exactly the shape of a real highly-available deployment, and the CDK change is smaller than you'd expect.
Locked
This exercise builds on Opening the security group for HTTP — run synth & validate there until every assertion passes, then this code will unlock.
Go to Opening the security group for HTTP