This document is a guide for setting up The Things Network's routing services in a local or private environment. If you already have some knowledge about how the backend works and if you are comfortable with a command line, this is the perfect place to start.
In this guide we will get everything up and running on your local machine (on
localhost). We will rely on the community account server of The Things Network (
account.thethingsnetwork.org) so that you can use your TTN Account to manage devices in your local network. If you don't want your environment to use community accounts, you can implement your own account server that is compliant with the Account Server API Specification.
- Install and start Redis.
- Install and start Mosquitto
- Create a working directory. In this document we will use
~/ttn. All commands are executed from this directory.
masterbranch) macOS, 64 bit Linux, 32 bit Linux or arm Linux.
masterbranch) for macOS, 64 bit Linux, 32 bit Linux or arm Linux. We did not test this guide on Windows, but that might work too :)
The Discovery Server
The configuration for the Discovery server will be stored in
id: mynetwork-discovery tls: true key-dir: discovery/ auth-servers: ttn-account-v2: "https://account.thethingsnetwork.org" local: "file://discovery/server.pub" discovery: master-auth-servers: - ttn-account-v2 - local
This configuration creates a discovery server called "mynetwork-discovery". The server will use TLS and get its keys from
./discovery. It uses the public TTN account server and a local certificate for authentication, and both "account servers" are seen as "master servers".
With this configuration in place, we will generate the public/private keypair for the Discovery server:
$ ttn discovery gen-keypair --config ./discovery/ttn.yml
Since we use TLS, we need to create a certificate for
$ ttn discovery gen-cert localhost --config ./discovery/ttn.yml
You can now start the discovery server:
$ ttn discovery --config ./discovery/ttn.yml
Keep the discovery server running while you set up the other components.
Routers, Brokers and Handlers authenticate with the discovery server using "access tokens". In the public community network you could get those with the command
ttnctl components token [router/broker/handler] [id], but as we're building a private network, we have to manually create these access tokens with the command
ttn discovery authorize [router/broker/handler] [id]. For the Router you would use the following command:
ttn discovery authorize router mynetwork-router --config ./discovery/ttn.yml
You can use the access token that is printed to your console in the router's configuration. Use the appropriate commands to do the same for the Broker and Handler.
The configuration for the Router will be stored in
id: mynetwork-router tls: true key-dir: router/ auth-servers: ttn-account-v2: "https://account.thethingsnetwork.org" discovery-address: "localhost:1900" auth-token: THE DISCOVERY ACCESS TOKEN THAT YOU GENERATED FOR THE **ROUTER** router: server-address-announce: localhost skip-verify-gateway-token: true
This configuration creates a router called "mynetwork-router". The server will use TLS and get its keys from
./router. It uses the public TTN account server for authentication. It connects to the discovery server on
localhost and uses the access token we just generated to authenticate with the discovery server. The Router announces itself as being on the
localhost address. Furthermore it skips verification of the gateway token, because we're in a private network. You can remove this line if you do want to verify gateway tokens.
Just like with the discovery server, we have to generate a public/private keypair and a TLS certificate:
ttn router gen-keypair --config ./router/ttn.yml ttn router gen-cert --config ./router/ttn.yml
In this case we don't have to specify that we're running on
localhost when generating the certificate. The command will just take that from the configuration file.
The TLS certificate we generated for the discovery server is not trusted by the operating system, so we have to manually trust it. To do so, we can append it to a
ca.cert file in the
cat discovery/server.cert > router/ca.cert
You will have to do the same when you set up the Broker and Handler.
You can now test your configuration by starting the Router:
$ ttn router --config ./router/ttn.yml
The configuration for the NetworkServer will be stored in
id: mynetwork-networkserver tls: true key-dir: networkserver/ auth-servers: ttn-account-v2: "https://account.thethingsnetwork.org"
Again we have to generate a public/private keypair and a TLS certificate:
ttn networkserver gen-keypair --config ./networkserver/ttn.yml ttn networkserver gen-cert --config ./networkserver/ttn.yml
Brokers authenticate with the NetworkServer using access tokens. You can create an access token with the following command:
ttn networkserver authorize mynetwork-broker --config ./networkserver/ttn.yml
The configuration for the Broker will be stored in
id: mynetwork-broker tls: true key-dir: broker/ auth-servers: ttn-account-v2: "https://account.thethingsnetwork.org" discovery-address: "localhost:1900" auth-token: THE DISCOVERY ACCESS TOKEN THAT YOU GENERATED FOR THE **BROKER** broker: server-address-announce: localhost networkserver-cert: broker/networkserver.cert networkserver-token: THE NETWORKSERVER ACCESS TOKEN THAT YOU GENERATED
The TLS certificate we generated for the discovery server and the NetworkServer are not trusted by the operating system, so we have to manually trust them. For the discovery server, we'll do the same as in the Router, for the NetworkServer, we can append the certificate to the
ca.cert file or we can copy the NetworkServer's certificate and set the
networkserver-cert in the configuration to
broker/networkserver.cert. We will do the latter.
cat discovery/server.cert > broker/ca.cert cp networkserver/server.cert broker/networkserver.cert
Again we have to generate a public/private keypair and a TLS certificate:
ttn broker gen-keypair --config ./broker/ttn.yml ttn broker gen-cert --config ./broker/ttn.yml
Now we will tell the discovery server which
DevAddr prefix we will handle with this Broker. In this case, we use a prefix that TTN reserved for private networks:
26000000/20. This prefix allows you to issue 4096 distinct addresses to devices in your private network, which should be more than enough (remember that device addresses are not unique; you can easily give 100 devices the exact same address). If you need a larger address space, you should file a request with The Things Network Foundation. If you are setting up a large network, you might have to apply for your own NetID from the LoRa Alliance, which will give you your own prefix.
ttn broker register-prefix 26000000/20 --config ./broker/ttn.yml
The configuration for the Handler will be stored in
id: mynetwork-handler tls: true key-dir: handler/ auth-servers: ttn-account-v2: "https://account.thethingsnetwork.org" discovery-address: "localhost:1900" auth-token: THE DISCOVERY ACCESS TOKEN THAT YOU GENERATED FOR THE **HANDLER** handler: server-address-announce: localhost broker-id: mynetwork-broker mqtt-address: localhost:1883
Again we have to copy the discovery server certificate and generate a public/private keypair and a TLS certificate:
cat discovery/server.cert > handler/ca.cert ttn handler gen-keypair --config ./handler/ttn.yml ttn handler gen-cert --config ./handler/ttn.yml
TTN's backend components communicate using gRPC. Gateways, use different protocols, which are translated to gRPC with so-called bridges. The widely used
packet_forwarder protocol is handled by the
gateway-connector-bridge. If you followed this guide from the start, you should already have the correct version.
Unfortunately, this bridge does not support configuration files, so we will use CLI flags to configure it. We still need to have the discovery server certificate, so let's create an empty directory for the bridge and copy the discovery server certificate to the
cat discovery/server.cert > bridge/ca.cert
We will need the following command line arguments to connect the bridge to your private backend:
--ttn-discovery-server "localhost:1900" --root-ca-file "bridge/ca.cert" --ttn-router "mynetwork-router"
Starting Everything Together
Just run each of the following commands in separate tabs:
ttn discovery --config discovery/ttn.yml ttn router --config router/ttn.yml ttn networkserver --config networkserver/ttn.yml ttn broker --config broker/ttn.yml ttn handler --config handler/ttn.yml gateway-connector-bridge --root-ca-file "bridge/ca.cert" --ttn-router "localhost:1900/mynetwork-router"
You can also use a
Procfile as shown below and use (for example)
forego to start everything.
dsc: ttn discovery --config discovery/ttn.yml rtr: ttn router --config router/ttn.yml ns: ttn networkserver --config networkserver/ttn.yml brk: ttn broker --config broker/ttn.yml hdl: ttn handler --config handler/ttn.yml br: gateway-connector-bridge --root-ca-file "bridge/ca.cert" --ttn-router "localhost:1900/mynetwork-router"
ttnctl is done by editing
discovery-address: localhost:1900 mqtt-address: localhost:1883 router-id: mynetwork-router handler-id: mynetwork-handler
ttnctl also needs to have the discovery server certificate, for that we have to create a
ca.cert file in
touch ~/.ttnctl/ca.cert cat discovery/server.cert >> ~/.ttnctl/ca.cert
Now you can register your application to your private Handler:
ttnctl applications register
And manage your devices in the same way as you would do on the public community network.
Questions or Issues
If you have questions or remarks after following this guide, feel free use the forum or the
#private-backend channel on Slack. This is a community-supported guide, so please help each other out.
You should now have a fully operational private backend. Now you should probably do some of the following:
- Read how to deploy the private backend using docker-compose
- Periodically update
ttnto the latest version
- Enable persistence in Redis
- Configure backups
- Secure your MQTT/AMQP broker with usernames and passwords
- Help with development of TTN's open source routing services