This blog post was written under the Pusher Guest Writer program.

Security is one of the most important aspects of a server. Faulty security practices can pave the way for attackers to gain unauthorized access to your server. As a developer you need to take control of your server security – but since servers are messy and managing them is tough, it can be very frustrating. I’ve been there, learned some lessons the hard way, and found success. In this blog post, we will see an overview of basic steps that we can take to enhance the security of our server.

SSH Key Pair Authentication

Accessing your server using a plain text password is very dangerous. Always use a SSH key pair to access your server, as they are more secure. Here, we will go over the process of creating SSH keys and setting up your server to enable SSH key based authentication.

You can create a pair of SSH keys using the following command:

ssh-keygen -t rsa -b 4096 -f id_filename
  • -t rsa – Create a RSA type key pair
  • -b 4096 – The encryption to use for creating the SSH key (how strongly encrypted should the key pairs be). While 2048 can be adequate, I like to go higher, up to 4096
  • -f id_filename – The name of key pair files that will be generated

Once you execute this command, two files will be generated. id_filename is the private key and should never be shared with anyone. The other file is id_filename.pub, which is the public key and can be shared to get access to servers.

To copy the SSH public key to a remote server, execute the following command:

ssh-copy-id -i ~/.ssh/id_filename user@host

Now, you are set with the SSH key based authentication method and can securely connect to your servers using SSH key pairs.

Restrict Password Authentication

One of the primary steps to secure a server is to restrict password authentication. Accessing a server with a plain text password is potentially harmful and should always be avoided. Any attacker can try guessing your passwords, plus you have an overhead in keeping them secure, as you need to reset them after regular intervals.

To restrict password authentication, edit the SSH configuration file to have the following line:

# /etc/ssh/sshd_config

PasswordAuthentication no

To make sure that the changes take effect, you will need to restart your SSH service. You can do this using the following command:

sudo service ssh restart

Restrict Root User Access

root user is a GOD user with a permission to execute any command without a password. If an attacker gains access to your server as a root user, they can execute any malicious operation, including deleting the data on your server or the server itself. Therefore, it is always recommended to block the root user from having any access to the server. Instead, you should create a new user and add it to the sudo group. A sudo user can run commands as a root user, with the added protection that they will need to enter a password to execute any commands. If an attacker gains access as the sudo user, they still won’t be able to do any damage unless they know the password.

To restrict access to the root user, edit the SSH configuration file to have the following line:

# /etc/ssh/sshd_config

PermitRootLogin no

To make sure that the changes take effect, you need to restart your SSH service. You can do using the following command:

sudo service ssh restart

To create a new user and add it to the sudo group, run the following commands:

sudo adduser [username]

sudo usermod -a -G sudo [username]

Configure the Firewall

A firewall blocks network traffic in accordance with a set of rules. To check the firewall rules defined for your server, you can use the iptables command:

sudo iptables -L -v

# Output

Chain INPUT (policy ACCEPT 0 packets, 0 bytes) 
pkts bytes target     prot opt in     out     source               destination


Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) 
pkts bytes target     prot opt in     out     source               destination


Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target     prot opt in     out     source               destination
  • The rules defined in the INPUT chain monitor the network traffic that is coming to the server
  • The rules defined in the OUTPUT chain monitor the network traffic that is going outside from the server
  • The rules defined in the FORWARD chain monitors the network traffic that is coming from outside the server and going outside the server, eg for the routing servers like node balancers

We will use Uncomplicated Firewall (UFW) to configure our firewall rules. UFW provides a human friendly GUI over the iptables command to configure the firewall rules. You can install UFW using the following command:

sudo apt-get install -y ufw

Once, UFW is installed you can activate the basic rules:

ufw allow http
ufw allow https
ufw allow ssh

Configure Fail2Ban

Fail2Ban is a service which reads the authentication log files on your server to understand whether there are a large number of failed authentication attempts from a particular host. If it finds any malicious attempts, it will block any network traffic from that particular host for a defined amount of time by updating the firewall rules.

The official definition of Fail2Ban:

“Fail2Ban scans log files and bans IPs that show the malicious signs – too many password failures, seeking for exploits, etc.”

First, you need to install Fail2Ban

sudo apt-get install -y fail2ban

This will download and install the Fail2Ban package. All the configuration files for Fail2Ban are stored in the /etc/fail2ban directory. The official package ships with a jail.conf file which has all the necessary configuration options with default values for setting up Fail2Ban.

Never edit the jail.conf file as it is tracked in the repository of Fail2Ban codebase. Whenever the package is updated, the jail.conf file is overwritten by the new file and you will lose your local configurations. Create a copy of jail.conf file in the jail.local file and overwrite any configurations that you want to.

You can create a new copy using this command:

sudo cp jail.conf jail.local

Next, write down any configuration that you need to overwrite in the jail.local file. Following is the recommended configuration:

ignoreip = 127.0.0.1/8


findtime = 600


bantime = 600


maxretry = 5
  • ignoreip – The IPs specified in this parameter will be never blocked. You can specify multiple hosts by separating them with spaces
  • findtime – This is the amount of time during which the failed authentication attempts should happen to trigger a block
  • bantime – The maximum amount of time to block a host
  • maxretry – The maximum number of failed authentication attempts to trigger a block

MySQL Security

Most of our applications communicate with databases performing various operations on the website. It is very important to secure access to our MySQL server to prevent exposing our data. We should never use the root user to connect and perform operations on a database. The first thing to do is create another user which would be used to connect to the database:

CREATE USER 'my_user'@'%' IDENTIFIED BY 'some_secure_password';

If you are going to connect to your database from a specific host, then restrict the user access to that specific host:

# Hostname

CREATE USER 'my_user'@'somehost.com' IDENTIFIED BY 'some_secure_password';

# Wildcard hostname
CREATE USER 'my_user'@'*.somehost.com' IDENTIFIED BY 'some_secure_password';

You can even specify the IP address to restrict the access to server:

# IP Address

CREATE USER 'my_user'@'192.168.1.0' IDENTIFIED BY 'some_secure_password';

# Subnet 192.168.1.1 through 192.168.1.254

CREATE USER 'my_user'@'192.168.1.%' IDENTIFIED BY 'some_secure_password';

Next, we need to make sure that this user does not have all the privileges on the database. We will grant only the necessary privileges for the user, to make sure that no harm would be ever done to database through this user:

GRANT ALTER, CREATE, DELETE, INDEX, INSERT, LOCK TABLES, SELECT, UPDATE on my_app.* TO 'my_user'@'-SPECIFICATIONS-';

Conclusion

In this article, we have covered how to set up basic security for your server. We have covered the configuration options necessary to get started, and the examples above should help you fill in the gaps and give an overview of some of the other configuration options available to you.

How do you intend to implement these security concepts? Can you think of any advanced use cases? What are they? Let us know in the comments!