VSCode Remote Development with VirtualBox

Alvin Lucillo
Nullify
Published in
8 min readJul 26, 2022

--

If you’re using the same laptop for work and personal projects, you might have already encountered some conflicts if the projects use the same tools, frameworks, and workspace. For example, if your development environment uses Docker and Kubernetes, things can get messy when you switch from work to personal workspace and vice versa. I, too, had the same struggle, and I addressed it with VirtualBox using “headless” virtual machines (VMs). That’s right, you can work directly from VSCode with the entire VSCode extensions, environment variables, toolings, and what have you inside another virtual machine that is hidden (yes, you can just connect to it via VS Code or any terminal, so you just deal with it via commands).

In this article, we will use an existing MERN project with K8S and Docker. You can just follow along, but if you’re interested in the specifics of that project, find more here: MERN in K8S

We will cover the following in this article:

  1. Configuring the VM with Ubuntu 22.04 live server
  2. Accessing the VM from VSCode from the host machine
  3. Setting up the existing project
  4. Accessing the app outside the VM

Before anything else, let’s be clear about some terminologies I used throughout this article:

  • VM — Virtual machine
  • Host machine — where VirtualBox is installed and where we access the VMs; VMs sit on top of the host machine
  • K8S — Shorthand for Kubernetes, an orchestrating tool for containers
  • Reverse proxy — forwards incoming requests to another server or application

In addition, I am using Ubuntu on my host machine. If I provided commands for Ubuntu and you’re using Windows, you may want to search for the commands applicable for it. If you’re using Mac, I believe you’re fine.

Download the following before you begin:

  • Ubuntu Server 22.04 (I didn’t use the Desktop version as I only intend to interact with the server via terminal)
  • Download then install
    VirtualBox for creating VMs
    Remote SSH (by Microsoft) VS Code Extension

1. Configuring a new VM with Ubuntu 22.04 live server

  • Open VirtualBox and click Machine>New
  • Enter any name to identify your VM, choose Type: ‘Linux’, and Version: ‘Ubuntu (64-bit)’
  • Select memory size; 8000 MB is fine (~8 GB)
  • Choose ‘Create a virtual hard disk’
  • Choose ‘VDI (VirtualBox Disk Image)’
  • Choose ‘Dynamically allocated’
  • Select disk size; 50GB is fine
  • You will see your new VM on the left side; instead of starting and stopping your VMs via GUI, I will encourage you to use these commands:
    VBoxManage startvm “Ubuntu” — type headless-starts your VM in headless mode (no GUI)
    VBoxManage controlvm “name of your VM” poweroff-stops your VM
  • Start your VM with the command above. You’ll see something like: VM “Ubuntu” has been successfully started.
  • For now, let’s use a VM window to set the server. After the initial setup, you won’t need to do this again. Click your VM on the list of VMs and click ‘Show’ on the menu (the one with the green right arrow icon). You will see a window pop up.
  • Select Ubuntu 22.04 ISO file you downloaded earlier. This step mounts the ISO file as the first boot device, so you can install it. If this doesn’t work, close the window and select ‘Power off the machine’. Right-click your VM from the list, click Settings, go to the System tab, go to the Motherboard tab, and ensure that Optical is the first in the Boot Order list (you can use the arrow up button). After that, click the Start icon (with the green right arrow icon)
  • Select “Try or Install Ubuntu”
  • Select the language of your choice (note it may take a while before you get here; some lines get printed out)
  • Select ‘Update to the new installer’
  • Select the keyboard layout
  • Select ‘Ubuntu Server’ because we’re logging on to the server (as opposed to minimized Ubuntu Server)
  • For network connections, proceed with the default values.
  • For proxy, leave it blank.
  • For the Ubuntu archive mirror, proceed with the default values.
  • Select ‘Use an entire disk’
  • For storage configuration, proceed with the default values.
  • Select ‘Continue’ to confirm the installation on the disk; it says ‘Confirm destructive action’ but that’s fine because we’re only using a virtual disk
  • Fill out your machine name, username, and password
  • Select ‘Install OpenSSH server’ — this will help us connect VSCode from your host machine
  • Once you see ‘Install complete!’, select ‘Reboot Now’. If it is stuck in reading the CD drive, just close the window and select ‘Power off the machine’
  • Enter your username and password to log in
  • You should see your VM like this after a successful login:
  • Power off your VM then right-click on your VM, go to the Network tab, select Adapter 1 tab, then choose ‘Bridged Adapter’ for the Attached to. This setting allows your VM to have its own IP address as if it’s also connected to your network like a physical machine. Afterward, start the VM.
  • Retrieve the IP address of your VM by running ifconfig -a inside the VM. It’s the beside inet like inet 192.168.0.1. If the command doesn’t display anything, install THE network tools: sudo apt install net-tools
  • Try to log in to your VM from your host machine by typing: ssh username@ipaddress where username is your VM’s username and ipaddress is the IP address retrieved from the previous step. If prompted about proceeding to connect (this is for first-time SSH only), provide ‘yes’. If prompted for the password, type it in. If you see something like ‘Welcome to Ubuntu 22.04,’ then you have successfully remotely logged in to your VM.

2. Accessing the VM from VS Code from your host machine

  • From the last step, we can log in using a password, but we don’t want to log in with a password every time when connecting from VS Code, that is why we will need to generate the public and private keys. The keys will be used to identify the host machine and let it access your VM.
  • Generate the public and private keys by typing in ssh-keygen on your host machine’s terminal. Usually, the keys are placed in ~/.sshdirectory. For Windows users, search for the counterpart command. More on that here.
  • On your VS Code, look for the green box on the lower-left corner, which shows ‘Open a Remote Window’ when you hover your mouse cursor over it. Click it, then select ‘Open SSH Configuration File’. You can also get here via CTRL+SHIFT+P then type in ‘Remote-SSH’. It will show you a config file. Use the contents below for that config file. Host can be any value that identifies your VM. HostName is the IP address of your VM. User is the username you use to log in to the VM. IdentifyFile is the private key file generated from the previous step.
    Host ubuntu-vm
    HostName 192.168.0.1
    User ubuntu
    IdentityFile ~/.ssh/id_rsa
  • Click again the green box on the lower-left corner and select ‘Connect to host’. Select the host (e.g., ubuntu-vm from the config above). If prompted for the password, enter it. After that, Remote-SSH is setting up your VM, so you might see ‘Setting up SSH Host ubuntu-vm’ notification on the lower-right corner. You’ll know it’s done if you see your host(e.g., SSH: ubuntu-vm) on the lower-left corner.
  • Using your VS Code connected to your VM, open the authorized_keys file (see sample directory below from my VM) and fill it with the public key file’s contents from the previous step (it’s the one that has the same name as your IdentifyFile from the config file from the previous step but with .pub file extension)
    /home/ubuntu/.ssh/authorized_keys
  • Close your VS Code window then open the host again. It should no longer ask for the password. This is because you let your VM know that you allow any SSH into your VM by adding your host machine’s public key to the authorized_keys of your VM, which is a security mechanism to protect unauthorized access. Now, let’s start with setting up an existing project.

3. Setting up the existing project

  • The existing project requires you to install minikube, which requires at least 2 processors. To ensure this is set on your VM, go to the Settings of your VM, select System, go to the Processor tab, then set Processors to 2. Power off your VM if this setting is disabled.
  • Now that we have set up the headless VM, you don’t need to start it via VirtualBox. You can just power it off and on using these commands:
    VBoxManage startvm “Ubuntu” — type headless
    VBoxManage controlvm “Ubuntu” poweroff
  • After starting your VM, you can log in to it viassh ubuntu@192.168.0.31
  • If you see something like ‘remote refused’ when you try to ssh to it the VM after powering it on, wait for a few seconds; the server is just starting up.
  • Go to this repo https://github.com/alvinlucillo/k8s-todo. This is the existing project. It uses Kubernetes and Docker.
  • Install the required tools from the repo and the setup steps just until you can see the Kubernetes services are ‘Running’ via kubectl get all

4. Accessing the app outside the VM

  • So you have set up your VM that you can power on and off via commands using VS Code, and you can interact with it using VS Code too. You also got the existing project running — at least its Kubernetes resources. Nothing’s stopping you now, but hold on. How are you going to access the app outside the VM? If you read my previous article, the app is accessible via the cluster’s IP, which is minikube’s IP. But how are you going to reach the cluster IP inside the VM by using the VM’s IP? This is where reverse proxy comes in. We will use nginx for reverse proxy.
  • Essentially, when we hit the VM’s IP address using a web browser, we are sending HTTP requests to that server. The server doesn’t know what to do with it, so your web browser will probably show you ‘the site can’t be reached.’ Usually, when an HTTP request hits a server, it uses port 80 then returns a response.
  • To receive that HTTP request, let’s install nginx: sudo apt install nginx
  • Try to hit your VM’s IP address via a web browser, and you’ll see something like this: “Welcome to nginx!”
  • Now, let’s ensure that our request gets to the minikube cluster.
  • Unlink existing symbolic file for default: sudo unlink /etc/nginx/sites-enabled/default
  • Create a new file: sudo nano /etc/nginx/sites-available/reverse_proxy_todo
  • Paste the following to that new file:
    server {
    listen 80;
    server_name localhost;
    location / {
    proxy_pass http://192.168.49.2;
    }
    }
  • The IP address is the minikube cluster’s IP address. Retrieve it via: minikube ip
  • Create a new symbolic file (i.e., shortcut) for that new file you created: sudo ln -s /etc/nginx/sites-available/reverse_proxy_todo /etc/nginx/sites-enabled/reverse_proxy_todo
  • Restart nginx: sudo systemctl reload nginx
  • Hit the VM’s IP address again on your host machine’s web browser

--

--

Alvin Lucillo
Nullify

Software engineer, writer, self-taught pianist, and a lifelong learner