blowstack logo

Secure Linux Server

First steps

Last update

20 min.
  1. System updating
  2. Creating non-root user
  3. Checking the safety of the current system
  4. SSH Keys generation
  5. SSH secure configuration
  6. Firewall secure configuration
  7. Fail2Ban secure configuration
  8. Allow access to specific countries based on IPs
  9. Summary


Initial Linux installation has a lot of room for hardening against an unauthorised 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 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 comming 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 user to log 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 very important step before going further because you have to be sure about the safety of the current installation. We are going to use legendary Rkhunter which scans the appropriate parts of the system in the search for rootkits, backdoors and exploits.

apt install rkhunter


rkhunter --check


The checkng will take a while but it's worth to do it. Input enter when asked to continue the process. At the end it will summarise the status of your system. If it turned out that your system has rootkits please don't disregard this and google it name/file immediately to find out it's 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 commnad:

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 restrtictive so set appropriate values aacording 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 usefull when using SSH protocole.



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

 Choose any port not yet assigned preferebly 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 the point 2 instead as the additonal security measure. Not knowing the user name make 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 point 4.

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 authenication.



Disable the possibility to authenticate based on 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 considererd insecure. 

HostbasedAuthentication no


Disable rhost authentiacation 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 authentiaction methods.

IgnoreRhosts yes


Take a closer look at MaxStartups label. It's often neglected but important configuration because 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 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 conenctions are greater than the start value the server start dropping next connection with probability defined in the rate value. When number of connections reached the full value the server starts refusing all connections to the SSH deamon. Depending on the size and type of your system you definently should consider proper values, my proposition is more restrictive than the default one.

MaxStartups 5:50:30


Next reduce max authentiaction 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 chose the password authentication reduce the number to four, that way an unsuccessfull  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 is some environments. Good news is that you can reduce it to one and try if everything works as indeded, single sessiosn is always enough to use shell at least.

MaxSessions 1


There are two important parameters which when set to no improve security but they can disable some of your software as well. For example if you use some database clients which connects to your server by SSH orf 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 than 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 usefull 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 to mention that this tool perform 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 extensive database of ip address and their loactions

sudo apt install geoip-bin geoip-database



Then create a script in the geoip bin folder to enable filtering and logging of incomming connections. The most important is 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 it's 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


Finaly 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 more restrictive config of the recommended values presented above.


Recent posts

BlowStack 2021
Portfolio Cheat