Migrating from NGINX to AWS CloudFront Functions. Benefits, use cases, and DevOps insights
Serverless edge computing: How to migrate NGINX traffic to CloudFront Functions with Terragrunt.

NGINX vs. CloudFront Functions
If you’ve ever managed edge traffic with NGINX, you know the drill: endless CVE patches, container rebuilds, and delayed deployments. While NGINX is a powerful tool, maintaining it at scale can drain time and resources. In this article, we’ll walk you through what NGINX does, what CloudFront Functions bring to the table, and how the migration simplified our DevOps workflows with Terraform and Terragrunt. By the end, you’ll see why shifting from containers to serverless edge computing might be the upgrade your infrastructure needs.
What was our previous NGINX setup?
What is NGINX? NGINX is an open-source web server and reverse proxy widely used for load balancing, caching, and request routing. It’s extremely fast and flexible, but requires ongoing patching and maintenance. In our previous setup, NGINX was containerized and deployed either:
- As part of a Docker Compose stack on Docker Swarm running on EC2
- As a service on an AWS Fargate-powered ECS cluster.
Infrastructure was managed using Terragrunt, allowing us to keep configurations in code and deploy across multiple environments consistently.
NGINX was responsible for all the little – but vital – things that happen before a request hits the application server: path rewrites (like swapping /old-path/ for /new-path/), redirects for old API endpoints, host-based routing, and header manipulation. It worked, sure, but it felt like pushing a heavy cart uphill. The downsides were glaring:
While effective, this approach had several downsides:
- Security: Frequent CVE alerts flagged our NGINX version
- Operational Overhead: Managing Docker images, container orchestration, and rolling updates
- Deployment Delays: Changes required container rebuilds and ECS/Fargate task redeployments
Why migrate to AWS CloudFront Functions?
The goal was to migrate all edge logic managed by NGINX to AWS CloudFront Functions to achieve:
- Easier management of rewrite/redirect logic
- Quicker deployments using Terraform and Terragrunt
- Improved security posture by removing the need to patch and manage NGINX.
CloudFront Functions let you run lightweight JavaScript at the CDN edge, during the viewer request or viewer response phase. This enables ultra-low-latency routing and transformation without managing servers or containers.
The benefits are clear as a bell: no infrastructure to manage, global propagation in seconds, and it's fully integrated with your existing CloudFront distributions. It’s a real game-changer for simple edge use cases.
Read also: Combinati - next level dPCR
Managing CloudFront Functions with Terraform and Terragrunt
Just like with NGINX, we kept everything in infrastructure-as-code. Using Terraform and Terragrunt, we can:
- Version-control every single one of our CloudFront Functions.
- Deploy consistently across development, staging, and production environments.
- Roll back quickly if something goes sideways.
This setup makes sure we treat the edge logic itself as code. It ensures complete traceability – you always know who changed what and when – and it drastically cuts down on human errors.
Our Terragrunt structure looks something like this:
# terragrunt.hcl
inputs = {
cloudfront_functions = [
{
name = "rewrite_old_path"
runtime = "cloudfront-js-1.0"
handler = "handler"
code = file("../functions/rewrite_old_path.js")
trigger = "viewer-request"
}
]
}
Practical use cases: Migrating common NGINX rules to CloudFront Functions
Let’s break down how some of the most common NGINX configurations translate into CloudFront Functions. This will give you a clear picture of what the migration looks like in practice.
Use Case 1: Path Rewrite
This is arguably the most common task. NGINX lets you use a powerful, if sometimes cryptic, rewrite directive.
Previous NGINX Configuration:
location /old-path/ {
rewrite ^/old-path/(.*)$ /new-path/$1 permanent;
}
Equivalent CloudFront Function:
function handler(event) {
const request = event.request;
if (request.uri.startsWith('/old-path/')) {
request.uri = request.uri.replace(/^\/old-path\/(.*)/, '/new-path/$1');
}
return request;
}
Use Case 2: API Version Redirect
You often need to send users from an old API version to a new one, telling the browser the change is permanent.
Previous NGINX Configuration:
location /api/v1/ {
return 301 /api/v2/$request_uri;
}
Equivalent CloudFront Function:
function handler(event) {
const { uri } = event.request;
if (uri.startsWith('/api/v1/')) {
return {
statusCode: 301,
statusDescription: 'Moved Permanently',
headers: {
location: { value: uri.replace(/^\/api\/v1\/(.*)/, '/api/v2/$1') },
},
};
}
return event.request;
}
Use Case 3: Host-Based Routing
NGINX handles this with multiple server_name and proxy_pass blocks. It’s a fine approach, but it keeps that complexity locked inside your container.
Equivalent CloudFront Function:
function handler(event) {
const request = event.request;
const host = request.headers['host'].value;
if (host === 'us.example.com') {
request.origin = {
s3: { domainName: 'us-bucket.s3.amazonaws.com', region: 'us-east-1' },
};
} else if (host === 'eu.example.com') {
request.origin = {
s3: {
domainName: 'eu-bucket.s3.eu-west-1.amazonaws.com',
region: 'eu-west-1',
},
};
}
return request;
}
Benefits observed after NGINX migration
After migrating to CloudFront Functions, the results were immediate and substantial. We got a huge boost in operational effectiveness.
- Faster deployments – Edge logic updates now take mere seconds. We completely eliminated the wait time for container builds and image pushes.
- Lower maintenance – We no longer spend time patching containers or keeping NGINX versions up to date. That's a zero-cost win for the team.
- Improved security – Our security scans are clean. We removed the entire NGINX attack surface, eliminating alerts related to its CVEs.
- Infrastructure simplification – We were able to decommission several old NGINX services. Less running means less to worry about.
- Unified IaC – Every routing rule is now version-controlled and deployed consistently using Terraform. This makes our entire edge architecture repeatable and traceable.
From heavy containers to lightweight edge logic
Migrating NGINX responsibilities to CloudFront Functions has streamlined our operations, improved security, and accelerated deployment cycles. By managing everything in Terraform and Terragrunt, we achieved a repeatable, trackable, and low-maintenance edge architecture. If your stack still relies on NGINX for edge routing and rewrites, this approach could simplify your setup significantly while eliminating common maintenance and security headaches.
At Kellton Europe, we help organizations modernize their cloud infrastructure with scalable, secure, and cost-efficient architectures. Get in touch with our cloud experts and let’s design an edge solution that works for your business.
FAQ
Why migrate from NGINX to AWS CloudFront Functions?
CloudFront Functions eliminate the need to manage NGINX servers, improving deployment speed, scalability, and security – all while running lightweight JavaScript at the edge.
What are the main advantages of CloudFront Functions over NGINX?
They remove infrastructure overhead, deploy globally within seconds, and integrate seamlessly with AWS services. No container patching or maintenance required.
How do CloudFront Functions improve DevOps workflows?
By combining Terraform and Terragrunt, teams can manage configurations as code, automate deployments, and make edge updates faster and more reliable.
Can CloudFront Functions replace all NGINX use cases?
Not entirely. They’re ideal for routing, redirects, and header rewrites, but for complex reverse proxy logic or caching strategies, Lambda@Edge or NGINX on EC2/Fargate may still be needed.
Maciej Piesio
DevOps Engineer
Maciej Piesio is a DevOps engineer focused on AWS and Kubernetes. With roots in Linux administration and experience across multiple cloud platforms, he builds scalable, reliable systems through automation and clean infrastructure design.

Sebastian Spiegel
Backend Development Director
Inspired by our insights? Let's connect!
You've read what we can do. Now let's turn our expertise into your project's success!