Een verplaatsbare hostingoplossing achter CGNAT

Al ruim een jaar loop ik met een idee rond: een hostingoplossing die ik zonder gedoe meerdere keren kan uitrollen, en die gewoon werkt — ook achter een internetverbinding met een dynamisch IP, of erger nog, achter Carrier-Grade NAT (CGNAT). Geen vast IP, geen bereikbaarheid van buitenaf, dus normaal gesproken einde verhaal voor wie zelf iets wil hosten.
Het idee was simpel genoeg om op te schrijven: laat een virtuele machine in mijn thuislab zelf een WireGuard-tunnel opzetten naar een goedkope VPS, en zet vervolgens al het inkomende verkeer van die VPS door naar die VM. De VPS fungeert dan als vaste, stabiele voordeur; de VM kan intussen overal staan, achter welke verbinding dan ook.
Ik werk regelmatig met ISPConfig — wat mij betreft een van de betere hostingpanels voor Linux. De vraag die ik mezelf stelde was of zoiets fatsoenlijk overeind blijft wanneer je er een VPN-tunnel als WireGuard tussen zet. Op papier klinkt het simpel; in de praktijk blijkt het technisch nog best complex.
Van idee naar werkende opzet
Inmiddels host ik op experimentele basis websites via precies deze constructie, en het draait. Het is gelukt om het volgende voorelkaar te krijgen:
- Het echte IP van bezoekers blijft behouden. Verkeer wordt met DNAT doorgezet naar de VM, zonder masquerading. Daardoor ziet de VM — en dus ook de logs, en fail2ban — het daadwerkelijke IP van een bezoeker, niet een generiek tunnel-adres. Zonder dat zou elke vorm van misbruikdetectie zinloos zijn.
- Halfopen verbindingen komen er niet doorheen. Op de VPS vangt SYNPROXY de TCP-handshake af vóórdat er ook maar iets de tunnel in gaat. SYN-floods en halfopen verbindingen stranden dus al aan de voordeur, in plaats van de tunnel en de VM te belasten.
- Fail2ban werkt zoals het hoort. Omdat de VM de echte bezoekers-IP's ziet, kan er op de VM zelf ingegrepen worden bij verdacht verkeer — precies zoals bij een server met een eigen, direct bereikbaar IP.
- Het werkt inmiddels ook via IPv6, naast IPv4 — dezelfde constructie, gespiegeld voor beide address families.
Waarom niet gewoon Tailscale of een Cloudflare Tunnel?
Die vraag komt vast bij verschillende lezers in gedachten, en terecht — beide lossen het CGNAT-probleem prima op, om vergelijkbare redenen als hierboven: ook zij leggen de verbinding vanaf jouw kant op, niet andersom. Dus puur technisch gezien werken ze net zo goed. Het is dan ook geen kwestie van "wat werkt", maar van wat bij je past.
Wat mij aan deze opzet aantrekt, is dat ik zelf precies weet wat er gebeurt bij elke stap, en dat er geen derde partij tussen zit die morgen zijn voorwaarden kan wijzigen of een dienst kan aanpassen. Het draait bovendien op willekeurig TCP-verkeer — web én mail, zonder onderscheid — waar een Cloudflare Tunnel bijvoorbeeld vooral is toegesneden op HTTP(S). En het bezoekers-IP zit letterlijk in het pakket zelf, op kernelniveau, in plaats van dat ik een header van een derde partij moet vertrouwen.
Daar staat tegenover dat ik dit allemaal zelf bouw én onderhoud, en dat een kant-en-klare oplossing als Cloudflare gratis DDoS-bescherming biedt op een schaal die ik met SYNPROXY alleen niet evenaar. Wie snel en zonder gedoe een dashboardje thuis wil ontsluiten, is bij Tailscale of Cloudflare waarschijnlijk beter af.
Een prettige bijkomstigheid van deze aanpak: ik ben niet gebonden aan het platform van één partij. Er zijn talloze goedkope, verrassend stabiele VPS-aanbieders, en ik kan zo overstappen zodra een andere partij beter bevalt — de tunnel en de configuratie verhuizen gewoon mee. Bij Tailscale of Cloudflare zit die vrijheid er per definitie niet in.
Kortom: geen van beide is "beter". Het is maar net wat je zoekt.
Waar dit toe leidt
Het bijzondere zit 'm niet in de tunnel zelf, maar in wat die mogelijk maakt: omdat de VM altijd zelf naar de VPS "belt" om de tunnel op te zetten, maakt het niet uit welk netwerk eronder zit. Verplaats de VM naar een andere locatie, een andere internetverbinding, of zet een kopie ergens anders warm klaar als failover — de buitenwereld ziet steeds hetzelfde, stabiele publieke adres.
Nog altijd experimenteel, nog altijd met ruwe randjes hier en daar. Maar het werkt, en dat is precies waar ik ruim een jaar naar op zoek was.
Testpagina
Via https://s3.gigabitjes.nl test ik momenteel deze oplossing. Klik maar even — misschien zie ik jou IP binnenkort in mijn logs voorbij komen 😸