Self-hosted service
WebThingsIO/gateway avatar
WebThingsIO/gateway

WebThings Gateway ships four packaging routes and turns off TLS checks for its tests

WebThings Gateway - a self-hosted web application for monitoring and controlling a building over the web

2,646 stars331 forksTypeScriptMPL-2.0

At a glance

What is it?
WebThings Gateway is a self-hosted Web of Things gateway written in TypeScript under MPL-2.0, meant to sit on a Raspberry Pi or a small box and expose a building's devices over the web. Since the 2.0 release the documented install is a container, but the source build still carries a Python 2 instruction and two ports worth knowing.
Who is it for?
WebThings Gateway fits someone who wants local control of their own building's devices without handing them to a cloud service, and who is prepared to run a Node process with access to Bluetooth and USB devices on their own network. Three things to know before you start.
Can I use it commercially?
Yes, with conditions. MPL-2.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
Is it still maintained?
Yes. The repository last received commits 9 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • WebThingsIO/gateway2,646 ★ · +1
Star history
Repository2026-10-042026-11-14
WebThingsIO/gateway2.6k2.6k

1 Stars in the last 41 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

Four packaging routes, and only one is recommended

The installation section is short because it delegates. Since the 2.0 release the recommended route is a container image. Alongside it there is a snap package, which the readme labels experimental, and a source build documented at length. The source tree shows what the four routes actually are: a directory of tooling for Debian packages, one for RPM packages, one for a Raspberry Pi disk image, one for the container, and a snap directory beside them. That is a lot of packaging surface for one application, and it is also the clearest signal of what this project is: something meant to be imaged onto a small computer and left running. Two separate readme files at the root, one for the container and one for the snap, mean each route has its own instructions. The container route is the one the compose file supports, and it is configured to share the host's network rather than publish ports, with the port mapping left commented out and a note explaining that the two are mutually exclusive.

The build copies the source, deletes the TypeScript, then compiles

The build script is one line and it is unusual. It removes the build directory, copies the source tree into it while dereferencing symbolic links, then finds and deletes every TypeScript file inside that copy, and only then runs the compiler and the bundler. Two things follow. The application is compiled TypeScript output rather than a bundler target, which explains why the bundler step comes last and why the source copy is flattened. And the deletion step means the compiler reads from somewhere other than the copy, so a stale file left in the source tree cannot survive into a release. There is a separate script that starts the built application without rebuilding it, which is the one to use in a restart loop, and a watch mode that runs the build in parallel with the bundler. Two editor-oriented scripts round it out: one sets a debug flag and launches on a fixed inspector port for an attached editor, and one does the same on the default inspector port for a terminal session.

The test suite disables certificate verification

One line in the test script sets an environment variable that tells Node not to reject unauthorised TLS certificates, and it is applied to the whole jest invocation. That is a common thing to do when a test suite talks to a self-signed local server, and the readme does explain that a self-signed certificate means adding a browser exception. It is still the sort of setting that belongs in a test-only code path rather than being visible in a script anyone might reuse, so it is worth knowing that it is there. The same script runs the tests in band, collects coverage and asks the runner to report open handles, which is what makes a suite with sockets and servers terminate rather than hang. The dependency check is a shell script run as a fourth step after the tests, so a stale or unused dependency fails the same command as a broken test.

Two ports, two certificates, and a proxy trust setting

Setup splits into two paths and both use the same two ports. The plain web server listens on one port and is the one you load first; after domain registration the secure server listens on another and is what you use afterwards. If you use the provided tunnelling service, the plain page walks you through setting up a domain and registering, and the secure port works afterwards. If you bring your own certificate, the server looks for two named files in an ssl sub-directory of a profile directory you name in the configuration, and the readme gives the openssl commands for a self-signed pair. The container build rewrites one configuration value with sed, turning off the flag that says the app sits behind a forwarding proxy.

The Fedora path still installs a Python 2 pip

The build prerequisites are given per distribution and they have not all aged equally. The Debian list is a normal set of development packages for Bluetooth, Boost, D-Bus, FFI and USB, plus Python 3's package installer. The Fedora list installs both the version 2 and version 3 development packages for Python bindings, and then runs a version 2 pip to install a single module. That is a leftover from before the project dropped version 2, and it is the kind of instruction that will fail or warn on a current machine. The macOS list is the shortest and pins a specific Python minor version through the package manager, with a note that you may need to point the generic interpreter name at it for D-Bus to build.

One requirement file pins a tag, the readme installs a branch

The gateway depends on a separate Python addon library, and the two places that install it disagree. The requirements file pins that library to a specific version tag and gives it an egg name for pip. The manual build instructions in the readme, repeated three times for three distributions, install the same library with no version at all, which means whatever the default branch holds that day. So a source build done by following the readme gets a different version of the addon than a container build does. That is a small thing, but it is the kind of divergence that turns into a bug report about a library behaviour that changed upstream, so pin it yourself if you are building from source.

Bluetooth needs file capabilities, and the container needs privileges

Talking to a Bluetooth adapter from a program is a privileged operation, and the readme handles it in one line per interpreter:

bash
sudo setcap cap_net_raw+eip $(eval readlink -f `which node`)
sudo setcap cap_net_raw+eip $(eval readlink -f `which python3`)

Two capability bits are set on the resolved paths of the Node binary and the Python binary so that both can open a raw socket without being root. The container reaches the same problem from the other side: the compose file carries a comment saying that if you use Bluetooth the container has to run in privileged mode, with the setting left commented out, and a similar commented block for passing USB devices through. The image itself adds the user to the dialout group and creates a GPIO group with a hard-coded identifier, so the container's idea of who may touch hardware is defined in the Dockerfile rather than in the compose file.

Editorial conclusion

WebThings Gateway fits someone who wants local control of their own building's devices without handing them to a cloud service, and who is prepared to run a Node process with access to Bluetooth and USB devices on their own network. Three things to know before you start. Read the container's build before you trust it with a network, because it runs its application user with passwordless sudo and rewrites a proxy trust setting in the shipped configuration. Decide how you will terminate TLS, since the server needs a certificate pair in a specific directory and offers either a provided tunnelling service or your own. And accept the bleeding edge, because the current release is a beta that has been in beta since April 2026 while the branch has moved on since.

Frequently asked questions

How do I install WebThings Gateway?

As of the 2.0 release the readme recommends the container image. There is also an experimental snap package, and you can build from source, which needs a long list of native development packages that differ per distribution, Node installed through a version manager, and a file capability set on the Node and Python binaries so they can reach the Bluetooth adapter.

What ports does WebThings Gateway use?

Two. The plain web server listens on 8080 and is what you load to set up a domain, and the secure server listens on 4443 and is what you load afterwards. The container exposes both, and the Fedora firewall instructions additionally open 5353 over UDP for network discovery.

How do I use my own SSL certificate with WebThings Gateway?

The secure server looks for privatekey.pem and certificate.pem in an ssl sub-directory of the user profile directory named in the configuration. The readme supplies openssl commands for generating a self-signed pair, and warns that you will need to add a browser security exception if you do. Alternatively you can use the provided tunnelling service, which issues a domain under webthings.io instead.

How do I run the WebThings Gateway tests?

npm run test runs four things in sequence: the linter, the build, the jest suite and a dependency check. The browser tests need Google Chrome and a JDK installed as well, and a single test is run with npm run jest followed by the built test file. To debug without an editor, npm run debug builds and launches the application with the inspector attached.

What is WebThings Gateway?

A self-hosted web application for monitoring and controlling a building over the web, and an open source implementation of the Web of Things gateway pattern from the standards body. It is written in TypeScript, published under the Mozilla Public License, and its current release is a beta of the 2.1 line.

Official sources

  1. License: MPL-2.0
  2. Project website
  3. README
  4. Releases
  5. WebThingsIO/gateway on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/webthingsio-gateway.svg)](https://hysenlabs.com/projects/webthingsio-gateway)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/webthingsio-gateway.svg)](https://hysenlabs.com/projects/webthingsio-gateway)

Was this useful?