How to run VS Code on the server!
Tags: webdev, vscode, productivity, codercom
Published: 2019-03-11 07:23:33

VS Code is my favorite editor for web development. The integrated terminal, the great plugin ecosystem, debugger, and excellent TypeScript support make it just perfect. Its one reason I keep coming back to developing locally. Because while I could run `vim` on the terminal and work remotely, I'm just not as productive in `vim`.

Of course there are other options. Cloud development is pretty great. Working on a project entirely remote on a browser is liberating. My project is always ready to be worked on, untethered from my machine. But cloud editors each have their own drawbacks. Ultimately, I want to drop into the terminal, start and stop services, and do all that I am able to do from my local machine. If only there was a way to run VS Code directly on a remote server, it would be the best of both worlds.

Well, now there is! Thanks to `code-server` by coder.com 

{% github codercom/code-server %}

# Getting started

To get started, you'll need to log into your remote development server. This can be something like a Droplet from Digital Ocean, an AWS Lightsail instance, or any other cloud or internet connected server one would want to use. `ssh` access is needed.

One could then log into the remote server and either run code-server in docker or just use one of their binary releases. I used the the binary distribution for my purposes

https://github.com/codercom/code-server/releases

Here is an example of how that might go

```bash
mkdir ~/code-server
wget -qO- LINK_TO_DESIRED_BINARY \
  | tar xvz --strip-components=1 -C ~/code-server
```

The `code-server` binary comes with a few options. At the time of this writing, it seems that the application had some trouble when given a relative paths on my system. So I wrote a super simple wrapper around it in bash, decided to call it `code` and place that in `~/bin` which is my `PATH` variable.


`vim ~/bin/code`
```bash
#!/usr/bin/env bash
abs=$(realpath .)
req=$1
if [[ ! $1 =~ ^\/ ]];
then
  req="$abs/$1"
fi;

if [[ ! -d $req ]];
then
  echo "ERROR: path does not exist"
  echo "$req"
  exit;
fi;

~/code-server/code-server $req --no-auth
```
`chmod +x ~/bin/code`

This script starts `code-server` with the `no-auth` option. The `no-auth` option disables the built-in encryption functionality and the password authentication page. I do this because I would rather encrypt the traffic through a proxy server or through a SSH tunnel. I can also password protect the page using the web server that proxies connections.

Now to start the server, I simply open a project similar to how I would with VS Code directly.

`code /path/to/project`

This will start serving VS Code over port `8443`. There are two ways to connect to it; either through an SSH tunnel or by using a web server reverse proxy.

# SSH Tunneling / Port Forwarding

You can forward a remote port from the server to your local client by using SSH. Here is how it would look to format port `8443` from the server to your local machine.

```bash
ssh -N -L 0.0.0.0:8443:localhost:8443 login@your-server \
  2> /dev/null
```

This command won't give you the remote shell, it will just do the port forwarding. Now you can open your browser and visit `http://localhost:8443`. Behold! You are now using VS Code, running on your server, from your browser!

 
<img src="https://thepracticaldev.s3.amazonaws.com/i/yu7tdjf7djj12kcuveo4.jpg" width="50%" />

What is pretty incredible is that you have access to the terminal as well! This is very powerful stuff--so beware! 

One final piece is to proxy any other running services on unprivileged ports, like port `3000` or `8080`. One way to do this is by opening another terminal and making another connection.

```bash
ssh -N -L0.0.0.0:3000:localhost:3000 login@your-server \
  2> /dev/null
```

Or proxy both ports at once


```bash
ssh -N \
  -L 0.0.0.0:8443:localhost:8443 \
  -L 0.0.0.0:3000:localhost:3000 \
  login@your-server \
  2> /dev/null
```


# Web Server Reverse Proxy

Note: this option is for if you want to handle encryption and password protection yourself.

```bash

BE SURE TO ENCRYPT AND PASSWORD PROTECT PUBLIC URLS.

```

Correctly setting up a reverse proxy through a web server is a more involved process. I will provide only an overview of what you need to make this work.

* Make sure you have an SSL certificate. You can get one using `certbot` by Let's Encrypt.
* Configure a web server to create reverse proxy between port 8443 and your desired URL. Be sure to proxy websocket traffic as well.
* Password protect access to the URL

In my case, I also want to proxy services running for development purposes, like port `3000` or `8080`. 

### APACHE

You'll need to ensure that the proper modules are loaded
```bash
sudo a2enmod rewrite
```

Then a configuration might be something that starts like this

```apache
<VirtualHost ip_address:443>
  # Enable Modules
  RewriteEngine On
  SSLEngine On

  # Configure basics
  ServerName your.address
  ServerAdmin whoever@your.address


  # Proxy Traffic
  RewriteCond %{HTTP:Upgrade} =websocket
  RewriteRule /(.*)           ws://localhost:8443/$1 [P,L]
  RewriteCond %{HTTP:Upgrade} !=websocket
  RewriteRule /(.*)           http://localhost:8443/$1 [P,L]

  # Require Password
  AuthUserFile /path/to/.htpasswd
  AuthGroupFile /dev/null
  AuthName "Title"
  AuthType Basic
  require valid-user

  # Use SSL
  Include /etc/letsencrypt/options-ssl-apache.conf
  SSLCertificateFile /etc/letsencrypt/live/yourwebsite.com/fullchain.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/yourwebsite.com/privkey.pem

  SSLProtocol all
  SSLCipherSuite HIGH:MEDIUM
  # And so on...

```

### NGINX
I've not tried doing this for `code-server` with NGINX yet. NGINX is particularly apt for this. Here are some references on where I would start:

Encrypt traffic and reverse proxy w/ websockets
https://gist.github.com/steve-ng/ed6de1fa702ef70bd6ce

Password protect
https://www.digitalocean.com/community/tutorials/how-to-set-up-password-authentication-with-nginx-on-ubuntu-14-04

# Other options 
### Let `code-server` handle its own encryption

Another option is to not include the `--no-auth` option and let `code-server` do its thing. Here is a resource for more information on this would work on Digital Ocean

https://github.com/codercom/code-server/blob/master/doc/admin/install/digitalocean.md

### Use coder.com

I should also mention that coder.com has a cloud service for this.

https://www.coder.com

# Overview

Running VS Code on the cloud untethers the developer from their workstation. One could install their plugins, configure the editor to their liking, and work directly from the could. The environment is always there, ready to go.