Online VS Code for frontend and backend development

A guide about setting up a remote programming environment with all the pros of VS Code and multi-user support. Works on Chromebooks!

In this article, I’ll cover how to set up a remote coding environment using code-server. If you want the tutorial, skip to Requirements.


I’m teaching a beginners class on programming based on my introduction to programming. The students all work on Chromebooks, a sad part of reality I had to work my way around. I recalled hearing about some project enabling VS Code in the cloud, which sounded perfect! After a bit of searching, I found this video from Fireship.

So, the restraints for this project was

After realizing these goals, I set out to a quest to use the newly implemented reverse-proxy in Kvarn as a HTTPS relay for code-server. Kvarn also hosts the user-friendly homepage.


This is designed to be a light-weight and performant package. I’ll use this for Rust development with Kvarn, with about 20 concurrent users, so I’m using a virtual machine with 6 threads (probably overkill) and 2 GB memory.

I also greatly recommend installing the Fish shell (Arch package) if you intend for any beginners to access the shell, since Fish’s autocompletion and ergonomics are very friendly (and also a very nice shell to work with compared to Bash).

User management

I had two options for Linux user management. If you have no interest in the motivations of my choices here, jump to Installation.

The first was to assign each remote user a local Linux user. This would imply creating several Linux users with their own home directory, each with a instance of code-server running, which means Kvarn would have to route to different ports depending on user. This has the advantage of sandboxed files, separate shells, and separate extensions. Though, a lot of configuration would have to be done to set all users’ passwords and shell.

The second alternative was to have all one one user. This only needed one code-server, reducing complexity. I also only needed to set up two users; one running Kvarn with privilege to run doas and the other running code-server and hosting all the users files.

I settled for the second option as the first didn’t offer many benefits but was a lot harder to set up and maintain.


First, set up a OS on the machine. I recommend Arch Linux as it’s stable yet cutting-edge and has the best wiki in Linux-land. See the installation guide for directions.

Install the linux-lts package for better stability.

During this installation, the user icelk will be running Kvarn and codeonline will be running code-server and owning the files. Naturally, you can change these names. To create these users run

# useradd icelk -m -G wheel
# useradd onlinecode -m -G wheel

Important: we need to create the doas configuration file so we can use root privilege (without the bloated sudo).

Create /etc/doas.conf with

permit nopass root

permit persist :wheel

Next, install all the needed packages. Here, the command for Arch is listed, but the packages should be available for your distro too. Run rustup as the user icelk.

Fish and NeoVim aren’t needed, but I strongly recommend Fish, as stated above, and NeoVim is very nice to edit in compared to vi. OpenSSH is needed for remote control. ufw and iptables-nft are needed for a firewall.

# pacman -Suy git ufw iptables-nft rustup opendoas fish neovim openssh
$ rustup default stable

Then, install code-server by running (to preview the install process) the following as onlinecode (doas -u onlinecode fish to get a shell as onlinecode)

$ curl -fsSL https://code-server.dev/install.sh | sh -s -- --dry-run

Then remove the -s -- --dry-run part to do the install.

Next, install my proxy server. Run as icelk.

$ git clone https://github.com/Icelk/code-server-proxy.git kvarn-proxy
$ cd kvarn-proxy
$ cargo build

Now, make sure you have your certificates in a safe place. I put them in /home/icelk/.private/.

Note: the certificate (or fullchain) must be named cert.pem and the private key pk.pem and be located in the current directory for my program to recognise them.

That’s all!


First, we need to configure code-server. To get the default configs, start and stop the included service.

# systemctl start code-server@onlinecode
# systemctl stop code-server@onlinecode

Then, change the following values in /home/onlinecode/.config/code-server/config.yml

password: <your password here>

doas should already be configured (and sudo removed from your system ;). So let’s discuss some options in the config! The nopass option is to enable root to execute programs as any other user in services. persist remembers the password you entered for about 5 minutes, just convenience.

You need to symlink /home/onlinecode/web/home/icelk/kvarn-proxy/web/ for Kvarn to find the homepage. The permissions are a bit of a problem. See the end of Security for more info. The ln -s command can be run as either icelk or onlinecode.

# chmod 755 /home/onlinecode/
$ ln -s /home/icelk/kvarn-proxy/web /home/onlinecode/

You might notice you can’t ls the contents of ~/web/ as onlinecode. This is OK, since it’s icelk running Kvarn who’ll be accessing the files.

Now when you create new folders for new users and in the online editor they have the permissions drwxr-xr-x, granting icelk access to read them. As Kvarn is ran as icelk and will try to access these files, this is crucial.

Now, let’s create a service for the Kvarn proxy you just built! With nvim /etc/systemd/system/code-server-proxy.service, enter

Description=Online coding environment

ExecStart=sh -c "cd /home/icelk/.private && bin=/home/icelk/kvarn-proxy/target/debug/code-server-proxy && setcap CAP_NET_BIND_SERVICE=+eip $bin && exec doas -u icelk $bin"


This makes sure we have network access before starting the service. The [Install] section makes it possible to automatically start the server at boot. The command run enters icelk’s private directory, where cert.pem and pk.pem should be stored (make sure to chmod 600 cert.pem pk.pem so only you have read access to them), then enables non-superusers to bind ports under 1024 with the program and lastly drops root privileges (by executing the binary as -u (user) icelk) and starts the Kvarn proxy.

Next, you need to port forward port 100. This varies wildly across routers, so fiddle around in your router’s interface or duck it.

To harden the system and to set up a UWF firewall, read the Security section below.


If you want extra security, a firewall is a good start. This will block all network access, both to the Internet and locally. UFW is simple and only requires a few commands to configure.

# ufw default deny outgoing
# ufw default deny incoming
# ufw allow 22
# ufw allow 100
# ufw allow out 53
# ufw enable
# systemctl enable ufw

Now only SSH access, the website at port 100, and DNS is allowed.

To upgrade the system or do anything else which requires network access, you need to enable outgoing HTTP traffic. doas ufw allow out 443 will allow outgoing HTTPS traffic, but no HTTP traffic. Outgoing port 80 can be used for that. After you are done with accessing the network, use doas ufw delete allow out 443 to disable outgoing HTTP traffic.

Tip: use doas ufw status to query the current firewall configuration.

Next, we’ll disable user onlinecodes permission to get superuser access through doas. This is very important if you chose a weak password for onlinecode. If you recall, we allowed all members of the wheel group to use doas. To remove onlinecode from the group wheel, type

# gpasswd -d onlinecode wheel

The permissions of /home/onlinecode/ are a bit wanky. All other users have read access to their files (but as the user will be exclusively used for untrusted remote users, this isn’t a problem). These files are needed for the files and homepage part of code-server-proxy. I’ve tried to keep the permissions as strict as possible for security, but it’s important for you to double check everything. Mainly that the onlinecode user does not have access to Kvarn’s certificates.

Please send an email to me if the permissions aren’t working for you so I can fix it in this article!

Running it

I’m glad you’ve come so far! To start the system now and on boot (swap enable --now with start if you don’t wait it to start on boot), run the following with superuser privileges

# systemctl enable --now code-server-proxy
# systemctl enable --now code-server@onlinecode

You are ready to go! Visit https://<your website>:100/ to view the homepage.

Each user gets their own directory in /home/onlinecode/<username>/, so get a shell as onlinecode (doas -u onlinecode fish) and mkdir for all the users. For example, mkdir bob frank bill.

Closing thoughts

I think the UI is quite good, simple but functional. Open an issue on GitHub or mail me if you have any ideas of improvement.

The Backend services section on the homepage enables users to connect to their server. See these lines for the implementation.

Stability - Kvarn giving bad gateway Regarding stability, Rust has served me well. The only problem is a 502 Bad Gateway error from Kvarn on the first load of online VS Code. It’ll maybe get resolved in the future with improvements to the reverse proxy of Kvarn.

My httPWM project has been running on a RaspberryPi more than a month now!

If you encounter any issues with this article, or any bug in my software, please email me so I can improve the experience for everybody. Please help if you encounter any bugs!

If you found this article helpful, consider sharing this site to your friends and family. It helps a ton in SEO and for my motivation to continue.

And, lastly, thanks to you for reading this!

Last edited at Mon, 2022-03-28, 14:59 +00:00.