Building a Fully Automated DevOps Lab on AWS with Nginx
In this post, I'll walk you through setting up a complete DevOps lab on AWS using EC2, Nginx, and GitHub Actions for CI/CD. This is perfect for anyone wanting hands-on experience with environment separation, automated deployments, and production-grade configurations.
Project Overview
We are hosting a static site on an EC2 instance with Nginx. The key features include:
- Automated CI/CD using GitHub Actions and AWS SSM
- Separate production and staging environments
- Security best practices for a public-facing site
Environments:
-
Production:
/usr/share/nginx/html/DevOps/current -
Staging:
/usr/share/nginx/html/DevOps-staging
Environment Setup
EC2 Setup:
- OS: Amazon Linux 2
- Nginx installed from the package manager
- Runs as non-root user
nginx - Directories:
/usr/share/nginx/html/DevOps/current # production
/usr/share/nginx/html/DevOps-staging # staging
- Set proper permissions:
sudo chown -R ec2-user:ec2-user /usr/share/nginx/html/DevOps*
Git & Branching
We follow a simple branching strategy:
- Main branch: production-ready code
- Feature branches: work on new features
Example:
git checkout -b feature/add-header
Merge to main after testing in staging. Production deploys are triggered only on tags:
on:
push:
tags:
- "v*.*"
CI/CD Pipeline
GitHub Actions workflow automates deployment:
- Checkout code
- Configure AWS credentials
- Deploy via AWS SSM:
aws ssm send-command \
--targets "Key=InstanceIds,Values=<EC2-ID>" \
--document-name "AWS-RunShellScript" \
--parameters '{"commands":["cd /usr/share/nginx/html/DevOps/current","git pull origin main","sudo systemctl reload nginx"]}'
Production deploys happen only on tags; staging can be deployed manually or via a branch workflow.
Nginx Configuration
Main Server Block:
- Serves
/DevOps/current - Listens on HTTP 80 (HTTPS optional)
-
Security:
- Disable directory listing
- Limit HTTP methods to GET/HEAD
- Block hidden files
- Add security headers
- Cache static assets (
/styles/)
Monitoring endpoint
/nginx_statusrestricted to localhost
Staging Server Block:
- Serves
/DevOps-staging - Optional port 8080 or subdomain
staging.example.com
Environment Separation
| Environment | Directory | Branch/Deployment |
|---|---|---|
| Production | /DevOps/current |
main branch + tag deployment |
| Staging | /DevOps-staging |
feature branches, manual testing |
Monitoring & Logs
- Nginx logs:
/var/log/nginx/access.log&/error.log - Stub status:
/nginx_statusrestricted to localhost - Optional: integrate Prometheus/Grafana or AWS CloudWatch
Security Quick Wins
Nginx:
- Enable HTTPS and security headers
- Limit HTTP methods
- Block hidden files
- Cache static assets
OS:
- Run Nginx as non-root user
- Limit SSH access via security groups
- Keep the system updated
CI/CD:
- Secrets stored securely in GitHub Actions
- Only tag-based deployments
Monitoring:
- Restrict
/nginx_statusto localhost - Monitor logs regularly
Commands Reference
Check Nginx config:
sudo nginx -T
sudo nginx -t
Reload Nginx:
sudo systemctl reload nginx
Git workflow:
git add -A
git commit -m "message"
git push origin main
git tag v1.0.1
git push origin v1.0.1
Deployment: fully automated via GitHub Actions & AWS SSM
Next Steps / Recommendations
- Add HTTPS with Let’s Encrypt
- Automate staging deployments via branch workflows
- Integrate monitoring dashboards (Prometheus/Grafana)
- Implement rollbacks using symlinked releases (
current)
This setup gives you a production-ready DevOps lab, complete with CI/CD, environment separation, monitoring, and basic security. You can now experiment, extend, and even turn this into a learning playground for more advanced DevOps practices.
Top comments (0)