I use a registered domain with DNS validation and then CNAMEs that I resolve locally. Basically:

  1. Register a domain ("server.com") and put it on some public DNS that can do DNS validation with acme.sh.
  2. Use DNS validation to get a certificate on your domain from Let's Encrypt. You can just grab a wildcard one ("*.server.com").
  3. CNAME all of your services on a public DNS to an internal address ("email.server.com" → "server.internal", "plex.server.com" → "server.internal").
  4. Resolve your internal address on a local DNS server with an A record ("server.internal" → 192.168.0.123). This can often just be done on your router.
Since you use DNS validation, you just API keys for your public DNS service that acme.sh can use. No need to have any VPN network interfaces for getting your certificate. Your wildcard certificate also doesn't leak any details about your services.

I like this approach. Thank you.

Would it work if a user's device that is already connected to the VPN, but has custom DNS override to say 8.8.8.8 ? How can I allow my users to be able to use 8.8.8.8 DNS override and still work seamlessly?

I think you'd at least have to have the fallback DNS set to your local DNS resolver in order to get the server.internal resolved to a A record.