Exposing my services behind CGNAT without Cloudflare
I describe my homemade solution when I need to expose my services behind a CGNAT, without using Cloudflare.
At home, on my Proxmox server, I host two VMs that serve this blog, my Nextcloud space, and a BorgBackup instance to host backups for a friend.
When everything is working properly, thanks to my fiber connection and my public IPv4 address, I can easily expose all of my services by linking my subdomains to my IP provided by my LiveBox:

However, when this fiber connection fails, I have to use a backup 4G connection, which does not offer me a direct public IPV4 address! My 4G connection shares a single public IPV4 address with a whole host of other 4G customers thanks to what is known as CGNAT. This mechanism does not allow me to expose my services, so I had to find a workaround.
The solution, which is simple, fast, and free, is to set up a Cloudflare tunnel. I install a client on my main server, entrust the management of my domains to Cloudflare, configure a tunnel, and I can once again expose my services.
Except that Cloudflare is lava 🌋 because it is on its way to becoming the leading proxy and web policeman, giving it unprecedented power to control global traffic: it can decide to authorize certain connections under the guise of protecting against DDOS attacks, filtering CSAM content, and blocking malware... But as usual, entrusting such a mission to a private actor means trading security for freedom: tomorrow, Cloudflare will become a mega web enforcer that will have the right to give you access to a particular online service only if you meet its criteria. It could cut off access to third-party browsers, smartphones it deems obsolete, certain operating systems, certain IP addresses or countries... in short, I don't want to feed this machine.
So it became clear to me that I had to do without such a solution. I wanted to learn how to configure my own proxy, on demand, without using such a provider: so no VPN or alternatives to Cloudflare such as Tailscale or others. I knew it was possible, particularly by using a VPS and configuring an SSH tunnel. But I didn't know anything about the subject and had only vaguely read a few comments on the internet. Until I took the bull by the horns, deleted my Cloudflare account, and did my research online. That's when I found the four resources that enabled me to achieve my goal:
- How to access a Linux server behind NAT via reverse SSH tunnel
- How to use a Reverse SSH tunnel to reach a server behind a NAT
- Roll your own Ngrok with Nginx, Letsencrypt, and SSH reverse tunnelling
- SSH Reverse Tunneling
Source No. 3 provided a comprehensive overview of what I wanted to do and reassured me that it was possible, as my current configuration corresponds exactly to the situation described in the article.
My main VM runs Caddy, configured to route requests to the right services based on subdomains. SSL certificates are managed by Caddy. So I already met the prerequisites for SSH reverse tunneling to work. All I had to do was:
- Configure a VPS
- I chose to use a Debian 12 droplet, hosted on a server in Germany via DigitalOcean.
- I modified the configuration of the /etc/ssh/sshd_config to set GatewayPorts on yes
- Redirect my domains to the public IP of the VPS
- I configured what was needed in my OVHCloud manager
- Open an SSH tunnel from my main VM
- With the command line ssh -fN -R 443:localhost:443 root@[Public IPV4 of my VPS]
And as if by magic, just with the help of SSH, I could continue to use my HTTPS services by switching to my own proxy, without Cloudflare!
