Creating/Securing a Remote Dev Environment
Tags: cloudflare, digitalocean, vscode, tutorial
Published: 2021-06-07 15:18:19

### Introduction

A *remote development environment* is an environment/server hosted externally (i.e. not on your local machine) that you connect to remotely to perform your development work on.

Using the [Remote-SSH](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh) extension on [Visual Studio Code](https://code.visualstudio.com/), you can develop on a remote machine while maintaining the feel and responsiveness of developing on your *local machine*.

![A diagram explaining how Remote-SSH works on VS Code](https://code.visualstudio.com/assets/docs/remote/ssh/architecture-ssh.png)
Image Source: [Visual Studio Code / Microsoft](https://code.visualstudio.com/docs/remote/ssh)

The way this is achieved is via a SSH Tunnel. But you can secure this a step further by requiring proof of identity via an SSO Identity Provider (like Google, Github, Facebook, Active Directory, etc) by using Cloudflare Access and Cloudflare Tunnel.

There are numerous benefits to using a remote environment to perform your development on. Here's just a few:

1. You can switch machines without losing your work. Since your work is not on your local machine, that means that you can switch from your desktop to your laptop and not lose anything.
2. You can develop your application/system on an environment that closer replicates the environment that your product will be deployed to.
3. There's less of a security risk if your local machine is lost/stolen. Your code/files aren't on there.
4. Colleagues and other developers can also connect to your remote development environment to help debug or perform any other necessary work.

### Goals

By the end of this tutorial, you will have:

1. A DigitalOcean droplet setup with your development stack
2. Visual Studio Code setup locally with the Remote-SSH extension
3. The [cloudflared](https://developers.cloudflare.com/cloudflare-one/glossary#cloudflared) *daemon* installed both on your remote and local machines
4. An SSH config on your local machine to easily connect to your remote machine using Cloudflare Tunnel and Cloudflare Access

## Prerequisites

- A generated SSH Key
  - You will need to upload your public key to DigitalOcean
  - You will need your private key in order to SSH into your Droplet initially
- A [DigitalOcean](https://blake.link/digitalocean) account
  - New users can use the link above to get a $100 credit valid for 60 days when you add a payment method to your account
- A [Cloudflare](https://www.cloudflare.com/) account with a domain added
  - This domain will be used by you to connect to the remote machine
- A [Cloudflare for Teams](https://developers.cloudflare.com/cloudflare-one/setup) account already setup
  - A free plan is available
- A [SSO Integration](https://developers.cloudflare.com/cloudflare-one/identity/idp-integration) already setup within Cloudflare for Teams
  - In this tutorial I'm using a GSuite integration to verify my identity
- [Visual Studio Code](https://code.visualstudio.com/) installed on your local machine

## Step 1 — Configuring Cloudflare

You will create an access policy for your selected domain.

Cloudflare Tunnel is a service which provides a secure connection between the nearest Cloudflare datacenter and your remote machine, without opening public ports. This tunnel is how you will connect to your remote machine securely. Previously this was a part of Cloudflare's paid Argo service, but as of April 2021 has been made free of charge.

From your Cloudflare dashboard, select the domain (or *zone*) that you have chosen to use for this tutorial.

You need to **create an access policy**. This policy will determine who has access to your Droplet. 

Click on the **access** tab on your domain's Cloudflare dashboard. Scroll down to **Access Policies** and hit **Create Access Policy**.

Give an application name, and the subdomain that you will use to connect to your Droplet (decide this now, you'll need it again later in this tutorial). For session duration, decide how long a session should be valid for.

You need at least 1 policy. Create one by giving it a name. Then add an include-rule. For this tutorial, I decided on "emails ending in" and the domain of my GSuite account.

![A screenshot of a sample access policy.](https://i.imgur.com/IkP0cqw.png)

Once you're done, hit **save**. Now that your Cloudflare settings are configured, it's time to create your remote machine.

## Step 2 — Creating your Droplet

You will create a Droplet on DigitalOcean with a new user, your preferred tools/programs, and the `cloudflared` daemon.

To begin, **visit [this link](https://cloud.digitalocean.com/droplets/new)** to access the Droplet creation page.

For this tutorial, you will use **Ubuntu 20.04** as your operating system.

For the Droplet plan select the configuration that you think you will need for your development work. From personal experience, the Regular Intel, 4GB / 2 CPUs plan works great on a stack with Java 11, Apache Maven, Git, and Docker.

Next, select your preferred datacenter. Typically, the datacenter closest to you is the best option to minimize latency.

For additional options, enable **IPv6 and User data**. Monitoring is optional but recommended if you wish to view stats about your Droplet online.

A text field will appear after selecting the user data checkbox. This is where you will paste a script to be executed when the server initially boots for the first time.

Below is a script that I have provided for you to use. It creates a new user, optionally installs some packages, and installs `cloudflared`. There is a variable for the name of the user to create.

{% gist https://gist.github.com/heyimblake/8eb905a3760ce1456a759a7ea8093637 %}

Back to the Droplet creation panel - For authentication select *SSH Key* and upload your public SSH key if you don't already have a key uploaded.

The remaining options are optional. I recommend changing the hostname to something you recognize, such as the domain name that you plan on using for that Droplet.

Once finished configuring your options, press **Create Droplet**. You've just created your remote machine! The next step is to configure it and ensure it is secure.

## Step 3 — Securing your Droplet

You will configure the `cloudflared` daemon and setup the SSH tunnel on your Droplet.

On the DigitalOcean panel, navigate to your newly-created Droplet. Copy the public IPv4 address listed.

You are going to have to **SSH into your Droplet** with the username that you configured in the script provided. To do this, on your local shell run `ssh <your configured username>@<copied IP address> -i <path to your private SSH key>`. 

An example might look like `ssh sammy@XXX.XXX.XXX.XXX -i ~/.ssh/id_rsa`.

Navigate to `/etc/cloudflared/` using `cd /etc/cloudflared`.

Before proceeding, ensure that `cloudflared` is up-to-date. Run `sudo cloudflared update`.

Next, you need to **authenticate `cloudflared`** with your desired zone (domain). 

Run `cloudflared login`. It should output a link, which you can then copy to your web browser and load.

On the website, it is important that you **select the zone that you will be using** to connect to the Droplet with. Click **Authorize**. You can close that website once done.

Return back to your SSH session. You now need to **move the newly-downloaded certificate** to `/etc/cloudflared/cert.pm`. Do this by running `sudo mv /home/sammy/.cloudflared/cert.pem /etc/cloudflared/cert.pem`, replacing `sammy` with your configured username.

Now is the time to create the tunnel. 

Do this by running `cloudflared tunnel create NAME`, replacing `NAME` with a label for your tunnel. An id should then be printed out after running the command. Make note of it.

Next, you need to **create a configuration file** telling `cloudflared` what to do when it runs.

Modify and copy the provided config file below. Replace `XXX` with the id of your created tunnel, and `YOUR.DOMAIN.HERE` with the hostname that you wish to use to connect to your Droplet. The apex domain must match the one you selected when authenticating `cloudflared`.

{% gist https://gist.github.com/heyimblake/b426e15e574cc0d12c43c513de0c0f8b %}

Create the file `/etc/cloudflared/config.yml` by using your favorite text editor (such as [vim](https://vimhelp.org/) or [nano](https://www.nano-editor.org/docs.php)) and pasting your modified config template from above.

To **create the DNS record** for your configured domain name, run `cloudflared tunnel route dns <id> <subdomain>` where `id` is the id of the tunnel, and `subdomain` is the subdomain you selected in your config file. You can verify on your Cloudflare DNS page that a CNAME record was created.

The `cloudflared` daemon is now fully configured. It's time to start it! It's best to **run the daemon as a service**.

Run `sudo cloudflared service install` and `sudo service cloudflared start`.

To **verify that there were no errors** in the service starting, run `sudo service cloudflared status`. You should see the  tunnel being started with some connections being made. Those connections are to nearby Cloudflare datacenters.

With your remote machine configured, it's now time to configure your local machine so it is able to connect to your Droplet over this secure tunnel.

## Step 4 — Configuring your local machine

You will configure your local machine to use the Cloudflare Tunnel when SSHing into your Droplet, and install the Remote-SSH extension in Visual Studio Code to be able to modify files on your Droplet seamlessly.

**Install `cloudflared` on your local machine**. You can view full instructions from [Cloudflare's website](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation). It supports Mac, Linux, Windows, and Docker. Again, it's best to run the daemon as a [service](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/run-tunnel/run-as-service).

You do not need to authenticate the daemon on your local machine (i.e. do not run the login command). 

Now, you need to **update your local SSH config** to make use of `cloudflared` for your Droplet. The daemon has a feature which will generate most of this config for you.

Run `cloudflared access ssh-config --hostname YOUR.DOMAIN.HERE`, replacing the variable with your domain that you put in your config on your Droplet.

Determine where your local SSH config is. On Mac, it's located at `~/.ssh/config`.

It should print something out like this to add to your SSH config:

```txt
Host YOUR.DOMAIN.HERE
  ProxyCommand /usr/local/bin/cloudflared access ssh --hostname %h
```

Note, the path in your proxy command may be different depending on your operating system. That's why its important to use what the program gave to you after running the command.

Append the printed text to your local SSH config using your preferred text editor. Add an additional line under the Host labeled `User` with your Droplet's username (see below for an example). This makes it easier for Visual Studio Code.

```txt
Host YOUR.DOMAIN.HERE
  ProxyCommand /usr/local/bin/cloudflared access ssh --hostname %h
  User sammy
```

**Try connecting to your Droplet** using this updated SSH config. Run `ssh YOUR.DOMAIN.HERE`. If all goes well, your browser should open prompting you to select an identity provider, you login, and authorize the request. Once authorized, your local terminal will SSH into your Droplet and you can close the opened webpage.

Now it's time to setup your local Visual Studio Code IDE. Open VS Code and **install the [Remote-SSH](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh) extension**.

Once installed, by default the extension should show remote targets from your local SSH config file. You can select your newly-added target to connect to it.

You can also use the `opensshremotes.openEmptyWindow` VS Code command to select a remote target.

After authentication (or if your session is still valid from your test), VS Code will connect to your Droplet and automatically install the VS Code Server (first boot only).

From here, you can install extensions onto your Droplet, create directories/files, and even open a terminal in VS Code.

![Image of Visual Studio Code, editing a file remotely.](https://i.imgur.com/zLk59w8.png)

### Conclusion

Remote development environments are a great way to work. They allow you to develop and test your product in an environment closer to production, permits switching machines, and allows multiple people access to the environment. Using Cloudflare Access and Cloudflare Tunnel, this access can be granted or denied based on authentication through SSO providers, providing a clean way to authenticate and authorize users.