…Or someone else’s computer
Sometimes your development machine is not sufficient for various reasons: For example, you need to build an x86/amd64
Docker image and do not want to pay the cost of QEMU, or it is on a limited internet; for these and other reasons, I created a terraform to bootstrap a development machine with a single command.
Of course, Codespaces is the ideal solution for this. However, it does not exist in my region, and it is expensive.
My solution relies on the following:
- Terraform for provisioning and de-provisioning.
- Cloud-init for initial configuration.
- Tailscale to create a secure tunnel between the machine located in the cloud and my machine.
- asdf for installing languages and tools.
I have chosen Vultr because they are cheap and have machines in my region.
Provisioning
Let us take a look into the terraform script, which is responsible for provisioning the machine and setting the Cloud-init:
locals {
user_data = templatefile("cloud-init.yaml", {
user = var.USER
tskey = var.TAILSCALE_AUTHKEY
})
}
resource "vultr_instance" "workstation" {
plan = "vc2-1c-1gb-sc1"
region = "sao"
os_id = "387"
enable_ipv6 = true
user_data = local.user_data
}
variable "USER" {}
variable "TAILSCALE_AUTHKEY" {}
Another important script is the cloud-config. It is used by Cloud-init to run a set of commands at the very first boot. We will install Docker and its plugins, Tailscale, and asdf.
Please note that we are not messing with ports; we will keep all closed, and the only access is through the VPN (Tailscale).
#cloud-config
---
users:
- name: ${user}
shell: /usr/bin/bash
ssh_import_id: gh:${user}
sudo: ALL=(ALL:ALL) NOPASSWD:ALL
groups: docker
lock_passwd: true
chpasswd:
expire: false
ssh_pwauth: false
apt_update: true
apt_upgrade: true
apt:
sources:
tailscale.list:
source: deb https://pkgs.tailscale.com/stable/ubuntu focal main
keyid: 2596A99EAAB33821893C0A79458CA832957F5868
docker.list:
source: deb https://download.docker.com/linux/ubuntu focal stable
keyid: 9DC858229FC7DD38854AE2D88D81803C0EBFCD88
packages:
- curl
- git
- docker-ce
- docker-ce-cli
- docker-compose-plugin
- tailscale
runcmd:
- |
cat << 'EOF' >> /home/${user}/.bashrc
. $HOME/.asdf/asdf.sh
. $HOME/.asdf/completions/asdf.bash
EOF
- su ${user} -c 'git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.11.0'
- tailscale up -authkey ${tskey}
Another interesting point, we are going to fetch the public keys for SSH access from GitHub, that is what this line does:
ssh_import_id: gh:${user}
With all variables in place and the region and plan selected, we can start the provisioning.
Copy the terraform.tfvars.example
to terraform.tfvars
and fill out the values:
VULTR_APIKEY = "apikey"
TAILSCALE_AUTHKEY = "authkey"
USER = "github_username"
Then, use terraform to apply:
terraform init
terraform apply
During the setup, it gets configured the Tailscale and the SSH public keys fetched from GitHub, this allows connecting to the machine with a single command:
It can take a while, you can follow the progress on the dashboard or wait for the new machine has been added to Tailscale.
ssh vultr
This is possible because Tailscale has a feature named magic DNS, which will add the hostname of each machine, by this way, you do not need to remember addresses or open ports, everything works out of the box.
It is also possible to use VSCode remote development, which turns it a real game changer.
Exposing to the Internet
Remember I told you you don’t need to open ports or IP addresses?
With Cloudflare Tunnel, you can remain occult, and the only traffic is coming up from Cloudflare with Tunnel. A true zero-trust environment.
Let’s suppose you have your blog running and binding only on localhost. You can expose it by running the command below; you will need an account and a domain set on Cloudflare.
cloudflared login
cloudflared tunnel run --url localhost:3000 blog
You can also run it as a service. To do this, run:
cloudflared service install
More details on how to setup Cloudflare Tunnel in https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/tunnel-guide/local/.
WARP
If for any reason you need an alternative to Tailscale, Cloudflare WARP is a good option. Cloudflare WARP is technically a VPN; it connects to Cloudflare’s 1.1.1.1. Cloudflare has a lot of PoPs (Point of Presence) around the world, which could have a better decision on the routes and delivery a lower latency.
The setup is pretty much the same as used to expose an internal service to the internet by using cloudflared
.
tunnel: 953db4ee-d6c7-4e63-b5a0-7b02f4258abd
credentials-file: /root/.cloudflared/953db4ee-d6c7-4e63-b5a0-7b02f4258abd.json
warp-routing:
enabled: true
Then run:
cloudflared tunnel run yourservice
With WARP, you can create fine-grained rules of who can access the service; for example, all people with email @company.com
.
More information on this page.
Costs
You only pay for the time while the cloud instance is running, to dispose of it, you just need to run:
terraform destroy
Source Code
github.com/skhaz/my-cloud-workspace