NodeJS for the Web Pi Kiosk

Andrea Giammarchi
4 min readMar 28, 2018

--

In case you missed the news, the Minimalistic Web Kiosk for RPi got updated with the missing piece to have a fully HW Accelerated Web experience through the Pi 3, or others.

Look at the Three.js geometry cube demo @ 720p

Shit just got real !

There is a JavaScript driven WebKitGTK+ with GLib 2 super powers but that’s not enough, we want to use dev friendly technologies such NodeJS and anything related, don’t we?

Requirements

You followed each step in the previous post, or you used the remote script to install everything. Either ways, you’d be good.

The TL;DR version here, as alarm user is:

bash <(curl -s archibold.io/kiosk/nodejs)

But I bet you want to know what the hack that’s doing.

First of all, NodeJS and npm

These two modules are a part, and that’s cool, if you ask me.

pacman -Sy --needed --noconfirm nodejs npm

Run previous command as root user, or use su -c "pacman ...." to exec the command as root from your alarm user.

Configure npm

If you’d like to be able to use npm install -g module without needing root privileges, all you need to do is to configure a prefix that does not require those privileges.

mkdir -p ~/.npm-packages/bin
npm config set prefix '~/.npm-packages'

Above commands will create a .npm-package/bin folder in the user home directory, and it will set such folder as npm prefix.

The next step is to inform the user environment that such folder might contain binaries.

echo '
# npm and nodejs global modules
export PATH="$PATH:$HOME/.npm-packages/bin"
export NODE_PATH="$NODE_PATH:$HOME/.npm-packages/lib/node_modules"
' >> ~/.bashrc

I took a chance to sneak in the NODE_PATH variable too, so that modules not found in a local folder would be searched as last resort in such place.

Bootstrap node instead of browsing

The .xinitrc file would have a ./.browse --fullscreen ... page at its very end, but instead we want to start a NodeJS script.

Keep in mind the following things:

  • npm start is an absolute overhead in ARM environment. It’s been slow for years and it’s not improving much in there. Just node index.js instead, to be as fast as possible.
  • the .js you start should be in charge of launching the .browse file, just remember such file accepts various arguments too.

To simplify things for now, I’ve created the most basic index.js file I could think of:

const path = require('path');
const BROWSER = path.join(__dirname, '.browse');
const WWW = path.join(__dirname, 'www');
// be sure requests and paths
// are from WWW and not the user root.
process.chdir(WWW);
const express = require('express');
const server = express();
server.use(express.static(WWW));
server.listen(8080, () => {
const child = require('child_process').spawn(
BROWSER,
[
'--fullscreen',
process.argv[2] || 'http://localhost:8080/'
],
{stdio: 'inherit'}
);
child.once('exit', code => process.exit(code || 0));
process.once('exit', () => child.kill());
});

Above index.js file will bootstrap node into the already present folder, serving anything in there as static.

This is an hello world demo, but roots to do anything else you want/need are there too.

Remember to npm install express thought, or nothing would possibly work.

Only port 8080 ?

It’s annoying to digit any port, and 8080 , or any alternative, ain’t not exception.

If you’d like to forward to 80 any incoming traffic, you need root privileges to create, and enable, the following file:

[Unit]
Description=localhost 80 to 8080 service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
ExecStart=/usr/bin/iptables -t nat -I OUTPUT -p tcp -o lo --dport 80 -j REDIRECT --to-port 8080
[Install]
WantedBy=multi-user.target

That would be /etc/systemd/system/localhost-80to8080.service file, and you need to systemctl enable ... such file too.

Reachable only via IP ?

Nope, you can always ask your home router to recognize a generic name such http://pi-kiosk/ in the network.

All you need is a name in the /etc/hostname file, and a:

dhcpcd -s $(cat /etc/hostname)

operation. That should make you able to reach your device via your current network without too many troubles.

What’s next for a Web Kiosk ?

At this point you have all tools to bootstrap in reasonable time, and in many platforms, even if I’ve targeted Raspberry Pi GPU, at boot, anything you want.

Please remember ARM 64 bit is not fully supported yet, but I’d argue what works there works definitively better, and faster, than its 32bit counterpart.

If you’d like to have a similar Electron experience, with the ability to use NodeJS modules from the browser, I strongly suggest you to have a look at my node-worker module: you can do pretty much everything with it, except tasks that requires root access.

For GPIO and/or root related tasks, you can always follow all my instructions and do whatever you want on a root account, but that’s not something I’d encourage here.

Remember there are modules to do that too, but that’s out of this post scope.

Have fun with Internet of Things through the Web!

--

--

Andrea Giammarchi

Web, Mobile, IoT, and all JS things since 00's. Formerly JS engineer at @nokia, @facebook, @twitter.