Skip to main content

This guide aims to help all administrators with security concerns. While we are not going to discuss any security “rocket science,” but we will go through the basic aspects of securing your Linux server from intruders and outside attack. In this first section, we will see the best practices for improved security, and in next part we will discuss some of tools that will help us to secure our server.

Why is security important for linux?

We know Linux is more secure and less prone to the virus than other popular operating systems, but there are still many issues out there that need to be fixed by the administrator. You must identify the needs of the server and what kind of application workload you are going to run on it. For example, if your server functionality is that of a web server, then it is also necessary to secure your web server services. Remember that Linux is open source, and thus it is open for anyone to identify the loopholes inside the operating system.

Securing SSH

Unlike the older Unix operating systems, nowadays nobody prefers to use telnet. SSH creates a secure data transfer between server and client, whereas telnet transfers the data in plain text. So SSH is the entry point for entering your operating system. You can improve the security of SSH sessions by doing below steps:

Disable root Login

The root user has superior power and can execute any command in the operating system. If your server is accessible by anyone on the internet, then it is better to disable root login directly from the SSH. Generally, intruders will try to crack or guess root user password first to penetrate your system.

Disable root login in the system by changing “PermitRootLogin” parameter in sshd_config file.

[root@ip-10-0-0-76 ~]# vi /etc/ssh/sshd_config

Find and uncomment the PermitRootLogin, and change the value to “no”.

PermitRootLogin no

Save the file and restart sshd service for Red Hat and CentOS. If you are running Ubuntu or Debian system, then restart the ssh service to reflect the changes.

Enable Detailed Logging for SSH

You can enable detailed logging for SSH through sshd_config file:

[root@ip-10-0-0-76 ~]# vi /etc/ssh/sshd_config

Find the “LogLevel” parameter and change the value to verbose:


If you want more detailed logging, then you can use the value DEBUG, DEBUG1, DEBUG2, and DEBUG3 instead of VERBOSE. Logging with a DEBUG level violates the privacy of users and is not recommended.

Linux Kernel Security Hardening

These are some more advanced security options. The kernel is complicated and performs micro-level operations. If you have to divide it down from security perspective, then it can include file systems, networking, processes, debugging, and more. Hardening the system in these areas are dependent upon the kernel you are using. By using system control interface, we can change the settings of the kernel. You can use sysctl command or edit the “/etc/sysctl.conf” file.

Open the “/etc/sysctl.conf” file:

root@ip-10-0-0-150:~# vi /etc/sysctl.conf

Add lines below at the end of file:

# Avoid a smurf attack
net.ipv4.icmp_echo_ignore_broadcasts = 1

# Turn on protection for bad icmp error messages
net.ipv4.icmp_ignore_bogus_error_responses = 1

# Turn on syncookies for SYN flood attack protection
net.ipv4.tcp_syncookies = 1

# Turn on and log spoofed, source routed, and redirect packets
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1

# No source routed packets here
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0

# Turn on reverse path filtering
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

# Make sure no one can alter the routing tables
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0

# Don't act as a router
net.ipv4.ip_forward = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0

# Turn on execshield for reducing worm or other automated remote attacks
kernel.exec-shield = 1
kernel.randomize_va_space = 1

# Tune IPv6
net.ipv6.conf.default.router_solicitations = 0
net.ipv6.conf.default.accept_ra_rtr_pref = 0
net.ipv6.conf.default.accept_ra_pinfo = 0
net.ipv6.conf.default.accept_ra_defrtr = 0
net.ipv6.conf.default.autoconf = 0
net.ipv6.conf.default.dad_transmits = 0
net.ipv6.conf.default.max_addresses = 1

# Increase system file descriptor limit
fs.file-max = 65535

# Allow for more PIDs (Prevention of fork() failure error message)
kernel.pid_max = 65536

# Increase system IP port limits
net.ipv4.ip_local_port_range = 2000 65000

# Tuning Linux network stack to increase TCP buffer size. Set the max OS send buffer size (wmem) and receive buffer size (rmem) to 12 MB for queues on all protocols.
net.core.rmem_max = 8388608
net.core.wmem_max = 8388608

# set minimum size, initial size and max size
net.ipv4.tcp_rmem = 10240 87380 12582912
net.ipv4.tcp_wmem = 10240 87380 12582912

# Value to set for queue on the INPUT side when incoming packets are faster then the kernel process on them.
net.core.netdev_max_backlog = 5000

# For increasing transfer window, enable window scaling
net.ipv4.tcp_window_scaling = 1

Save and exit from file and reboot your machine.

The purpose of each parameter has been explained with comments in the text. Remember, you need to identify whether these parameters are required for tuning your OS or not. For example, if you are increasing your buffer size, then it is going to cost you more memory usage on the server.

File and Directory Permissions

The major benefit of Linux is it can have more than one user. If your Linux server is multipurpose and many users are accessing the server then it is very important to restrict files and directory permissions. These permissions define who can read, write, and execute your files and directories. You can view directory permissions by “ls -l” command.

root@ip-10-0-1-128:~# ls -l /etc/passwd
-rw-r--r-- 1 root root 2378 Jul 12 12:08 /etc/passwd

In the above output, the first ten characters show the permissions of the file. The dash (-) character at first indicates whether it is file or directory. If the first character is a dash (-) then it is a file; d is for directory and s for special file. The next three characters define the file owner’s permissions. The above file has read and write permissions for the owner. Next three characters indicate the permissions for the group which file belongs. Here the group root has only read permission on the file. Last three characters indicate permissions for all other users, which are not the owner or part of the group.

You can change the permission of file or directory with chmod command:

[root@ip-10-0-0-222 ~]# chmod 644 document
[root@ip-10-0-0-222 ~]# ls -l document
-rw-r--r--. 1 root root 16 Jul 2 04:03 document

Above command provides read and write permissions to the file owner and read permissions to the group and others.

If you want to change ownership and group of file, you can use chown command:

[root@ip-10-0-0-222 ~]# chown linuxacademy:linuxacademy document
[root@ip-10-0-0-222 ~]# ls -l document
-rw-r--r--. 1 linuxacademy linuxacademy 16 Jul 2 04:03 document

We have changed the ownership of document file from root to linuxacademy.

Sticky Bit Permissions

A sticky bit permission is special permission which is useful when a directory has full permissions for everyone, but you don’t want anyone to delete a file or directory except the owner or group owner. You can assign sticky bit permissions in two ways:

[root@ip-10-0-0-222 ~]# chmod 1777 document
[root@ip-10-0-0-222 ~]# chmod +t document1

If you want to remove a sticky bit permission, then you can use one of the commands below:

[root@ip-10-0-0-222 ~]# chmod 0777 document
[root@ip-10-0-0-222 ~]# chmod -t document1

Firewall and Open Ports

Configuring firewalls are very important, as intruders can scan your open ports and might try to get into your system through those ports. Detect the listening ports, and close the ports which aren’t required. You can check listening ports by using the netstat command:

root@ip-10-0-0-58:~# netstat -tulp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 *:ssh *:* LISTEN 1298/sshd
tcp6 0 0 [::]:ssh [::]:* LISTEN 1298/sshd
udp 0 0 *:bootpc *:* 926/dhclient

Attribute (t=TCP, u=UDP, p=Port, l=Listening)

You can use a firewall to block all the open ports. iptables is one option for advanced administrators. However, if you are using Red Hat 7 or CentOS 7 then firewalld is good alternative option, depending on what the administrator more comfortable using. Ubuntu also offers a default, less complicated firewall, “ufw” (uncomplicated firewall).


iptables allows the user to create security rules to meet the security requirements of Linux. You can configure rules for different protocols. You can configure rules for IPv4/IPv6, as well as UDP/TCP protocols. iptables requires superuser privileges to configure rules.

If you don’t have iptables installed by default on your machine, then you can install it by using the following commands:

For Ubuntu or Debian:

root@ip-10-0-0-159:~# apt-get install iptables

For CentOS:

[root@ip-10-0-0-222 ~]# yum install iptables-services


[root@ip-10-0-0-222 ~]# yum install iptables

Display the status of iptables:

root@ip-10-0-0-159:~# iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination

Chain FORWARD (policy ACCEPT)
target prot opt source destination

Chain OUTPUT (policy ACCEPT)
target prot opt source destination

If you want flush all the iptables rules, then use command below. Be careful, it will delete all your iptables rules:

root@ip-10-0-0-159:~# iptables -F

Below command will block all the input traffic in your server. By default this will not allow any traffic to pass through in server. You need to open required ports for running services individully.

root@ip-10-0-0-159:~# iptables -P INPUT DROP

The below rules will allow only SSH and HTTP traffic on your host:

root@ip-10-0-0-159:~# iptables -A INPUT -p tcp --dport 80 -j ACCEPT
root@ip-10-0-0-159:~# iptables -A INPUT -p tcp --dport 22 -j ACCEPT
root@ip-10-0-0-159:~# iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT tcp -- anywhere anywhere tcp dpt:http
ACCEPT tcp -- anywhere anywhere tcp dpt:ssh

Chain FORWARD (policy ACCEPT)
target prot opt source destination

Chain OUTPUT (policy ACCEPT)
target prot opt source destination

The below rule will block specific TCP traffic for port 3306 and 25:

root@ip-10-0-0-159:~# iptables -A INPUT -p tcp --dport 25 -j DROP
root@ip-10-0-0-159:~# iptables -A INPUT -p tcp --dport 3306 -j DROP
root@ip-10-0-0-159:~# iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT tcp -- anywhere anywhere tcp dpt:http
ACCEPT tcp -- anywhere anywhere tcp dpt:ssh
DROP tcp -- anywhere anywhere tcp dpt:smtp
DROP tcp -- anywhere anywhere tcp dpt:mysql

Chain FORWARD (policy ACCEPT)
target prot opt source destination

Chain OUTPUT (policy ACCEPT)
target prot opt source destination

There are also more configurations, such as blocking IP addresses with specific ports, forwarding default ports to another port, and more. You can view the iptables man page to explore other options.


firewalld works as frontend controller for iptables to configure firewall rules. Unlike iptables, firewalld uses services and zones instead of chain and rules. All the configuration changes will be applied without restarting firewall daemon.

Install and start the firewalld service on Red Hat or CentOS with the commands below:

[root@ip-10-0-0-202 ~]# yum install firewalld
[root@ip-10-0-0-202 ~]# systemctl start firewalld.service
[root@ip-10-0-0-202 ~]# systemctl enable firewalld.service

Add rule to allow HTTP traffic. “–permanent” will make this rule persistent. “–zone” will add this rule in public zone:

[root@ip-10-0-0-202 ~]# firewall-cmd --zone=public --add-service=http --permanent

Reload the firewall so changes reflect immediately:

[root@ip-10-0-0-202 ~]# firewall-cmd --reload

The below rules will allow or deny tcp traffic:

[root@ip-10-0-0-202 ~]# firewall-cmd --zone=public --add-port=10050/tcp --permanent
[root@ip-10-0-0-202 ~]# firewall-cmd --zone=public --remove-port=10050/tcp --permanent

Again, you can configure many things using firewalld; these are only some basic examples for firewall configuration.


ufw is an easy-to-use firewall frontend. iptables and firewalld can be difficult for the beginner or a non-administrator to understand, but ufw allows you to enhance your security with less difficulties. ufw is typically installed in Ubuntu, by default, but if it is not then install it by using:

root@ip-10-0-1-128:~# apt-get install ufw

You can define the default policies in ufw. You should allow only the specific ports which need to be listened for by server and rest of the ports should be closed.

root@ip-10-0-1-128:~# ufw default deny incoming

Above command will deny any incoming traffic from the outside by default. Now you need to allow the ports that are necessary for the server:

root@ip-10-0-1-128:~# ufw allow ssh
Rules updated
Rules updated (v6)
root@ip-10-0-1-128:~# ufw allow 8080
Rules updated
Rules updated (v6)

To enable ufw, use the command below:

root@ip-10-0-1-128:~# ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup

As with iptables and firewalld, you can also do many more things with ufw, like allowing source IP to specific ports, etc.


Hopefully you now have some insight into basic Linux server security and hardening.In the next guide, we will discuss some useful tools for server hardening. Stay tuned!

Comments are disabled for this guide.