How I Secured my Server

Recently my server after becoming victim to a series of successful hacking attempts. Unfortunately, I’d become neglectful and complacent, and had forgotten that the internet is actually a writhing cesspool of malevolent horrors trying constantly to haul you and your websites into the depths of hell. Hopefully this list helps arm against the nightmares just as it did me!

This is a list of the eight major categories of server solutions I found helpful, and that have kept my server safe.

1. Routine Backups

It doesn’t get any more important than this. If you’re not regularly backing up your server, you’re vulnerable. At some point, a hacker might well successfully breach, despite your best efforts, and if you don’t have a backup on hand you have a potentially monumental recovery task ahead of you.

My server is a Linode that I rent. I can’t recommend them or their service enough. In addition to tight security measures in general (including 2FA built into their web service), they offer a paid backup service which keeps several entire copies of your server, stored a few days apart. They can be redeployed in a click of a button, and this can minimize downtime in the event of true catastrophe.

These Linode backups can also be deployed on a secondary Linode, allowing you to explore the entire backup, copy whatever information you might need, and transfer it back to your web server.

If you don’t have a hosting service that offers automatic backups but instead do your own hosting with your own physical servers, a Linode might be a handy tool for uploading off-site backups. Just tar everything up and upload it through a secure connection such as scp using keys. TechRepublic has an article on keyed scp uploads.

2. Auditing the server

One of my very favorite tools for server auditing is lynis. I ran this over and over again, finding different aspects of server security to correct. It checks file permissions, hardware settings, installed software, Apache and SSH configuration, password rules, and just about everything else. If you want to secure your server, this is an incredible tool to help guide you.

When it comes to finding problems already present, you should install and run chkrootkit and rkhunter. These programs look for root kits and other signs of infiltration. I have them set to run regularly as chron jobs and email the results to me.

0 3 * * 0 /usr/sbin/chkrootkit 2>&1 | mail -s "Chkrootkit Report"
0 3 * * 0 /usr/bin/rkhunter -c 2>&1 | mail -s "Rkhunter Report"

3. Secure user accounts

Many of my user accounts aren’t used by actual human beings. For those accounts, I generated random passwords for all of my user accounts in LastPass, and then stored them all in a secure LastPass note.

Additionally, go through your user directories and make sure they actually own all their files, especially in their web directory. Check for excessively permissive permissions that might have been set by accident, through laziness, or maliciously. File permissions should be as restrictive as reasonably possible.

Generally, within the web directory, permissions should be either 640 for files and 750 for folders, or 644 and 755 respectively. If you use the former permissions, which are slightly tighter, it’s important that the user is part of your web group (www-data on Debian), and that the files are owned by the user and that group predominately.

So for instance, I would execute the following instructions in my public_www directory:

chown -R peppe:www-data *
find /home/peppe/public_www -type d -exec chmod 750 {} \; 
find /home/peppe/public_www -type f -exec chmod 640 {} \; 

When the www-data user comes through, it’s able to read the files and directories, since it shares a group with the owner. Random other users are not. Most people find this particular setting draconian, and there’s nothing shameful about 755 and 644 permissions, but my predilection is to be as restrictive as reasonably possible.

If you use WordPress, file ownership and permissions become very complicated quickly. See more below.

4. Automatic updates

Updates are incredibly important, as updates are very often made in response to an exploit. If you don’t update in time, somebody might try their new exploit on you next!

If you have aptitude, add this to your daily crontab:

0 0 * * * (/usr/bin/aptitude -y update && /usr/bin/aptitude -y safe-upgrade) 2>&1 >> /var/log/auto_update.log

Additionally, you should periodically log into your server and do a larger, more complete update without the safe-upgrade argument. That looks like this on Debian:

aptitude update
aptitude dist-upgrade

Beyond that, any other software you use that isn’t controlled by aptitude should be updated. In particular, this includes WordPress or other platforms on the web server.

5. Securing SSH

The very first step in securing SSH is to disable root login and restrict the number of authorization retries. These two settings dramatically limit the server’s exposure to SSH attacks. I also chose to use an atypical port for SSH just to add a touch of obscurity, and for sake of example it’s shown here as 24. That’s not it, because if I posted it then it wouldn’t be very obscure!

I created a group (sshers), disallowing any logins from users not in the approved group. Every user who I would like to be able to access the server by SSH has to be added to the sshers group.

The remainder of the settings were recommendations made by the lynis auditing program.

Additionally, I created an ssh key so that I could log into my server more easily and securely. I use Pageant to store my key on my Windows machine, and have a second key for my Linux laptop. has an instructional post on setting up Pageant and keys with Windows.

Port 24
PermitRootLogin No
AllowGroups sshers
PubkeyAuthentication Yes
MaxAuthTries 2
StrictModes yes
MaxSessions 2
AllowAgentForwarding No
GatewayPorts No
X11Forwarding No
Protocol 2
ClientAliveCountMax 2
PermitEmptyPasswords No

6. Install Firewall / Secure Ports

I installed iptables. This is a simple firewall. There’s an excellent article on setting up iptables at PhenoixNap, but below are a basic collection of instructions I used to set it up. In order, they allow loopback traffic, HTTP traffic, SSH traffic, and HTTPS traffic. The final instruction disallows all other traffic. And incidentally, do not forget to allow SSH traffic if you’re logged in remotely.

iptables –A INPUT –i lo –j ACCEPT
iptables –A INPUT –p tcp ––dport 80 –j ACCEPT
iptables –A INPUT –p tcp ––dport 24 –j ACCEPT
iptables –A INPUT –p tcp ––dport 443 –j ACCEPT
iptables –A INPUT –j DROP

Another valuable program to install is fail2ban, which automatically bans anyone making suspicious requests to the server. Without doing any further configuration, fail2ban will ban scads of people on a regular web server. However, LinuxHandbook has an article on further configuring fail2ban. This tool is a most to limit denial-of-service attacks and control the quantity of random garbage spewed at your server by the Internet.

From my Windows laptop, I used Zenmap to analyze my server from the outside. Zenmap can scan your server for open ports, and give you confidence that everything is well.

7. Secure Apache

Once more, make sure everything is updated.

One very basic improvement to server security is to prevent your server from sending any information it doesn’t need to. On “Page not Found” pages and other server queries, your server can reveal its version, the operating system it’s being run on, and other such details potential hackers would like to have.

It’s always a good idea to turn off directory indexes and symbolic links, both of which are central in another of server hacking schemes. They can be turned on by directory as needed if you want them in the future.

For obvious reasons, web clients should be disallowed from accessing security-related files and anything that might contain a password hash.

# Server hardening
ServerTokens Prod
ServerSignature Off
TraceEnable Off
Options -FollowSymLinks
Options -Indexes

<FilesMatch "^\.ht">
    Require all denied

8. Secure WordPress

Here are some settings to your Apache configuration. xmlrpc.php is a legacy file included in WordPress installations for backward-compatibility that now represents nothing but a security hazard. Disable it. Additionally, no web client under any circumstances should be able to access wp-config.php. Ostensibly, WordPress prevents this, but now you can forcibly prevent it yourself here. This is part of the all-important rule: NEVER allow even theoretical access to passwords or password hashes. Most wp-config.php files have your database password stored in plaintext, which is a potential catastrophe in the making.

<Files xmlrpc.php>
	Order Allow,Deny
	Deny from all
<Files wp-config.php>
	Require all denied
	Require ip

WordPress file permissions are infuriating. You have one of two options: You can have a secure WordPress installation, or you can have a WordPress installation that works. If you want to be able to do updates inside WordPress, the files either need to be owned by www-data, or the permissions need to be set far too permissively. See this ithemes article for permissive but functional settings.

On my server, xmlrpc.php gets access requests constantly. So I added a little extra Easter egg: xmlrpc.php.

<Files xmlrpc.php>
	Redirect 301

If you want a well-protected WordPress, you’ve got more work to do. This GetAstra article on permissions provides excellent guidance on precise WordPress permissions. Once the permissions are properly set, you might find it easier to update WordPress from the terminal using wp-cli, described below. Additionally, I found that I had to add the following line to the end of my wp-config.php to allow me to update pages:

define( 'FS_METHOD', 'direct' );

A tremendously useful tool is wp-cli, a terminal-based tool for manipulating WordPress. I use it in this script updates WordPress cores and plugins. This allows forcible, automatic updates of both the WordPress cores and plugins, and it can be run with user permissions, avoiding the www-data group altogether.

Oh, and speaking of server security… That codeviewer.php file that appears to be able to open arbitrary files? It has a short whitelist of files, and I add them manually.

Leave a Comment