I recently moved and set up my server anew.
I still have a VPS gateway sitting in front of the actual laptop. (That will be important later.)
Earlier this year, I shifted from running everything on the same host to running different services in their own VMs. I had been using Debian Testing (future 12/bookworm), but with this setup, I wanted to switch to Stable (11/bullseye).
Unfortunately, the version of libvirt in Debian 11 does not seem to work with an nftables-based NAT running on the host, which is how I had been routing incoming traffic to the VMs. I tried to use iptables instead, and I was unable to get it working.
Eventually, I thought of a solution: Since incoming traffic came through a VPN (or Tor, etc.) anyway, I could set up the VPN to run in a VM and use nftables in that VM (rather than the host where nftables would interfere with libvirt) to route incoming traffic to the destination VM.
Similarly, Tor is running in its own VM and forwarding ports to the appropriate VM IPs, rather than localhost. I haven't set up I2P and Lokinet again yet, but I intend to set them up the same way.
(These work because they're actually establishing outgoing connections, which can then be used to receive requests.)
The biggest issue with this setup is that there are no instructions on the host to forward incoming traffic to VMs. This means that I can't connect over LAN, and if I end up again with an internet plan that supports hosting a server, I won't have an easy way to port forward from the router. (I might have to see if I can set up a WireGuard VPN on the router to forward to the VPN VM.)
If you visit this site via the clearnet, here's what the chain should look like: You → [any proxies or whatever you're using] → VPS gateway → VPN VM → HTTP VM
If you're connecting to the onion site, it should look something like this: You → [any additional proxies or whatever you're using] → 6 Tor nodes → Tor VM → HTTP VM