This is Part 4 of a series called Hello, World: Blog.
If you’ve followed all the previous posts, then you have a fully-functioning blog online - congratulations! But before we charge ahead and start adding posts, we should take a moment to consider security. Any web-facing server is vulnerable to attack, and even small sites get hacked. Let’s take some steps to protect ourselves by reducing the attack surface of our server.
In this post, you’ll:
- Set up public key authentication.
- Disable password authentication.
- Configure a basic firewall.
- Restrict the Git user’s terminal capabilities.
Public Key Authentication
Currently, our server is set up to use password authentication, which means that you provide a password each time you access the server. The problem is, passwords are only as strong as you make them, and even a strong password is susceptible to brute-force attacks over time. As an alternative, you can set up your server to use public key authentication.
On your local machine, generate a public / private key pair (if you don’t already have one). If you already have a key pair you’d like to use, skip down to
$ ssh-keygen -t rsa
When prompted for a file to save the key, press
Enter to accept the default. Then it will prompt for a passphrase (which is basically a password for your public key). It’s recommended to set a passphrase, but you can press
Enter to proceed without one.
Once the key is created, install it as an authorized key on the server. Replace
bannmoore with the username of your non-root user, and
IP_ADDRESS with your server’s IP.
$ ssh-copy-id bannmoore@IP_ADDRESS
Provide your password when prompted. You should see this:
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys bannmoore@ip_address's password: Number of key(s) added: 1 Now try logging into the machine, with: "ssh 'bannmoore@IP_ADDRESS'" and check to make sure that only the key(s) you wanted were added.
Note: If you want to use the same SSH key for multiple users, you’ll need to copy them individually. If you’ve followed this tutorial, make sure you also install the key for your Git user. Don’t install the ssh key on your root user (you’ll see why in a minute).
$ ssh-copy-id git@IP_ADDRESS
Once the key is installed, future logins from your local machine should use public key authentication. Test it out using
$ ssh bannmoore@IP_ADDRESS
Disable Password Authentication
After the SSH keys are installed, we should disable password authentication entirely. This will prevent anyone from accessing the server without your key, and is much more secure.
Note: This probably goes without saying, but don’t do this unless you’ve verified that public key authentication (the previous section) is working. If you disable password authentication without any keys installed, you’ll lock yourself out of the server.
Login to the server as your non-root user, then open the SSH daemon configuration in Nano.
bannmoore@blog:~$ sudo nano /etc/ssh/sshd_config
ChallengeResponseAuthentication should be correctly set if you haven’t modified SSH settings, but double-check those as well.
PasswordAuthentication no PubkeyAuthentication yes ChallengeResponseAuthentication no
Save and close the file (
ENTER). Then, reload the SSH Daemon.
bannmoore@blog:~$ sudo systemctl reload sshd
That’s it! From now on, you cannot connect remotely to the server using password authentication. Any user account without an installed SSH key will be effectively inaccessible. If you need to re-enable it later, you can do so by logging in using a key and modifying the
sshd_config file again.
Set up a Firewall
We should install a firewall on the server to restrict incoming connections. If you’re using DigitalOcean’s Ubuntu server, UFW will already be installed. If for some reason it isn’t, install it using
bannmoore@blog:~$ apt-get install ufw
The firewall will restrict all incoming connections by default, but there are specific applications we want to allow through. Namely, Nginx and OpenSSH.
These applications automatically add UFW profiles when they are installed. To see a list of available UFW profiles, use the
ufw app list command.
bannmoore@blog:~$ sudo ufw app list Available applications: Nginx Full Nginx HTTP Nginx HTTPS OpenSSH
ufw allow command configures the firewall to allow a specific profile. Allow the “OpenSSH” and “Nginx HTTP” profiles. Note that we only need to enable one Nginx profile - for now, we’ll select HTTP since our server hasn’t been configured for HTTPS (yet).
bannmoore@blog:~$ sudo ufw allow OpenSSH Rules updated Rules updated (v6) bannmoore@blog:~$ sudo ufw allow 'Nginx HTTP' Rules updated Rules updated (v6)
Now we can enable the firewall.
bannmoore@blog:~$ sudo ufw enable
Once the UFW firewall is running, you can check it using
bannmoore@blog:~$ sudo ufw status Status: active To Action From -- ------ ---- OpenSSH ALLOW Anywhere Nginx HTTP ALLOW Anywhere OpenSSH (v6) ALLOW Anywhere (v6) Nginx HTTP (v6) ALLOW Anywhere (v6)
If everything is set up correctly, you should still be able to SSH into the server and access the IP address in the browser.
Secure the Git User
In a previous tutorial, we created a Git user to manage our code repository. This user cannot use
sudo, so it’s less powerful than the non-root user, but it still has more access than it needs. For example, if you SSH in as the Git user, you get access to the full interactive shell. In this section, we’ll configure this user with a non-interactive git-shell so that it can only be used to perform Git operations.
Log into the server as the non-root user, then
su into the Git user.
$ ssh bannmoore@IP_ADDRESS bannmoore@blog:~$ su - git Password: git@blog:~$
As the git user, create a
git-shell-commands folder in the home directory.
git@blog:~$ mkdir ~/git-shell-commands
Open a file called
no-interactive-login in Nano.
git@blog:~$ nano ~/git-shell-commands/no-interactive-login
Paste in this content:
#!/usr/bin/env bash printf '%s\n' "You've successfully authenticated to the server as $USER user, but interactive sessions are disabled." exit 128
Ensure that this file is executable.
git@blog:~$ chmod +x ~/git-shell-commands/no-interactive-login
Now the git user is ready to use
git-shell. Logout of the Git user, back to the non-root user.
git@blog:~$ exit logout bannmoore@blog:~$
As the non-root user, modify the git user to use
git-shell instead of the default Bash shell.
sudo usermod -s $(which git-shell) git
Now, if you try to access the git user (through
ssh), the terminal will run the
no-interactive-login script, which displays a message and closes the shell.
bannmoore@blog:~$ su - git Password: You've successfully authenticated to the server as git user, but interactive sessions are disabled.
If necessary, you can use the
usermod command to re-enable the git user’s interactive shell.
sudo usermod -s /bin/bash git
With that, our server is more secure! We’re almost done - in the next and final post), we’ll finalize our site with DNS and HTTPS.