NGINX Out, ALB In - 70% Cheaper Redirects with Zero Servers
Before jumping into the why and how, here’s what we achieved:
✅ Replaced a single point of failure with AWS-native components
💸 Reduced monthly costs by 70%
🧑💻 No more SSH, servers, or NGINX restarts
🔐 Fully managed SSL with ACM
🛠️ Everything codified and versioned via Terraform
Why we left EC2 + NGINX behind (and how much it saved us)
We had a simple goal: redirect traffic for over 70 different domains.At first, we solved it with what we knew — an EC2 instance running NGINX with hardcoded
301 and 302 rules. It worked… until it didn’t.What started as a quick fix became an operational headache:
- Any new redirect meant SSH access and manual file editing
- Restarting NGINX came with downtime risks
- A single typo could break everything
- Most importantly: we were maintaining a full server just to handle redirects
Eventually, we asked ourselves: isn’t this just a glorified spreadsheet with SSL and uptime issues?
That question led us to redesign the whole setup using ALB, Terraform, ACM, and nothing else.
And it worked — spectacularly.
💰 EC2 vs ALB: The Cost of Simplicity
| ❌ EC2 + NGINX | ✅ ALB + Terraform | |
|---|---|---|
| Cost | ~$73/mo | ~$22.50/mo |
| Access | SSH/SSM required | No SSH/SSM ever |
| SSL | Manual setup | Auto SSL (ACM) |
| Maintenance | Manual file editing | Fully versioned in Terraform |
| Scalability | Single point of failure | Fully scalable rules |
| Downtime | NGINX restarts cause downtime | Zero downtime on rule changes |
That’s a ~70% reduction, with zero servers to maintain and full scalability.
🛠 The New Setup: ALB + Terraform + SSL + Logs
Once we made the switch, we wanted the entire solution to be automated, secure, and easy to maintain. Here’s what we built:
📊 Visual Overview: How the Flow Works
Sometimes it’s easier to understand this type of infrastructure visually. Here’s a high-level diagram that shows how user requests travel through Route 53, the ALB, and how redirect behavior is handled:

This shows:
- What happens when someone accesses a random or known domain
- How Route 53 routes requests to the ALB
- The difference between traffic arriving on port 80 and port 443
- What the ALB does when no matching redirect rule is found (default 404)
🔧 Components Used
- ALB (Application Load Balancer): Handles all HTTP/HTTPS requests
- Redirect Listener Rules: Define what gets redirected and where
- Route 53: Hosted Zones already managed all our domain DNS
- AWS ACM: For issuing and auto-renewing SSL certificates
- Access Logs: Enabled and pushed to S3 for auditing
- Terraform: Used to define everything as code
- Modules: We used Anton Babenko’s modules for
albandacm
🔐 Managing SSL Certificates with ACM
We used ACM (AWS Certificate Manager) to request certificates per domain, with auto-renewal enabled. Since we had all domains in Route 53, validation was done automatically via DNS — no manual setup needed.
Code:
module "acm" {
source = "terraform-aws-modules/acm/aws"
version = "~> 4.0"
domain_name = "example.com"
subject_alternative_names = ["www.example.com"]
zone_id = data.aws_route53_zone.main.zone_id
validate_certificate = true
}
🌐 ALB Listener Rules + Redirects
We implemented two listeners:
Port
80(HTTP): Redirects everything to HTTPSPort
443(HTTPS): Processes redirect rules (up to 100 max), default action is404
Code:
module "redirect_alb" {
source = "terraform-aws-modules/alb/aws"
version = "9.12.0"
name = "redirect-alb"
load_balancer_type = "application"
internal = false
vpc_id = aws_vpc.main.id
subnets = [aws_subnet.public_a.id, aws_subnet.public_b.id]
access_logs = {
bucket = aws_s3_bucket.alb_logs.bucket
enabled = true
prefix = "alb-access"
}
create_security_group = true
security_group_ingress_rules = {
http = {
from_port = 80
to_port = 80
ip_protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
https = {
from_port = 443
to_port = 443
ip_protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
http_listeners = [
{
port = 80
protocol = "HTTP"
action = {
type = "redirect"
redirect = {
port = "443"
protocol = "HTTPS"
status_code = "HTTP_301"
}
}
}
]
https_listeners = [
{
port = 443
protocol = "HTTPS"
certificate_arn = module.acm.certificate_arn
rules = [
{
priority = 10
actions = [{
type = "redirect"
redirect = {
host = "www.example.com"
status_code = "HTTP_301"
protocol = "HTTPS"
}
}]
conditions = [{
host_header = {
values = ["old-domain.com"]
}
}]
},
{
priority = 20
actions = [{
type = "redirect"
redirect = {
host = "www.blog.example.com"
path = "/blog"
status_code = "HTTP_301"
protocol = "HTTPS"
}
}]
conditions = [{
host_header = {
values = ["legacy-blog.net"]
}
}]
}
]
default_action = {
type = "fixed-response"
fixed_response = {
content_type = "text/plain"
message_body = "Not Found"
status_code = "404"
}
}
}
]
}
✨ Why This Worked for Us
✅ Fully serverless — no EC2 to maintain✅ ~70% cost savings
✅ All redirects are version-controlled in Terraform
✅ SSL certificates managed automatically (with renewals) via ACM
✅ Access logs enabled for auditing
✅ Default rule returns 404 to avoid exposing internal details
✅ Port 80 cleanly redirects to HTTPS (443)
✅ Ready to integrate with WAF or CloudWatch in the future
✅ Everything is Infrastructure-as-Code, ready for CI/CD pipelines
❌ What We Didn’t Use (And Why)
- Lambda@Edge – great for complex logic at scale, but overkill for simple 301s.
- CloudFront Functions – less Terraform support, more limits.
- S3 Static Hosting – no built-in SSL unless fronted by CloudFront.
In the end, simplicity won. ALB covered 100% of our use case — no Lambda, no CloudFront needed.
📌 Scaling Tip
AWS ALB supports up to 100 listener rules per listener.
If you need more, consider:
• 🧩 Use multiple listeners (e.g., different ports or multiple ALBs)
• 🚀 Move to CloudFront Functions or Lambda@Edge for large-scale redirects
• 🗂️ Group redirects using wildcard domains or path patterns
Plan your redirect strategy early to avoid scaling bottlenecks later.
💡 Lessons Learned
- Keep infrastructure as simple as the problem requires — NGINX was overkill for redirects.
- ALB rules are powerful, but don’t scale infinitely. Plan limits early.
- Terraform made experimentation and rollback safe and auditable.
- Relying on managed services like ACM for SSL removed 90% of the ops burden.
In short, we turned a fragile EC2 setup into a robust serverless system — saving money, effort, and future headaches.
🙋♂️ Need Help With This?
Considering a similar migration or want to simplify your redirect setup?
We’ve migrated this same pattern across multiple AWS accounts — and the ops team never looked back.
💬 Let’s chat on LinkedIn — happy to help or exchange ideas.
