Limit SSH access by IP address

This article describes how to specify which IP addresses can reach the SSH daemon on your server.

Note: All of the methods described here can result in inadvertently blocking yourself or other important traffic from reaching your server. Please exercise care.

Blocking SSH Traffic Before it Reaches Your Server

Ideally, IP address limitations should be implemented before the unwanted traffic even reaches your server:

Blocking SSH Traffic at Your Server

If you are unable to block unwanted traffic before it reaches your server, Linux has several facilities for limiting which IP addresses can connect to your SSH daemon. This article will present two different approaches:

  1. A "permissive" configuration that allows all but known malicious IP addresses.
  2. A "restrictive" configuration that allows only trusted IP addresses.

It is generally safer to use the "restrictive" configuration if possible.

Permissive Configuration

The permissive configuration allows access to everyone except the specified IP addresses.

iptables

For a permissive configuration place your iptables rules to drop traffic from specific IP addresses before your rule to allow all (other) SSH traffic.

# iptables -A INPUT -s 192.168.0.3 -p tcp --dport 22 -j DROP
# iptables -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
# service iptables save
# iptables -L

UFW

For a permissive configuration place your UFW rules to deny specific IP addresses before your rule to allow all (other) SSH traffic.

# ufw deny proto tcp from 192.168.0.3 to any port 22
# ufw allow ssh
# ufw status numbered

Firewalld

There are various ways to build a permissive configuration with Firewalld. A simple way is to add the SSH service and all unwanted IP addresses to the "drop" zone then add the SSH service to the default zone (usually "public").

# firewall-cmd --permanent --add-source=192.168.0.3 --zone=drop
# firewall-cmd --permanent --add-service=ssh
# firewall-cmd --reload
# firewall-cmd --list-all --zone=drop
# firewall-cmd --list-all

/etc/ssh/sshd_config

You can configure the SSH daemon itself to create a permissive configuration (see man 5 sshd_config for details). To do this you need to add a "Match Address" block to the end of /etc/ssh/sshd_config to override aspects of the main configuration. In this case, we will be disabling login methods for unwanted IP addresses.

# Put this at the end of /etc/ssh/sshd_config to block unwanted IP addresses
Match Address 192.168.0.3
   PasswordAuthentication no
   PubkeyAuthentication no

After making these changes, use sshd -t to check for syntax errors, then restart your SSH server daemon (systemctl reload sshd on RedHat or systemctl restart ssh on Debian/Ubuntu).

Restrictive Configuration

This configuration allows only specific IP addresses and drops other incoming SSH traffic.

iptables

For a restrictive configuration place your iptables rules to allow specific IP addresses before your rule to drop all (other) SSH traffic.

# iptables -A INPUT --source 192.168.0.8 -p tcp --dport 22 -j ACCEPT
# iptables -A INPUT -p tcp -m tcp --dport 22 -j DROP
# service iptables save
# iptables -L

UFW

For a restrictive configuration place your UFW rules to allow specific IP addresses before your rule to deny all (other) SSH traffic.

# ufw allow proto tcp from 192.168.0.8 to any port 22
# ufw deny ssh
# ufw status numbered

Firewalld

There are various ways to build a restrictive configuration with Firewalld. A simple way is to add the SSH service and all trusted IP addresses to the "trusted" zone then remove the SSH service from the default zone (usually "public").

# firewall-cmd --permanent --add-service=ssh --zone=trusted
# firewall-cmd --permanent --add-source=192.168.0.8 --zone=trusted
# firewall-cmd --permanent --remove-service=ssh
# firewall-cmd --reload
# firewall-cmd --list-all --zone=trusted
# firewall-cmd --list-all

/etc/ssh/sshd_config

You can configure the SSH daemon itself to create a restrictive configuration (see man 5 sshd_config for details). To do this you disable logins in the main body of /etc/ssh/sshd_config then add a "Match Address" section to the end so trusted IP addresses can login.

# Disable logins in the main body of /etc/sshd_config
PasswordAuthentication no
PubkeyAuthentication no

# Put this at the end to allow trusted IP addresses to login
Match Address 192.168.0.8
   PasswordAuthentication yes
   PubkeyAuthentication yes

After making these changes, use sshd -t to check for syntax errors, then restart your SSH server daemon (systemctl reload sshd on RedHat or systemctl restart ssh on Debian/Ubuntu).