How to Configure an Extended ACL on Cisco (with Examples)
An extended ACL filters on source AND destination address, protocol, and port — far more precise than a standard ACL. Two rules to remember: place an extended ACL close to the SOURCE, and account for the invisible deny ip any any at the end.
Part of the Access Control Lists (ACLs) learning hub
Step 1 — Write the ACL
This named extended ACL lets the 192.168.10.0/24 subnet reach any web server (TCP 80 and 443) and blocks everything else. Order matters: the router checks lines top-down and stops at the first match, so put specific permits before broader denies.
You don't have to type the final deny ip any any — it's implicit — but writing it makes the intent explicit and lets you see hit counts on denied traffic.
R1(config)# ip access-list extended WEB-ONLY
R1(config-ext-nacl)# permit tcp 192.168.10.0 0.0.0.255 any eq 80
R1(config-ext-nacl)# permit tcp 192.168.10.0 0.0.0.255 any eq 443
R1(config-ext-nacl)# deny ip any anyStep 2 — Apply it in the right direction
Apply an extended ACL inbound on the interface closest to the source, so unwanted traffic is dropped before it crosses the router. Here that's the interface facing the 192.168.10.0/24 hosts.
R1(config)# interface gigabitethernet0/0
R1(config-if)# ip access-group WEB-ONLY inStep 3 — Verify
show access-lists shows each line with a hit counter, so you can confirm the right traffic is matching; show ip interface confirms the ACL is applied in the direction you intended.
R1# show access-lists WEB-ONLY
R1# show ip interface gigabitethernet0/0Common mistakes (and the fix)
The usual ACL bugs: applying it in the wrong direction; placing an extended ACL near the destination (that's the rule for STANDARD ACLs); a broad permit or deny above a more specific line that shadows it; and an off-by-one wildcard mask. Test with the actual traffic and watch the hit counts.
A Fully Worked Example: Locking Down a Branch Office
Say R1 sits between a branch LAN (10.20.30.0/24) on GigabitEthernet0/1 and the WAN toward HQ and the internet on GigabitEthernet0/0. The requirement is that branch hosts may reach any web server (TCP 80 and 443) and resolve DNS (UDP and TCP 53), and receive the replies, but nothing else may leave the LAN. Because extended ACLs belong close to the source, this list is applied inbound on Gi0/1 — the LAN-facing interface — so junk traffic is dropped the moment it enters the router.
The key insight that makes this clean is direction. Applied inbound on Gi0/1, the ACL only ever inspects LAN-to-WAN packets; the replies come back inbound on Gi0/0, which has no ACL, so they are never checked. That is precisely why the 'near the source, inbound' rule is so convenient: you filter one direction of the conversation and never have to reason about return traffic or the 'established' keyword at all. DNS gets two lines because resolvers use UDP 53 for normal queries and fall back to TCP 53 for large responses and zone transfers.
The final deny ip any any is written explicitly with the log keyword. It is functionally identical to the implicit deny, but now every dropped packet generates a syslog message, which turns 'something on the LAN can't reach a service' from guesswork into a one-line answer.
R1(config)# ip access-list extended BRANCH-OUT
R1(config-ext-nacl)# permit tcp 10.20.30.0 0.0.0.255 any eq 80
R1(config-ext-nacl)# permit tcp 10.20.30.0 0.0.0.255 any eq 443
R1(config-ext-nacl)# permit udp 10.20.30.0 0.0.0.255 any eq 53
R1(config-ext-nacl)# permit tcp 10.20.30.0 0.0.0.255 any eq 53
R1(config-ext-nacl)# deny ip any any log
R1(config-ext-nacl)# exit
R1(config)# interface gigabitethernet0/1
R1(config-if)# ip access-group BRANCH-OUT inVerifying and Troubleshooting with Hit Counters, Logging, and Sequence Numbers
show access-lists prints a per-line match counter, and reading it correctly is most of ACL troubleshooting. A counter that climbs proves traffic is reaching the interface in the direction you applied the list; a counter stuck at zero usually means one of three things — the traffic never arrives on that interface, you applied the ACL in the wrong direction, or a broader line above it is matching first and shadowing it. Before a test, run clear ip access-list counters BRANCH-OUT so you are reading fresh numbers instead of accumulated history.
The log keyword (and its richer cousin log-input, which also records the ingress interface and source MAC address) makes the router emit a syslog message whenever a line matches. Attached to the trailing deny, it tells you exactly what the implicit deny would otherwise swallow silently. Logging is rate-limited and process-switches the matching packets, so it costs CPU — enable it to diagnose a problem, then remove it once you have your answer rather than leaving it on a production edge router.
Because named ACLs auto-number in increments of 10, you can maintain the list surgically. Insert a rule between existing lines by giving it an in-between sequence number, delete a single rule with 'no <seq>', and if you have exhausted the gaps, ip access-list resequence renumbers the whole list so you can keep inserting. show access-lists always displays the live sequence numbers, so it is your reference for both editing and confirming the order the router evaluates top-down.
R1# show access-lists BRANCH-OUT
Extended IP access list BRANCH-OUT
10 permit tcp 10.20.30.0 0.0.0.255 any eq www (245 matches)
20 permit tcp 10.20.30.0 0.0.0.255 any eq 443 (1032 matches)
30 permit udp 10.20.30.0 0.0.0.255 any eq domain (88 matches)
40 permit tcp 10.20.30.0 0.0.0.255 any eq domain (0 matches)
50 deny ip any any log (17 matches)
R1# clear ip access-list counters BRANCH-OUT
R1# configure terminal
R1(config)# ip access-list extended BRANCH-OUT
R1(config-ext-nacl)# 15 permit tcp 10.20.30.0 0.0.0.255 any eq 8080
R1(config-ext-nacl)# no 40
R1(config-ext-nacl)# exit
R1(config)# ip access-list resequence BRANCH-OUT 10 10Frequently asked questions
Standard vs. extended ACL — which one do I use, and why are they placed differently?
A standard ACL matches on source address only, so you place it close to the destination to avoid blocking that source from reaching everything else; an extended ACL matches source, destination, protocol, and port, so you place it close to the source to drop unwanted traffic before it consumes bandwidth. Use standard (numbered 1-99 or 1300-1999) for simple 'who can reach this device' rules and extended (100-199 or 2000-2699) whenever the decision depends on a service or destination. If you only need to control which hosts reach one router or VTY line, standard is enough.
After I applied the ACL, DNS and ping stopped working too — why is everything else blocked?
Every ACL ends with an invisible deny ip any any, so a list that only permits TCP 80 and 443 silently drops DNS, ICMP, NTP, and everything else. A 'web-only' ACL is doing exactly what you told it — you have to add explicit permit lines for any other service the hosts still need. Add a temporary deny ip any any log line to see in syslog what is actually being dropped.
My ACL permits outbound web traffic but the connection still fails — what about the replies coming back?
IOS ACLs are stateless, so permitting a flow in one direction does not automatically allow the return packets; if an ACL also filters the reverse direction, the replies hit the implicit deny. Either filter only the source-to-destination direction (inbound on the interface closest to the source, leaving the return path un-filtered), or add a permit line using the 'established' keyword, which matches only TCP segments with the ACK or RST bit set. The 'established' trick works for TCP only, not UDP or ICMP.
How do I insert or remove a single line without deleting and retyping the whole ACL?
Named extended ACLs (and modern numbered ones) use sequence numbers, auto-assigned in increments of 10, so from ACL config mode you can type '15 permit ...' to slot a line between 10 and 20, or 'no 40' to delete just that line. Run show access-lists to see the current sequence numbers before editing. If you run out of gaps, 'ip access-list resequence NAME 10 10' renumbers the whole list.
Where do the port keywords go, and how do I match a range of ports or a single host?
Extended syntax is protocol, then source with an optional port operator, then destination with an optional port operator — the operator applies to whichever address it follows, so 'eq 80' after the destination filters the destination port. Use eq, neq, gt, lt, or 'range 1024 65535' for ports, but only with TCP or UDP. Match one address with the 'host 10.1.1.1' keyword and everything with 'any' instead of writing wildcard masks.
Practice this on graded Cisco labs
Reading is step one — build Access Control Lists (ACLs) on real Cisco IOS and grade your own config, or try a free sample lab first.