EC2 + Docker Bootstrap Script
Provision the server once, the same way, every time.
Overview
Same EC2 box — but instead of typing commands by hand, you hand AWS a bootstrap script (user-data) that installs Docker, Git, Nginx, and Certbot, then launches your app on first boot. This is your first taste of repeatability: spin up an identical server in one click.
Architecture
EC2 runs a user-data script on first boot that installs the runtime, starts your container, and configures Nginx as a TLS-terminating reverse proxy in front of it.
- 1You paste the bootstrap script into the instance's user-data field.
- 2On first boot, the script installs Docker, Nginx, and Certbot.
- 3The script starts your container on an internal port (e.g. 8080).
- 4Nginx terminates HTTPS on 443 and proxies to the container.
An EC2 instance boots and runs a user-data script; Nginx terminates TLS on port 443 and proxies to a Docker container on an internal port.
What you'll understand
- Use EC2 user-data to run a setup script automatically on first boot.
- Write an idempotent bootstrap script that installs a full runtime.
- Put Nginx in front of your container as a reverse proxy.
- Add free HTTPS with Certbot and Let's Encrypt.
Prerequisites
- Completed Level 0 (Manual EC2 + Docker)
- A domain name pointed at the instance (for TLS)(optional)
- Comfort reading a bash script
Generated files
The files this template produces. Copy any of them straight into your project.
2 files
Runs automatically on first boot to provision the whole server.
#!/usr/bin/env bash
set -euo pipefail
# --- Install runtime ---
dnf update -y
dnf install -y docker git nginx
systemctl enable --now docker nginx
# --- Run the app container on an internal port ---
docker run -d --name web \
-p 127.0.0.1:8080:80 \
--restart unless-stopped \
nginx:1.27-alpine
# --- Reverse proxy: Nginx -> container ---
cat >/etc/nginx/conf.d/app.conf <<'NGINX'
server {
listen 80;
server_name _;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
}
NGINX
nginx -t && systemctl reload nginx
echo "Bootstrap complete: $(date -u)" >/var/log/bootstrap-done.logStep-by-step guide
- 1
Write the bootstrap script
Take the generated user-data.sh. It's idempotent-ish: every fresh instance ends up in the same known state. Read it top to bottom so nothing is magic.
- 2
Launch with user-data
Launch a new t3.micro and paste the script into Advanced details → User data. AWS runs it as root on first boot.
User-data only runs on the FIRST boot by default — reboots won't re-run it.
- 3
Verify it provisioned itself
SSH in and confirm Docker, the container, and Nginx all came up without you touching them.
sudo cat /var/log/cloud-init-output.log | tail -n 40Shows what the user-data script actually did on boot.
docker ps && systemctl status nginx --no-pager - 4
Add HTTPS
Point a domain's A record at the public IP, then run the Certbot helper to get a free, auto-renewing TLS certificate.
sudo bash enable-tls.sh app.example.com you@example.comIssues a cert and rewrites Nginx to redirect HTTP→HTTPS.
AI insight
Ask the assistant to explain, review, or recommend — authored for this template.
What changed from Level 0
The server is the same, but you no longer touch it by hand. A user-data script runs once on first boot to install everything and start the app, and Nginx now sits in front of your container to terminate TLS and proxy requests in.
- —user-data = a script AWS runs as root on first boot.
- —Nginx = reverse proxy + HTTPS termination on 443.
- —Certbot = free, auto-renewing Let's Encrypt certificates.
Security notes
TLS is now handled
InfoCertbot gives you real HTTPS with automatic renewal — a genuine step up from Level 0.
User-data runs as root
MediumAnything in the script runs with full privileges, so a mistake or secret in it is dangerous.
Keep secrets out of user-data; later levels inject them via the pipeline.
Still a one-off server
LowThe script is repeatable, but networking, IAM, and the instance itself are still created by hand.
Level 2 captures all of that in Terraform.
Cost notes
EC2 t3.micro + public IPv4
Same free-tier footprint as Level 0 (~$7.50 + ~$3.60/month if left running).
Certbot / Let's Encrypt
Free. No cost for issuing or renewing certificates.
Cleanup guide
Tear it down when you're done — the fastest way to avoid a surprise bill.
- 1
Terminate the EC2 instance.
Billing - 2
Remove the DNS A record you created for TLS.
- 3
Delete the key pair and security group if unused.