"It Didn't Work."
You launched the instance, waited five minutes, SSH'd in, and Nginx isn't running. Or the deploy user doesn't exist. Cloud-init is verbose — it logs almost everything. The challenge is knowing which log to read.
The two critical log files:
/var/log/cloud-init.log
This is cloud-init's internal debug log. It records every decision cloud-init made: which datasource it found, which modules it ran, whether YAML parsing succeeded, and the exit code of every command. Grepping it for warnings, errors, and tracebacks surfaces, respectively, a non-fatal skipped module, something that broke inside cloud-init itself, or YAML that failed schema validation.
/var/log/cloud-init-output.log
This captures the stdout and stderr of everything cloud-init executed — your shell scripts, runcmd commands, and package manager output. If a package install failed because of a lock file or a missing package name, the error message is here.
Checking overall status:
The cloud-init status --long command reports done on success, with a detail field naming the datasource, or error, in which case detail points to the specific module that failed.
A systematic debugging workflow:
Start with the overall status for the high-level verdict, then grep the internal log for errors and tracebacks, then tail the output log for the actual command failures. Finally, querying cloud-init for the user-data it actually received is invaluable for confirming your launch configuration delivered what you intended, rather than something malformed or empty.