Let’s consider this Phase II of building your own web server to host your WordPress site at home. When dealing with anything interwebs, security is something to be proactive about. Especially if you’re hosting your own Pi server from your home network. The following steps I pulled from a number of guides I found around the web, here’s what worked for me.
SSH Key Pair Authentication.
Up to now, we’ve used a password to connect to the Pi, using the default pi user. We’re going to ditch passwords and use the much more secure key pair authentication method which will help protect against brute-force password cracking attacks.
These next steps must be completed on your Linux or Mac OS desktop or laptop computer, not the Pi itself. Firstly, let’s generate the ssh keys for your machine:
1 | ssh-keygen |
This launches the SSH Key utility. Follow the on-screen instructions to create the keys on your desktop computer. To use key pair authentication without a passphrase, press Enter when prompted for a passphrase.
Two files have just been created in your ~/.ssh directory: id_rsa and id_rsa.pub. The public key is id_rsa.pub and will need to be uploaded to your Pi. The other file is your private key and will be kept in your ~/.ssh directory. Protect this file as if it’s a password because soon it will be the key needed to log into your Pi.
Upload the public key to your Pi using secure copy (scp) through Terminal by entering the following command on the computer you just used to generate the key pairs.
1 | scp ~/.ssh/id_rsa.pub username@your.pis.ip.address: |
Go back to your Pi terminal session and create a directory for the public key in your home directory (/home/username) with the following command:
1 | sudo mkdir .ssh |
Then move the public key in to the directory you just made:
1 | sudo mv id_rsa.pub .ssh/authorized_keys |
Finally, modify the permissions on the public key so they can’t be modified accidentally (or maliciously by the bad people). Be sure to replace example_user with the user you log into your Pi with.
1 2 3 | sudo chown -R example_user:example_user .ssh sudo chmod 700 .ssh sudo chmod 600 .ssh/authorized_keys |
At thsi point, the SSH keys have been generated and the public key has been installed on your Pi. You’re ready to use SSH key pair authentication! To test, log out of your terminal session and then log back in. The new session should be automatically authenticated with the SSH keys, bypassing the need to enter your password.
Disable SSH Password Authentication and Root Login
Now that we can securing log into the Pi without needing to type in our password every dang time, let’s make a few more tweaks to SSH configuration to tigten up security a little more. We’ll start by disabling password authentication and requiring all users connecting via SSH to use key authentication. Next, we’ll disable root login to prevent the root user from logging in via SSH.
To disable SSH password authentication and root login, open the SSH config file with:
1 | sudo nano /etc/ssh/sshd_config |
Find the line regarding PasswordAuthentication by typing CTRL+W then PasswordAuthentication followed by ENTER. Uncomment the line by removing the # in front of it and change the PasswordAuthentication setting to ‘no’. Your line should look like this now:
1 | PasswordAuthentication no |
Find the line regarding PermitRootLogin and modify to match below:
1 | PermitRootLogin no |
Save the changes to the SSH configuration file by pressing CTRL+X, and then Y, followed by ENTER.
Restart the SSH service to load the new configuration with the following command:
1 | sudo service ssh restart |
It’s getting hot in ‘ere, so let’s create a Firewall
Firewall block and limit traffic. This is an added layer of security for your Pi as it can help stop people from sniffing for open ports to hack into your device.
By default, your Pi doesn’t come loaded with any firewall rules, so we’ll get a set up a good starting point. First, let’s create a file to hold your firewall rules by entering the following command:
1 | sudo nano /etc/iptables.firewall.rules |
Next, let’s create the rules for our firewall. Paste the following content the Terinal and save your file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | *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 -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 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 22 -j ACCEPT # Allow ping -A INPUT -p icmp --icmp-type echo-request -j ACCEPT # Log iptables denied calls -A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7 # Drop all other inbound - default deny unless explicitly allowed policy -A INPUT -j DROP -A FORWARD -j DROP COMMIT |
Save the changes to the firewall rules file by pressing CTRL+X, then Y, and ENTER.
Finally, activate the firewall rules by entering the following command:
1 | sudo iptables-restore < /etc/iptables.firewall.rules |
Check to make sure your new rules are active with the following command:
1 | sudo iptables -L |
Your output should look similar to the the code below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | Chain INPUT (policy ACCEPT) target prot opt source destination ACCEPT all -- anywhere anywhere REJECT all -- anywhere loopback/8 reject-with icmp-port-unreachable ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED ACCEPT tcp -- anywhere anywhere tcp dpt:http ACCEPT tcp -- anywhere anywhere tcp dpt:https ACCEPT tcp -- anywhere anywhere tcp dpt:submission ACCEPT tcp -- anywhere anywhere state NEW tcp dpt:ssh ACCEPT icmp -- anywhere anywhere icmp echo-request LOG all -- anywhere anywhere limit: avg 5/min burst 5 LOG level debug prefix "iptables denied:" DROP all -- anywhere anywhere Chain FORWARD (policy ACCEPT) target prot opt source destination DROP all -- anywhere anywhere Chain OUTPUT (policy ACCEPT) target prot opt source destination ACCEPT all -- anywhere anywhere Now let's make sure these rules are reloaded any time we restart the Pi. To do this, we're going to create a simple startup script and then instruct the Pi to run the scritp after each boot. [cc lang="python"]sudo nano /etc/network/if-pre-up.d/firewall |
Copy and paste the following lines in to the file you just created:
1 2 | #!/bin/sh /sbin/iptables-restore < /etc/iptables.firewall.rules |
Save your file with CTRL+X, Y, ENTER. Lastly, set the script’s permissions with the following command:
1 | sudo chmod +x /etc/network/if-pre-up.d/firewall |
Install and Configure Fail2Ban
Fail2Ban is an application that prevents dictionary attacks (another brute-force password guessing technique) on your server. When Fail2Ban detects multiple failed login attempts from the same IP address, it will automatically create a temporary firewall rule to block traffic from the attacker’s IP address.
Install Fail2Ban with the following command:
1 | sudo apt-get install fail2ban |
You’re done! Fail2Ban is now installed and running on your Pi. If you’re curious if there’s been any nefarious activity on your Pi, you can check Fail2Ban’s logs at /var/log/fail2ban.log.