Linux Iptables: Block All Incoming Traffic But Allow SSH

Posted on in Categories Iptables, Linux last updated June 22, 2005

This is very common scenario. You want to permit access to a remote machine only by SSH. You would like to block all incoming traffic to your system except ssh connection under Linux.

Add following rules to your iptables shell script:

/sbin/iptables -A INPUT -p tcp --dport 22 -j ACCEPT
/sbin/iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT

First rule will accept incoming (INPUT) tcp connection on port 22 (ssh server) and second rule will send response of incoming ssh server to client (OUTPUT) from our ssh server source port 22.

However, iptables with kernel 2.4/2.6 provides very powerful facility to filter rule based upon different connection states such as established or new connection etc. Here is complete small script to do this task:

#!/bin/sh
# My system IP/set ip address of server
SERVER_IP="65.55.12.13"
# Flushing all rules
iptables -F
iptables -X
# Setting default filter policy
iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP
# Allow unlimited traffic on loopback
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
 
# Allow incoming ssh only
iptables -A INPUT -p tcp -s 0/0 -d $SERVER_IP --sport 513:65535 --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -p tcp -s $SERVER_IP -d 0/0 --sport 22 --dport 513:65535 -m state --state ESTABLISHED -j ACCEPT
# make sure nothing comes or goes out of this box
iptables -A INPUT -j DROP
iptables -A OUTPUT -j DROP

This script is purely strict firewall. It only allows incoming ssh. No other incoming service or ping request or no outgoing service or request allowed. Incoming ssh connection can be either new or already established one and that is what specified by state rule ‘-m state –state NEW,ESTABLISHED’. Outgoing ssh connection state can be established only. By default this script allows everyone to ssh in by rule -s 0/0. If you want this access limited by IP or network address then replace -s 0/0 with IP address. For example allow incoming ssh from IP 202.54.1.20:

# Allow incoming ssh only from IP 202.54.1.20
iptables -A INPUT -p tcp -s 202.54.1.20 -d $SERVER_IP --sport 513:65535 --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -p tcp -s $SERVER_IP -d 202.54.1.20 --sport 22 --dport 513:65535 -m state --state ESTABLISHED -j ACCEPT

Posted by: Vivek Gite

The author is the creator of nixCraft and a seasoned sysadmin and a trainer for the Linux operating system/Unix shell scripting. He has worked with global clients and in various industries, including IT, education, defense and space research, and the nonprofit sector. Follow him on Twitter, Facebook, Google+.

23 comment

  1. Try

    iptables -A OUTPUT -p tcp -d $SERVER_IP -s 0/0 –dport 22 –sport 513:65535 -m state –state ESTABLISHED -j ACCEPT

    iptables -A INPUT -p tcp -d 0/0 -s $SERVER_IP –dport 513:65535 –sport 22 -m state –state NEW,ESTABLISHED -j ACCEPT

  2. Following are correct two rules:

    iptables -A OUTPUT -p tcp -s $SERVER_IP -d 0/0 –sport 513:65535 –dport 22 -m state –state NEW,ESTABLISHED -j ACCEPT

    iptables -A INPUT -p tcp -s 0/0 -d $SERVER_IP –sport 22 –dport 513:65535 -m state –state ESTABLISHED -j ACCEPT

    Appreciate your post.

  3. If you have specified a default deny policy;

    iptables -P INPUT DROP
    iptables -P OUTPUT DROP
    iptables -P FORWARD DROP

    then why do you need the bottom two lines?

    iptables -A INPUT -j DROP
    iptables -A OUTPUT -j DROP

    Thanks.

  4. You have some funky characters on this page double “-” is being replaced by an mdash or something … this causes a copy and paste of the rules to fail (at least on my console)

    you have ” –sport”, there should be two characters before sport, with extra spaces this should be ” – – s p o r t”

    Cheers

  5. Hi,
    I want to configured the firewall but there is a 5 server on wan & also at lan.
    How I connect this all m/c through firewall for wan for ssh service.
    or which reule I inser for ssh_key.

    Nand

  6. Hi,
    I have a router wrt54gl with openwrt(kernel 2.4.x) and I can’t seem to block other lan users.
    router ip is 10.77.77.1 / netmask 255.255.255.0
    squid server is 10.77.77.228 3128 port
    iptables -F
    iptables -Z
    iptables -X
    iptables -t nat -F
    iptables -t nat -Z
    iptables -t nat -X
    iptables -A INPUT -s 10.77.77.228 -j ACCEPT
    iptables -A INPUT -d 10.77.77.228 -j ACCEPT
    iptables -A OUTPUT -s 10.77.77.1 -j ACCEPT
    iptables -A OUTPUT -d 10.77.77.228 -j ACCEPT
    iptables -A INPUT -s 10.77.77.1/24 -d 10.77.77.1 -j ACCEPT
    iptables -A INPUT -s 10.77.77.1/24 -d 10.77.77.228 -p tcp –dport 3128 -j ACCEPT
    iptables -A OUTPUT -d 10.77.77.1/24 -s 10.77.77.1 -j ACCEPT
    iptables -A INPUT -p udp –sport 67:68 –dport 67:68 -j ACCEPT
    iptables -A OUTPUT -p udp –sport 67:68 –dport 67:68 -j ACCEPT
    iptables -A INPUT -p udp –dport 53 -j ACCEPT
    iptables -A OUTPUT -p udp –dport 53 -j ACCEPT
    iptables -A INPUT -p tcp –dport 80 -j ACCEPT
    iptables -A INPUT -p tcp –dport 3128 -j ACCEPT
    iptables -A OUTPUT -p tcp –dport 3128 -d 10.77.77.228 -j ACCEPT
    iptables -A OUTPUT -p tcp –dport 80 -d ! 10.77.77.228 -j DROP
    iptables -A OUTPUT -p tcp –dport 3128 -d ! 10.77.77.228 -j DROP
    #this one redirect port 80 to 3128 squid server
    iptables -t nat -A PREROUTING -s ! 10.77.77.228 -p tcp –dport 80 -j DNAT –to 10.77.77.228:3128
    iptables -t nat -A POSTROUTING -s 10.77.77.1/24 -d 10.77.77.228 -j MASQUERAD
    iptables -A INPUT -j DROP
    iptables -A OUTPUT -j DROP

    I just want to allow 10.77.77.228, and all others to be blocked for all protocols, all ports except 80 port tcp, 53 udp(dns), 67,68 udp(dhcp). The above rules don’t work. I am still able to ping,ftp or p2p from any host from the lan.

  7. I would like to propose an alternative howto that I know that I would benefit from, probably many others too. I have several dedicated servers at a provider that charges $100/month for a firewall for EACH SERVER. This is like 1/3 to 1/2 the cost of each server. All I want is one machine reachable from the net at large to serve as my ssh entrance, and my web server load balancer. So I want to cut off all the other machines from inbound connections from the net. So they need to be able to accept connections on the internal subnet to get load balanced to. But they also need to be able to get out to the real world to download the occasional item, and also hit REST apis of various types. Maybe other stuff. I would think this is fairly typical, but I bet a lot of people shell out the ducats for the firewall service. Ouch, I says.

    So basically I want to say:
    allow only inbound connections on subnet X

    That’s it.

    fyi, I am a security idiot. Maybe that was apparent by my question.

    thanks

    dumbfounder

  8. I still have a problem with this, I’m able to connect from my computer to the “server”(actually it’s a vm”) but i can’t open a new ssh connection from this server to the outside.plz some help 🙂

  9. Hi,
    I’m trying to configure my debian router for my LAN users. I want to block p2p.
    I thought I could block all ports except http, dns, e-mail idt. Is it possible to do with iptables. At the moment my router is set up as simple gateway (Internet connection sharing).

    Thanks
    Miglanc

  10. Hello all. I am a Linux user and totally love it(currently loving LinuxMint). Cant wait to play around with this script on my laptop. Quick question for yall. I’m taking a windows systems security class, and need to do this kind of thing for class. Is there a way to do something just like this post on a widows 2000 system?any help would be greatly appreciated

  11. Hi Have used the above script for my webserver.
    SERVER_IP=”65.55.12.13″
    iptables -F
    iptables -X
    iptables -P INPUT DROP
    iptables -P OUTPUT DROP
    iptables -P FORWARD DROP
    iptables -A INPUT -i lo -j ACCEPT
    iptables -A OUTPUT -o lo -j ACCEPT

    # Allow incoming ssh only
    iptables -A INPUT -p tcp -s 0/0 -d $SERVER_IP –sport 513:65535 –dport 22 -m state –state NEW,ESTABLISHED -j ACCEPT
    iptables -A OUTPUT -p tcp -s $SERVER_IP -d 0/0 –sport 22 –dport 513:65535 -m state –state ESTABLISHED -j ACCEPT
    # make sure nothing comes or goes out of this box
    iptables -A INPUT -j DROP
    iptables -A OUTPUT -j DROP

    but i want to open out going smtp service so that server can send email alerts, now all the email alerts are getting queued only as soon as I stop the iptables service, mail go out. Pls help to open the smtp port and supporting ports so that mail alerts can be send to my employees.

    REgards
    Yogesh

  12. Hi all, Yogesh Kumar just a small observation. Given that this is a security related question and you are asking for advice – therefore implying that you may of made mistakes – would it not be prudent not to paste your public IP address in your post, but instead something like x.x.x.x?

    Just a thought…

  13. iptables block all traffice allow only 3 ip for specific port like 80 port what command i set in iptable pls help urgent

    iptables -I INPUT ! –src 1.2.3.4 -m tcp -p tcp –dport 80 -j DROP # if it’s not 1.2.3.4, drop it

  14. iptables block all traffice allow only 3 ip for specific port like 80 port what command i set in iptable pls help

    iptables -I INPUT ! –src 1.2.3.4 -m tcp -p tcp –dport 80 -j DROP # if it’s not 1.2.3.4, drop it

  15. Hi Guys,
    How do you set this one up? I only want SSH and Samba.

    With the Samba I want my Windows/Mac PCs to be able to connect to the samba shares and do the normal operations like Read/Write/Execute.

    With the SSH, I just to be able to access my Debian server on my Windows/Mac machine using Putty.

    1. That’s fairly easy. The basics is to add a line which allows to port 3306 and DROPs everything else to that IP.

      My attempt, should work. Remember to replace ‘SERVER_IP’ with the Server’s IP:

      I recommend to add the lines to the top of the chain for fast processing:
      sudo iptables -I INPUT 1 -p tcp -m tcp -d SERVER_IP –dport 3306 -j ACCEPT
      sudo iptables -I INPUT 2 -d SERVER_IP -j DROP

      If you want to append to the chain:
      sudo iptables -A INPUT -p tcp -m tcp -d SERVER_IP –dport 3306 -j ACCEPT
      sudo iptables -A INPUT -d SERVER_IP -j DROP

Leave a Comment