Install ThingsIX forwarder
In this guide we will explain how to configure and connect your LoRa® gateways onto the ThingsIX network. ThingsIX is launched as a data-only network and will add token support later (planned 2023 Q2). That means there is initially no reward system. As a result gateways don't have to be on-boarded and can freely join ThingsIX. Once token support is added you will need to on-board your gateways to set their details and owner to participate and earn rewards.
The ThingsIX packet forwarder is the access portal for your gateways to the ThingsIX network. Your gateways will need to send received packets to the ThingsIX forwarder and the forwarder will send them to their next destination. Once token support is added the forwarder will try to sell the data and participate in coverage mapping to earn rewards for its owner. The forwarder currently supports Semtech's UDP protocol and limited support for LoRa Basics™ Station.
Head over to the ThingsIX Discord to get community support.
Where to install the forwarder?
The first thing to decide is where to install the ThingsIX forwarder. You can run it on the gateway or on a server. What the best solution is depends on your personal situation. Some considerations are:
- Can you run custom software on the gateway? Do you require manufacturer support?
- Does the gateway have enough resources to run the ThingsIX forwarder? The ThingsIX forwarder is ~20MB in size and requires ~25MB of memory to operate.
- How many gateways do you need to manage? If you only have a few gateways adding a server for the forwarder might not be worth the investment. If you have a lot of gateways running the ThingsIX forwarder on a server may be easier to maintain.
- How good is the gateway connectivity and what are the data costs? The forwarder connects with the ThingsIX network and consumes more data than just packet traffic. It periodically retrieves route information and keep connections with remote routers to exchange data. If you have a limited network connection (for example 4G/LTE) it may be cheaper and easier to run the ThingsIX Forwarder on a server.
Once you decided where to run the forwarder it's time to install it. The recommended method to run the forwarder is through a docker image that you can find here.
We also ship binaries that you can find on the
release page
under Assets
.
If you prefer to build the forwarder from source you can take a look at its repository. You will require the Golang compiler that can be found here or install it through your package manager. We recommended that you build the software from an officially released version. You can find releases and their tags here.
git clone https://github.com/ThingsIXFoundation/packet-handling.git
git checkout tags/${tag}
cd packet-handling/cmd/forwarder
go build -ldflags="-s -w"
This guide assumes the use of the docker image.
Quick start
Make sure the /etc/thingsix-forwarder
folder exists on your system to store
the configuration and is writeable by the docker container:
mkdir -p /etc/thingsix-forwarder
Start the ThingsIX forwarder on mainnet:
docker run -d --name thingsix-forwarder \
-p 1680:1680/udp \
--restart unless-stopped \
-v /etc/thingsix-forwarder:/etc/thingsix-forwarder \
ghcr.io/thingsixfoundation/packet-handling/forwarder:${version} --default_frequency_plan=EU868
(replace ${version}
with the latest release, for example: 1.0.0
, note: no 'v' prefix should be used).
From version 1.0.8 onwards the flags for the frequency plan are required: --default_frequency_plan=EU868 or --default_frequency_plan=AU915 (of course you can set other plans too, but there currently aren't any routers on mainnet for that).
This example assumes that the ThingsIX forwarder listens on UDP port 1680. Make sure to open it in any firewalls and make sure to connect your gateways to it.
Wait a few minutes for ThingsIX forwarder to collect gateway EUIs: You should see a line like containing the EUI of the gateway(s) you connected if you run:
docker logs thingsix-forwarder
Like:
time="2022-11-24T13:42:39Z" level=info msg="unknown gateway recorded" file=/etc/thingsix-forwarder/unknown_gateways.yaml gw_local_id=0016c001f1500812
With the default configuration the forwarder will write recorded unknown
gateway id's to /etc/thingsix-forwarder/unknown_gateways.yaml
.
cat /etc/thingsix-forwarder/unknown_gateways.yaml
- local_id: 0016c001f1500812
first_seen: 1677672688
Now you can import the gateways and send the onboard message to ThingsIX:
docker exec thingsix-forwarder ./forwarder gateway import-and-push <owner>
owner
is your personal wallet address that you will import the gateways in and
receive earned rewards.
This command will generate for each recorded gateway that it imports into the forwarders gateway store an identity and uses this identity to generate an onboard message that is send to ThingsIX. It will also print the onboard message if you want to copy it manually. ThingsIX will store the onboard message for 4 hours. In this period you can go to the ThingsIX dashboard, connect your wallet and onboard the gateway. If you cannot do this within the 4 hours you will need to copy the onboard message yourself into the dashboard.
Example:
docker exec thingsix-forwarder ./forwarder gateway import-and-push 0x094cab3ecd74ee71fc583cf737dbc474f72301b0
Output (onboard message that was also sent to ThingsIX):
[{"address":"0x8ff8d3cc8563d01f5a08c7a3c5210464400ebe7e","chainId":80001,"gatewayId":"0x41e5d017723d2f8634f7b146f2c3d1d4691eb9fdd3c8dae801fa1bffed04ccd1","localId":"0016c001f1500812","networkId":"ce791683c0474aa9","owner":"0xab9baa9b464c1ac323e44fc803dbd6ef3ab1be56","signature":"0x376110ecfcebd9a477500c8ba2d812235808e4c5ac41d58c64f2f754f52e7f014dca307aac94242871d939ef4b24ba769e3ef5ffc8daded8b9929d9d195d2c421b","version":0}]
It is safe to run this command multiple times. Gateways that are already imported will be ignored.
After the gateways are imported in the forwarders gateway store their identity
is stored in /etc/thingsix-forwarder/gateways.yaml
. Make a backup of this file
since it contains the identity of your gateways. If you need to reinstall the
forwarder you can copy this file back to the same location.
Now you are all done to onboard your gateways on ThingsIX in our dashboard. See for instructions this page.
Detailed start
Configuration
The forwarder comes with build in configuration for all environments. The
defaults are in most cases sufficient. But it is possible to create custom
configuration when needed. You can configure which network the forwarder needs
to connect to with the --net
option. By default this is main
for mainnet,
other values are dev
, test
or ""
if you don't want any defaults and
configure everything yourself.
The source repository contains an example configuration that describes all
options and can be found here.
Most should be self explanatory but the Gateways
section require additional
explanation.
By default the forwarder only connects to routers that are registered for a frequency plan that at least 1 of the gateways in the forwarders store uses. This prevents forwarders to connect to routers for which it will never receive traffic.
You can set a default frequency plan for gateways that are not yet fully
onboarded through custom configuration under the key
forwarder.gateways.store.default_frequency_plan: <freq-plan>
. See the example
config
for an example.
Gateway store
The forwarder uses a gateway store that serves several purposes:
Gateways can earn rewards for their owner. Therefore the gateway and its owner need to be registered in ThingsIX (once token support is added). This requires the gateway to have an identity and the ability to proof that identity. ThingsIX uses ECDSA keys for identities and stores this key together with the gateways
local_id
in the gateway store. Thelocal_id
is known as the Gateway EUI and typically derived from the gateway's hardware. It is used in the communication between the gateway and the forwarder. While the gateway ThingsIX network id is derived from the private key and used in the communication between the forwarder and the ThingsIX network.Your gateways need to be able to connect to the forwarder. That is often done over the internet making this a public endpoint. The forwarder will only forward data for gateways in its store and drops packets for unknown gateways.
Convenience, the forwarder can be configured to record gateway id's in an unknown gateways file (default behavior). This file can be manually verified and unwanted gateways can be removed. After cleanup this file can be imported in the store. If you have many gateways this saves a lot of error prune work.
Start forwarder
In this guide we will run the container in the foreground so it can be stopped
and restarted from the command line. In practice you probably want to run the
container in the background, detached
and with a restart
policy. The forwarder opens an endpoint on port 1680/udp
for gateways to
connect to. This port must be published. The forwarder uses
/etc/thingsix-forwarder
as default location where to load and store data.
Therefore we mount the local directory /etc/thingsix-forwarder
into the
container.
Replace ${version}
with the latest image version that can be found
here
(for example 1.0.0, note: no 'v' prefix should be used).
docker run -d --name thingsix-forwarder \
-p 1680:1680/udp \
-v /etc/thingsix-forwarder:/etc/thingsix-forwarder \
ghcr.io/thingsixfoundation/packet-handling/forwarder:${version}
If you want to start the forwarder with default configuration on another network
just append --net=<network>
to the command with network one of dev
, test
or main
. The default is main
.
Now check the logs:
docker logs thingsix-forwarder
Output:
time="2022-11-24T12:55:32Z" level=info msg="***Starting ThingsIX Forwarder connected to mainnet***"
time="2022-11-24T12:55:32Z" level=info msg="use gateway store" path=/etc/thingsix-forwarder/gateways.yaml
time="2022-11-24T12:55:32Z" level=warning msg="accept all gateways in gateway store, including non-registered gateways"
time="2022-11-24T12:55:32Z" level=info msg="loaded gateway store" #-gateways=0
time="2022-11-24T12:55:32Z" level=info msg="Semtech UDP backend" fake_rx_time=false udp_bind="0.0.0.0:1680"
You will get a warning. That is normal and tells you that the forwarder accepts data from all gateways in the gateway store. Not only the gateways that have been onboarded on ThingsIX since that is not required at the moment. You can also see that the gateway store currently is empty. We will add a gateway in the next section.
If you need to pass in custom configuration you can use the --config
option.
Lets assume you want to rename the default gateway store from
/etc/thingsix-forwarder/gateways.yaml
to
/etc/thingsix-forwarder/my-gateway-store.yaml
.
We create the following file /etc/thingsix-forwarder/my-custom-config.yaml
:
forwarder:
gateways:
store:
file: /etc/thingsix-forwarder/my-gateway-store.yaml
Start the forwarder and order it to use the custom configuration file:
docker run -d --name thingsix-forwarder \
-p 1680:1680/udp \
--restart unless-stopped \
-v /etc/thingsix-forwarder:/etc/thingsix-forwarder \
ghcr.io/thingsixfoundation/packet-handling/${version} \
--config /etc/thingsix-forwarder/my-custom-config.yaml
Now check the logs:
docker logs thingsix-forwarder
Output:
time="2022-11-24T12:57:46Z" level=info msg="***Starting ThingsIX Forwarder connected to mainnet***"
time="2022-11-24T12:57:46Z" level=info msg="use gateway store" path=/etc/thingsix-forwarder/my-gateway-store.yaml
Fill gateway store
As can be seen from the logging the forwarder opens the endpoint for gateways on
0.0.0.0:1680/UDP
. Make sure this endpoint is accessible for your gateways and
that your gateways uses Semtech's UDP protocol. The next step is to configure
your gateway to use this endpoint. This is gateway specific and outside of this
guide. Please see your gateways documentation how to configure the LoRa packet forwarder
to forward packets to this endpoint.
Once you have configured your gateway to connect to the ThingsIX forwarder you will see the following in the logs:
time="2022-11-24T13:42:39Z" level=warning msg="event from unknown gateway, drop event" gw_local_id=0016c001f1500812
time="2022-11-24T13:42:39Z" level=info msg="unknown gateway recorded" file=/etc/thingsix-forwarder/unknown_gateways.yaml gw_local_id=0016c001f1500812gw_local_id=0016c001f1500812
This indicates that a gateway with id 0016c001f1500812
connected to your
forwarder but the gateway isn't in the gateway store. Therefore data from this
gateway is dropped. It also mentions that it recorded the gateway id in
/etc/thingsix-forwarder/unknown_gateways.yaml
. This is default behavior, all
unknown gateway id's are recorded to this file so they can be imported if
required.
Now its time to add your gateway into the forwarders gateway store. You have 2 methods:
- add a single gateway
- import recorded unknown gateways all at once
Add single gateway
Add the gateway to the forwarder and generate the onboard message that is required when onboarding the gateway in ThingsIX.
docker exec thingsix-forwarder ./forwarder gateway onboard-and-push 0016c001f1500812 0xab9baa9b464c1ac323e44fc803dbd6ef3ab1be56
Output:
+---+--------------------------------------------------------------------+------------------+--------------------------------------------+---------+--------------------------------------------------------------------------------------------------------------------------------------+
| | GATEWAY ID | LOCAL ID | OWNER | VERSION | GATEWAY ONBOARD SIGNATURE |
+---+--------------------------------------------------------------------+------------------+--------------------------------------------+---------+--------------------------------------------------------------------------------------------------------------------------------------+
| 1 | 0x876014aadd2ab2986e86d1963236321d035c4f6be067d64f156334c46793fc1d | 0016c001f1500812 | 0xAB9bAA9B464C1Ac323e44fc803dbd6Ef3AB1BE56 | 0 | 0x9dae16d11e71f9115be0d45c417e0ce20e5b60b618e99ec223afd2dd56d9cda4235f872ff45e13af71f6aeb7030d3719c2e62e279db0bf8ca20f6cb8ee55c28f1c |
+---+--------------------------------------------------------------------+------------------+--------------------------------------------+---------+--------------------------------------------------------------------------------------------------------------------------------------+
If the gateway was added you will see 2 id's:
THINGSIX ID
, once tokens support is added this is the gateway ID that needs to be registered on ThingsIX. It is derived from the generated gateways private key. You can find more about ThingsIX identities here.LOCAL_ID
, the is the gateway id as used for communication between gateway and forwarder.
We can check that the gateway is added to the forwarders store:
cat /etc/thingsix-forwarder/gateways.yaml
Output:
- local_id: 0016c001f1500812
private_key: 45c205d94851f92d2afc9be71c4dfa93bc37e9fd6666ad22158b40f3cd9d6f60
Batch import gateways
Another method is to batch import a list of recorded gateways. Adding gateways one by one becomes quickly a tedious job. The forwarder and the ThingsIX dashboard support batch imports. Gateways that are already in the store are ignored so its safe to run this command multiple times.
The gateway import command accepts the owners wallet address.
The forwarder will dump a json message that contains the gateway onboard message that are pushed to ThingsIX.
docker exec thingsix-forwarder ./forwarder gateway import-and-push 0xab9baa9b464c1ac323e44fc803dbd6ef3ab1be56
Output:
[{"address":"0xd5a9a02d571feeb44b837bf2c352b1158db5bfee","chainId":80001,"gatewayId":"0xcb932d6756f98908b4bfc6fc0d56102f1cd1516398fa1d89497b40057928767c","localId":"0016c001f1500812","networkId":"e50dd8b564f2cc77","owner":"0xab9baa9b464c1ac323e44fc803dbd6ef3ab1be56","signature":"0xd52a2bcf9bb76b80ecbed7864ad75bd9bad75acf3be49acfceeaf62f1d96517416dc00e629db2abb7adc1d6fe44db24edf1dfb07afcc90a84520bd27cbaae1761b","version":0},{"address":"0x4a2bcbccf30e43d7f684a4a36c3478bf1aa5f751","chainId":80001,"gatewayId":"0xa2da563b73e89b4e0c61482691a4a308e053800fa764a257f36c88c658f95162","localId":"aa16c001f1500812","networkId":"1421046d7bb45934","owner":"0xab9baa9b464c1ac323e44fc803dbd6ef3ab1be56","signature":"0xb82c35632597a0d302d1cbcf7e1169fd287c0ec4931e0845cf16ad52917ee4131fcb4ff8cc11368ddaf1edb3225136e48627bd862dcf31c24b0f04281f0bdf651c","version":0},{"address":"0x22f36eedcd609ae7a04bf0dfcb615b8c2946e77d","chainId":80001,"gatewayId":"0xe0e10b9d6c4c725a86d689f3d26b709c99a08e85727c77b34256b97724e0c718","localId":"ba16c001f1500812","networkId":"51fb370310db16b2","owner":"0xab9baa9b464c1ac323e44fc803dbd6ef3ab1be56","signature":"0x323ea47c9860e5bd91f8defcd7f1c3bd82e2c64714115b2a1eed2db01e7ab712533095ac5ea96ad4fbd4c88344c059b01f3385d6ee68aa749510718c67718cc71b","version":0},{"address":"0xc7ef3801235a8624c02f6ce081b8c87e23f3b973","chainId":80001,"gatewayId":"0xf77746cfaabb85efb8ee6ce5e67529509b6a0ec856d1a3ae5eb8dede9f7f3ca9","localId":"ca16c001f1500812","networkId":"b2396e5d8ecf82b0","owner":"0xab9baa9b464c1ac323e44fc803dbd6ef3ab1be56","signature":"0x9ab439c28b1e1f0580bd4774791e68e01811112a9176a2db0ebe162762da18533dfec867eaed4ebabc7075b877d6e02dd7a025260d835c97300abfe0a74ff9911c","version":0},{"address":"0x6465ce06f45e8e12331c9cb37b9ebbf1cadd02d1","chainId":80001,"gatewayId":"0xc13d2d3b4ce902dd4190ac13c3f86f79b41a000774c9ae2a069f54bf41ecef5e","localId":"da16c001f1500812","networkId":"b63b0ed382ac6ebb","owner":"0xab9baa9b464c1ac323e44fc803dbd6ef3ab1be56","signature":"0xb329e1363bc12924792e9390226df4a99efc32e055f9ca14390e86cb10024b0a4a0e5a5a0d56899efd452c0ef410c8130826935accb2b2694d1f6f859de3cacd1b","version":0}]
And check that the gateways are added to the gateway store.
cat /etc/thingsix-forwarder/gateways.yaml
Output:
- local_id: 0016c001f1500812
private_key: b598b56d5fd02763ebe702f0800f9e8600213fe1cff9bf0f50d10ee2da27028d
- local_id: aa16c001f1500812
private_key: fd5af545bdc224eee839c14c3931ba99198e10a646ffc87acbe43978ac903786
- local_id: ba16c001f1500812
private_key: f297568fa3954ab38b275af93e137c8016da8ffd8e0f471a5419a67f5b613c39
- local_id: ca16c001f1500812
private_key: 636bd3d58e3b5909a1ef1358eb3ecdf9084f0824a03fc03e8a5be476352e6c77
- local_id: da16c001f1500812
private_key: 5c641438d37ad0be09c527e3a3c3bfa4a1a58f20db3dac1ac313748a66961705
Gateway store overview
For an overview of gateways in the store use the gateway list
sub command:
docker exec thingsix-forwarder ./forwarder gateway list
Output:
+---+------------------------------------------------------------------+------------------+------------------+-------+------+---------+--------------+----------+----------+
| | THINGSIX ID | LOCAL ID | NETWORK ID | OWNER | BAND | VERSION | ANTENNA GAIN | LOCATION | ALTITUDE |
+---+------------------------------------------------------------------+------------------+------------------+-------+------+---------+--------------+----------+----------+
| 1 | cb932d6756f98908b4bfc6fc0d56102f1cd1516398fa1d89497b40057928767c | 0016c001f1500812 | e50dd8b564f2cc77 | | | | | | |
| 2 | a2da563b73e89b4e0c61482691a4a308e053800fa764a257f36c88c658f95162 | aa16c001f1500812 | 1421046d7bb45934 | | | | | | |
| 3 | e0e10b9d6c4c725a86d689f3d26b709c99a08e85727c77b34256b97724e0c718 | ba16c001f1500812 | 51fb370310db16b2 | | | | | | |
| 4 | f77746cfaabb85efb8ee6ce5e67529509b6a0ec856d1a3ae5eb8dede9f7f3ca9 | ca16c001f1500812 | b2396e5d8ecf82b0 | | | | | | |
| 5 | c13d2d3b4ce902dd4190ac13c3f86f79b41a000774c9ae2a069f54bf41ecef5e | da16c001f1500812 | b63b0ed382ac6ebb | | | | | | |
+---+------------------------------------------------------------------+------------------+------------------+-------+------+---------+--------------+----------+----------+
Detecting gateways
The forwarder automatically reloads the gateway store. You can check the logging to see if the gateways are loaded.
docker logs thingsix-forwarder
Output:
time="2022-11-24T13:52:20Z" level=info msg="***Starting ThingsIX Forwarder connected to mainnet***"
time="2022-11-24T13:52:20Z" level=info msg="use gateway store" path=/etc/thingsix-forwarder/gateways.yaml
time="2022-11-24T13:52:20Z" level=warning msg="accept all gateways in gateway store, including non-registered gateways"
time="2022-11-24T13:52:20Z" level=info msg="loaded gateway store" #-gateways=1
...
time="2022-11-24T13:53:30Z" level=info msg="gateway online" gw_local_id=0016c001f1500812 gw_network_id=4d7a325d4e0ee7d3
...
time="2022-11-24T13:54:11Z" level=info msg="delivered packet" airtime="113.152µs" coderate=CR_4_5 dev_addr=00b00b1e ...
List gateways in store
docker exec thingsix-forwarder ./forwarder gateway list
Output
+---+------------------------------------------------------------------+------------------+------------------+-------+------+---------+--------------+----------+----------+
| | THINGSIX ID | LOCAL ID | NETWORK ID | OWNER | BAND | VERSION | ANTENNA GAIN | LOCATION | ALTITUDE |
+---+------------------------------------------------------------------+------------------+------------------+-------+------+---------+--------------+----------+----------+
| 1 | cb932d6756f98908b4bfc6fc0d56102f1cd1516398fa1d89497b40057928767c | 0016c001f1500812 | e50dd8b564f2cc77 | | | | | | |
| 2 | a2da563b73e89b4e0c61482691a4a308e053800fa764a257f36c88c658f95162 | aa16c001f1500812 | 1421046d7bb45934 | | | | | | |
| 3 | e0e10b9d6c4c725a86d689f3d26b709c99a08e85727c77b34256b97724e0c718 | ba16c001f1500812 | 51fb370310db16b2 | | | | | | |
| 4 | f77746cfaabb85efb8ee6ce5e67529509b6a0ec856d1a3ae5eb8dede9f7f3ca9 | ca16c001f1500812 | b2396e5d8ecf82b0 | | | | | | |
| 5 | c13d2d3b4ce902dd4190ac13c3f86f79b41a000774c9ae2a069f54bf41ecef5e | da16c001f1500812 | b63b0ed382ac6ebb | | | | | | |
+---+------------------------------------------------------------------+------------------+------------------+-------+------+---------+--------------+----------+----------+
This command supports the --json
flag. If given the output is printed as a
json value.
If the last columns are missing it means that the gateway hasn't been onboarded and/or its details are not set. If that has been done the forwarder may need to sync with ThingsIX. That will happen automatically but can take some time.
Create gateway onboard message
If you want to (re)create a gateway onboard message for an already onboarded
gateway or want to copy the onboard message manually you can use the onboard
subcommand.
docker exec thingsix-forwarder ./forwarder gateway onboard 0016c001f1500812 0xab9baa9b464c1ac323e44fc803dbd6ef3ab1be56 --json
The first argument is the gateways local id for which you want to generate an onboard message the last argument is the gateways owner wallet address. It is safe to run this command multiple times if needed.
Output
[{"address":"0xd5a9a02d571feeb44b837bf2c352b1158db5bfee","chainId":80001,"gatewayId":"0xcb932d6756f98908b4bfc6fc0d56102f1cd1516398fa1d89497b40057928767c","localId":"0016c001f1500812","networkId":"e50dd8b564f2cc77","owner":"0xab9baa9b464c1ac323e44fc803dbd6ef3ab1be56","signature":"0xd52a2bcf9bb76b80ecbed7864ad75bd9bad75acf3be49acfceeaf62f1d96517416dc00e629db2abb7adc1d6fe44db24edf1dfb07afcc90a84520bd27cbaae1761b","version":0}]
Backup and security of the gateway store
Since the gateway store holds the private key for each gateway it is important to make a backup of the gateway store. If the store is lost you will need to import the gateways again in a new store. This generates new keys forcing you to onboard the gateways again on ThingsIX when token support is added. Onboarding gateways and setting gateway details comes with a fee that needs to be paid again. Therefore loosing your gateway store will come with a price.
Gateways that are onboarded on ThingsIX are stored in your Polygon wallet. If someone captures your gateway store it is not possible to take ownership of these gateways. That can only happen if someone gains access to your Polygon wallet.