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:1862 using 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.target

To 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.service

Linode 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_ELIDED

My 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 HTTPS

Of 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-4x

Example 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 :0

Don’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:0

Changelog

2026/10/21:

  • Fixed ssh cmdline args (-R vs -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.