How to lock down a new Ubuntu 12.04 or 14.04 VPS

I purchased a VPS and followed the following guide to lock it down some:

Login as root and change the password

[ # will denote a root shell prompt ]

# passwd
[ ... beneath a prompt+command will indicate the command will have some output, ask for further input or invoke some interactive environment, e.g. the nano text editor; within a text editor environment, ... will indicate there may be some text above and/or below the lines in which I'm interested ]

Set some ridiculously long password and store it in my local password manager, along with basic notes about the VPS’s IP address and the short name I’ll use to refer to it, e.g. in a shell alias on my local machine.

Add a “normal user”

I don’t want to spend most of my time authenticated as root, so I’ll create a normal user account:

# adduser michael

Set another ridiculously long password and store it in my local password manager along with the other notes for the VPS.

Customize sudoers

The sudo utility will enable my normal user account to run commands, modify files, etc. with root user privileges, but I want to modify the default sudoers config:

# visudo

For convenience, modify sudoers so that members of group sudo do not have to enter a password:


Close and save — make sure to confirm the save.

This setting is certainly convenient, but wouldn’t be such a good idea on a multi-tenant box. However, as I’m typically the only one who accessses my VPSs, and since I lock down sshd quite tightly (see notes below), the security concerns over doing this are mostly alleviated.

One caveat to mention — any publicly accessible network services should not be run as this sudo-enabled normal user, but as another non-sudoers user, or with the help of setuid/setgid and an unprivileged user/group like www-data.

Add the normal user to group sudo
# usermod -a -G sudo michael

I can double-check with:

# groups michael

I should seem something like:

michael : michael sudo
Switch to the normal user and setup .ssh
# su - michael
[ $ will denote a normal user prompt ]

$ mkdir .ssh && touch .ssh/authorized_keys
$ chmod 700 .ssh && chmod 600 .ssh/*
$ nano .ssh/authorized_keys

At this point I will copy/paste the public key/s from the machine/s I’ll be using to access the new VPS via ssh.

If I’ll be connecting from the VPS to other machines, I can do:

$ ssh-keygen -b 4096 -t rsa

I may or may not leave the “passphrase” blank, depending on my current level of paranoia.

Now I should have and id_rsa files under ~/.ssh.

Lock down SSH server

My philosophy is that sshd on a single-tenant box should be locked down very tightly. As necessary, the configuration can be relaxed.

Modify the sshd (SSH server) config file

Return to the root shell and open the config file for the SSH server:

$ exit
# nano /etc/ssh/sshd_config

I want to change and add to the defaults. What’s suggested below is not a replacement for the contents of the /etc/ssh/sshd_config file, but indicates only my typical changes or additions to the default settings:

Port 12345
PermitRootLogin no
PasswordAuthentication no
X11Forwarding no
UsePAM no
UseDNS no
AllowUsers michael

In practice, I usually set Port to something that doesn’t conflict with other things, in the neighborhood of 1025 – 65536. 🙂 I make sure to note the port number in my password manager, along with the rest of the notes for this VPS.

Restart sshd

# service ssh restart

Attempt to login remotely

Now from my local machine I’ll do something like:

$ ssh -p 12345 [email protected]

If I completed the above steps correctly, I should be logged in as my normal user, without having to enter a password, i.e. authentication was accomplished via public-key cryptography.

Basic firewall

Setting up a simple firewall with iptables is a good idea, especially for a VPS in the public cloud. On a local VM I may skip this step, that way I won’t have to modify the rules set in order to develop/test network services on arbitrary ports.

Create the rules set

# nano /etc/iptables.up.rules

For the most basic firewall protection, I copy in the rules set found in this repo next to, in the text file iptables.up.rules.


-A INPUT -i lo -j ACCEPT
-A INPUT ! -i lo -d -j REJECT
-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT
-A INPUT -p tcp -m multiport --destination-ports 80,443,12345 -j ACCEPT
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7


Note that port 12345 corresponds to the sshd Port I set in the previous section.

Load the rules

# iptables -F && iptables-restore < /etc/iptables.up.rules

I can inspect the current rules set like this:

# iptables -L -v

I should see something like:

Chain INPUT (policy DROP 501 packets, 51672 bytes)
pkts bytes target prot opt in out source destination
0 0 ACCEPT all -- lo any anywhere anywhere
0 0 REJECT all -- !lo any anywhere reject-with icmp-port-unreachable
1 28 ACCEPT icmp -- any any anywhere anywhere icmp echo-request
3585 271K ACCEPT tcp -- any any anywhere anywhere multiport dports www,https,12345
142 26324 LOG all -- any any anywhere anywhere limit: avg 5/min burst 5 LOG level debug prefix `iptables denied: '
1139 420K ACCEPT all -- any any anywhere anywhere state RELATED,ESTABLISHED

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

Chain OUTPUT (policy ACCEPT 88 packets, 6094 bytes)
pkts bytes target prot opt in out source destination
3963 995K ACCEPT all -- any any anywhere anywhere state RELATED,ESTABLISHED

Set the rules to load upon re/boot

I need to create a file:

# nano /etc/network/if-pre-up.d/iptables

Paste this into the new file:

/sbin/iptables-restore < /etc/iptables.up.rules

Save and make the script executable:

# chmod +x /etc/network/if-pre-up.d/iptables

Moment of truth

I’ll now reboot the VPS and make sure I can login remotely after a minute or so:

# reboot

Now try to connect once again via ssh, e.g. from my local machine:

$ ssh -p 12345 [email protected]

If I completed the above steps correctly, I should be logged in as my normal user, without having to enter a password.

If I made a mistake I probably won’t be able to login via ssh, so I’ll need access to the VPS’s console, which is usually provided through some browser applet or special SSH front-end, as indicated in the hosting company’s customer support site. If I’m setting up a local VM, then my virtualization software will give me access to the console.

In either case, after logging in through the console I’ll need to check the firewall rules and related files (see notes above), and the /etc/ssh/sshd_config file, for mistakes I may have made; and I may need to peek in the system logs for clues.

Update packages and run safe-upgrade

At this point I should be logged in as my normal user, ready to do some further admin work with the help of sudo. One of the first things I want to do is update the os packages via apt-get / aptitude

$ sudo apt-get update
$ sudo aptitude safe-upgrade
Set the timezone

If I want to set the server’s clock to correspond with my local timezone, I’ll do:

$ sudo dpkg-reconfigure tzdata

Select the appropriate timezone through the ncurses-based menu. Note that GMT / UTC may be preferrable, I find it depends on what I’ll be doing with the VPS.

Inspect and set the locale

I may want to inspect the “locale” settings for my VPS:

$ locale

The locale command will report something like:


That’s probably fine, but if something I didn’t expect or want was returned, I could run the following two commands:

sudo locale-gen en_US.UTF-8
sudo update-locale LANG=en_US.UTF-8

Changes will not be noticeable until I logout / login again. A complete listing of language and region codes is hosted on IANA’s website.

Automatic updates

I may or may not configure my VPS for some level of automatic updates, e.g. for security updates. In any case, the (version specific) instructions for doing so may be found on Ubuntu’s official help site.

Install some helpful things

This new VPS is probably bare-bones in terms of installed software, so I’ll now add some basic packages:

$ sudo apt-get install build-essential libssl-dev curl apache2-utils tmux dnsutils whois rsync htop iotop iftop

I may end up installing lots of additional packages, but the above list always serves me as a good starting point.

Leave a Reply

Your email address will not be published. Required fields are marked *