Skip to main content
This guide demonstrates how Network ACLs (NACLs) work in AWS and how they differ from security groups. It also shows a reproducible way to test NACL behavior by making security groups permissive so that the NACL is the only firewall affecting traffic.

Key differences (at a glance)

  • Security groups: stateful, operate at the instance/resource level, only support allow rules.
  • NACLs: stateless, operate at the subnet level, support allow and deny rules, and evaluate rules top‑down by rule number.
For more background, see the AWS documentation: Network ACLs and Security Groups.

Step 1 — Make security groups permissive (so NACLs are what you test)

Temporarily change the security groups for your EC2 instances to be permissive (allow all inbound and outbound traffic). This ensures the security group does not block anything and the NACL becomes the effective traffic filter.
A screenshot of the AWS EC2 Management Console on the "Change security groups" page, showing instance details and a dropdown list of available security groups (e.g., allow-http-sg, webserver-sg). The dialog includes options to add security groups and Save or Cancel the changes.
Set the instances to a single permissive security group (for example, webserver-sg) and edit that group’s inbound and outbound rules to allow all traffic.

Step 2 — Confirm both instances are on the same subnet

NACLs are applied to subnets. If both instances are in the same subnet, the same NACL rules will apply to both.
A screenshot of the AWS EC2 Management Console showing two running t2.micro instances (server-2 and server1). The server1 instance is selected and its networking details are shown, including public IPv4 3.82.5.183 and private IPv4 10.1.1.82.

Step 3 — Edit the subnet’s Network ACL rules

  1. Open the VPC console → Security → Network ACLs.
  2. Select the ACL associated with the subnet that contains your instances.
  3. Remember: rules are evaluated top‑down by rule number. An explicit Deny with a lower rule number will be matched before a later Allow.
Start by modifying inbound rules to allow only SSH (TCP port 22) and leave other protocols implicitly denied by the default catch‑all deny at the bottom. Because NACLs are stateless, you must also add matching outbound rules to allow return traffic (or vice versa). Practical notes:
  • If you allow inbound SSH (22), add outbound rules that permit the ephemeral port range (typically 1024–65535) so the SSH session can establish return traffic.
  • If you allow outbound HTTP/HTTPS, add inbound rules to permit the ephemeral return ports for responses.
Try SSH to confirm connectivity:
Typical successful ping output (when ICMP is allowed):
Because both instances are on the same subnet, SSH and other allowed traffic should behave the same for both.

Step 4 — Allow HTTP/HTTPS for your web server

Add inbound rules to permit HTTP (TCP 80) and HTTPS (TCP 443) so that web traffic reaches your instance. When adding them, give them rule numbers that place them after your SSH rule if you want SSH evaluated first. The VPC console will display the inbound rules and the final DENY catch‑all.
A screenshot of the AWS VPC console showing the Network ACLs page, listing several ACLs and their associations. The lower panel displays inbound rules (SSH 22, HTTP 80, HTTPS 443 allowed and a catch‑all deny) for the selected ACL.
After adding HTTP/HTTPS allows, your website should be reachable by browsing the instance’s public IP (assuming a web server is installed and running).

Troubleshooting package downloads and ephemeral ports

If a server doesn’t yet have a web server (for example, server two), try installing NGINX. You may see downloads hang or ping fail if the NACL does not permit return traffic on ephemeral ports. Failing ping example when NACL blocks return traffic:
A package manager stall example (downloads stuck at 0 B/s):
Why this happens:
  • NACLs are stateless. If you permit outbound HTTP(S) for package downloads, the inbound responses from remote servers use ephemeral ports (client-side ports typically in the 1024–65535 range). If inbound rules do not explicitly permit those ephemeral return ports, the responses will be dropped.
Temporary fixes:
  • Add an inbound rule that allows the ephemeral port range 1024–65535 (recommended over allowing all).
  • As a short-term measure, you can add an inbound “allow all” rule (e.g., rule number 130) to let downloads complete, then tighten rules afterward.
After permitting the necessary return traffic, the installation should complete:
Start NGINX:
Verify the site from a browser — you should see the default NGINX welcome page.
A web browser window showing the default "Welcome to nginx!" landing page, indicating the nginx web server is installed. Several browser tabs and an IP address are visible in the address bar.
After installation, remove any temporary overly-permissive rules and rely on the explicit inbound/outbound rules you need (for example, SSH, HTTP, HTTPS plus ephemeral return ports where applicable).
NACLs are stateless: you must explicitly add matching rules for both inbound and outbound traffic (or otherwise permit return traffic). Security groups are stateful and automatically allow return traffic for permitted connections.

Example: using explicit Deny rules with NACLs

NACLs support explicit Deny rules, which security groups do not. Because rules are evaluated by ascending rule number, a Deny with a lower number will override a later Allow. Example use case:
  • Deny SSH from a specific CIDR block (lower rule number).
  • Allow SSH from other sources (higher rule number).
A screenshot of the AWS VPC Network ACLs console showing a list of network ACLs and their associated VPC/subnets. The lower pane displays inbound rules (SSH, HTTP, HTTPS, all traffic) with port ranges, sources and Allow/Deny icons.

Summary checklist

  • Confirm security groups are permissive while testing NACLs so security groups do not interfere.
  • Remember NACL evaluation order: lower rule numbers are evaluated first.
  • For any allowed outbound traffic, explicitly allow inbound return traffic (ephemeral ports) as NACLs are stateless.
  • Use Deny rules in NACLs when you need to explicitly block traffic at the subnet level.
Further reading and references:

Watch Video