Hybrid Enough: OpenStack & libvirt


Since Enough now supports deployments of hosts with libvirt instead of OpenStack, one can imagine deploying a single host in the cloud and the rest of the hosts on physical machines. The host in the cloud runs the DNS and a reverse proxy behind a public IP for the example.com domain and is deployed with:

$ enough --domain example.com service create website

The services on physical machines (for instance a Nextcloud) are deployed with:

$ enough --domain lan.example.com service create --driver libvirt cloud

A VPN is added to example.com so that lan.example.com can become a client, otherwise there is no way for the reverse proxy running on example.com to reach the hosts in lan.example.com because they have no public IP.

The DNS at example.com delegates the lan.example.com zone to the DNS that runs in lan.example.com. It serves two purposes:

  • a user that connects to the VPN can conveniently ssh debian@cloud.lan.example.com despite the fact that it has a private IP on the physical machine
  • the postfix server running at postfix.lan.example.com can identify as lan.example.com which can be verified to be a real domain name instead of a fake one that would be denied by the receiving SMTP server

This is not too complicated but the implementation requires a significant number of manual steps that should be documented:

  • Creating the libvirt host and populating the ~/.enough/lan.example.com directory for it
  • Retrieving the VPN client credentials for lan.example.com
  • Writing a playbook to install the VPN client credentials on bind.lan.example.com, publish the route, configure nat with nft (in a way that is similar to what the VPN server does)
  • Writing a playbook to delegate lan.example.com from example.com
  • Writing a playbook to reverse proxy cloud.example.com to cloud.lan.example.com so that it is visible from the net
  • Add the admin ssh public key so it is installed by the authorized_keys playbook and they can conveniently ssh debian@bind.lan.example.com as well as ssh debian@bind.example.com
  • Set the public facing FQDN of cloud.lan.example.com to be cloud.example.com instead via an ansible variable
  • Set the postfix.lan.example.com mailname and HELO name to lan.example.com via an ansible variable
  • Install the root CA of lan.example.com in website.example.com so that the reverse proxy can use https://cloud.lan.example.com which does not have a Let’s Encrypt certificate
  • Setup the backups so that lan.example.com hosts are uploaded to OpenStack weekly

Special thanks to @pilou for the domain name naming idea: using lan.example.com instead of example.lan.