Improve this doc
Getting Started with and

Looking for other boards documentation? Click here.

Getting Started With Intel NUC and Node.js

Introduction

In this guide we will build a simple Node.js web server project on a Intel NUC. Along the way you will learn the basics of resin.io. We will walk through getting a Intel NUC online and deploying some Node.js code to it.

We will also look into using the built in web terminal to run test commands and debug issues. Once you have a handle on the resin.io deployment workflow, we will introduce you to resin sync and our CLI which will allow you to increase your development speed on resin.io.

What You Will Need

  • An Intel NUC mini PC from Intel.
  • A 4GB or larger USB thumb drive.
  • A HDMI enabled LCD screen and HDMI cable.
  • A simple USB keyboard.
  • A power supply unit for the NUC.
  • An ethernet cable or WiFi adapter to connect your device to the internet.
  • A resin.io account.

Getting Help

Before we get started building something cool, lets just point out some places to get help. If at anytime while using resin.io you find yourself stuck, confused or alone remember that there is a team of helpful and friendly support engineers just one click away.

The best place to chat with us is in the resin.io forums. Post your questions to the Troubleshooting section, where our engineers can help address any issues you may be having with resin.io.

We also love to meet users in our community chat at gitter.im.

Read more about our approach to support at resin.io/support(https://resin.io/support).

To help us understand all the moving parts in resin.io, lets first define a few terms that will be used later in the guide.

  • Application:

    This is a group of devices or "fleet" that will all run the same application code. When you provision a device, it will automatically be associated to the application. You can add as many devices to an application as you like, its also possible to migrate devices to other applications.

  • resin remote:

    A remote git repository that is associated to your application. Any code pushed to the master branch of this repo will be built and deployed as a container on all devices in the application. This git repo uses SSH keys to secure it, so don't forget to set up your SSH key.

  • Container:

    A Docker container that essentially is a bundle of your application code and all its dependencies. It runs as an isolated process in userspace on the resinOS host.

Let's Jump In

If you don't already have a resin.io account head over to our signup page, during the sign up process you will be asked to set up an SSH key so you can securely push code.

Adding an SSH Key

SSH keys use the power of public-key cryptography to secure your connection when sending your code to us. In order to secure your git connection, you need to add your public SSH Key (you should never share your private key with anyone.)

Simply paste your public key into the box provided on the UI and click save. Alternatively you can import your key from Github, just click on the Octocat icon.

Don't have a SSH key?

If you don't have an ssh key or have never used one, we recommend you take a look at Github's excellent documentation on the subject and how to generate a key pair for your OS.

Once generated, SSH keys are easy to use. In fact you generally don't have to think about it at all. Once you're set up just git push your code to resin.io and it's taken care of automatically and securely.

Import SSH key From GitHub

For convenience we provide the ability to import your public SSH key from GitHub - just click on the Octocat icon in the bottom right-hand corner (we use GitHub's public APIs to retrieve this data.)

You will then have to enter your github username into the prompt:

If you don't have a ssh key setup yet, but want to explore resin.io, just click skip. Note that you will not be able to push code to your Intel NUC until you have a ssh key saved. This can be done at anytime from the Preferences page on the dashboard.

Creating an Application

To create an application simply type in a name, select the Intel NUC type from the drop down list and click the create button. You should now be taken to the dashboard of your newly created application:

This dashboard may not look like much right now, but this is where you will command and manage a whole fleet of Intel NUCs.

Adding Your First Device

This is the application dashboard where all of the devices connected to your application will be shown, along with their statuses and logs.

Click the Download resinOS button to get the resin.io operating system (resinOS) image for your application. A list of available versions is available via the dropdown. In general, the most recent version is recommend.

Warning: Versions ending in .dev are for development purposes only, and should not be used in production. More details on the differences between dev and prod images can be found here.

Note: The .img may seem large, but your browser will download a compressed version and decompress it on the fly using http compression, so the download will be much, much faster than you expect!

Before your resinOS download begins, a prompt will appear asking you to specify how your device will connect to the internet. Currently there are two connectivity options:

  • Ethernet cable, this option requires NO configuration as is the default.
  • Wifi, in which case you must specify the network name orSSID and passphrase for the network your device will connect to.

Once you have selected your connectivity option, click the Download Device OS button to get the resin.io operating system image configured for your application and network.

When the download completes you should have a .img file with a name like resin-myFleet-1.1.1-1.7.0-dc6c40fe05aa.img where "myFleet" is the name you gave your application on the dashboard.

Create a Bootable USB drive

Now we have to flash the downloaded .img file onto our USB drive. We recommend using Etcher, a simple, cross platform USB drive writer and validator. Head over to the Etcher homepage and get install it, it only takes a few seconds :)

You can of course use any other USB drive writing software you like, some options are:

Note: Before you flash resinOS to your USB drive you may need to formatted it as FAT32. WikiHow has great instructions on how to do this.

For simplicity this tutorial will assume you are using Etcher. Once you have Etcher installed, start it up. You may be asked to allow Etcher administrative privileges. This is just so Etcher can access your USB drive.

To create a bootable resinOS USB drive follow these 3 easy steps:

  1. Click "Select image" button and find your applications resinOS .img file.
  2. If you haven't already done so, insert your USB drive into your computer. Etcher will automatically detect it. If you have more than one USB drive inserted, you will need to select the appropriate one.
  3. Click the "Flash!" button.

Etcher will now prepare a bootable USB drive and validate that it was flashed correctly. Right! time for a spot of tea as flashing the USB drive can take roughly 3 or more minutes depending on the quality of your USB drive.

Etcher will give you a little ping! when it's done, and safely eject the USB drive for you.

Note: You can burn several USB drives with the same .img file and all the devices will boot and provision into your application's fleet. You can also disable the auto-ejecting or write validation steps from the Etcher settings panel.

Setting Up Your Device

Put the USB drive into your device and connect either the ethernet cable or WiFi adapter. Ensure that the HDMI screen and keyboard are connected up.

Now connect up the power supply and turn the device on by pushing the small round button on the top of the device.

Press the F10 key while the BIOS is loading in order to enter the boot menu. Next, select the UEFI : USB option from the boot menu so that the device will boot from your USB drive.

Once the device boots, you should see it pop up on you resin.io dashboard. It will immediately go into a "flashing internal media" state. This means that the device is flashing the resinOS onto your internal flash media.

Warning: The resinOS will completely overwrite the internal media of your NUC, so if you have important data on the device, we recommend that you make a backup before you attempt provisioning the NUC on resin.io.

After a few minutes, the OS will be fully flashed to the internal media and the device will shut itself down. At this point, you will see on the dashboard that the device is in a "Post-provisioning" state. You can now remove the USB drive and press the power button once again.

Your NUC should now automatically boot into the resin.io OS and you should see the device online and in an "Idle" state on your dashboard, ready and waiting for some code to be deployed.

Note: If for some reason your device does not boot into resinOS, you may need to go back into the BIOS and make sure the boot order correctly selects to boot from the internal SATA drive and not from USB.

Deploying Code

Now that we have a device or two connected to a resin.io application, lets deploy some code and actually start building something.

A nice first project to get your feet wet is a simple Express.js web server which will serve a static page on port :80. All the project source code can be found here on github.

To clone the project, run the following command in a terminal or your preferred git client:

$ git clone https://github.com/resin-io-projects/simple-server-node.git

Once the repo is cloned, change directory into the newly created simple-server-node directory and add the resin git remote endpoint by running the command git remote add shown in the top-right corner of your application page:

$ cd simple-server-node
$ git remote add resin <USERNAME>@git.resin.io:<USERNAME>/<APPNAME>.git

Note: On other git clients there may be an alternative way to add a remote repository.

So now we have set up a reference in our local git repository (the one on our development computer) to the resin.io application remote repository. So when we push new changes to this remote repository it will get compiled and built on our servers and deployed to every device in the application fleet.

Now to deploy this code to all device(s) in the application just run the command:

$ git push resin master

If you want to completely replace the source code of the application with a new source tree, you may need to force the push by running git push resin master --force, due to how git works.

Note: On your very first push, git may ask you if you would like to add this host to your list of allowed hosts. Don't worry about this, just type 'yes' and carry on your merry way.

You'll know your code has been successfully compiled and built when our friendly unicorn mascot appears in your terminal:

This means your code is safely built and stored on our image registry. It should only take about 2 minutes to build your code and subsequent builds will be quicker because of build caching.

Your application will now be downloaded and executed by all the devices you have connected in your application fleet. You may have to wait about 6 minutes for the first push... So time for more tea, but don't worry, all subsequent pushes are much, much faster due to Docker layer sharing. You can see the progress of the device code updates on the device dashboard:

You should now have a node.js web server running on your device and see some logs on your dashboard. If you go to the Actions page for your device, you can enable a public URL, this URL is accessible from anywhere in the world.

If you follow the URL, you will be served a page saying "Hello, World!". Alternatively you can point your browser to your devices IP address.

You should now have a basic idea of how to deploy a node.js application on resin.io. If you feel like you have a handle on docker and Node.js projects, then skip over the next section and go straight to "Using the web terminal".

Let's dive into the code

So in the root directory of our project we see a number of files, the most important ones to focus on are:-

  • Dockerfile.template : This is basically a recipe file on how to build and run our application container.
  • package.json : This is a JSON file that describes how our node.js project is built, what dependencies it has and it's entry point. Read more about it on the npm docs.
  • server.js : This is the entry point to our application code and is where all the fun happens!

The most important part of a resin.io project repo is usually the Dockerfile or Dockerfile.template. The .template version allows you to define template variables like %%RESIN_MACHINE_NAME%% which enables you to push the same repository to multiple different architecture fleets.

If we look at our Dockerfile.template, the first thing we see is:

FROM resin/%%RESIN_MACHINE_NAME%%-node:slim

This line has quite a bit packed into it. The first thing that happens is that the %%RESIN_MACHINE_NAME%% place holder gets stripped and replaced with the resin device name. For example if your application type is a Intel NUC, the line will be replaced with:

FROM resin/nuc-node:slim

Which tells the resin builder that this is the docker image we want as our base. Checkout the full list of official resin device names and the matching dockerhub base images.

We also have a :slim tag associated to the base image which denotes that we want the stripped down version only contains the minimal packages needed to run node, so no node-gyp and other build-essentials. If you need to build some native modules, say node-i2c, you should switch to :latest tag. We also have a number of pinned version tags, which should be used for production devices. Checkout the full list of -node tags, if you want to target a specify node.js version or a fixed date build.

Next up we have 3 line which were commented out:

RUN apt-get update && apt-get install -yq \
   alsa-utils libasound2-dev && \
   apt-get clean && rm -rf /var/lib/apt/lists/*

This is just a demonstration of how you can use apt-get to install dependencies in your container. In this case we would install some useful linux sound utilities.

The next two directives are pretty straight forward and key parts of using docker.

# Defines our working directory in container
WORKDIR /usr/src/app

# Copies the package.json first for better cache on later pushes
COPY package.json package.json

As the comments say, WORKDIR set our working directory for any RUN, COPY or CMD commands following it. So the next line would effectively COPY our package.json in the root of our directory to usr/src/app/package.json. Check out the Docker reference pages for more info on these commands.

We can now build all our node.js modules and dependencies, this is done using the RUN command. We also build with the --production flag and clear the cache in the same step in order to keep the final image size smaller.

# This install npm dependencies on the resin.io build server,
# making sure to clean up the artifacts it creates in order to reduce the image size.
RUN JOBS=MAX npm install --production --unsafe-perm && npm cache clean && rm -rf /tmp/*

# This will copy all files in our root to the working  directory in the container
COPY . ./

# Enable systemd init system in container
ENV INITSYSTEM on

# server.js will run when container starts up on the device
CMD ["npm", "start"]

After the npm install we copy the rest of our source code into the working directory, we do this after so that later builds can benefit from build caching. So we will only trigger a full npm install if we change something in package.json.

The last 2 commands are runtime directives. The ENV INITSYSTEM on is used to enable the systemd init within the container. This is useful for a number of reasons, like keeping the container open after application crash and handling /dev updates as new USB devices are plugged in. If you don't want an init system, just set it to off or remove the line for the Dockerfile.

The last command, CMD is perhaps one of the most important. This command defines what will run at container start on your Intel NUC, in our example we have told npm to start a process. It should be noted that you can only have one CMD per Dockerfile.

In our package.json the parts to focus on are our "scripts" and "dependencies":

{
  "name": "simple-server-node",
  "version": "1.0.0",
  "description": "A simple Expressjs Web server on resin.io",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node server.js"
  },
  "dependencies": {
    "express": "*"
  }
}

The "dependencies" section allows us to define node modules and their versions we want to use in our application. For a production application we recommend pinning the versions.

The "scripts" allow us to point to the server.js as our starting point for the whole application, so we get our awesome "Hello, World!" server when the container starts up :)

Using the Web Terminal

Often while developing and deploying code, it helps to run a few test commands or check some log files. For this resin has a handy built in web terminal which you can use from the comfort of your dashboard, or command line (check the later section on CLI and resin sync for this).

To fire up a terminal session on your device you need to two things:

  1. An online device.
  2. A running container.

Number .1 is usually pretty easy, but number .2 catches people pretty often. Since if the main process of the docker container crashes or ends, the container effectively stops and there is nothing for the web terminal to SSH into :( . For this reason we normally recommend using the systemd init system during development as this will ensure your container is always up and running, even if your application code crashes.

To start a session, just navigate to the >_ Terminal page for the device and hit the "Start the terminal session" button. It will take a few seconds to establish a connection and then you are good to go.

Note: Currently if you navigate away from the >_ Terminal page, you session will be killed. This is a known issue and will be remedied very soon.

Using Resin Sync to Develop Fast

Okay, so now we know how to provision a device and push code. There is just one glaring problem...

Do I really have to go through the whole git add, git commit, git push dance every time I forget a semicolon?

Luckily, our nifty little command line tool resin sync is here to save the day. It allows you to quickly sync source code and file changes across to one of the devices in your fleet, so you can rapidly iterate code on this test device before releasing it to the whole fleet.

Note: Resin sync will only work on ResinOS v1.1.4+ and Agent v1.8.0+.

Setting up resin sync.

Resin sync is bundled in with our handy resin CLI. The CLI allows you to basically do all your resin.io management from the comfort of the command line. Read the CLI reference more info on all the cool things it can do.

Warning: Currently resin sync is NOT supported on Windows. Support is currently being worked on, you can check the progress on this on the git repository.

To install resin CLI and sync you need at least node.js 4.0.0 on your development machine, then run:

$ npm install --global --production resin-cli

You may need to run the install with admin privileges depending on how you have installed node.js.

Note: If you already have resin CLI installed, you will need to upgrade to resin-cli v4.0.0+

Once the CLI is installed globally, login with your resin account:

$ resin login

You should then be presented with 3 options to login. The recommended method is Web authorisation which will open a dialog in your web browser and ask you to authorise the use of the CLI.

resin:simple-server-node shaun$ resin login
______          _         _
| ___ \        (_)       (_)
| |_/ /___  ___ _ _ __    _  ___
|    // _ \/ __| | '_ \  | |/ _ \
| |\ \  __/\__ \ | | | |_| | (_) |
\_| \_\___||___/_|_| |_(_)_|\___/

Logging in to resin.io
? How would you like to login? (Use arrow keys)
❯ Web authorisation (recommended)
  Credentials
  Authentication token
  I don't have a Resin account!

Setting up Node.js cross-compilation

Cross-compilation is not needed when using resin sync and Node.js as it is an interpreted language. Interpreted languages are programming languages in which programs may be run from source code form, they do not need to be compiled.

Using resin sync

You are now ready to start using resin sync, so open a terminal in the directory which we were using earlier in this guide. Make a trivial change to your source code and then run:

$ resin sync --source . --destination /usr/src/app

It should prompt you to select a device, then it will sync all the files in the root of your directory to /usr/src/app on your selected device and finally it will restart the container. You should see something similar to:

resin:simple-server-node shaun$ resin sync --source . --destination /usr/src/app
Getting information for device: 5dc2c87ea2caf79bc4e25ae638c6d5a35a75cecf22e8f914331dcb2f588f4b
Application container stopped.
Synced /usr/src/app on 5dc2c87.
Application container started.

resin sync completed successfully!

Your new code changes should be up an running in under 30 seconds, Great success!!

Some Notes and Caveats on Resin Sync
  • Resin sync directly syncs all the files in the root of your directory to the selected destination directory on your device. If you are using a compiled language you will need to set up cross-compiling on your local development machine and include a .resin-sync.yml file that tells resin sync how to compile your code and sync the resulting executable.

  • It is not possible(~easy) to install dependencies using resin sync. So if you need to do an apt-get or add something to either your Dockerfile, package.json or requirements.txt, then you will need to go through the standard git push resin master build pipeline.

  • If you know the device UUID you can just run: resin sync <uuid>. This is useful for using resin sync programmatically, in say a gulp workflow, as it does not require interactive action to confirm the destination device.

  • If no --destination / -d option is set, an interactive dialog will ask you to provide a destination directory. You can skip this by hitting 'enter' and resin sync will use the /usr/src/app device directory as the default sync destination.

  • After every resin sync the updated settings are saved in .resin-sync.yml in your projects's local directory and will be used in later invocations. You can also change any option by editing '.resin-sync.yml' directly.

  • A caveat, if you are using a DSA key, some newer openSSH clients do not allow them by default. So you may have to add the following option to ~/.ssh/config : PubkeyAcceptedKeyTypes=+ssh-dss

  • Resin sync is currently permitted to device owners only. The owner of a device is the user who provisioned it, so you will not be able to use resin sync on devices of shared applications that you did not provision.

One last Tip!

One of the many useful features of resin-cli is resin ssh, this command allows you to quickly SSH into a device's running container and run test commands or pull out some logs.

Provided you are already logged in on the CLI and you have a device online, you can use resin ssh <uuid> to access the container. Here is an example:

resin:simple-server-node shaun$ resin ssh 5dc2c87
Connecting with: 5dc2c87
[email protected]:/# uname -a
Linux Intel NUC-5dc2c8 3.10.93 #1 SMP PREEMPT Wed Apr 20 10:25:12 CEST 2016 x86_64 GNU/Linux

Example Projects to Build From

There are even more hidden treasures in the resin.io platform and tools, but we will get into those a bit later. For now why not fork one or two of our example projects and build something grand.

SORRY! we currently don't have any other Node.js projects for the Intel NUC. How about submitting one to us at [email protected] .

Enjoy Resinifying All the Things!