Advanced Configuration
Session Key Filter (SKF)
A Session Key Filter (SKF) is a device address (devAddr) and network session key (NwkSKey) pair stored on a route. When a Hotspot reports an uplink on a devAddr that has one or more SKFs, the Helium Packet Router verifies the packet's Message Integrity Code (MIC) against the stored keys before buying it. Packets that fail the check are dropped before purchase, so they never reach the LNS and incur no Data Credit cost.
SKFs ensure that a route purchases and forwards only the payloads its operator intends to receive. Device addresses are not globally unique: every LoRaWAN network assigns devAddrs from the same 32-bit space, so a device on an unrelated network can transmit on a devAddr that falls within a Helium route. Without SKFs, the Packet Router cannot verify these packets, and the OUI pays for payloads that may not correlate to any device the operator intends to receive data from.
SKF Behavior
Two settings determine how the Packet Router treats an uplink: whether the packet's devAddr has any
SKFs on the route, and the route's ignore_empty_skf flag. SKFs are added per devAddr;
ignore_empty_skf is a single flag set for the entire route.
| devAddr on the route | ignore_empty_skf: false | ignore_empty_skf: true |
|---|---|---|
| Has one or more SKFs | Delivered only if the MIC matches a stored key | Same; the flag has no effect when SKFs exist |
| Has no SKFs | Delivered without any MIC check | Dropped |
A devAddr can hold multiple SKFs, and the Packet Router checks the MIC against each of them. This supports LNS platforms such as ChirpStack that assign the same devAddr to multiple devices.
Join requests are not filtered by SKFs. They are matched by DevEUI/AppEUI pair and carry no devAddr, which is why a device with a missing or stale SKF can join successfully while its uplinks are dropped.
OTAA devices derive a new NwkSKey on every join. Once a device rejoins, its existing SKF no longer matches and its uplinks are dropped, which is the symptom described in Device Able to Join but Not Uplink. In practice, SKFs are kept in sync programmatically by the LNS, typically using one of the tools in Automated EUI and SKF Route Updates.
Any SKF updater implementation should remove old session keys, not just add new ones. Stale SKFs accumulate on the route, and the Packet Router keeps buying uplinks that match an old key, such as from a device that was deleted from the LNS but is still transmitting.
Managing SKFs
The commands below use the Config Service CLI with an owner or delegate keypair configured, as
described in Config Service Interaction. As with other route
commands, omitting --commit performs a dry run that prints the change without applying it.
List the SKFs on a route:
helium-config-service-cli route skfs list --route-id <route-id>
Add an SKF. The devAddr is eight hex characters with no 0x prefix, and the session key is the
device's hex-encoded NwkSKey (in ChirpStack, found in the device's Activation tab):
helium-config-service-cli route skfs add --route-id <route-id> --devaddr <devaddr> --session-key <nwkskey> --commit
An SKF can also carry a per-device max copies value via --max-copies. When the flag is omitted,
the SKF is created with max_copies set to 1. A value of 0 falls back to the route-level setting.
See Max Copies for how the SKF-level value overrides the route-level setting.
Remove an SKF:
helium-config-service-cli route skfs remove --route-id <route-id> --devaddr <devaddr> --session-key <nwkskey> --commit
For bulk changes, route skfs update --route-id <route-id> --update-file <file> --commit applies a
JSON file of add and remove actions, limited to 100 updates per request.
Enforcing SKFs
By default (ignore_empty_skf: false), a devAddr with no SKFs accepts all traffic unchecked.
Enabling the route's ignore_empty_skf flag closes this gap: the Packet Router drops all traffic on
any devAddr that has no SKFs, so only devices with registered session keys get through.
Check the current value by looking for the ignore_empty_skf field in the output of:
helium-config-service-cli route get --route-id <route-id>
Enable enforcement:
helium-config-service-cli route update ignore-empty-skf --route-id <route-id> --ignore --commit
To disable it, run the same command without --ignore. The flag sets the value by its presence;
there is no --ignore true or --ignore false form.
Automated EUI and SKF Route Updates
As the ecosystem of LNS operators grows, an increasing number of developers have open-sourced their tooling for running a Helium-enabled LNS. These tools enable functionality such as EUI and SKF automation to per-tenant Data Credit accounting.
A selection of the tools are outlined below. All of them run alongside a ChirpStack deployment.
| Tool | Capabilities | Documentation |
|---|---|---|
| Helium Route Updater | Automates adding and removing EUIs, and enables and maintains SKFs for your devices | ChirpStack Docker Compose setup |
| Disk91 Helium Chirpstack | EUI management and per-tenant Data Credit accounting | Repository readme |
| Chirpstack-hpr by Bones | EUI and SKF management | Getting started guide |
Max Copies
Given that LoRaWAN devices openly broadcast uplinks, it's common for multiple Hotspots to capture
the same device uplink within the Helium Network. LNS operators can customize the number of
duplicate uplinks they wish to receive and pay for by setting a max copies amount, also known as
"multibuy." Configuring the max_copies setting offers several significant advantages:
- Better downlink performance: If the max copies setting is 10, the LNS will receive up to 10
copies of the same uplink, and the downlink will be sent by the Hotspot with the best RSSI of
those 10, per the selection mechanism of the LNS.
Helium reports Hotspots' responses in chronological order, which can be challenging for scheduling downlinks because the first Hotspot to report may not necessarily be the closest or have the strongest RSSI/SNR attributes. This is important for downlink scenarios such as Class-C devices, ADR, confirmed uplinks, or standard downlinks on Class-A devices. Leveraging multibuy ensures that there is a strong Hotspot available to deliver the downlink message. - Geolocation: It is possible to leverage Hotspot metadata to estimate the sensor location without GPS or Wi-Fi.
- Multilateration: For devices that do not have internal location-solving abilities (GPS), the metadata of the packet report and Helium Network can be leveraged to solve for a device location.
The Helium Network charges for each response for a given payload. Each Hotspot that reports a payload from a given device is eligible to be rewarded. The LNS operator can choose how many reports they would like to buy. For instance, for a multibuy value of 10 on a device that only receives 8 reports, the OUI would be charged 8 DC ($0.00008 USD). This assumes the payload was less than 24 bytes.
There are two levels of granularity for the max copies setting:
- Route level: Applies to all devices registered under the route.
- SKF level: Applies only to the device with the specified network session key (NwkSKey). This configuration overrides the route-level max copies setting.
As an example, if the LNS operator has a route that contains devices A and B, and configures a route-level max copies setting of 2 and an SKF-level max copies setting of 5 for device B, then device A will inherit the route-level max copies setting of 2, and device B will use its SKF-level max copies setting of 5.
Improve Join Performance
Since Over-the-Air Activation (OTAA) devices require a network joining process before they start transmitting valuable sensor data, it is beneficial to ensure the network joining process is as effective as possible.
Join performance can be improved by increasing the number of copies of the same join request the LNS receives, because then the join accept will be delivered by the Hotspot with the best RSSI, increasing the possibility of a successful delivery.
Join requests are free on the Helium Network. LNS operators can leverage max copies to improve the join performance without additional cost overhead.
As an example, the LNS operator can define a route-level max copies setting of 20 and an SKF-level max copies setting of 1 for all devices. This will have the effect of allowing up to 20 copies of join requests and 1 copy of each uplink. This way, the devices will have a much better chance to join, without consuming extra DC from the uplinks once joined.
Config Service Interaction
The Config Service can be used to manage an OUI and devAddr. There are two ways to interact with the Config Service:
- Using the Command-Line Interface (CLI).
- Alternatively, you can write scripts to interact with the Config Service directly through gRPC APIs for a more programmatic approach.
Hotspot Location Data
Hotspot location data can be requested from the Config Service using either the CLI or gRPC APIs.
EUI Pair Wildcard
In some applications, deployers may have many DevEUIs all associated under the same AppEUI, and it might be inconvenient to provision all those EUI pairs individually. If the LNS operator would like to receive Join Requests for all devices under a certain AppEUI, simply input 0000000000000000 for the DevEUI when adding an EUI pair.
Add and Remove Delegate Keys
Note that only the owner key can perform the actions below. OUI owners can add delegate keys by running:
helium-config-service-cli org update delegate-add --pubkey <public key of the delegate key pair you are trying to add> --keypair <relative path of your **owner** keypair path> --commit
OUI owners can remove delegate keys by running:
helium-config-service-cli org update delegate-remove --pubkey <public key of the delegate key pair you are trying to remove> --keypair <relative path of your **owner** keypair path> --commit
Set up NGINX for ChirpStack Docker
NGINX can be used for web serving, reverse proxying, caching, load balancing, SSL, and more. To set it up on ChirpStack Docker, add the following section to docker-compose.yml:
nginx:
image: nginx:latest
container_name: chirpstack_nginx
restart: always
volumes:
- './logs/nginx:/var/log/nginx'
- './configuration/nginx.conf:/etc/nginx/conf.d/default.conf'
ports:
- 80:80
- 443:443
depends_on:
- chirpstack
networks:
- iot-network
and then create a new file called nginx.conf under the configuration directory, with the following content:
upstream chirpstack_upstream {
server chirpstack:8080;
}
server {
listen 80;
server_name _;
location ^~ /api {
grpc_pass grpc://chirpstack_upstream;
}
location / {
proxy_pass http://chirpstack_upstream;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_redirect off;
}
}