The fun adventure of running VSCode locally with purely native functionalities.

If you want just the working solution, then jump to the Solution section.

Why?

I like to code from my couch. But I don’t have a laptop only iPad.

How? (Requirements)

  • it has to support iPad, - ssh remote plugin is not an option, only browser based solution is possible;
  • use only Microsoft Visual Studio Code binary and avoid 3rd party repositories;
  • run it in the local network (so tunnel is not an option since it is proxied over the Internet);
  • it would be nice if connection would be secure.

Architecture

We are considering 2 machines in the local network:

  • linux server - running vscode server;
  • iPad - client of vscode server.

The (painful) story to the success

Command

We are starting with simple knowledge: code supports running itself as http server with command:

code serve-web --host 0.0.0.0 --port 1234 --connection-token super-secret

It appears that we can re-configure everything we want, to achieve the goal:

  • host on which server is listening (default: localhost),
  • port to something static (default: random),
  • secret (token) which is required to connect and its passed as GET param (default: random).

We have everything what we needed, so post can be ended here, right?

Problem 1: Unathorized Client

When we try to launch the above command and open our code instance from the iPad we can notice the popup with error:

An unexpected error occurred that requires a reload of this page.
The workbench failed to connect to the server (Error: Connection error: Unauthorized client refused)

According to the github issue one of the components will fail for non-localhost server hosting without tls.

OK, so we can run it over localhost, but behind https proxy like nginx. Nothing simpler, right?

Problem 2: Find the working nginx config

Code runs a lot of things over websockets and here is a big issue, because we need to configure the proxy in the correct way. Here I encountered 3 major subproblems.

Error: WebSocket close with status code 1006 behind nginx proxy

It will show-up for the configurations where proxy is with websocket support disabled as described for example here.

Error: Extension file not found when code-server serve-local

Something executes, but there are some problems with interactions and server shows errors about missing files as in this case. This is mostly related to websockets and invalid Host header.

No error, but still it doesn’t work

And finally - my favourite - no errors, but when you try to open folder from the browser it just doesn’t work - no errors at all.

Solution

It took me a long hours to find the working combination of settings. Below you can find complete, working example.

1. Generete SSL certs

# as root
mkdir /etc/ssl/vscode # or whenever you want to put it
cd !$
openssl req -new -key code.key -out code.csr -subj "/C=US/ST=State/L=City/O=HOST/CN=YOUR_HOST"
openssl x509 -req -days 365 -in code.csr -signkey code.key -out code.crt

2. NGINX Config

# in case you don't have it, instructions for ubuntu
sudo apt install nginx
sudo systemctl enable nginx
sudo systemctl start nginx

Create nginx config file in: /etc/nginx/sites-available/code:

server {
    listen 443 ssl;
    server_name hangar.local;

    ssl_certificate     /path/to/cert.crt;
    ssl_certificate_key /path/to/cert.key;

    ssl_protocols       TLSv1.2 TLSv1.3;
    ssl_ciphers         HIGH:!aNULL:!MD5;

    location / {
        proxy_pass         http://127.0.0.1:3291/;
        proxy_http_version 1.1;

        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header REMOTE-HOST $remote_addr;
        proxy_set_header   Upgrade          $http_upgrade;
        proxy_set_header   Connection       "Upgrade";
        proxy_connect_timeout      60;
        proxy_send_timeout         90;
        proxy_read_timeout         90;
        proxy_buffer_size          4k;
        proxy_buffers              4 32k;
        proxy_busy_buffers_size    64k;
        proxy_temp_file_write_size 64k;
        add_header X-Cache $upstream_cache_status;
    }
}

In above config please replace the paths to your certs. I will be also using port 3291 for hosting code server over localhost, feel free to replace it if you want.

Now, enable it:

sudo ln -s /etc/nginx/sites-available/code /etc/nginx/sites-enabled/code
sudo systemctl restart nginx

3. Start code server

code serve-web --port 3291 --connection-token YOURSECRET

Protip, you can also create the alias from it to run it easier in your .bashrc or .zshrc:

alias codeserver='code serve-web --port 3291 --connection-token YOURSECRET'

4. Open it in the browser

Go to the https://YOUR_HOSTNAME/?tkn=YOURSECRET and wait for a moment until vsode will launch.

I recommend to add above url as bookmark to simplify the process of launching Code Server from the browser.

Finito!