Have you ever wanted to host a Virtual Machine on Google Cloud where your Cloudflare domain is only accessible via clients on your Tailscale network? This project aims to facilliate setting up your VM with Tailscale for private networking, installing and configuring Caddy as a reverse proxy, and configure new custom Cloudflare DNS hostnames. The configuration has been tested on Ubuntu 22.04 running on an AMD64 machine.
You aim to run a VM on GCP accessible exclusively at your.domain.com, and want to restrict access to it so that it's only available when you are connected to your Tailscale network, regardless of your location, be it at home or elsewhere.
The process of setting up Tailscale on your VM along with UFW, installing and configuring Caddy, managing DNS settings on Cloudflare, and adjusting your GCP Firewall rules involves numerous steps and is susceptible to mistakes. After navigating through this process myself, I decided to streamline and automate it to some extent, aiming to make it easier for others to implement.
- SSH access to a VM running Ubuntu 22.04 on Google Cloud Platform.
- The access scopes for the VM need to be configured to
Allow full access to all Cloud APIs
. As this is not the default configuration, you might have to stop the VM to modify theAccess scopes
settings to activate this feature, before you can restart the VM and run these scripts. - GCP CLI installed on your VM (usually installed by default)
- Git installed on your VM (usually installed by default)
- Tailscale account
- Tailscale API Access Token
- Cloudflare Account with a hosted domain (you'll need to provide the email address you sign in with)
- Cloudflare API Access Token
- Cloudflare ZoneID
-
Clone the Repository
On your VM, clone this repository to get started:
git clone https://github.com/danielraffel/GCPTailWall.git
-
Change Directory
Change into the cloned directory:
cd GCPTailWall
-
Run Setup Script
Execute the setup script with sudo privileges:
sudo bash setup.sh
Note: Running
setup.sh
will create avariables.txt
file. If you rerun the script and this file exists, it will automatically executesetup_GCPTailWall.sh
with the previous configurations. Deletevariables.txt
if you wish to start fresh.
- Tailscale Configuration: Configures your VM with Tailscale for secure, private networking. You'll be prompted to copy a link to your browser to approve this.
- UFW Configuration: Locks down the VM with UFW (Uncomplicated Firewall), making it accessible only via the Tailscale network. Port 22 is left open for SSH access.
- GCP Firewall Rules: Opens necessary firewall rules on GCP to ensure Tailscale and specified services running on the hostnames can communicate.
- Caddy Reverse Proxy: Configures Caddy to proxy requests to your services based on the hostnames and ports you specify.
- Cloudflare DNS Management: Sets up DNS entries on Cloudflare for your services, using the hostnames you provide and directs to your TailscaleIP.
During the setup.sh
execution, you'll be prompted to enter the following:
- Custom hostnames for your services and their corresponding TCP port. You can create one or multiple
- Your Google Cloud VPC name (default is used if left blank)
- Your SSH key username.
- Tailscale API Access Token (obtain from Tailscale Admin)
- Cloudflare API Access Token (obtain from Cloudflare API Access Token) * Instructions below
- Cloudflare Zone ID (obtain from ZoneID
- Email address used to sign in to Cloudflare
After setup.sh
finishes, it automatically executes setup_GCPTailWall.sh
with the configurations you provided.
[jq](https://manpages.ubuntu.com/manpages/xenial/man1/jq.1.html)
is installed as part of the setup to process JSON data, which is necessary for interacting with Tailscale and Cloudflare APIs during the setup process.
- If you've not used certain Google Cloud APIs the Google CLI might ask you to enable them and retry again.
- If you're getting permission errors such as "Request had insufficient authentication scopes" then you probably did not enable the Access Scopes. To fix this go to GCP Console > Compute Engine and then stop the VM you want to install this script on. Once stopped, select
edit
and scroll down toAccess scopes
and selectAllow full access to all Cloud APIs
then presssave
and restart the VM. You need to do this for the Google CLI to have the ability to perform lots of API calls on your behalf. - The file
example.variables.txt
includes all possible variables thatsetup.sh
creates withinvariables.txt
. If you prefer to manually create the file, you can then runsetup_tailscale.sh
withsudo bash setup_tailscale.sh
. - If you're having a hard time Creating a Cloudflare API Token
- Log in to your Cloudflare dashboard.
- Navigate to My Profile > API Tokens.
- Click Create Token.
- Use the "Edit zone DNS" template as a starting point.
- Set permissions to Zone > DNS > Edit.
- Include all the zones you want Caddy to be able to issue certificates for, or select "Include all zones" if you prefer.
- Complete the token creation process.
Caddy is primarily employed as a proxy to facilitate the hosting of multiple hostnames on a single virtual machine. It is particularly advantageous due to its ability to automate the creation and renewal of SSL certificates, ensuring that even hostnames behind a Tailscale network can securely serve domain names over SSL.
This configuration aims to secure the virtual machine by closing off public ports such as 80 and 443. Utilizing the Cloudflare module with Caddy offers a reliable and secure alternative for the server to periodically connect with Cloudflare for SSL certificate renewal, without exposing these ports to the public.
The decision to opt for a precompiled version of Caddy including the Cloudflare DNS module stems from consistent difficulties encountered when attempting to compile xcaddy with the Cloudflare DNS module using go. These challenges proved insurmountable, leading to the selection of a precompiled solution to bypass these issues.
The decision to hardcode the binary for Linux ARM64 is due to convenience. Modifying the setup script to detect the operating system and architecture to adjust the download URL accordingly would be a simple task. It's something I might consider implementing in the future. At present, my usage is limited to complimentary VMs that run Ubuntu. For now, I left a comment in setup_tailscale.sh where you can manually update the URL to pre-compiled binaries should you need to switch to something else.