Secure Linux Server

Last update

First steps

cover image

  • System updating
  • Creating non-root user
  • Checking the safety of the current system
  • SSH Keys generation
  • SSH secure configuration
  • Firewall secure configuration
  • Fail2Ban secure configuration
  • Allow access to specific countries based on IPs
  • Summary

Initial Linux installation has a lot of room for hardening against unauthorized access to the system, no matter what distribution you use. After reading this post you will get the knowledge how to secure your server in record time.

All presented commands have to be executed with admin privileges. In most distributions it will be just sudo before the actual command.


System updating


Make sure you have an up to date system. It's important because it can download available security updates. Additionally we are going to install some security software in the coming steps so the newer repos the better.

apt update
apt upgrade



Creating non-root user


We need a user with admin privileges but on the other hand it can't be the root user. Moreover we are going to block root users from logging through SSH into the server soon. The solution is a new user with sudo privileges.

adduser new_user_name


Add the newly created user to sudo group

gpasswd -a new_user_name sudo



Checking the safety of the current system


This is a very important step before going further because you have to be sure about the safety of the current installation. We are going to use the legendary Rkhunter which scans the appropriate parts of the system in the search for rootkits, backdoors and exploits.

apt install rkhunter


rkhunter --check


The checking will take a while but it's worth it. Input enter when asked to continue the process. At the end it will summarize the status of your system. If it turns out that your system has rootkits please don't disregard this and google its name/file immediately to find out its severity and importance.


SSH Keys generation


It's a good practice to generate an individual ssh key for every server you have. Get back to the local machine and generate a strong rsa key:

ssh-keygen -t rsa -b 4096


Send the new key into the server:

ssh-copy-id user@server


To log with specific key use this command:

ssh -i ~/.ssh/specific_ssh_fkey



SSH secure configuration


Back to the server. Open ssh_config file which holds ssh configuration. You should find it in /etc/ssh folder

nano /etc/ssh/sshd_config


There is a lot to cover. SSH config shouldn't be too restrictive so set appropriate values according to your needs. The presented config below is secure enough for most of the systems.



There is a cheat cheat available for SSH which can be useful when using SSH protocol.



Start with changing the default SSH port . It's important because the default 22 port will always be the first attacked by a potential intruder. If you are not sure what ports are already assigned by your system check it in /etc/services.

 Choose any port not yet assigned preferably from private/dynamic group (49152-65535)

Port 49152


You should restrict using SSH by the root user. Root is the default user name in most Linux systems with admin privileges. Use the newly created user from point 2 instead as the additional security measure. Not knowing the user name makes it harder to enter into your system.

PermitRootLogin no


It's a good idea to make it more restrictive by selectively choosing what users actually can use SSH.

AllowUsers new_user_name


Enable logging by the previously created key from the SSH Keys generation paragraph.

PubkeyAuthentication yes


You should definitely block the possibility to log into your system by standard password, the only way to connect should be by the key.

PasswordAuthentication no


Disable interactive mode to enter passwords. It's not needed when you use key based authentication.



Disable the possibility to authenticate based on the host method. In general it facilitates logging into the system based on public keys but only users from .rhosts or etc/hosts.equiv files which is considered insecure.

HostbasedAuthentication no


Disable rhost authentication which uses rhosts and /etc/hosts.equiv

RhostsAuthentication no


Additionally disable altogether .rhost and .shost files usage related to the previously disabled host and rhosts based authentication methods.

IgnoreRhosts yes


Take a closer look at the MaxStartups label. It's often neglected but an important configuration because it can reduce severity of DOS attacks to the SSH service. It specifies the maximum concurrent not yet authenticated connections to the SSH service based on probability or direct value. So you can just type i.e 16 and it will drop the next additional tries immediately or use three values separated with semicolon which are translated into start:rate:full and this way you start using probability.

If concurrent number of connections are greater than the start value the server starts dropping the next connection with probability defined in the rate value. When the number of connections reaches the full value the server starts refusing all connections to the SSH daemon. Depending on the size and type of your system you definitely should consider proper values, my proposition is more restrictive than the default one.

MaxStartups 5:50:30


Next reduce max authentication tries per connection. The default value 6 is unacceptable. You should only use the key based authentication so it's value should be set to one. If you choose the password authentication, reduce the number to four, that way an unsuccessful  third and fourth will be additionally logged (by default if authentication fails after half the number specified it starts logging it).

MaxAuthTries 1


By default SSH can have up to 10 sessions per one network connection which is highly insecure in most cases because a hacker can use other sessions without need to reauthenticate. Notice that allowing multiple sessions means that multiplexing can be used which can be needed in some environments. Good news is that you can reduce it to one and try if everything works as intended, a single session is always enough to use shell at least.

MaxSessions 1


There are two important parameters which when set to not improve security but they can disable some of your software as well. For example if you use some database clients which connect to your server by SSH or FTP client using SFTP.

AllowTcpForwarding no
X11Forwarding no



Firewall secure configuration


Before proceeding further please restart the ssh service depending on the used distribution then disconnect and connect again to the server.

service ssh restart


systemctl restart sshd


systemctl restart ssh 


After restarting you should be connected through the new designated port (different than 22) and it also means that the old one can be blocked. To be sure about what port SSH is run check it by yourself:

lsof -i -n -P


Then enable the Linux firewall. 

ufw enable


Next allow the new SSH port and deny the old one.

ufw allow new_ssh_port
ufw deny 22


If you always use a fixed IP from ISP you can restrict the firewall rules further. Allow SSH connection only from this IP.

sudo ufw allow from to any port new_ssh_port


At the end, restart the firewall.

service ufw restart



Fail2Ban secure configuration


Time to install extremely useful software which level up your server security instantly. With proper config it will even double it! Install the fail2ban then start and enable the service.

apt install fail2ban
 service fail2ban start
 service fail2ban enable


It's worth mentioning that this tool performs actions based on logs from the various services. The more important logs you store the better. By default it will also filter SSH logs so let's focus on the configuration then.


Allow access to specific countries based on IPs


Install GeoIP to get access to an extensive database of ip addresses and their locations.

sudo apt install geoip-bin geoip-database



Then create a script in the geoip bin folder to enable filtering and logging of incoming connections. The most important is the ALLOW_COUNTRIES parameter, put there your allowed locations. The rest of the script is mostly related to logging based on specific scenarios and you can keep it that way.

# License: WTFPL

# UPPERCASE space-separated country codes to ACCEPT

if [ $# -ne 1 ]; then
  echo "Usage:  `basename $0` " 1>&2
  exit 0 # return true in case of config issue

if [[ "`echo $1 | grep ':'`" != "" ]] ; then
  COUNTRY=`/usr/bin/geoiplookup6 "$1" | awk -F ": " '{ print $2 }' | awk -F "," '{ print $1 }' | head -n 1`
  COUNTRY=`/usr/bin/geoiplookup "$1" | awk -F ": " '{ print $2 }' | awk -F "," '{ print $1 }' | head -n 1`

if [[ "$RESPONSE" == "ALLOW" ]] ; then
  logger -p $LOGDENY_FACILITY "$RESPONSE sshd connection from $1 ($COUNTRY)"
  exit 0
  logger -p $LOGDENY_FACILITY "$RESPONSE sshd connection from $1 ($COUNTRY)"
  exit 1


Remember you make the script executable.

chmod +x /usr/local/bin/


For now we have only ip filtering done by the geoip. We need to pass its results to ssh service. Go to /etc/hosts.allow and update so it will get the geopip results.

sshd: ALL: spawn /usr/local/bin/ %a


Finally block all the others ips in the /etc/hosts.deny file.

sshd: ALL




If you followed all the above recommendations you have a quite secure server at the moment. Yet there are still possible actions you can take to harden it more. For example you can think about a more restrictive config of the recommended values presented above.

Recent posts