New
Discover how Dropbox streamlined dev environments & cut costs by switching 1000 developers to Coder

Read the success story

Connect to a remote server with VS Code

author avatar
Ben Potter
 on September 15th, 2021

Historically, using a development environment across multiple devices would mean compromises on speed, access, or device options. With VS Code however, developing from any device is much more approachable.

  • VS Code (Remote SSH): Use VS Code to connect and develop on a remote machine
  • code-server: Access VS Code from the web browser, runs on a remote machine

Both of these tools have their advantages and disadvantages. For most of my projects, I develop remotely on cloud servers. With other projects (e.g iOS development), I use my local machine but use tunnels to connect to it from any device.

Here's my workflow:

  • I use VS Code (Remote SSH) for near-local experience
  • I use code-server to connect from unfamiliar devices (e.g Grandma’s computer) or “light” devices such as an iPad or Chromebook
  • I also use VS Code on my MacBook and open it up with code-server --link

Installing code-server

code-server is an open source project that hosts VS Code in the web browser. It can be installed on a remote server or locally (to make your local environment remote).

Use code-server’s install script:

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

# install:
curl -fsSL https://code-server.dev/install.sh | sh

Run as a Docker container:

# note: running code-server as a Docker container
# will not expose your local projects and settings.
#
# to persist any dependencies installed use a custom image,
# mount volumes, or add them to the home directory

mkdir code-server && cd code-server
docker run -it --name code-server -p 127.0.0.1:8080:8080 \
  -v "$PWD:/home/coder" \
  -u "$(id -u):$(id -g)" \
  -e "DOCKER_USER=$USER" \
  codercom/code-server:latest

Other options in our docs: Installing code-server

Syncing code-server and VS Code settings (optional)

You can also configure code-server to use the same settings and extensions as VS Code.

# on the machine/container with code-server installed:
vim $HOME/.config/code-server/config.yaml

Add the VS Code directories. On OSX, they are:

# config.yaml

user-data-dir: "/Users/username/Library/Application Support/Code"
extensions-dir: "/Users/username/.vscode/extensions"

Connect to a remote server

Once you have code-server and/or VS Code Remote installed, it’s time to make them accessible remotely. Normally, this would require either port forwarding, configuring firewalls, or a VPN,

Option 1: code-server —link

If you’ll only be connecting remotely from the web browser, you can use the code-server --link flag to get a public tunneled URL. Instead of authenticating with a password, you’ll be prompted to log in with GitHub. Future logins with the tunneled URL will verify your GitHub account.

You can also add link: true to code-server’s config.yaml to launch with —link by default.

Secure tunnel, domain, and TLS with code-server --link

Note: code-server —link will not proxy your SSH server. Other options, such as inlets can do this for you.

Option 2: Self-host a tunnel with inlets PRO (code-server and SSH)

Inlets PRO is a self-hosted tunneling software with abstractions that makes it simple to expose local services to the internet. Inlets is not free, so you’ll need a license for inlets PRO. Their personal plan is $22.50/mo. Since this is also a self-hosted solution, you’ll need access to a remote server and a domain name.

Alex Ellis, the founder of Inlets (and OpenFaaS), and I connected and he provided some excellent support when preparing this guide. Inlets offers a lot of flexibility when it comes to self-hosting tunnels, but also has the inletsctl tool to get up and running quickly!

Installing inlets-pro

If you already have a server, you can use the inlets documentation to install & configure inlets-pro. In this example, I use inletsctl to deploy an “exit” server that will cost roughly $5/mo on DigitalOcean. The inlets docs has examples for different providers that work great, just be sure to include the LetsEncrypt flags.

inletsctl create --provider digitalocean \
 --access-token DIGITALOCEAN_ACCESS_TOKEN \
 --region nyc1 \
 --letsencrypt-domain code.bpmct.net \
 --letsencrypt-email [email protected] \
 --letsencrypt-issuer prod

Be sure to replace the domain, email, and optionally the region. Also include a DigitalOcean access token from your account.

After the server is created, inletsctl will return the server’s IP address. Add a DNS A record for your custom domain to the IP. Inlets will also give an example command on how to start a tunnel. Change the —upstream flag to the where code-server is hosted (usually 127.0.0.1:8080). Also, this is where you add your inlets license.

inlets-pro http client --url "wss://[server IP]:8123" \
  --upstream "code.bpmct.net=http://127.0.0.1:8080" \

Starting HTTP client. Version 0.8.6 - 18d8e239f940d8694532e332867c25f823439cc6
Licensed to: Ben Potter <********>
Upstream:  => http://127.0.0.1:8080
Connecting to proxy
Connection established.. OK.

# access at https://code.bpmct.net


# if you're on Linux, you can generate a systemd service file
inlets-pro http client generate=systemd

After that, you’ll be able to access your secure tunnel via your domain.

Self-hosted inlets tunnel with code-server's authentication

Tunneling a SSH server with inlets is also possible. To do this, we’ll need to log in to the exit server (the one we created with inletsctl) and run a second instance of inlets in TCP mode. We’ll also need to edit our local machine’s SSH settings so that it can listen on another port (since the exit server already uses port 22).

# add additional local SSH port (2222)
# add a line: "Port 2222"
sudo vi /etc/ssh/sshd_config

# ssh into the exit server (DigitalOcean emails the root password)
ssh root@[SERVER_IP]

# run a TCP exit server as well
inlets-pro tcp server \
 --auto-tls \
 --auto-tls-san=[DOMAIN_NAME] \
 --control-port 8124 \
 --auto-tls-path=/tmp/tcp_certs/

# generate systemd service to keep TCP server running
inlets-pro tcp server --generate=systemd --auto-tls \
 --auto-tls-san=[DOMAIN_NAME] \
 --control-port 8124 \
 --auto-tls-path=/tmp/tcp_certs/

# create the service (ensure it has the proper flags)
sudo vim /etc/systemd/system/inlets-pro-tcp.service

# run the service on start, and start it up now
systemctl enable --now inlets-pro-tcp

# go back to our local machine
exit

# tunnel SSH as well
inlets-pro tcp client \
 --url "wss://[DOMAIN_NAME]:8124" \
 --upstream "127.0.0.1" \
 --ports 2222

# now you can ssh from any device into your local machine
# ssh -p 2222 code.bpmct.net

Installing/enabling a SSH server

If you want to access your dev environment over VS Code Remote SSH, you’ll need an SSH server running on your machine. Most operating systems have a built-in -SSH server that just has to be enabled.

Looking forward

It’s clear there are a lot of options when it comes to developing in the cloud. Wherever you are developing (local machine, managed service, or private datacenter), developers can have smooth workflows without compromises.

I’m particularly interested in how we can enable these workflows while also reducing the setup/friction associated with developing on remote servers such as provisioning, managing access keys, or setting up tunnels. Here are a few things we’re exploring at Coder:

  • a single tunnel to a server for SSH and multiple IDEs (hint. JetBrains)
  • extension for tunneling ports inside code-server
  • 1-click provisioning and access for dev servers
  • dev teams using containers for their dev environments (local, remote, or hybrid)

Thoughts? We’d love to hear on Twitter or Slack.

Subscribe to our Newsletter

Want to stay up to date on all things Coder? Subscribe to our monthly newsletter and be the first to know when we release new things!