Pi Web Server Security

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.

Chris Hood

Chris Hood is an internet marketer with more than 15 years experience in email, organic and paid search marketing for e-commerce businesses. Chris spends most of his downtime riding bikes, tinkering with Raspberry Pis and updating this website. Say hey to Chris sometime.

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.