Written by

Have you ever dealt with a long term project, involv­ing the embed­ding of a lot of (cir­cu­lar) depen­den­cies, that ends up tak­ing a full day to install local­ly, only to debug a small fea­ture? Of course you have! We all know the awk­ward sit­u­a­tion when you delay start­ing the debug­ging ses­sion sim­ply because you don’t want to run it local­ly.

Well, here’s the good news: you don’t have to do that. Thanks to remote debug­ging, you can run your envi­ron­ment on your stag­ing servers 1) and work on it from your IDE! Let’s look at how.

Web Development ecosys­tems have evolved a lot over the last few years. Not only frame­works and tool­ing, but often whole envi­ron­ments. The most vis­i­ble change over the last 4 years has been the mas­sive adop­tion of VSCode as the main IDE used by most of Web Developers. Using Electron, based on JavaScript, sus­tained by Microsoft Open Source teams, with improved sta­bil­i­ty and a real per­for­mance peak, and backed by a large com­mu­ni­ty pro­vid­ing a lot of exten­sions, it’s prob­a­bly the best bet for your day-to-day tool.

A real­ly cool tool pro­vid­ed by the Microsoft Dev team is a set of exten­sions allow­ing you to work on remote machines using var­i­ous pro­to­cols, like the ven­er­a­ble SSH! Thanks to our plat­form, which gives you SSH access by default, you can exploit these exten­sions eas­i­ly.

Start your engines! Here’s the com­plete guide!

Pre-requisites

First, you need VSCode (of course). Please note that the Remote Extensions can only work with the offi­cial release, not the OSS edi­tion as this uses non-free com­po­nents. Install this using your reg­u­lar pack­age man­ag­er (on Linux), or down­load the cor­rect ver­sion for your OS.

You also need to enable key-based SSH access on your always­da­ta account. You can refer to the offi­cial doc­u­men­ta­tion on Using SSH Keys if you’re not com­fort­able with the process.

We rec­om­mend you rely on the SSH con­fig file to declare your hosts, which will be eas­i­er to use inside VSCode. On your local machine, cre­ate a $HOME/.ssh/config file with the fol­low­ing con­tent:


Replace the [ad-account] with your alwaysdata’s account name, and set the path to your SSH pri­vate key accord­ing to your local set­up.

On Windows, you may have to refer to this config file in the exten­sion set­up.

Ensure your SSH con­nec­tion is ready by run­ning $ ssh alwaysdata in your ter­mi­nal. If you’re logged onto alwaysdata’s servers, you’re ready!

On the Server From Your Couch

Launch VSCode and go to the Extensions Panel (Ctrl+Shift+X) and install the Remote — SSH and Remote — SSH: Editing Configuration Files.

Now, using the Remote Explorer Panel, or the Command Palette > Remote-SSH: Connect to Host… (F1), acti­vate the con­nec­tion to the alwaysdata host. After a while 2), you will be con­nect­ed to the remote always­da­ta serv­er. You can see it in the Status Bar with the green noti­fi­ca­tion SSH: alwaysdata. Let’s do a test and try to File > Open… a file or fold­er: your Palette explor­er should now dis­play your remote envi­ron­ment! You can also see that the con­sole (Ctrl+`) is set to your remote envi­ron­ment too.

Congratulations! You’re now remote­ly work­ing from your local IDE to your remote always­da­ta account, with­out any dif­fer­ences! Now begins the real jour­ney on How to Remotely Full-Stack Debugging Your App.


A quick note before div­ing in: when you’re work­ing remote­ly on our servers with the Remote — SSH Extension, VSCode con­sid­ers the remote fold­er you’ve opened as the cur­rent work­space (as it does with local projects). In order to do this, it saves its con­fig files in the usu­al .vscode hid­den direc­to­ry at the root of your remote project. We real­ly rec­om­mend ignor­ing this fold­er in your ver­sion­ing tool (like .gitignore) and not remov­ing it from your remote envi­ron­ment.

In this guide, when we refer to some set­tings, they’re work­space relat­ed, so are saved in this remote fold­er. Thanks to VSCode inter­nals, the Remote Explorer Panel mem­o­rizes your remote work­spaces, allow­ing you to reopen them quick­ly when you wish to start a new remote debug­ging ses­sion.


JavaScript: One Language to Rule Them All

To illus­trate this guide, we choose to focus on one lan­guage for both the back­end and fron­tend. This is for exam­ple pur­pos­es only, and you can work on any kind of archi­tec­ture you want. Just install the right debug­ger in VSCode, and you’ll be fine. Keep in mind that always­da­ta sup­ports any kind of lan­guage you want, so feel free to pick the best choice for your needs!

Thanks to our mar­ket­place, you can deploy a boil­er­plate of a large range of back­end Web frame­works right from your account. In your admin­is­tra­tion pan­el, go to the Web > Sites sec­tion, click the Install an appli­ca­tion but­ton, pick up Express.js by click­ing the gear wheel, and fol­low the installer instruc­tions.

Now you have an Express.js app! Click on your URL to open a new win­dow point­ing to your brand new site, you should see the famous Hello World! wel­come mes­sage! Now let’s work on it from our local IDE.

A first thing to notice is how the same code­base will be used in dif­fer­ent con­texts: devel­op­ment and pro­duc­tion. The site you’ve just accessed is a pro­duc­tion ver­sion. We will work on the same code­base but run it from the SSH access, in devel­op­ment mode. This means every change we’ll make won’t be up on the pro­duc­tion ver­sion until you restart your site from your admin­is­tra­tion pan­el.

This dif­fer­ence pro­duc­tion vs devel­op­ment is only valid for per­sis­tent process lan­guages, like Node.js, Python, Ruby… Transient state lan­guages, like PHP, are sys­tem­at­i­cal­ly re-run on every request, so your changes will be applied imme­di­ate­ly, with­out the need to restart your site.

In VSCode, open your remote work­space by acti­vat­ing the alwaysdata con­nec­tion and open the fold­er just cre­at­ed by the mar­ket­place installer. You’re ready to dev!

To be able to run our app in devel­op­ment mode, let’s first add a debug run­ner. Open the package.json file and add a debug script:


As our app expects the PORT envi­ron­ment vari­able to know which port to lis­ten to, let’s try run­ning it from the VSCode inte­grat­ed ter­mi­nal: PORT=3000 npm run debug. You should see a mes­sage that your app is ready. But you can’t access the remote port from your local machine!

Fortunately, VSCode Remote Extension allows you to declare local port to for­ward 3) to your remote envi­ron­ment. In the Remote Explorer Panel, add a new port to the Forwarded Ports sec­tion. Enter 3000. Now, you should be able to point your brows­er to http://localhost:3000, and access your remote app in debug mode!

To avoid enter­ing the for­ward­ed ports each time you start a ses­sion, in the local users’ pref­er­ences, tick the Remote: Restore Forwarded Ports option (or enter "remote.restoreForwardedPorts": true into your local User/settings.json file).

Fine, we’re now able to run our app from VSCode and access it local­ly through for­ward­ed ports. Now let’s see how to real­ly work and debug it!

Run, Fail, Then Run Again

See Behind the Code

Let’s run our app attached to the VSCode debug­ger. It allows you to set break­points, and inspect your call stack, even remote­ly! Install the Debugger for Chrome exten­sion. We will also edit our debug script to run it with inspect mode enabled:


We run the inspec­tor on an uncom­mon port to avoid any con­flicts, espe­cial­ly with the final part of this guide. Feel free to ignore it right now how­ev­er.

Now we need a debug task that will run our app and attach the debug­ger to it. Go to the Run and Debug Panel (Ctrl+Shift+D). The pan­el is actu­al­ly emp­ty. Click the cre­ate a launch.json link, and select Node.js in the opened Palette. The action will cre­ate a new .vscode/launch.json file in your remote envi­ron­ment (you can see it from your Explorer Panel). Fill it with the fol­low­ing con­fig­u­ra­tion:


Here are some inter­est­ing set­tings:

  • runtimeExecutable: we run the app through npm
  • runtimeArgs: here’s our debug script; we also add the script-prepend-node-path to avoid warn­ings due to the node bina­ry path in the filesys­tem, which is spe­cif­ic to the always­da­ta archi­tec­ture
  • port: the port we pre­vi­ous­ly choose to attach our node’s inspec­tor to
  • env: the expect­ed envi­ron­ment vari­ables, here the port the Express.js app want to lis­ten to

We’re now ready to run our app with the debug­ger. Launch the Debugger with the green arrow in the Run Panel (or hit F5). Your npm debug script is run by VSCode, and you can still access your app in your brows­er.

Now open the app.js file, and put a break­point on the res.send line (6) by click­ing the gut­ter (or hit F9 when high­light­ing the line). Reload your brows­er. Your app should pause just before exe­cut­ing the res.send instruc­tion and you can ana­lyze and debug your app from the Run and Debug Panel!

Lazy Times for Overbooked Developers

Sadly, hav­ing to re-run your app each time you edit the files is more than a bit tedious. Let’s con­fig­ure hot reload­ing on the serv­er-side:

  1. Install Nodemon on your project from the inte­grat­ed ter­mi­nal: npm install --save-dev nodemon
  2. Edit the debug script in the package.json file to run the app with nodemon: NODE_ENV=development nodemon --inspect=9321 --exitcrash app.js
  3. Edit the debug­ger con­fig­u­ra­tion in the launch.json file by adding the "restart": true option, allow­ing the debug­ger to re-attach each time node­mon restarts the app

Now run the debug­ger con­fig­u­ra­tion again and reload your brows­er: you should be able to reach the app. Edit the Hello World! string and save the file. Your app is auto­mat­i­cal­ly reloaded and the debug­ger re-attached. Reload your brows­er: you’ve got the new mes­sage!

As devel­op­ers, we’re often lazy: let’s con­fig­ure the brows­er to reload itself when the serv­er app is reloaded too:

  1. Install livere­load in your project: npm install --save-dev livereload connect-livereload
  2. The livere­load injec­tor needs you to serve a valid HTML page to be able to inject the livere­load script. Let’s add Pug as a tem­plate engine, and Helmet to man­age secu­ri­ty head­ers for our served pages: npm install --save pug helmet
  3. Configure your app to ren­der Pug tem­plates, and enable LiveReload in devel­op­ment mode:
  4. Create a views/index.pug file at the root of your project:
  5. In the Remote Explorer Panel > Forwarded Ports Section, add a new port to for­ward: 35729, allow­ing your brows­er to access the livere­load serv­er.

Now run the debug­ger con­fig­u­ra­tion again. Reload your brows­er, it should enable the LiveReload mode (vis­i­ble as a WebSocket request in the Network Panel). Edit the mes­sage sent to the tem­plate. At the save, the app will be restart­ed, the debug­ger reat­tached to it, and your brows­er reloaded with­out any actions from your side!

Debugger on Every Floor

All in One

VSCode offers a large choice of exten­sions, giv­ing you a ful­ly inte­grat­ed expe­ri­ence. So why not run and con­trol our test­ing brows­er from our IDE direct­ly? It’s time to install the Browser pre­view Extension.

Let’s cre­ate a debug­ger con­fig­u­ra­tion ready to run the Browser Preview. In your launch.json file, add a new con­fig­u­ra­tion after the Server Debug Mode one:


Obviously run­ning the Browser Preview with­out run­ning the app in the back­ground is per­fect­ly use­less. So let’s cre­ate a Compound that will run both from our debug­ger. Still in the launch.json file, add a compounds entry right after the configurations one:


Now in your Run and Debug Panel, select the Client/Server con­fig­u­ra­tion, and run it. Your app is start­ed in devel­op­ment mode with Nodemon and attached to the debug­ger, and a Browser Preview Panel should open, point­ing to the app address 4).

Run, Forest!

We’ve got a Browser Preview, attached to the inter­nal debug­ger. Let’s see what we can do with it!

  1. Create a static/js/main.js file at your project root lev­el, with the fol­low­ing con­tent:
  2. Update our index.pug, load a main.js script into the page:
  3. Now edit our app.js to serve sta­t­ic files:

If you run the app right now, you should be able to click on the title and see the alert box pop­ping in the VSCode noti­fi­ca­tions. But you can’t access the files in the debug­ger, because it needs to be aware of the loca­tion of the files.

Edit the Browser Preview: Launch Configuration in launch.json file and add the map­ping to the files:


Now run the debug­ger task again. Add a break­point in the main.js file. Click the title. Your script is paused and you can inspect the call stack from the inte­grat­ed debug­ger inspec­tor!

Let’s fin­ish by enabling live reload­ing of fron­tend assets too. Update the app.js file by adding the LiveReload watch instruc­tion after cre­at­ing the livereloadServer:


You can now edit the main.js file and have your brows­er reloaded auto­mat­i­cal­ly!


This was a long jour­ney and a long arti­cle just to give you some of the basics of Full-Stack Remote Debugging. What’s incred­i­bly use­ful is the pos­si­bil­i­ty of keep­ing your code­base in your always­da­ta account, free­ing your local envi­ron­ment of the com­plex stack to main­tain.

You can run your code remote­ly in devel­op­ment mode, attach the back­end to the local debug­ger, run your Web app in a Browser con­tain­er, and run a sec­ond debug­ger in par­al­lel, attached to this pre­view!

This gives you the abil­i­ty to test and debug in a pro­duc­tion-like envi­ron­ment with all the mod­ern tool­ing you may expect. Even more fun: when your debug­ging ses­sion is done, you just have to restart your Site from your always­da­ta admin­is­tra­tion pan­el and your changes are online!

As pre­vi­ous­ly men­tioned, thanks to the VSCode ecosys­tem, debug­gers are avail­able for many mod­ern back­end lan­guages like Python, Ruby, PHP, and more. No need to stick to JS, you can use this guide with any kind of lan­guage you host on your account.

We hope this will help you to improve your dai­ly work­flow. Want to know more about advanced use-cas­es of your always­da­ta account? Let us know in com­ments about how we can help you reach new lev­els in your every­day tasks!

Notes   [ + ]

1. Maybe pro­vi­sioned by your team­mates DevOps
2. During which VSCode installs the need­ed com­po­nents remote­ly and starts a remote devel­op­ment serv­er in the back­ground.
3. SCode relies on Port Forwarding and needs the SSH Server to have AllowTCPForwarding enabled. We at always­da­ta dis­able this for secu­ri­ty rea­sons, but we’ve for­tu­nate­ly found a way to run VSCode Port Forwarding with­out com­pro­mis­ing secu­ri­ty issues!
4. Due to the way com­pounds are run, the Browser Preview may point to about:blank page instead of http://localhost:3000. There’s a workaround relat­ed to the abil­i­ty to run pre-tasks (see the issue). While wait­ing for the fix, you can man­u­al­ly update the address to load your app in the Preview Panel.