Ephemeral ports
Ephemeral Ports — Complete Deep Dive ⭐¶
What Are Ephemeral Ports?¶
When a client initiates any TCP/UDP connection, the OS automatically assigns a temporary high-numbered source port for that session. The server's response travels back to this port — not back to the server's own listening port.
Client OS assigns: source port = 54231 (ephemeral — random, temporary)
Client sends: 54231 → server:80 (HTTP request)
Server responds: server:80 → 54231 (HTTP response)
The response targets the client's ephemeral port, not port 80. Port 80 is only the destination of the request — not the return.
Ephemeral Port Ranges by OS ⭐¶
Different operating systems use different ranges:
| OS / Service | Ephemeral Port Range |
|---|---|
| Amazon Linux (EC2 default) | 32768 – 60999 |
| Linux (general kernel) | 32768 – 60999 |
| Windows Server 2008+ | 49152 – 65535 |
| Windows XP / Server 2003 | 1025 – 5000 (legacy) |
| macOS | 49152 – 65535 |
| AWS NAT Gateway | 1024 – 65535 (widest) |
| AWS ELB / ALB | 1024 – 65535 |
Safe AWS NACL rule (covers all clients):
Allow outbound TCP: 1024 – 65535
AWS recommends 1024–65535 in NACL outbound rules to safely cover all OS types, NAT Gateways, and Load Balancers.
Using a narrower range (e.g., 49152–65535 only) will break connections from Linux clients whose ephemeral ports fall in 32768–49151.
Stateful vs Stateless — Why Only NACL Needs This¶
| Security Group (Stateful) | NACL (Stateless) | |
|---|---|---|
| Tracks connection? | ✅ Yes — remembers the session | ❌ No — each packet evaluated alone |
| Return traffic? | Auto-allowed | Must add explicit outbound rule |
| Need ephemeral port rule? | ❌ No | ✅ Yes — mandatory |
Correct NACL Rule Set for Common Scenarios¶
Web Server (HTTP + HTTPS):
| Direction | Rule # | Action | Protocol | Port | Source/Dest |
|---|---|---|---|---|---|
| Inbound | 100 | ALLOW | TCP | 80 | 0.0.0.0/0 |
| Inbound | 110 | ALLOW | TCP | 443 | 0.0.0.0/0 |
| Outbound | 100 | ALLOW | TCP | 1024–65535 | 0.0.0.0/0 |
SSH Access:
| Direction | Rule # | Action | Protocol | Port | Source/Dest |
|---|---|---|---|---|---|
| Inbound | 200 | ALLOW | TCP | 22 | your-IP/32 |
| Outbound | 200 | ALLOW | TCP | 1024–65535 | your-IP/32 |
EC2 Initiating Outbound (e.g., calling an external API):
| Direction | Rule # | Action | Protocol | Port | Source/Dest |
|---|---|---|---|---|---|
| Outbound | 300 | ALLOW | TCP | 443 | 0.0.0.0/0 |
| Inbound | 300 | ALLOW | TCP | 1024–65535 | 0.0.0.0/0 |
When EC2 is the client, the ephemeral rule flips: outbound = specific port (443), inbound = ephemeral range (response comes back in).
The Two-Direction Mental Model¶
CLIENT side SERVER side
────────── ──────────
Request → src: ephemeral dst: 80/443/22/etc
NACL outbound: allow 443 NACL inbound: allow 443
Response ← dst: ephemeral ⚠️ src: 80/443/22/etc
NACL inbound: allow NACL outbound: allow
1024-65535 ⚠️ 1024-65535 ⚠️
Every NACL direction pair needs: - Specific port for the request - 1024–65535 for the ephemeral response
Common Debugging Scenario¶
Symptom: HTTPS works from browser to server — but server can't initiate
outbound calls to an external API.
Reason: NACL has outbound 443 allowed (request goes out)
but NACL inbound has no rule for 1024-65535
→ API response is blocked at the subnet boundary
Fix: Add NACL inbound rule: Allow TCP 1024-65535 from 0.0.0.0/0