I'm encountering some unexpected routing behavior with my ECS Fargate setup, and I'm hoping to clarify whether this is typical. Here's what I have going on:
- I'm using a VPC that has both public and private subnets.
- There's an internet-facing Application Load Balancer (ALB) operating in the public subnets.
- My Fargate task, running NGINX, is located in the private subnets and doesn't have a public IP.
- I have a NAT Gateway in the public subnet to manage internet access.
- The ALB forwards HTTP traffic to the Fargate task on port 80, and the health checks for the task are passing, plus the security groups are wide open for testing.
The issue arises when I set the default route of the private subnet's route table to the NAT Gateway (0.0.0.0/0 to NAT Gateway). In this configuration:
- The Fargate task doesn't respond to requests from public clients accessing the ALB, leading to timeouts on web browsers or curl commands.
- However, the ALB's health checks work fine, and I can query the task internally.
When I switch the default route to the Internet Gateway (0.0.0.0/0 to Internet Gateway), here's what happens:
- Everything functions correctly, and the public clients can see the NGINX page, even without a public IP for the Fargate task.
From my tcpdump inside the task, I only observe traffic from the ALB's internal ENIs and no traffic from public clients when using the NAT Gateway.
My understanding is that the Fargate task should theoretically respond to the ALB, but it seems like the return traffic goes directly to the client's public IP via the NAT Gateway instead of going back through the ALB, causing issues with TCP flow.
So, is it standard for this situation with ALB + Fargate in private subnets and a NAT Gateway to behave like this? Why is the response path not routed through the ALB, and is the use of the IGW route just a risky workaround? Any suggestions on how to manage this without moving the task to a public subnet would be greatly appreciated!
2 Answers
Just a thought: are the private and public subnets possibly sharing a route table? If you're getting timeouts from both browsers and curl, it suggests that the requests aren't even reaching your ALB. When the ALB can’t connect to the Fargate task, you’d typically see a 503 Service Unavailable instead. Double-check that your routing tables are set up correctly — public and ALB traffic should go through the Internet Gateway, while your private/ECS routes should point to the NAT Gateway.
It sounds like you're dealing with some classic ALB and Fargate routing issues. The ALB maintains two connections: one with the client and another with your target (the Fargate task). When a request comes through the ALB, it effectively NATs the traffic to your task, meaning it manages the IP addresses. For your setup, since you're using the NAT Gateway as the default route for your private subnets, the return traffic from your Fargate task goes to the NAT Gateway, which can disrupt your connection. You don’t actually need a NAT Gateway for this connection; the Fargate task should respond directly to the ALB, and the ALB should then send the response back to the client. Try configuring it so your private subnet's route table doesn’t route through the NAT for that traffic. It should work as intended without that additional routing confusion!

Related Questions
How to Build a Custom GPT Journalist That Posts Directly to WordPress
Cloudflare Origin SSL Certificate Setup Guide
How To Effectively Monetize A Site With Ads