Harden your public webserver (Part 3: shutdown SSH)
This is the third part of a three-part tutorial.
Closing this port will make your server unmaintainable. Allowing access only to your private IP address will not work if you use dynamic IPs. Unfortunately, this is common practice in Germany, for example.Regardless of that, you won't be able to access your beloved server while on vacation.
The solution I am showing here allows you to access your server from anywhere.
For this we use Wireguard. Wireguard is a free, modern and very secure VPN solution that is also very resource-efficient (unlike OpenVPN, for example).
Install and configure wireguard
For simplicity's sake, I'm showing this for Linux. The configuration on Windows, Mac, iOS and Android differs only slightly.
Install Wireguard on your server:
apt install wireguard
Install wireguard on all of your clients.
On your server:
Generate wireguard keys:
#/etc/wireguard/
wg genkey | tee privatekey | wg pubkey > publickey
Your private key is in
/etc/wireguard/privatekey
Your public key is in:
/etc/wireguard/publickey
Create a preshared key:
#/etc/wireguard/
cd /etc/wireguard/
mkdir psk
cd psk
wg genpsk > presharedkey
Your preshared key is in /etc/wireguard/psk/presharedkey
Create a server configuration:
#/etc/wireguard/wg0.conf
[Interface]
Address = 172.80.11.1/28
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT;\
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT;\
iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
ListenPort = 51820
PrivateKey = <copy and paste from \
# /etc/wireguard/privatekey on your server>
# Client configuration
[Peer] PublicKey = <publickey from client config>
PresharedKey = <copy and paste from \
/etc/wireguard/psk/presharedkey>
AllowedIPs = 172.80.11.2/32
PersistentKeepalive = 25
Enable portforwarding:
# /etc/sysctl.conf
# comment out the following line
net.ipv4.ip_forward=1
And activate your changes:
sysctl -p
Start and enable your config:
systemctl enable --now wg-quick@wg0.service
On your client:
If not already done. Install wireguard on the client as well.Repeat the step from above to generate the keys.
Create a client configuration:
#/etc/wireguard/wg0.conf
[Interface]
PrivateKey = <copy and paste from /etc/wireguard/privatekey\
# on your clinet>
Address = 172.80.11.2/28
# Server is your clients peer
[Peer]
PublicKey = <copy and paste from /etc/wireguard/publickey\
#from your server>
PresharedKey = <copy and paste from \
#/etc/wireguard/psk/presharedkey from your server>
AllowedIPs = 172.80.11.1/32
Endpoint = <YourServerIP>:51820
PersistentKeepalive = 25
You have now created the missing client key and can add it to the configuration on the server side:
PublicKey = <publickey from client config>
Start and enable your config:
systemctl enable --now wg-quick@wg0.service
Test connection:
You should see a connection on both with the following command:
wg show
If not, check if the firewall blocks port 51820/UPD or if the Wireguard service is running:
# should show show active
systemctl status wg-quick@wg0
Often there is a typo in the configuration.
Configure SSH on your server
This part is a little tricky.
Please be sure to check beforehand whether wireguard can establish a stable connection. Otherwise you will be locked out.
It's best to make a backup/snapshot beforehand.
The SSH process must be started after the Wireguard process.
We can set this via SystemD. Add wg-quick@wg0.service as required to sshd.service.
#/etc/systemd/system/sshd.service
[Unit]
Description=OpenBSD Secure Shell server
Documentation=man:sshd(8) man:sshd_config(5)
After=network.target auditd.service
# make SSH start after Wireguard
Requires=wg-quick@wg0.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run
[Service]
EnvironmentFile=-/etc/default/ssh
ExecStartPre=/usr/sbin/sshd -t
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecReload=/usr/sbin/sshd -t
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process Restart=on-failure
RestartPreventExitStatus=255
Type=notify
RuntimeDirectory=sshd
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target Alias=sshd.service
This setting is not to be executed on the client!
Now change your SSH listener:
# /etc/ssh/sshd_config
ListenAddress 172.80.11.1
Restart SSH:
systemctl restart ssh.service
Your server is now only accessible from outside via Wireguard over SSH.
Since SSH only listens to this IP, you don't need to do any firewall settings. You can leave port 22 open for SSH worldwide.