Set up public SSH

This chapter will focus on creating an out-of-band backup SSH tunnel (non-WireGuard, non-Traefik based), using a public gateway port on the sentry. This backdoor connection will ensure that you retain access to the Raspberry Pi even during emergency maintenance cycles, including restarting Traefik, restarting Docker, or even rebooting the system (the persistent tunnels will be restarted on boot).

---
title: SSH and wireguard operate independently
---
graph TD;
S1[SSH client] -->|Public TCP port 2220| SSH
W1[Wireguard client] -->|Public UDP port 51820| WG
subgraph Docker server
    SSH[SSH server]
    WG[Wireguard server]
end

Ensure the SSH server is secure

During the rpi-imager configuration, you should have selected the option for SSH to Allow public-key authentication only. You should double-check that this setting was applied:

Run this on the Raspberry Pi
cat /etc/ssh/sshd_config | grep "^PasswordAuthentication"
(stdout)
PasswordAuthentication no

If correctly setup, it should show that PasswordAuthentication is disabled (thus requring the use of keys rather than passwords).

Open the firewall for SSH (port 2220)

Open the SSH port in the firewall

The example TCP port used for the SSH tunnel is 2220. Make sure you open this port in the public sentry firewall (i.e., DigitalOcean firewall).

Install dependencies

AutoSSH is used to create a reliable SSH tunnel.

Run this on the Raspberry Pi
sudo apt-get update
sudo apt-get install -y autossh

Enable SSH GatewayPorts on the sentry

To expose a public reverse tunnel via SSH, you must enable the non-default GatewayPorts setting in the server’s SSH config, which allows reverse tunnels to be published to the WAN interface of the sentry:

Run this on the Raspberry Pi
sentry sshd-config GatewayPorts=yes
Tip

This will permanently alter the sentry’s /etc/ssh/sshd_config file and will then restart sshd. To restore the setting, run the inverse command:

To disable GatewayPorts
## This is the default setting:
sentry sshd-config GatewayPorts=no

With GatewayPorts=no, the reverse tunnels can only be accessed from the sentry’s loopback (lo) interface at 127.0.0.1, effectively blocking public access.

Make a one-time transient tunnel

Forward the public sentry port 2220 to the local Raspberry Pi port 22:

Run this on the Raspberry Pi
sentry ssh-expose 2220 22

To check the status:

Run this on the Raspberry Pi
sentry ssh-expose
(stdout)
## Active tunnels:
HOST            PUBLIC_PORT  LOCAL_PORT   TYPE
----            -----------  ------------ ----
sentry          2220         22           transient

With the tunnel active, you can ssh to the Pi from anywhere, going through the reverse tunnel public port:

[bash]: Run this on your workstation:
ssh -p 2220 pi@pi.example.com

To stop the service later:

Run this on the Raspberry Pi
sentry ssh-expose 2220 22 --close

Make a persistent tunnel

To make a persistent connection that will survive a reboot, you must enable the systemd linger privilege for the pi user:

Run this on the Raspberry Pi
sudo loginctl enable-linger ${USER}

To create a persistent connection, use the the --persistent flag:

Run this on the Raspberry Pi
sentry ssh-expose 2220 22 --persistent
(stdout)
## Active tunnels:
HOST            PUBLIC_PORT  LOCAL_PORT   TYPE
----            -----------  ------------ ----
sentry          2220         22           persistent

Reconfigure SSH clients

On your personal workstation, you can create a new config for accessing the Pi through the public sentry reverse tunnel:

[bash]: Run this on your workstation:
cat <<EOF >> ~/.ssh/config
Host pi.example.com
    User pi
    Port 2220
    ControlMaster auto
    ControlPersist yes
    ControlPath /tmp/ssh-%u-%r@%h:%p
EOF

Test the public SSH connection to the Pi

[bash]: Run this on your workstation:
ssh -t pi.example.com w

The w command prints a list of the currently logged in users, and their remote IP address (-t is important to ensure the current connection is included):

(stdout)
18:24:29 up 5 days, 33 min,  1 user,  load average: 0.10, 0.07, 0.08
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
ryan     pts/2    127.0.0.1        18:24    0.00s  0.01s  0.01s w
Tip

Unfortunately there is no way to show the real origin IP address of the connection; it will always show the IP address of the tunnel (127.0.0.1).