Server Fault is a question and answer site for system and network administrators. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Below is the result of iptables-save from a Ubuntu Linux server. My question is, is there anything wrong or sub-optimal about it?

For example I believe the rules are processed in order, so should the rules for ports 80 and 3306 (www/mysql) be moved to the top?

Also, what do the rules after the DROP do? They seem similar to rules further above.

# Generated by iptables-save v1.4.1.1 on Sun Feb 13 16:11:59 2011
:INPUT DROP [1:52]
:OUTPUT ACCEPT [496336:22258327]
-A INPUT -p tcp -m tcp --dport 10000 -j ACCEPT 
-A INPUT -i lo -j ACCEPT 
-A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -j ACCEPT 
-A INPUT -p tcp -m tcp --dport 80 -m state --state NEW -j ACCEPT 
-A INPUT -p tcp -m tcp --dport 443 -m state --state NEW -j ACCEPT 
-A INPUT -p udp -m udp --dport 53 -m state --state NEW -j ACCEPT 
-A INPUT -p tcp -m tcp --dport 53 -m state --state NEW -j ACCEPT 
-A INPUT -p udp -m udp --dport 69 -m state --state NEW -j ACCEPT 
-A INPUT -p tcp -m tcp --dport 69 -m state --state NEW -j ACCEPT 
-A INPUT -p tcp -m tcp --dport 25 -m state --state NEW -j ACCEPT 
-A INPUT -p tcp -m tcp --dport 110 -m state --state NEW -j ACCEPT 
-A INPUT -p tcp -m tcp --dport 143 -m state --state NEW -j ACCEPT 
-A INPUT -p udp -m udp --dport 123 -m state --state NEW -j ACCEPT 
-A INPUT -p icmp -j ACCEPT 
-A INPUT -p tcp -m tcp --dport 20 -m state --state NEW -j ACCEPT 
-A INPUT -p tcp -m tcp --dport 21 -m state --state NEW -j ACCEPT 
-A INPUT -p tcp -m tcp --dport 3306 -m state --state NEW -j ACCEPT 
-A INPUT -p udp -m udp --dport 3306 -m state --state NEW -j ACCEPT 
-A OUTPUT -o lo -j ACCEPT 
# Completed on Sun Feb 13 16:11:59 2011
share|improve this question
up vote 4 down vote accepted

I would probably move the RELATED,ESTABLISHED ... ACCEPT rule on the INPUT chain to the very top of that chain. Unless most of your connections are extremely short-lived, I'd wager that the vast majority of incoming packets are going to be part of a connection and should be ACCEPTed by that rule.

To get a better feel for where packets are landing in your ruleset, you can run this:

iptables -t filter -L -n -v

and pay particular attention to the packet and byte counts. You will probably notice that the rule I mentioned above has claimed the most packets by a rather large margin. If any other rules have matched a significant number of packets, you could optimize your ruleset by moving them up ahead of less "popular" rules.

Finally, I notice that your OUTPUT chain has ACCEPT policy. That makes the ACCEPT rules on the OUTPUT chain redundant, and they should be removed. Similarly, since your INPUT chain policy is DROP, the final DROP rule on the INPUT chain is unnecessary.

share|improve this answer
Thanks for the tips. So are you saying that the last 3 rules (i.e. the 3 lines before COMMIT) can be removed? – DisgruntledGoat Feb 13 '11 at 23:59
@DisgruntledGoat: You're welcome. And yes. – Steven Monday Feb 14 '11 at 0:02
One final question (I hope!) - the rules on ports 3306 show 0 packets/bytes. Is this normal? Is it because there are no connections coming from outside (i.e. Apache communicates with MySQL locally). – DisgruntledGoat Feb 14 '11 at 12:15
@DisgruntledGoat: Since all communications with MySQL are happening on localhost, all such traffic will be going through the loopback adapter, lo. You have a rule high up on the INPUT chain that accepts all connections through lo, and that includes all your MySQL connections. So yes, in your case, you are seeing exactly what I would expect to see. – Steven Monday Feb 14 '11 at 17:17

In general arranging the rules so that you exit the firewall quickly is a good thing. If most of the traffic is to ports 80 and 3306 then they should as you suggest be higher up the list for the INPUT table.

Iptables works on tables. You have 3, INPUT, FORWARD and OUTPUT. The DROP command is in the INPUT table. The rules after the DROP are for the OUTPUT chain so they will be processed for outgoing packets only. They could be removed as the policy on the OUTPUT table is to ACCEPT and they are ACCEPT rules.

share|improve this answer
  1. Why -A INPUT -p tcp -m tcp --dport 10000 -j ACCEPT not divided into NEW / REL, EST as others?
  2. Lots of --state NEW is redundant, why making CPU decides whether it was NEW each time(?). You'd better create additional chain 'INPUT.NEW', and use single -A INPUT -m state --state NEW -j INPUT.NEW to pipe packets into it.
  3. INPUT.NEW then can be populated with port comparisons. The number of lines there can be reduced if you'd use -m multiport.
  4. Accepting all ICMP's is insecure since it means not only echo-requests. Select only those ICMPs you're okay to have allowed (this can be as a few as just echo-requests). And remember that legitimate other protos (TCP for e. g.) specific ICMPs would be handled with RELATED anyway.
  5. There's little sense (if any) allowing OUTPUT to be only NEW,RELATED,ESTABLISHED. Permit it w/o sub-dividing.
share|improve this answer
Re point 4 - I added ICMP because of the answer on this question. The server wasn't pingable before so RELATED wasn't handling it. – DisgruntledGoat Feb 14 '11 at 12:18
@DisgruntledGoat, RELATED wouldn't do that (and I didn't say contrary), you're horribly mistaken both in understanding of mine words and ICMP. Read at least this: – poige Feb 14 '11 at 13:49

Looks good. I would drop the accept on port 20 as it should be handled as a related packet to an FTP connection. I usually put port 123 as the first check to minimize latency for NTP.

For the OUTPUT chain only DROP or REJECT rules would make sense. The existing output rules don't do anything but duplicate the policy.

You may want to look at your counters and adjust the ordering of rules accordingly.

Consider using different chains for new connections on each interface.

Consider logging non-accepted packets.

Using a tool like Shorewall to build the firewall might make it easier to get everything in place.

share|improve this answer

Rather than using one explicit rule per protocol/port combination, I'd strongly suggest using ipset.

Make 2 sets, one each for TCP and UDP:

ipset -N Allowed_TCP_Ports portmap --from 0 --to 65535
ipset -N Allowed_UDP_Ports portmap --from 0 --to 65535

Populate each set:

for p in $TCP_PORTS; do ipset -A Allowed_TCP_Ports; done
for p in $UDP_PORTS; do ipset -A Allowed_UDP_Ports; done

You can then simplify your port-related rules into just 2 rules:

-A INPUT -p tcp -m set --match-set Allowed_TCP_Ports dst -j ACCEPT 
-A INPUT -p udp -m set --match-set Allowed_UDP_Ports dst -j ACCEPT 

Note: I'm removing -m state --state NEW matches. I mean, what for? After the -m state --state RELATED,ESTABLISHED rule, all packets are either NEW or INVALID.

Note 2: Ubuntu's ipset package is bollixed; you must download and install from source. I've explained how in my blog. You can read it here: .

share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.