Getting remote access to your home server doesn’t have to be a pain. Usually, you just pay your internet company for a static IP address and that’s that. Often, it works. You pay a bit each month, your router gets an address that works, and you can forward ports again. Problem solved!
But hold on, there’s another way!
If you’ve already got a VPS with a public IP (maybe for a website, VPN, or something else), you can use it to reach your home server. Think of it as a go-between, a secret path from the internet to your server at home. That’s what I did! Instead of paying my internet company extra, I made a reverse SSH tunnel using my VPS. Now I have stable access to my home server, even though it’s hidden behind my internet provider’s NAT.
This isn’t just some idea, it’s a real setup that actually works.
Table of Contents
The Real Obstacle: Dynamic IPs and Provider-Level NAT
So, lots of home internet companies give out IP addresses that change now and then. It can be annoying since your IP can change when you restart your modem or when your IP \lease\ is up. It makes getting to your stuff from afar tricky because the address keeps moving.
But here’s something even more annoying: CG-NAT, which is short for carrier-grade NAT.
With CG-NAT, your router doesn’t get a real public IP anymore. Instead, it gets a private address that can’t be reached from the outside. The public IP is with your internet company and shared by lots of people. It’s like your home server is stuck behind two walls: one on your router and another at your internet company.
Why does this matter?
Before, NAT was only in your house. Your router had the public IP, so you could forward traffic through ordinary port forwarding. Now, the public IP is often with your internet company, serving a building, a block, or a whole area. Your router gets an address that isn’t reachable from the outside world. Traffic from the outside can’t reach you unless your provider lets it.
That’s why DDNS doesn’t work here. A dynamic DNS name can map a host name to the \current\ address, but that address belongs to the provider, not your router. You might know the number, but you don’t control it. Data from the outside just disappears into the provider’s NAT and goes nowhere.
Possible Routes Around the Problem
The direct, paid route
The most obvious fix is to order a dedicated static IP from the ISP. Once the router receives a real public address, everything returns to the old, comfortable model: forward ports, bind services, connect normally.
There is nothing wrong with that path. In fact, if you do not already have a VPS and have no intention of renting one, paying for a static IP may be the tidiest solution.
NAT traversal via external services
There are also third-party tools that sidestep the issue from another angle. Remote desktop software such as TeamViewer or AnyDesk can help in certain situations. Overlay networks like Tailscale and ZeroTier can stitch devices together across hostile network boundaries. Cloudflare Tunnel can expose web applications without requiring a public IP on your own side.
Useful? Absolutely. Universal? Not quite.
Each of those approaches comes with its own trade-offs—service dependency, product-specific constraints, account requirements, transfer ceilings, or architectural opacity.
The route I chose
I already had a VPS with a public IP. So instead of buying a static address for the house, I pressed that VPS into service as a bridge.
SPONSORED
If you need a VPS for this setup, providers like Fornex — a trusted hosting provider with 16 years of experience — offer reliable servers suitable for reverse SSH tunnels and self-hosting projects.
The idea is elegantly simple: the home server initiates the outbound connection itself, because outbound traffic is normally allowed even behind NAT. That connection remains open and carries a reverse SSH tunnel. Once the tunnel is in place, I can reach the home server by connecting to the VPS.
The VPS becomes a public doorstep. Behind that door sits the machine at home.
Reverse SSH Tunnel Through a VPS
Here is the essential flow:
Home server (behind NAT) → outbound SSH session → VPS (public IP)
The tunnel opens a port on the VPS and maps it back to the SSH service on the home server.
From the outside, any client—a laptop, a phone, another workstation, anywhere—connects to the VPS on that designated port and lands on the home server as though it were directly exposed.
This approach has a few virtues that make it especially appealing.
First, the home server initiates the link, so NAT does not block the arrangement. Second, if the home-side IP changes, the concept still holds; the server merely reconnects outward again. Third, from the client’s perspective, the only stable public endpoint that matters is the VPS.
Naturally, the VPS must remain online around the clock. But if you already keep one for other duties, that requirement is hardly a burden.
Step 1. Prepare SSH on the VPS
On the VPS, the SSH daemon must be willing to host a reverse tunnel that listens beyond localhost. Open the SSH server configuration file:
sudo nano /etc/ssh/sshd_config
Add or adjust these parameters:
Port 2222
GatewayPorts yes
ListenAddress 0.0.0.0
ListenAddress ::
A brief reading of what these lines accomplish:
- Port 2222
I moved SSH on the VPS to a non-standard port. This is optional—you may keep port 22—but I preferred a small bit of separation. If you do this, remember to open that port in the VPS firewall. - GatewayPorts yes
This is the linchpin. Without it, a reverse-forwarded port is ordinarily bound only to localhost on the VPS. In other words, the tunnel exists, but nobody outside the VPS can use it. WithGatewayPorts yes, the port can listen on external interfaces as well. - ListenAddress 0.0.0.0 / ::
These directives make the SSH daemon listen on all IPv4 and IPv6 interfaces.
After editing, apply the changes:
sudo systemctl restart ssh
At this point, the VPS is ready to accept reverse tunnels and expose them outward.
Step 2. Open the Reverse Tunnel from the Home Server
Now move to the home server. It needs outbound internet access and an SSH client.
To test the idea manually, run:
ssh -N -R 2223:localhost:22 <user>@<vps ip> -p 2222
This command deserves a proper dissection.
-R 2223:localhost:22
On the VPS side, SSH opens port 2223 and forwards all traffic arriving there tolocalhost:22on the initiating machine—the home server.-N
No remote shell, no command execution. The SSH session exists purely to carry the tunnel.-p 2222
Connect to the custom SSH port configured on the VPS.
Once the command is active, inspect the VPS with ss -tnlp or netstat and verify that port 2223 is listening. If everything is configured correctly, you should see it bound to 0.0.0.0:2223, which means the forwarded endpoint is reachable externally.
Step 3. Keep the Tunnel Alive with autossh
Running the tunnel by hand is tolerable for a quick proof of concept. It is dreadful for daily life.
Links drop. Routers reboot. The line flickers. Residential internet is not known for monastic stability. So the tunnel needs a caretaker—something that watches the connection and revives it when it breaks.
That tool is autossh.
Install autossh
On a Debian or Ubuntu-based home server:
sudo apt install autossh
Create a systemd service
Now create a dedicated service unit:
sudo nano /etc/systemd/system/autossh-tunnel.service
Populate it with the appropriate configuration for your environment. The exact unit file will vary depending on your chosen user, path, and options, but the central idea remains the same: launch autossh on boot and let it maintain the reverse tunnel.
In my setup, several options matter:
ServerAliveInterval
Sends keepalive packets on a schedule.ServerAliveCountMax
Defines how many keepalive failures are tolerated before the connection is considered dead.
Together, values like 30 and 3 mean the tunnel is treated as broken after roughly 90 seconds of silence.
-M 0
Disables the separate monitoring port. In this mode, autossh trusts SSH keepalives instead.AUTOSSH_GATETIME=0
Prevents autossh from pausing before restart attempts. If the line snaps, recovery begins immediately.
Enable and start the service
After saving the unit file:
sudo systemctl daemon-reload
sudo systemctl enable autossh-tunnel.service
sudo systemctl start autossh-tunnel.service
From here on, the home server will raise the tunnel automatically at boot and re-establish it when connectivity falters.
A reboot test is worthwhile. Restart the home machine, then check the VPS and confirm that the forwarded port reappears.
SSH Keys: Necessary for a Passwordless Tunnel
For autossh to work unattended, the home server must be able to authenticate to the VPS without interactive password entry. That means SSH keys.
Generate a key on the home server
ssh-keygen -t ed25519 -C "autossh tunnel key"
Copy the key to the VPS
ssh-copy-id -i ~/.ssh/id_ed25519.pub <user>@<vps-ip>
Verify passwordless login
ssh <user>@<vps-ip>
If the setup is correct, the session should open without asking for the account password.
A small but important security note: if this key is compromised, an intruder could authenticate to the VPS as that user. It is wise to create a dedicated VPS user for tunneling and keep its privileges narrow.
Step 4. Connect to the Home Server Through the VPS
Once the reverse tunnel is alive, access becomes pleasantly straightforward.
From any client device, connect to the forwarded port on the VPS:
ssh -p 2223 <user>@<vps-api>
Although you are dialing the VPS, the tunnel passes you through to the home server’s SSH service. In effect, the VPS is only the visible facade. The destination behind it is your machine at home.
You can make this even cleaner with an SSH config entry on your client systems:
Host home-server
HostName <vps-api>
Port 2223
User <user_ot_home>
After that, the command shrinks to:
ssh home-server
The same idea can be extended to scp and rsync, which is very convenient when file transfer is part of the routine.
Other Options I Thought About
Here are some other ideas that came up.
Cloudflare Tunnel
Cloudflare Tunnel is pretty cool. Your home server makes a connection to Cloudflare, and all traffic comes through that. You don’t need a public IP at home, and you don’t need a VPS. It’s a smart setup.
For what I needed, though, it wasn’t the best. The free plan only lets you transfer about 100 MB per file. That’s good if you just need to get to your admin stuff or a small website. But it’s tight if you’re moving backups, photos, or videos. You can pay for more, but then I thought, Why not just use my own VPS?
Tailscale or ZeroTier
Overlay VPNs like Tailscale and ZeroTier are other good choices. They get through NAT pretty well and create a private network for your devices.
In theory, it seemed perfect. Just put the app on my server, laptop, and phone, and they all act like they’re on the same network.
So, why didn’t I use them?
It’s not a bad solution at all. It’s actually really good. I just liked keeping things simple with the SSH tunnel setup. One program, not much to set up, nothing else needed, no extra accounts, and I know exactly what’s going on from start to finish. I know what’s happening, where it’s happening, and why it works again when it breaks.
That kind of reliability is pretty nice.
Wrapping Up
So, after using this setup every day, I’m pretty happy with it. My VPS is like a solid little helper, connecting me to my home server that’s usually hidden away. Autossh keeps the tunnel going strong, and I can get to my stuff from almost anywhere. Plus, I don’t even need a static IP from my internet company.
Here’s something to think about:
If you’ve already got a VPS for other things—like websites, a VPN, email, or whatever—then using it to reach your home server is smart. One server doing two things, and no extra cost for a static IP at home.
But, if you don’t already have a VPS and don’t need one for anything else, things are different. It might be easier, cleaner, and maybe even cheaper in the long run to just pay your internet provider for a static IP. There’s no single right way to do it. It really depends on what you’re already doing and how much control you want.
And that’s basically it!