In this article I will show you which steps you need to do to secure your root server. It consists of the general practises of setting up and the detailed implementation on Debian Buster.
Change the SSH port to a custom one
Most attackers try to find an open SSH port on the default port number (which is 22) and will pass by if there is no open port. So you definitely should change the port number of your SSH connection.
Open /etc/ssh/sshd_config with your favorite editor and set following line:
Port XXXX
XXXX is the placeholder for the portnumber you want the ssh server to listen for connections on.
Now restart the SSH daemon service:
service ssh restart
Don’t close the existing SSH connection and try to login with a new SSH connection using the new configuration. If you can successfully login you can close the previous SSH connection.
Setup cooldown after failed logins
To prevent Bruteforce and Dictionary attacks you should setup the server to reject logins for a user account for some time if the user failed a given amount of login attempts in a row.
You can achieve this by using fail2ban. Run
apt-get install fail2ban
to install it. Check that it is running:
systemctl status fail2ban.service
the output should look like this:
● fail2ban.service - Fail2Ban Service Loaded: loaded (/lib/systemd/system/fail2ban.service; enabled; vendor preset: Active: active (running) since Sun 2022-08-28 23:10:03 CEST; 7min ago Docs: man:fail2ban(1) Main PID: 971 (fail2ban-server) Tasks: 3 (limit: 105) Memory: 14.0M CGroup: /system.slice/fail2ban.service └─971 /usr/bin/python3 /usr/bin/fail2ban-server -xf start
Configure Fail2Ban
To configure fail2ban create a file in /etc/fail2ban/jail.d by copying /etc/fail2ban/jail.conf:
cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.d/temperary-block-account-on-failed-logins.local
Now open the created file with your favorite text editor and edit the rules according to your needs:
nano /etc/fail2ban/jail.d/temperary-block-account-on-failed-logins.local
Remove the warning that says that you should not modify that file to avoid confusions when you need to edit the file on a later point in time, as it relates to the jail.conf file, not the files within jail.d.
Also don’t forget to active Fail2Ban for the sshd by uncommenting the line
enabled = true
within the sshd section of your created rule file.
The default settings block an ip address on all ports for 10 minutes after 5 failed login attempts within the last 10 minutes.
For more details on the settings within the rule file you can take a look on this links:
After finishing the rule configuration you need to restart Fail2Ban:
systemctl restart fail2ban
Send email notification on failed login attemps
If an IP address gets blocked for too many failed login attempts the server should notify you by sending an email to you for further investigation.
First install Sendmail:
apt-get install sendmail sendmail-cf m4
And configure it:
sendmailconfig
The default config is already fine for sending emails. If you don’t want sendmail to handle incoming emails you should close all unneeded ports except for port 25. Take a look at the section „Close unneeded ports“ on how to achieve this.
Now to setup fail2ban to send the notification email when an account is banned, open the configuration file you created in the previous step:
nano /etc/fail2ban/jail.d/temperary-block-account-on-failed-logins.local
Look for the line defining the „action“ key:
action_ = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
And change it to:
action = %(action_mwl)s
or
action = %(action_mw)s
Depending on how much detail about the incident you want the notification email to contain.
Now look for the line defining the „destemail“ key:
destemail = root@root
And change its value to the email address you want the notification email to be sent to.
Also look for the „sender“ key:
sender = root@<fq-hostname>
And change its hostname (the part behind the @) to the full qualified domain name of the machine which will send the notification email.
Now restart fail2ban to activate your new config settings and start the fail2ban client:
systemctl restart fail2ban
fail2ban-client start
You now should have received a notification email on the configurated email address stating that the server has started correctly.
Now you can check that everything works correctly by opening another SSH terminal and try to connect to the server with wrong credentials 6 times.
You now should have received an email notifying you that your IP address has been blocked. You can list all currently blocked IPs by using your existing SSH connection:
fail2ban-client status sshd
The output should look similar to this:
Status for the jail: sshd |- Filter | |- Currently failed: 0 | |- Total failed: 5 | `- File list: /var/log/auth.log `- Actions |- Currently banned: 1 |- Total banned: 1 `- Banned IP list: xxx.xxx.xxx.xxx
Now run the following command to unblock the IP manually:
fail2ban-client set <jailname> unbanip <ipaddress>
In the example jailname is „sshd“ and IP address is the IP address you want to unblock.
Close unneeded ports
You should close all ports in your firewall except those which are used by services you want to be available to the public. This significantly reduces the amount of services that might be attacked.
For this, you need to install UFW:
apt-get install ufw
Block all incoming traffic:
ufw default deny incoming
Allow all outgoing traffic:
ufw default allow outgoing
Now allow all ports where your server shall listen to incoming traffic. At least you need to allow the SSH port to be able to access the server:
ufw allow xxxx
You need to run this command for every service you wish to allow to be accessed from external systems.
Now enable UFW:
ufw enable
To check if all ports are closed correctly you can run a port scanner such as Nmap. For Windows I suggest using Zenmap, a graphical frontend for Nmap:

For more details you can take a look at UFW tutorial at digitalocean.com.
Send notification email on SSH login
You should configure your server to send a notification email when someone successfully logs in via SSH so that you will know if your server has been hacked. For this, first create a script „notify-ssh-login.sh“:
if [ -n "$SSH_CLIENT" ]; then { IPADDR="$(echo $SSH_CLIENT | awk '{print $1}')" echo "Subject: [$$CATEGORY$$] SSH Login: ${USER} from ${IPADDR}" echo "" echo "User ${USER} logged in via SSH from ${IPADDR} onto $(hostname -f)". } | sendmail -f "$$CATEGORY$$ <root@$$HOSTNAME$$>" $$RECIPIENT$$ fi
Replace $$HOSTNAME$$ with the hostname of your Gitlab server, $$CATEGORY$$ with the category (for example „Gitlab Runner“) and $$RECIPIENT$$ with the mail address to send the log to.
Now set the x-bit to make it executable:
chmod +x notify-ssh-login.sh
Now run the script to test it. You should receive an email that not yet contain location data, since it was not called while an SSH login.
Now set a symlink in /etc/profile.d to your notify-ssh-login.sh to run the script when a user logs in:
cd /etc/profile.d
ln -s ~/notify-ssh-login.sh
Keep your server up to date
You need to regularly update all services and applications that you run on the server to ensure, that possible critical vulnerabilities are getting patched as soon as possible.
First update the package list:
apt-get update
And then install all updates:
apt-get upgrade
You need will be asked if you want to install the packages. Input „y“ followed by the return key to ackknowledge.
Maybe you want to automatically update the server. For this, first create the script file update-server.sh at a location you like with following content:
#!/bin/bash LOGFILE=update-server.log cd "$(dirname "$0")" echo "Logs:" > $LOGFILE echo "Working directory set to $(dirname "$0")" | tee -a $LOGFILE (apt-get update && apt-get upgrade -y) 2>&1 | sed 's/^/ /' | tee -a $LOGFILE { echo "Subject: [$$CATEGORY$$] Server update report" echo "" echo "$(cat $LOGFILE)" } | sendmail -f "$$CATEGORY$$ <root@$$HOSTNAME$$>" $$RECIPIENT$$
Replace $$HOSTNAME$$ with the hostname of your Gitlab server, $$CATEGORY$$ with the category (for example „Gitlab Runner“) and $$RECIPIENT$$ with the mail address to send the log to.
Now set the x-bit to make it executable:
chmod +x update-server.sh
Now test run the script. You should receive an email with the logs.
Now open the /etc/crontab file and add following line:
0 0 * * * root /srv/apt/update-server.sh
The update could get stuck when an upgrade provides a new version of a config file that you have changed manually, because Dpkg in this case will ask what to do. To prevent this error from occuring, you can create a file „70changedconffile“ in /etc/apt/apt.conf.d:
Dpkg::Options { "--force-confdef"; "--force-confold"; }
This will ensure that Dpkg will automatically keep the manually changed config files without further asking.