My mother lives on a different continent. I sometimes need to provide remote assistance for her Linux PC, on issues such as printing failures. I wanted to set up a secure remote access solution that didn’t require any action on my mother’s part aside from turning on her PC. To make this work, I’ve set up a port-forwarding outbound SSH connection from her PC to my server.
Background
I wanted to be able to connect to my mother’s PC using ssh, since with that
baseline, I could make anything else work. However, I didn’t want to just open a
port-forward on her firewall/router. A port forward exposes her PC to attack,
and is brittle; if the router is ever replaced, neither the port forward
configuration, nor the static DHCP reservation for her PC that allows it to
work, are likely to be replicated. Remotely walking someone through configuring
this would probably be painful. The alternative was to have her PC make an
outbound connection to a known location, with a remote port forward. Then I can
simply connect to the same location and make use of that remote port forward to
get access to the SSH server on her PC.
Explanation
When my mother’s PC boots, a systemd unit launches ssh to connect to my
Linode server. This uses a dedicated SSH key that only allows port forwarding;
no command may be run. This connects to a dedicated user ID on the server so if
there is any security issue, only the dedicated account is compromised.
This SSH connection has some remote port forwards enabled. On the server, it
will listen for connections on 127.0.0.1:1862, and forward any such connection
back to port 862 on my mother’s PC, where sshd is running. This listening
socket is only available to processes running on the server, and not exposed
to the general Internet, so is hidden from direct attack. Note that I use
port 862 rather than 22 for SSH on most of my systems to reduce the amount of
port-scanning etc. that SSH has to deal with.
Whenever I want to connect to my mother’s PC, I use my Linode server as an SSH jump host. If I was to do this manually, I would:
-
On my laptop, connect to my Linode server using SSH, with local port 1862 forwarded to
127.0.0.1:1862. -
On my laptop again, in parallel, connect to
127.0.0.1:1862using SSH, which gets forwarded over two SSH connections; first from my laptop to my Linode, and then over the remote port forward set up by the SSH connection from my mother’s PC to the Linode, and thus ultimately arrives at the sshd running on my mother’s PC, where the regular login process proceeds.
By using SSH’s ProxyJump feature in ~/.ssh/config, I can automate all of
this; see the configuration files below.
I also port-forward a variety of ports on my laptop, so that I can connect to various network services on my mother’s PC and printer.
Diagram
+------------+ +-----------------------+ +-----------+
| Mother PC | | Linode server | | My laptop |
| | | | | |
| ssh -------+----+-----> sshd sshd <--+-----+-ssh |
| | | | | | | | |
| fwd<-------+----+-fwd listen <----+ | | |
| | | | | | |
| v | +-----------------------+ +-----------+
| sshd |
+------------+
┌────────────┐ ┌───────────────────────┐ ┌───────────┐
│ Mother PC │ │ Linode server │ │ My laptop │
│ │ │ │ │ │
│ ssh ───────┼────┼─────► sshd sshd ◄──┼─────┼─ssh │
│ │ │ │ │ │ │ │ │
│ fwd◄───────┼────┼─fwd listen ◄────┘ │ │ │
│ │ │ │ │ │ │
│ ▼ │ └───────────────────────┘ └───────────┘
│ sshd │
└────────────┘ (This diagram was created using asciiflow.)
TODO: separate the diagram into a sequence of steps to better highlight how everything works.
Config Files
Mother’s PC
/etc/systemd/system/wdo-avon-port-forward.service:
[Unit]
Description=avon.wwwdotorg.org port forward
After=network.target
[Service]
User=port_user
ExecStart=/usr/bin/ssh -i /home/port_user/.ssh/id_ed25519_fwds \
-o ServerAliveInterval=60 \
-o ExitOnForwardFailure=yes \
-p 862 -nNT \
-R 127.0.0.1:1862:127.0.0.1:862 \
port_user@avon.wwwdotorg.org no_command
RestartSec=15
Restart=always
KillMode=mixed
[Install]
WantedBy=multi-user.targetTo install and enable that service, run:
sudo systemctl daemon-reload
sudo systemctl enable wdo-avon-port-forward.service
sudo systemctl start wdo-avon-port-forward.serviceLinode Server
~port_user/.ssh/authorized_keys:
# Also allow -L for (unused) port 100 since permitopen=none disallows connection/port-forwarding
restrict,command="bash -c 'while true; do sleep 60; done'",port-forwarding,permitopen="127.0.0.1:100" ssh-ed25519 CLIENT_PUBKEY_ELIDEDMy Laptop
~swarren/.ssh/config:
Host woodland-4x
User elided
IdentityFile /home/swarren/.ssh/id_ed25519_xxx
HostName 127.0.0.1
Port 1862
ProxyJump swarren@avon.wwwdotorg.org:862
LocalForward 8631 127.0.0.1:631 # CUPS
LocalForward 5800 127.0.0.1:5800 # VNC web
LocalForward 5900 127.0.0.1:5900 # VNC
LocalForward 8080 192.168.1.14:80 # HP printer HTTP
LocalForward 8443 192.168.1.14:443 # HP printer HTTPSOf course, ~elided/.ssh/authorized_keys on my mother’s PC contains entries for
swarren’s SSH keys on my laptop, as does ~swarren/.ssh/authorized_keys on the
Linode server.
How I connect:
ssh woodland-4xExample URL I open in the web browser: https://127.0.0.1:8443/ (for access to the printer’s admin web page).
VNC
Once I’ve connected, I can run the following on my mother’s PC to run a screen-scraping VNC server:
x11vnc -rfbauth ~/.vnc/passwd -localhost -display :0Don’t forget to perform one-time setup to set the password using:
x11vnc -storepasswd ~/.vnc/passwd… and connect to it from my laptop by running:
gvncviewer localhost:0Changelog
2026/10/21:
- Fixed
sshcmdline args (-Rvs-L) in the systemd unit file to match what’s really there. This file wasn’t available when I wrote the blog post, so I used a similar-but-different system for reference. - Reformatted systemd unit file so it’s more readable. Unfortunately, the syntax likely cannot be pasted directly now due to the manual line-breaks.
- Added note about use of alternate SSH port number.
- Enhanced some text. Moved diagram after explanation for better context.