This episode automates instance configuration: creating and managing SSH keypairs, sending cloud-init user data for automatic setup at boot, and understanding the 169.254.169.254 metadata service and config drive as its alternative.

In episode 4 you successfully created instances — but you were still touching VMs manually. In the cloud world, touching servers one by one is an anti-pattern. Instances should configure themselves at boot: hostname, user, SSH key, packages, and even running scripts. That's the job of cloud-init.
Episode 5 covers three things that work together: SSH keypairs for secure passwordless access, user data sent to cloud-init when an instance is born, and the metadata service and config drive as the channels for that information.
An SSH keypair allows you to log into instances without a password. The public key is stored in OpenStack; the private key stays on your machine. The easiest way — OpenStack generates the keypair itself:
openstack keypair create mykey > mykey.pem
chmod 600 mykey.pemopenstack keypair create mykey > mykey.pem redirects the private key to the mykey.pem file. Don't forget chmod 600 — if the permissions are too loose, SSH refuses to use the key.
You can also use a keypair you already own:
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N ""
openstack keypair create --public-key ~/.ssh/id_ed25519.pub mykeyOnce the keypair is registered, include --key-name when creating an instance:
openstack server create --image ubuntu-jammy --flavor m1.small \
--network private --key-name mykey ubuntu-vmcloud-init is the de-facto standard for initializing instances in the cloud. On an instance's first boot, cloud-init reads configuration from the metadata service, then performs: setting the hostname, creating users, injecting SSH keys, installing packages, and even executing scripts. All without a manual login.
User data is a script or configuration you attach when creating an instance. Create a file first:
cat > user-data.sh <<EOF
#!/bin/bash
set -euo pipefail
apt-get update
apt-get install -y nginx
echo "hello-openstack" > /var/www/html/index.html
systemctl enable nginx
EOFThe script above installs nginx and replaces the default page when the instance first boots.
Tip
Make sure user data starts with the #!/bin/bash shebang so cloud-init recognizes it as a script, not as cloud-config YAML. The cloud-config format is also supported and more declarative.
openstack server create --image ubuntu-jammy --flavor m1.small \
--network private --key-name mykey --user-data user-data.sh \
ubuntu-nginxopenstack server create --user-data user-data.sh sends the script to the metadata service. Wait a few minutes after the status becomes ACTIVE, then access it via a floating IP, which we'll learn in episode 7 — nginx should already be running.
Every instance can retrieve information about itself from the metadata service at the link-local address http://169.254.169.254/. This is the same address AWS uses — keeping cloud-init compatible across clouds.
curl -s http://169.254.169.254/openstack/latest/meta_data.jsonThe output of curl -s http://169.254.169.254/openstack/latest/meta_data.json is JSON containing the instance name, project, and more. Commonly used endpoints:
| Endpoint | Contents |
|---|---|
/latest/meta_data.json | Instance metadata |
/latest/user_data | The user data you sent |
/latest/network_data.json | Network configuration |
Not every environment provides DHCP metadata. The solution is the config drive — a small partition mounted into the instance as the CONFIG-2 or config-2 disk. Nova automatically writes user data and metadata to the config drive when the instance is created:
openstack server create --image ubuntu-jammy --flavor m1.small \
--network private --key-name mykey --config-drive true ubuntu-cfgInside the instance, the config drive contents can be read:
sudo mkdir -p /mnt/config
sudo mount /dev/vdb /mnt/config
ls /mnt/config--config-drive true guarantees user data is available even when DHCP is not working — a pattern often used in environments with strict networking.
Episode 5 turns your instances from "empty servers" into "automatically provisioned servers": SSH keypairs for secure passwordless access, cloud-init user data for provisioning at boot, and the metadata service and config drive as the information channels from the cloud to the instance.
Key takeaways:
http://169.254.169.254/ from inside the instance.In episode 6, we'll cover Neutron Networking Fundamentals — the SDN architecture with the ML2 plugin and mechanism drivers, the difference between provider networks and self-service networks, and the concepts of subnets and ports that form the foundation of all OpenStack networking. Prepare yourself, because the networking phase begins!