Securing the Ubuntu server is crucial for protecting every service that works over your server – especially when those services are exposed to the Internet. While steps in this article are most applicable for fresh installations of Ubuntu, they can also be applied to production servers (with appropriate maintenance windows and backups).

This article shows you how to secure the latest stable version of Ubuntu (version 16.04 LTS, also known as Xenial Xerus). After completing the steps in this article you will have a secure platform to build on. In addition to securing the server itself, we also recommend implementing a WAF and DDoS mitigation system to prevent threats from getting through in the first place. (StackPath has a 15-day free trial you can try out.)


Before taking steps to harden your Ubuntu server, you should have a basic understanding of the following:

  1. Common file editors like: vi, vim, and nano
  2. Basic directory moving (cd)
  3. Using SSH for connections
  4. File structures on Linux
  5. apt package manager

Steps for Hardening Ubuntu

If you already have Ubuntu installed, skip to the section titled Base System Installation. If you are installing Ubuntu for the first time, proceed to the next step.

BIOS Security Password

When hardening your operating system you have to take all aspects of security into account. That includes protecting physical access to BIOS with a strong password. Enter the BIOS settings on your server and activate this option.

Fresh Installation

For a fresh and clean installation, select Install Ubuntu Server from this window. Then enter the hostname for your system. (I have named mine UbuntuServerBlog.)

Home Directory Encrypting

With Ubuntu you can protect the /home directory with encryption from the beginning of the installation process by selecting Yes in this window.

Disk Partitioning

It’s essential to have a secure partitioning scheme for the operating file systems storage. Usually this means segregating partitions. (Typically you first create the partitions when you are installing the operating system for the first time.)

You can partition disks from this window. The disks are defined as follows:

    • /boot contains necessary files for booting the system that contains the kernel
    • /swap is the swap memory used when the RAM is full
    • /home is for user files
    • /usr is typically used for application software, binary files and documentation
    • /var is for logs, Pid files, queues, temporary files, and content pages served by the web server
    • / is for key system operation and configuration files

For security reasons it’s recommend to isolate data files from operating system files. If a file system has problems with space, it could affect another file system and server operation.

Automatic Updates

You should never automatically update Ubuntu. Updates should be done manually within proper maintenance windows. To disable automatic updates, select the No automatic updates option in this window.

Base System Installation

To harden any operating system you should start by having the minimal amount of software required for a working server. Fortunately, Ubuntu makes this easy. Instead of being pre-installed, all software, including SSH, is installed and configured separately.

Only choose what you absolutely need from this list, including standard system utilities.

Use Sudo Instead of Root

Sudo is a great security feature. With Ubuntu you don’t have to use the root user (and you don’t need it). Instead you can grant privileged roles to yourself and other users. Digital Ocean shows you how to do this.

Configure Open SSH Management (Client and Server)

When using SSH to manage servers with Ubuntu, you can perform authentication three different ways: 1) username and password authentication which is the default option, 2) private and public key authentication which is the method we’ll use, and 3) token authentication.

On Server

First install the openssh-server locally:

luise@ubuntuServerBlog:~$ sudo apt install openssh-server

Then generate authorization keys for RSA:

sudo ssh-keygen -t rsa 
[sudo] password for luise:  
Generating public/private rsa key pair. 
Enter file in which to save the key (/root/.ssh/id_rsa):  
Created directory '/root/.ssh'. 
Enter passphrase (empty for no passphrase):  
Enter same passphrase again:  
Your identification has been saved in /root/.ssh/id_rsa. 
Your public key has been saved in /root/.ssh/ 
The key fingerprint is: 
SHA256:tsrronalb0Qr9qCofKvQCjDPBbNw9fQJh2b51WA7al0 root@ubuntuServerBlog 
The key's randomart image is: 
+---[RSA 2048]----+ 
|    . oo. oo     | 
|   . o=+ o...    | 
|. +  o..o.o E    | 
| o +  . .o o     | 
|o . .. .S .      | 
|.= .+ +o .       | 
|o.+o B  .        | 
|=.o.+.o.         | 
|++++.=*.         | 

Now we’ll check the server’s public key fingerprint. Put this information in a trusted place where your users can see it. You can do this for both MD5 and SHA256 fingerprints.

For SHA256 hash:

sudo ssh-keygen -l -f /etc/ssh/ -E SHA256 
2048 SHA256:S9DwGt5nASjltxil0ReXmzSYUEewKXu881m8CKeTU+I root@ubuntuServerBlog (RSA)

For MD5 hash:

sudo ssh-keygen -l -f /etc/ssh/ -E md5 
2048 MD5:04:1a:cb:48:8e:6c:44:85:94:fd:bc:e8:65:75:3f:20 root@ubuntuServerBlog (RSA)

For connecting to the server, possible fingerprints for SSH are:

MD5: 04:1a:cb:48:8e:6c:44:85:94:fd:bc:e8:65:75:3f:20

SHA256: S9DwGt5nASjltxil0ReXmzSYUEewKXu881m8CKeTU+I

Again, put this information in a trusted place. The ECDSA algorithm comes by default with Ubuntu, but if you are going to use RSA, you need to change a line in your sshd_config file.

Edit the server file /etc/ssh/sshd_config:

sudo nano /etc/ssh/sshd_config

Comment out the following line (adding #):

HostKey /etc/ssh/ssh_host_ecdsa_key

#HostKey /etc/ssh/ssh_host_ecdsa_key

Save the file, then restart the SSHD service:

sudo service ssh restart

Now connect to the Ubuntu server from the client.

On User Client

The user client could be a Windows, Linux, or Mac PC. It does not matter. In this case I will use a Linux Debian client with username clientluis.

Let’s connect to the server for the first time under the server account.

From here you should check that the server fingerprint (red characters) matches the previously-created fingerprint. By default it’s an MD5 hash function:

clientluis@debianleb:~$ ssh luise@ 
The authenticity of host ' (' can't be established. 
RSA key fingerprint is 04:1a:cb:48:8e:6c:44:85:94:fd:bc:e8:65:75:3f:20. 
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '' (RSA) to the list of known hosts. 
luise@'s password: 
Welcome to Ubuntu 16.04.1 LTS (GNU/Linux 4.4.0-31-generic i686) 

* Documentation: 
* Management: 
* Support: 

28 packages can be updated. 
0 updates are security updates. 

*** System restart required *** 
Last login: Sat Sep 10 01:43:28 2016 from 

You successfully connected to the server. Now quit the server and return to your client again.

When using SSH to manage servers, you can authenticate by “user/password” or by the user client private/public key pair. The latter is more secure as it requires some to have your physical computer to access the server remotely (in addition to a password).

The following steps are for creating the keys (private/public) for the user client (“clientluis” in this case). Once the keys are created, the public key has to be copied to the server so the server knows that you can connect to it.

You should have your SSH Key pair from the previous steps. If you don’t, go ahead and create it:

ssh-keygen -t rsa 
Generating public/private rsa key pair. 
Enter file in which to save the key (/home/clientluis/.ssh/id_rsa):  
Created directory '/home/clientluis/.ssh'. 
Enter passphrase (empty for no passphrase):  
Enter same passphrase again:  
Your identification has been saved in /home/clientluis/.ssh/id_rsa. 
Your public key has been saved in /home/clientluis/.ssh/ 
The key fingerprint is: 
23:74:8e:fd:c7:a5:99:bf:a3:22:d2:1d:47:42:20:d9 clientluis@debianleb 
The key's randomart image is: 
+--[ RSA 2048]----+ 
|      .o..       | 
|      ..E .      | 
|      . ..       | 
|     . =  . .    | 
|      o S  o  .  | 
|       . o...=   | 
|       . ..o*    | 
|      . o o. ..  | 
|       . . ...oo | 

RSA public keys will be located at /home/clientluis/.ssh/ RSA is an algorithm that uses asymmetric keys for encrypting and signing. You can share the public key with anyone you wish to communicate with, but the private key is the one that needs to be protected. In this case, the public key is used to authorize the user “clientluis” from the server.

Issue the command ssh-copy-id to copy your public key to the server:

ssh-copy-id -i .ssh/ luise@ 
The authenticity of host ' (' can't be established. 
RSA key fingerprint is 04:1a:cb:48:8e:6c:44:85:94:fd:bc:e8:65:75:3f:20. 
Are you sure you want to continue connecting (yes/no)? yes 
Warning: Permanently added '' (RSA) to the list of known hosts. 
luise@'s password:  
Now try logging into the machine, with "ssh 'luise@'", and check in: 
to make sure we haven't added extra keys that you weren't expecting.

Next time you connect to the server you will be prompted for your passphrase (access to your private key) that was created before.

Connect to the server:

ssh luise@ 
Enter passphrase for key '/home/clientluis/.ssh/id_rsa':

Now you are on the server and can configure it from a management device (desktop, laptop, etc). Check file permissions for the ssh authorized key you copied (with ssh-copy-id). It must be owned by your user and group:

luise@ubuntuServerBlog:~$ ls -l .ssh/authorized_keys  
-rw------- 1 luise luise 402 Sep  4 12:22 .ssh/authorized_keys

Now you need to edit the file /etc/ssh/sshd_config:

nano /etc/ssh/sshd_config

We’ll add a line so the sshd daemon only listens on the authorized IP on the server interface. Find the line in the file that starts with #ListenAddress, then add the following line below it with your server IP:


It’s always good to have a second interface just for management. In this case you should put the Management IP address there.

Next we’ll restrict password authentication. This way your server will authenticate more securely using your authorized public key pair and, of course, a client passphrase to access your private key. You can also consider a multifactor approach with OATH-TOTP.

Find the line that starts with #PasswordAuthentication and add the following line below it:

#PasswordAuthentication yes 
PasswordAuthentication no

The next three line changes will improve security further. Still working with the same files using Nano, do the following:

In the file /etc/sshd/sshd_config, include this line at the end of the file to deny X11 forwarding for SSH:

X11Forwarding no

Replace the line Loglevel INFO with the following line to record more information about SSH login attempts:

LogLevel INFO  // Erase this one 

Replace the line LoginGraceTime 120 with the following line to reduce the grace time for creating an SSH connection:

LoginGraceTime 120 // Erase this one 
LoginGraceTime 10

That was the last change we’ll make in the sshd_config file. Before moving on, save the file and exit the Nano editor.

Now restart the server SSH daemon:

sudo service ssh reload

Edit the file /etc/hosts.allow:

nano hosts.allow

This file contains a list of IPs permitted to access the server via SSH.

Include the following line, which indicates the authorized client IP for management, and then save the file:


Edit the file /etc/hosts.deny:

nano hosts.deny

This file contains a list of IPs that are denied SSH access.

Include the following line, then save the file.

sshd: ALL

This is an implicit deny which is a good security practice.

Add Security Login Banner

You should warn users about consequences of connecting to the server. To do this, you’ll need to edit the file /etc/

sudo nano /etc/

Add a warning message similar to this:


Now let’s disable the banner message from motd.

Edit the file /etc/pam.d/sshd:

sudo nano /etc/pam.d/sshd

Comment out the following two lines to avoid banner messages from motd:

session    optional  motd=/run/motd.dynamic 
session    optional noupdate 
#session    optional  motd=/run/motd.dynamic 
#session    optional noupdate

Now edit the file /etc/ssh/sshd_config:

sudo nano /etc/ssh/sshd

Uncomment the following line to show the banner message you created:

#Banner /etc/ 
Banner /etc/

Save the file and restart the SSHD Service:

sudo service ssh restart

Next time you connect from the client machine you should see something like this:

clientluis@debianleb:~$ ssh luise@ 
Enter passphrase for key '/home/clientluis/.ssh/id_rsa':  
Last login: Sat Sep 10 02:30:07 2016 

Remove Unneeded Services (Using rcconf)

By default, the base install of Ubuntu comes with a few services. You can check the services currently installed and remove what you don’t need.

List the installed network services:

luise@ubuntuServerBlog:~$ netstat -lp 
(Not all processes could be identified, non-owned process info 
 will not be shown, you would have to be root to see it all.) 
Active Internet connections (only servers) 
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name 
tcp        0      0 *:ssh                   *:*                     LISTEN      -                
tcp        0      0 *:telnet                *:*                     LISTEN      -                
tcp        0      0 *:sunrpc                *:*                     LISTEN      -                
tcp6       0      0 [::]:ssh                [::]:*                  LISTEN      -                
tcp6       0      0 [::]:sunrpc             [::]:*                  LISTEN      -                
udp        0      0 *:sunrpc                *:*                                 -                
udp        0      0 *:kerberos4             *:*                                 -                
udp        0      0 *:bootpc                *:*                                 -                
udp6       0      0 [::]:sunrpc             [::]:*                              -                
udp6       0      0 [::]:kerberos4          [::]:*                              -      

Uninstall Telnet (telnetd server):

sudo apt-get remove telnetd

Disable rpcbind (portmapper):

/etc/init.d$ sudo update-rc.d -f rpcbind remove
perl: warning: Setting locale failed. 
perl: warning: Please check that your locale settings: 
LANGUAGE = "en_US:en", 
LC_ALL = (unset), 
LC_CTYPE = "UTF-8", 
LANG = "en_US.UTF-8" 
    are supported and installed on your system. 
perl: warning: Falling back to a fallback locale ("en_US.UTF-8"). 

Also remove software like the Dhcp client and ftp:

sudo apt-get remove isc-dhcp-client ftp info eject

Install the utility rcconf to help you disable unnecessary services:

sudo apt-get install rcconf

Run rcconf:

sudo rcconf

Uncheck all of the services in this window that appears. Then click Ok and exit.

Run rcconf again to check that your changes were saved. The window that appears should look like this.

Disable IPv6 (if not being used)

Check for IPv4 and IPv6:

sudo ifconfig 
enp0s3    Link encap:Ethernet  HWaddr 08:00:27:a6:d1:95   
          inet addr:  Bcast:  Mask: 
          inet6 addr: fd58:20a0:5afd:0:a00:27ff:fea6:d195/64 Scope:Global 
          inet6 addr: fe80::a00:27ff:fea6:d195/64 Scope:Link 

The green lines show you have an IPv6 address.

Edit the file /etc/sysctl.conf:

sudo nano /etc/sysctl.conf

Add the following line, save the file, and exit:

net.ipv6.conf.all.disable_ipv6 = 1

Run sysctl to load the previous line as a kernel parameter:

/etc$ sudo sysctl –p

Confirm that you no longer have IPv6 on your server – just IPv4:

/etc$ sudo ifconfig 
enp0s3    Link encap:Ethernet  HWaddr 08:00:27:a6:d1:95   
          inet addr:  Bcast:  Mask: 
          RX packets:3035 errors:0 dropped:0 overruns:0 frame:0 
          TX packets:1397 errors:0 dropped:0 overruns:0 carrier:0 
          collisions:0 txqueuelen:1000  
          RX bytes:220187 (220.1 KB)  TX bytes:228137 (228.1 KB) 

Add Some Network Protection

Edit the file /etc/sysctl.conf:

/etc$ sudo nano /etc/sysctl.conf

Uncomment the following lines and save the file. This is to prevent the server (at the kernel level) from receiving syn attacks, ICMP redirects, and source routed packets:

#net.ipv4.conf.all.accept_source_route = 0 
#net.ipv6.conf.all.accept_source_route = 0 
#net.ipv4.conf.all.accept_redirects = 0 
#net.ipv6.conf.all.accept_redirects = 0 
#net.ipv4.conf.all.send_redirects = 0 
net.ipv4.conf.all.accept_source_route = 0 
net.ipv6.conf.all.accept_source_route = 0 
net.ipv4.conf.all.accept_redirects = 0 
net.ipv6.conf.all.accept_redirects = 0 
net.ipv4.conf.all.send_redirects = 0 

Run sysctl to load the previous line:

/etc$ sudo sysctl –p

Protect Grub

It’s assumed that version 2 of Grub is being used.

Generate the hash for the grub password:

Enter password:  
Reenter password:  
PBKDF2 hash of your password is  

Edit the file /etc/grub.d/40_custom:

/etc$ sudo nano /etc/grub.d/40_custom

At the end of the file, include the following lines to add a user and the corresponding hash password created before (the red part must be the same as the one created with grub-mkpasswd-pbkdf2).

set superusers="luise" 
password_pbkdf2 luise 

Save the file and quit.

Update Grub:

sudo update-grub2 
Generating grub configuration file ... 
Found linux image: /boot/vmlinuz-4.4.0-36-generic 
Found initrd image: /boot/initrd.img-4.4.0-36-generic 
Found linux image: /boot/vmlinuz-4.4.0-31-generic 
Found initrd image: /boot/initrd.img-4.4.0-31-generic 

Check the file /boot/grub/grub.cfg to confirm that the lines were added correctly (near the end of the file):

sudo cat /boot/grub/grub.cfg 
# menu entries you want to add after this comment.  Be careful not to change 
set superuser="luise" 
password_pbkdf2 luise 
grub.pbkdf2.sha512.10000.25E25776978D46E948077793B1529EB3407D85C9071C5B0C046B15361677AB61C955148693DFDCCB92ACFEBD5BE7652BAF53571AEC6E143BDD1B1845AB5A0C65.4FEC54088721BB158B3BFF87FEAAF9C9FC2FF252B35202C6927EC852BC883791E1309B43629C902167668D80479C03E4E9789900B24C07D2C546FE4838E4A4E3 ### END /etc/grub.d/40_custom ### ### BEGIN /etc/grub.d/41_custom ### ### END /etc/grub.d/41_custom ###

Now reboot the system:


Next time you boot the system you’ll be asked for the username and password to access the Grub menu.

Harden User Accounts

Disable shell for user accounts that are not supposed to interactively connect to the server.

Edit the file /etc/passwd:

/etc$ sudo nano /etc/passwd

Add the word nologin at the end of lines for desired users:

luis2:x:1001:1001:Luis prueba,,,:/home/luis2:/bin/bash 
luis2:x:1001:1001:Luis prueba,,,:/home/luis2:/bin/nologin 
For User Monitoring

Install the acct package to track user activity on the server:

/etc$ sudo apt-get install accton

Enable logging and reporting:

/etc$ accton on
For Security Profiles

To enforce profile parameters for all users, edit the file /etc/profile:

/etc$ nano /etc/profile

Then add the following lines and save the file:

# To enforce to all users profiles 
readonly HISTFILE 
readonly HISTSIZE 
readonly HISTIGNORE 

By default, the sudo software is already installed on Ubuntu. All users who want administrative privileges must use sudo, but you can allow specific commands to specific users. For example, you can add the following line to the file /etc/sudoers to permit the user “luis” to execute the command ifconfig (he must enter his password):

luis ALL=(ALL) PASSWD: /sbin/ifconfig

In this case, the user “luis” can only execute the ifconfig command and nothing else with sudo/root privileges.

Network Firewall for the Server

Ubuntu comes with a firewall manager for Iptables called ufw. Check the configuration (with Iptables) to see all traffic that is currently permitted to the server:

sudo iptables -L 
[sudo] password for luise:  
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     

You can check the status of the ufw:

sudo ufw status 
Status: inactive

Now we'll enable the firewall. Doing this will apply default rules, denying all incoming traffic and allowing all outgoing traffic. It’s recommended to do this directly on the server console, although the SSH connection you are using stays up as long as you do not close it:

sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y 
Firewall is active and enabled on system startup 

You can check with the command iptables –L to see how the rules were changed.

Now, permit your SSH connection. First, allow SSH only from your client host (in this case, client host is

sudo ufw allow from to port 22 
Rules updated

By default, incoming ICMP traffic (e.g. Ping) is allowed. It is normally a good practice to block all ICMP and use it on a per-demand basis or for doing specific troubleshooting. To disable ICMP, change ACCEPT to DENY in the file /before.rules for the INPUT chain.

Edit file /etc/ufw/before.rules:

sudo nano /etc/ufw/before.rules

Find the following lines and substitute the ACCEPT string for DROP:

# ok icmp codes for INPUT 
-A ufw-before-input -p icmp --icmp-type destination-unreachable -j ACCEPT 
-A ufw-before-input -p icmp --icmp-type source-quench -j ACCEPT 
-A ufw-before-input -p icmp --icmp-type time-exceeded -j ACCEPT 
-A ufw-before-input -p icmp --icmp-type parameter-problem -j ACCEPT 
-A ufw-before-input -p icmp --icmp-type echo-request -j ACCEPT 
# ok icmp codes for INPUT 
-A ufw-before-input -p icmp --icmp-type destination-unreachable -j DROP 
-A ufw-before-input -p icmp --icmp-type source-quench -j DROP 
-A ufw-before-input -p icmp --icmp-type time-exceeded -j DROP 
-A ufw-before-input -p icmp --icmp-type parameter-problem -j DROP 
-A ufw-before-input -p icmp --icmp-type echo-request -j DROP 

Reset the firewall for the ICMP rules to take effect:

sudo ufw reload 
Firewall reloaded

Now, create the rules to permit web traffic for HTTP and HTTPS services:

sudo ufw allow from any to port http 
[sudo] password for luise:  
Rule added 
luise@ubuntuServerBlog:~$ sudo ufw allow from any to port https 
Rule added

Now create the rules to permit incoming web traffic to your server for HTTP and HTTPS services:

sudo ufw status 
Status: active 
To                         Action      From 
--                         ------      ---- 22            ALLOW       80            ALLOW       Anywhere           443           ALLOW       Anywhere    

Activate firewall logs:

sudo ufw logging on 
Logging enabled

Logging (Syslog)

Rsyslog, a log processing system, is already installed with the base installation of Ubuntu. For sending syslog to a remote syslog server, edit the file /etc/rsyslog.conf:

sudo nano /etc/rsyslog.conf

Add the line with the hostname or IP of the remote syslog server and port UDP 514:

*.* @hosname_of_syslog_server:514

Remember that the syslog server (another server) must be up so that it can receive the logs from this server. In another post we show you how to redirect logs to a central syslog server.

Restart the rsyslog service:

/etc/init.d$ service rsyslog restart  
==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units === 
Authentication is required to restart 'rsyslog.service'. 
Authenticating as: Luis Enrique,,, (luise) 

Check Security with Tiger GPL Application

Install the tiger utility that comes with some security and assessment tools (chkrootkit, tripwire, and more.):

sudo apt-get install tiger

Run tiger to check your system security. This process could take a few minutes:

sudo tiger

Look, analyze, and follow recommendations indicated in the output. The results location is in the last line of the output:

09:54> Performing check of embedded pathnames... 
09:54> Security report completed for ubuntuServerBlog. 
Security report is in `/var/log/tiger/'.

Check the file (marked in red) and be aware of the “Alerts” outputs. Those must be treated immediately.


After following the steps above and directing the alerts generated by tiger, you'll have a secure operating system to build your web application on. As you add other software such as web servers like Apache and Nginx, and database management systems like MySQL, make sure to harden them as well.

In another tutorial we show you how to harden Apache on UbuntuIf you have any other methods for hardening the Ubuntu server, let us know in the comment section below.

Start 15-day Trial

Every Secure Content Delivery Plan includes WAF and DDoS mitigation.

Choose plan