My Extra Secure SSH Setup
Tagged with computers, linux, raspberry pi, ssh, vnc, x2go on May 2, 2024
Although normal life has been getting in the way, I finally figured out how to make my “server” as secure as it can be. I’ve set things up so I can only connect to my Raspberry Pi 400 (“Pi” for short) from one external IP address using the Secure Shell Protocol (SSH). That IP address will come from my laptop computer, regardless of where I am in the world.
Remote Services on the Pi
There are only two services I will regularly use when I need to access the Pi. The first is SSH, for command line routines, and the second is the X2Go server, for graphical routines. The X2Go client connects by SSH, as does rsync. I’m leaving the VNC service running as a backup, since I can only connect to it with RealVNC’s cloud service.The only reason I wanted to use a VPN was to tie SSH to one IP address, but I couldn’t get it to work right. I subsequently found a more elegant solution, so I removed the VPN.
SSH Was Already Secure
I was already using best practices with SSH:
- Public key authentication
- No password login
- No root login
I even moved the port number to avoid the simple scanners. Still, seeing the attempted connections to the port I moved it to continued to irritate me. I simply had to block all those IP addresses in a way that made sense.
Extra Secure SSH
The Pi’s IP address is tied to duckdns.org, a dynamic subdomain service. I tied the laptop computer’s IP address to duckdns as well and adapted a routine I found at a couple of Linux forums. The routine runs on the Pi. Here’s the BASH script, which I call access.sh, with some things changed to protect my connection. It has to be run as root (sudo) because it adds and deletes firewall rules:
#!/bin/bash HOSTNAME=sub.domain.dom IPFILE=/home/username/access.txt Current_IP=$(host $HOSTNAME | head -n1 | cut -f4 -d ' ') if [ ! -f $IPFILE ]; then /usr/sbin/ufw allow from $Current_IP to any port 22 proto tcp echo $Current_IP > $IPFILE else Old_IP=$(cat $IPFILE) if [ "$Current_IP" = "$Old_IP" ] ; then echo IP address has not changed else /usr/sbin/ufw delete allow from $Old_IP to any port 22 proto tcp /usr/sbin/ufw allow from $Current_IP to any port 22 proto tcp echo $Current_IP > $IPFILE echo iptables have been updated fi fi
The firewall denies all incoming connections except the one allowed by a single rule. I’ve been letting this script run as a root level cron job (sudo crontab -e) for a couple of days (every five minutes), and it hasn’t failed to work properly. The IP address changed yesterday morning due to a one-hour power outage.
Again, I’m leaving the VNC service running as a backup. That’s just in case this script stops working or something else out of my control happens.
Image by Jessie Kirk, CC BY 4.0, via Wikimedia Commons
← Previous ArticleNext Article →