This is a Web-based version of Microsoft's open source VS Code text editor backed by Google Drive. It is a server that runs on a remote GNU/Linux machine and affords clients access to the editor, a terminal, and optionally a graphical desktop. Specifically, it is Gitpod's OpenVSCode Server distribution configured to use Google accounts for authentication and Google Drive (via Rclone) for storage.
To support running graphical applications, it can optionally provide a virtual desktop using TigerVNC and a hosted copy of the Web-based noVNC client.
This project uses Linux namespaces for containerization, and as such only supports recent versions of that kernel. Practically, it requires a multicore server or virtual machine because it creates an independent container running a separate instance of Node, Rclone, TigerVNC, and noVNC's proxy server for each authenticated user. Running it as a microservice is infeasible.
As in OpenVSCode Server, some preferences and extensions are stored in the client's browser, and others are stored on the filesystem. The former class mean that a user's experience can change as they move from seat to seat, and the latter pose performance problems for certain addons. In particular, language extensions and run/debug support are unlikely to work when installed by users, so out of the box most compilation and execution should be performed on the command line. If language extensions are needed, it may be possible to support them by copying their files into the container's VSCode installation directory rather than running them out of each user's home.
Isolation is accomplished using containers and processes, and is at most as secure as the hosting Linux kernel. This project is designed to be run on a headless server; running it on a desktop may expose the rest of the system, via the X Window System, to attacks including privilege escalation and write access to other users' Google Drive files.
You need two things: a Google domain with a registered OAuth application permitting authentication and access to Google Drive, and a server or virtual machine to run this project on.
This section assumes (1) that your school or organization uses Google Workspace, (2) that you have an account in the same domain as your students or users, and (3) that your account has access to the Google Cloud console. Unless you request Google's approval, only users from the single domain in question will be able to log in; therefore, if (1) is not true, you might consider registering your own domain for Google Cloud Identity Free and creating domain accounts for your users. If (2) or (3) is not true, you will need to ask your IT department for assistance.
-
Go to console.cloud.google.com, sign in with your domain account, and accept the terms of service if applicable.
-
In the upper-left corner of the page, click Select a project:
-
In the upper-right corner of the resulting dialog, click new project:
-
Give your project a(n internal) name and hit create:
-
Once the Notifications panel shows a green check mark, click select project:
-
If no sidebar is open on the left side of the page, click the hamburger button in the upper left:
-
In the sidebar on the left, hover over APIs & Services and select Enabled APIs & services:
-
At the top of the page, click enable APIs and services:
-
Scroll down to find Google Workspace and click Google Drive API:
-
Click the blue enable button and wait for the spinner to go away and the page to reload:
-
On the left side of the page, click OAuth consent screen:
-
Set User Type to Internal and click create:
-
Give your project a (user-facing) name, provide the required contact email addresses, and hit save and continue:
-
Click the add or remove scopes button:
-
Under Manually add scopes, enter
https://www.googleapis.com/auth/drive
, click add to table, then click update: -
Click save and continue:
-
On the left side of the page, click Credentials:
-
At the top of the page, click create credentials and choose OAuth client ID:
-
Set Application type to Web application and give it a(n internal) name:
-
Under Authorized redirect URIs, click add URI:
-
Enter the domain name at which you will host your server and hit create:
-
Click the download JSON button in the resulting dialog, and save the file for later:
This section illustrates how to set up a hosted VM on Google Cloud, which is free in the short term under the service's trial. There is no technical reason this project has to be hosted on Google infrastructure. Skip this section if you already have a server or VM available.
-
From the Google Cloud console at console.cloud.google.com, click the activate button in the upper-right corner of the page and follow the resulting steps to start your free trial:
-
In the upper-left corner of the page, click Select a project or the name of the selected project:
-
In the upper-right corner of the resulting dialog, click new project:
-
Give your project a(n internal) name and hit create:
-
Once the Notifications panel shows a green check mark, click select project:
-
If no sidebar is open on the left side of the page, click the hamburger button in the upper left:
-
In the sidebar on the left, hover over VPC network and select IP addresses:
-
Click the reserve external static address button:
-
Give the IP address a name, set its Network Service Tier to Standard, and hit reserve:
-
Take note of the IP address on the resulting page, as you will need it later:
-
In the sidebar on the left, hover over Compute Engine and select VM instances under virtual machines:
-
Click the blue enable button and wait for the spinner to go away and the page to reload:
-
At the top of the page, click create instance:
-
Select a name and region, and leave the default Debian boot disk image selected:
-
Under Firewall, check both Allow HTTP traffic and Allow HTTPS traffic:
-
Expand networking, disks, security, management, sole-tenancy, expand Networking, then expand default under Network interfaces:
-
Set External IPv4 address to the one you created above and hit done:
-
At the bottom of the page, hit the create button:
-
On the resulting page, wait for the Status spinner to turn into a green check mark, then click the SSH button:
Follow these steps to launch this project. They assume you are sitting at a shell prompt on the server or VM on which you want to host your instance. If the domain you used as the authorized redirect URI when registering the OAuth application does not yet point to the server or VM, first configure your domain's nameserver to serve an A record (and/or AAAA record, if applicable) mapping that domain to the server or VM's IP address.
-
Run the command:
$ unshare --version
If the current version number is less than 2.38, upgrade the distribution to a newer version if possible. For instance, in the case of Debian, you should be running bookworm or later. To upgrade from bullseye:
$ sudo sed -i s/bullseye/bookworm/g /etc/apt/sources.list $ sudo apt update $ sudo apt dist-upgrade $ sudo apt autoremove --purge $ sudo reboot
If you have an old version of the command but upgrading your distribution is infeasible, instead run the following additional commands, verifying that the version number printed by the last line is now 2.38:
$ sudo apt install binutils uidmap $ curl -o util-linux-2.38-2_amd64.deb http://snapshot.debian.org/archive/debian/20220413T031740Z/pool/main/u/util-linux/util-linux_2.38-2_amd64.deb $ ar x util-linux-2.38-2_amd64.deb data.tar.xz $ tar xf data.tar.xz ./usr/bin/unshare $ curl -o libc6_2.33-1_amd64.deb http://snapshot.debian.org/archive/debian/20211212T154235Z/pool/main/g/glibc/libc6_2.33-1_amd64.deb $ ar x libc6_2.33-1_amd64.deb data.tar.xz $ tar xf data.tar.xz ./lib/x86_64-linux-gnu/ld-2.33.so ./lib/x86_64-linux-gnu/libc.so.6 ./lib/x86_64-linux-gnu/libc-2.33.so ./lib/x86_64-linux-gnu/libnss_files.so.2 ./lib/x86_64-linux-gnu/libnss_files-2.33.so $ rm data.tar.xz $ cat >unshare <<-tac #!/bin/sh mypath="\`realpath "\$0"\`" mydir="\`dirname "\$mypath"\`" exec "\$mydir/lib/x86_64-linux-gnu/ld-2.33.so" --library-path "\$mydir/lib/x86_64-linux-gnu" "\$mydir/usr/bin/unshare" "\$@" tac $ chmod +x unshare $ sudo ln -s "$PWD/unshare" /usr/local/bin $ `which unshare` --version
-
Run the command:
$ sudo apt install python3-certbot-apache
-
Run the command:
$ sudo certbot --apache
-
Answer the configuration prompts and wait for verification to complete. (Note that this requires HTTP to be allowed through any firewall(s) in addition to HTTPS.)
-
Run the command:
$ sudo cp /etc/apache2/sites-available/000-default-le-ssl.conf /etc/apache2/sites-available/openvscode-gdrive.conf
-
Edit the
openvscode-gdrive.conf
file, replacing theDocumentRoot
line with the following:ProxyPass / http://localhost:8000/ ProxyPassReverse / http://localhost:8000/ RewriteEngine on RewriteCond %{HTTP:Upgrade} websocket [NC] RewriteCond %{HTTP:Connection} upgrade [NC] RewriteRule ^/?(.*) "ws://localhost:8000/$1" [P,L]
-
Run the command:
$ sudo a2dissite 000-default 000-default-le-ssl
-
Run the command:
$ sudo a2enmod proxy_http proxy_wstunnel
-
Run the command:
$ sudo a2ensite openvscode-gdrive
-
Run the command:
$ sudo systemctl restart apache2
-
Run the command:
$ sudo apt install unzip
-
Follow the Deno installation instructions at deno.land, being sure to use a version no older than 1.21.0.
-
Run the command:
$ sudo apt install git
-
Use
git clone
to clone this repository, thencd
into the resulting directory. -
Run the command:
$ ./deps.ts
-
Answer each of the configuration prompts or hit enter to select its default. If you want support for GUI applications, be sure to answer
y
at the appropriate time. -
Upload the JSON file you downloaded when registering the OAuth application and rename it to
config.json
. -
Run the command:
$ sudo apt install uidmap fuse3
-
Try running the command:
$ unshare --map-auto whoami
It should output
nobody
. If it instead tells you that youdon't exist
, you are hitting a util-linux bug that manifests when your user ID does not match your primary group ID. You may be able to work around this by changing your primary group:$ sudo usermod -g `id -u` `whoami` $ logout
-
If you do not want your instance to support GUI applications, skip this step. Otherwise, run the command:
$ sudo apt install xkb-data x11-xkb-utils x11-xserver-utils
-
Run the command:
$ ./main.ts
The easiest way to start a server process that survives the end of your login session is to use
bash
's disown
builtin:
$ ./main.ts >>disown.log 2>&1 &
$ disown %1
Alternatively, you can run the server from within a terminal multiplexer such as screen
or tmux
.
Note that disowning via nohup
currently breaks garbage collection of stale sessions, thereby
causing major resource leaks for instances shared by many users.