Thanks to a hackers and/or bots trying to inject malware into my WordPress installation, I am forced to learn how to administrate my host better. Surprisingly enough, I find myself enjoying learning how to manage and secure a production server; A skill which will definitely help me become a better developer moving forward. So far here’s what I’ve done to deter and hopefully mitigate the hacking attempts on my site.
This guide assumes you are running an Ununtu 14.x up.
Set the proper timezone
This will make log files easier to understand and keep track of SSL certificates
dpkg-reconfigure tzdata
Setup a hostname
You can name this anything you want, I used “livehost”
echo "livehost" > /etc/hostname hostname -F /etc/hostname
Now verify the hostname change
hostname
Now setup a Fully Qualified Domain Name (FQDN) in your /etc/hosts file
127.0.0.1 localhost.localdomain localhost 127.0.1.1 ubuntu <your server ip> livehost.example.com livehost
Now you can set an A Record to your domain name pointing to your hostname livehost.example.com to access your server.
Disabled remote root login and changed the SSH port
I changed my SSH port to something lower than 1024 but not 22 (learn why here) then set PermitRootLogin to no.
sudo nano /etc/ssh/sshd_config
Installed Fail2Ban
installed it with the following command
sudo apt install fail2ban
We’ll copy the default config and jail settings and modify the copies we made.
sudo cp /etc/fail2ban/fail2ban.conf /etc/fail2ban/fail2ban.local sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local sudo nano /etc/fail2ban/jail.local
SSH is already enabled by default in Ubuntu, so you’ll just need to enable the services you want to watch over. Do note that Fail2Ban won’t start if you enable a filter on a service that’s not installed/running.In this instance I just added a custom filter and changed the destemail setting so I can get notifications. You will need to install sendmail to get this feature working, see below.
[DEFAULT] destemail = email@example.com [wordpress] enabled = true filter = wordpress logpath = /var/www/html/example.com/log/access.log port = 80,443
I also made a custom wordpress filter in /etc/fail2ban/filter.d/wordpress.conf , you can read more about it here. This basically checks the access log of my site and filters it using regular expressions.
# Fail2Ban filter for WordPress # # [Definition] failregex = <HOST> - - \[(\d{2})/\w{3}/\d{4}:\1:\1:\1 -\d{4}\] "POST /wp-login.php HTTP/1.1" 200 ignoreregex =
after saving the changes, restart the service.
sudo service fail2ban restart
Installed and Setup IPTables
IPTables is already installed with Ubuntu so I just needed to setup a new configuration file
sudo nano /etc/iptables.firewall.rules
I used the following configuration which I Googled to allow SSH, HTTP/HTTPS and a few other ports for testing then closed everything else for security Note that the port setting should be the same as with setting in the /etc/fail2ban/jail.local and /etc/ssh/sshd_config values.
*filter # Allow all loopback (lo0) traffic and drop all traffic to 127/8 that doesn't use lo0 -A INPUT -i lo -j ACCEPT -A INPUT ! -i lo -d 127.0.0.0/8 -j REJECT # Accept all established inbound connections -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # Allow all outbound traffic - you can modify this to only allow certain traffic -A OUTPUT -j ACCEPT # Allow HTTP and HTTPS connections from anywhere (the normal ports for websites and SSL). -A INPUT -p tcp --dport 80 -j ACCEPT -A INPUT -p tcp --dport 443 -j ACCEPT # Allow ports for webmin -A INPUT -p tcp --dport 10000 -j ACCEPT # Allow SSH connections # The -dport number should be the same port number you set in sshd_config -A INPUT -p tcp -m state --state NEW --dport 321 -j ACCEPT # Allow ping -A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT # Allow sendmail -A OUTPUT -p tcp --dport 25 -j ACCEPT -A OUTPUT -p udp --dport 53 -j ACCEPT -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # Log iptables denied calls -A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7 # Reject all other inbound - default deny unless explicitly allowed policy -A INPUT -j REJECT -A FORWARD -j REJECT COMMIT
Activate the new firewall rules now
sudo iptables-restore < /etc/iptables.firewall.rules
Then make sure to run the firewall rules on startup by editing this file
sudo nano /etc/network/if-pre-up.d/firewall
Insert the following script
#!/bin/sh /sbin/iptables-restore < /etc/iptables.firewall.rules
Save the changes then set the permissions
sudo chmod +x /etc/network/if-pre-up.d/firewall
Install Let’s Encrypt
Let’s encrypt is a free SSL certificate supported by a lot of popular browsers. I use this to encrypt traffic on my sites at no extra cost. Before installing the package make sure you have set your timezone and hostname already. If you’ve done that already you can update everything first.
sudo apt update && sudo apt upgrade
Once everything has updated, install GIT so we can clone the repository on Gtihub later
sudo apt-get install git
Now clone the official GitHub repository to /opt/letsencrypt
sudo git clone https://github.com/letsencrypt/letsencrypt /opt/letsencrypt
Then navigate to /opt/letsencrypt
cd /opt/letsencrypt
Now make sure nothing is using port 80. I had trouble with this even after closing Apache which was the only application I though was using port 80. So to keep it simple I just killed all processes using port 80
sudo lsof -t -i tcp:80 -s tcp:listen | sudo xargs kill
Now we are ready to create a certificate that will auto renew. Just change the domain name to the domain name you’re creating a certificate for.
sudo -H ./letsencrypt-auto certonly --standalone --renew-by-default -d example.com -d www.example.com
If everything worked properly you should see something like this. Take note of the Certificate and key paths, we will need this later when configuring the SSL certificate for Apache.
Now we will set a cron job to automatically renew the certificate and update Let’s Encrypt. Open crontab
sudo crontab -e
Then append the following lines
0 0 1 * * /opt/letsencrypt/letsencrypt-auto renew 0 0 1 * * cd /opt/letsencrypt && git pull
Now we need configure apache for the SSL certificate. Appenbd this to your sites config file typically found in /etc/apache2/sites-available/example.com.conf. The SSLCertificateFile and SSLCertificateKeyFile paths were echoed after you created your certificate earlier. This will also set TLSv1.2 to be used instead of the default TLSv1
<VirtualHost *:443> SSLEngine On SSLProtocol -all +TLSv1.2 SSLCertificateFile /etc/letsencrypt/live/mikemamaril.com/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/mikemamaril.com/privkey.pem ServerAdmin root@mikemamaril.com ServerName mikemamaril.com ServerAlias www.mikemamaril.com # Index file and Document Root (where the public files are located) DirectoryIndex index.html index.php DocumentRoot /var/www/html/mikemamaril.com/public_html # Log file locations LogLevel warn ErrorLog /var/www/html/mikemamaril.com/log/error.log CustomLog /var/www/html/mikemamaril.com/log/access.log combined </VirtualHost>
Ensure that the Apache SSL module is enabled, and enable the virtualhost configuration:
a2enmod ssl a2ensite example.com
Then restart the Apache service
service apache2 restart
You can visit WhyNoPadlock to troubleshoot any insecure content you may have on your page. If you’re using WordPress you can use Really Simple SSL to force HTTPS to any visitors visitors to your site.
Get alerts when someone uses sudo
For that extra touch to paranoia, I also setup an email notification to let me know if someone uses the sudo command. I start off by making a new file
sudo nano /etc/sudoers.d/my_sudoers
pasting in the following content, you’ll need to change the email address to the one you wish to use.
Defaults mail_always Defaults mailto="your@email.com"
Save the changes then set the file permissions
sudo chmod 0440 /etc/sudoers.d/my_sudoer
If you don’t have a mail server setup yet you will need to install one. I used sendmail.
sudo apt install sendmail
The install script hanged on me and I found that the following commands worked to finished the installation.
cd /etc/mail/tls sudo openssl dsaparam -out sendmail-common.prm 2048 sudo chown root:smmsp sendmail-common.prm sudo chmod 0640 sendmail-common.prm sudo dpkg --configure -a
When you’re done installing sendmail, configure it:
sudo sendmailconfig
Reboot server on OOM (Out Of Memory)
This will reboot the server if the system panics, literally.
sudo nano /etc/sysctl.conf
the append this to the config
vm.panic_on_oom=1 kernel.panic=10