How to use aws nlb with nginx ingress controller for ssl
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
Using an AWS Network Load Balancer in front of ingress-nginx is a common way to expose Kubernetes services with stable Layer 4 behavior and AWS-managed networking. The first design choice is where TLS should terminate, because the annotations and NGINX settings differ depending on whether decryption happens at the NLB or inside NGINX.
Pick One TLS Model First
There are two common models.
In the first model, the NLB terminates TLS with an ACM certificate and forwards plain HTTP to the ingress controller. This is simpler when you want certificate management in AWS.
In the second model, the NLB passes encrypted TCP traffic through to NGINX and NGINX terminates TLS using a Kubernetes secret. This keeps certificate handling inside the cluster.
Do not mix these models accidentally. Most broken setups come from configuring annotations for NLB termination while also expecting NGINX to receive raw TLS.
NLB TLS Termination With ingress-nginx
If you want the NLB to terminate TLS, the Service exposing ingress-nginx needs the AWS load-balancer annotations and an ACM certificate ARN.
A typical Service manifest looks like this.
In that configuration, the NLB accepts HTTPS on port 443, decrypts it, and forwards HTTP to the NGINX controller on port 80.
That means your application-level Ingress can stay simple.
TLS Passthrough or TLS at NGINX
If you want NGINX to terminate TLS instead, forward TCP and keep the NLB out of certificate management. Then create the TLS secret in Kubernetes and reference it from the Ingress.
This is the better model when you need NGINX-specific TLS features, custom certificate rotation inside the cluster, or end-to-end encryption all the way to the controller.
Client IP and Proxy Protocol Considerations
A common follow-up issue is losing the original client IP address. Depending on how traffic is forwarded, you may need the PROXY protocol enabled and the ingress-nginx controller configured to trust it.
If you enable proxy protocol on the AWS side, make sure the controller config matches. Otherwise, NGINX interprets the connection incorrectly and requests can fail in ways that look unrelated to TLS.
Also ensure your health checks are pointed at the controller's expected path and port. For many deployments, /healthz on the controller is the safest target.
Helm-Based Installation Pattern
Many teams deploy ingress-nginx with Helm and pass the annotations through values.
That keeps the AWS-facing configuration on the Service where it belongs, instead of scattering TLS concerns across unrelated Ingress resources.
Common Pitfalls
The biggest mistake is not deciding where TLS terminates. If the NLB terminates TLS, NGINX usually receives HTTP. If NGINX terminates TLS, the NLB should not also decrypt the connection.
Another mistake is setting the backend port wrong. In NLB termination mode, port 443 on the load balancer often forwards to port 80 on the controller.
A third issue is forgetting health checks, proxy protocol alignment, or ACM certificate region mismatches. Any of those can make the service look healthy from one layer and broken from another.
Finally, do not debug only the Ingress resource. With NLB-backed ingress, the Service annotations are often where the real problem lives.
Summary
- Decide first whether TLS terminates at the NLB or at NGINX.
- For AWS-managed certificates, use ACM and Service annotations on the
ingress-nginxcontroller Service. - In NLB termination mode, the controller often receives plain HTTP on port
80. - If NGINX terminates TLS, use Kubernetes TLS secrets and an Ingress
tlssection. - Keep health checks and proxy protocol settings aligned with the chosen model.
- Most SSL failures in this setup come from mixing two termination strategies unintentionally.
Related reading
- How to use AWS S3 CLI to dump files to stdout in BASH?
- How to use AWS SDK C XRay in a AWS Lambda Layer implemented in C called by a Lambda function in Python?
- How to use AWS SQS/SNS as a push notification queue for heavy processing tasks via PHP?
- How to use awscli inside python script?
- How to use ConfigMap configuration with Helm NginX Ingress controller - Kubernetes
- How to use Docker Image in ECR with AWS EKS
- How to use DynamoDB fine grained access control with Cognito User Pools?
- How to use helm with token based authentication system on EKS

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.