This guide shows an example of configuring The Things Stack using configuration files, with an example domain thethings.example.com
and TLS certificates from Let’s Encrypt.
If configuring The Things Stack as localhost
on a machine with no public IP or DNS address, see the localhost
section.
In addition to the written instructions below, video instructions for installing The Things Stack are available on The Things Network youtube channel.
Show video
Configuration Files
The Things Stack requires two configuration files when installing with Docker: docker-compose.yml
and ttn-lw-stack-docker.yml
. The files are provided below:
Download the example docker-compose.yml
for The Things Stack Enterprise here.
Download the example ttn-lw-stack-docker.yml
for The Things Stack Enterprise here.
Download the example docker-compose.yml
for The Things Stack Open Source here.
Download the example ttn-lw-stack-docker.yml
for The Things Stack Open Source here.
Create the following folder structure with docker-compose.yml
and ttn-lw-stack-docker.yml
:
docker-compose.yml # defines Docker services for running The Things Stack
config/
└── stack/
└── ttn-lw-stack-docker.yml # configuration file for The Things Stack
Make sure you replace the example server address thethings.example.com
in ttn-lw-stack-docker.yml
with the address of your deployment. The easiest way to do this is to use the search and replace function in your preferred code editor.
Next, proceed to the instructions below on how to change additional settings for production deployments.
Configuration Files Explained
docker-compose.yml
docker-compose.yml
defines the Docker services of The Things Stack and its dependencies, and is used to configure Docker.
ttn-lw-stack-docker.yml
ttn-lw-stack-docker.yml
contains the configuration specific to The Things Stack deployment and is used to configure The Things Stack. When The Things Stack starts, it searches through ttn-lw-stack-docker.yml
for component server addresses, a TLS certificate source, client authentication credentials, and other configuration parameters.
The configuration options in ttn-lw-stack-docker
can also be specified using command-line flags or environment variables. All configuration options have a corresponding environment variable and command-line flag. See the Configuration Reference for more information about the configuration options.
Settings in docker-compose.yml
and ttn-lw-stack-docker.yml
files are explained in detail in Understanding Docker Configuration and Understanding The Things Stack Configuration sections below. Further, we provide tips for running The Things Stack in production.
Understanding Docker Configuration
In this section, configuring Docker is explained with an example docker-compose.yml
file.
Docker runs an instance of The Things Stack, as well as an SQL database and a Redis database. The Things Stack components are inherently stateless and depend on the underlying SQL and Redis databases to store data.
Note:
For high deployment availability, it is recommended to set up redundancy in above mentioned databases.In docker-compose.yml
file, Docker is configured to run three services:
- PostgreSQL database
- Redis
- The Things Stack
PostgreSQL Database
The configuration in this guide uses a single instance of PostgreSQL. Note that the volumes
need to be set up correctly so that the database is persisted on your server’s disk.
In production, replace the image
with a working, stable tag from Docker Hub - TimescaleDB.
The simplest configuration for PostgreSQL looks like this (excerpted from the example docker-compose.yml
):
|
|
Note:
Alternatively, you can use a managed TimescaleDB database, like Timescale Cloud. In that case, make sure to configure the Identity Server, Application Server and Network Operations Center databases.In production, replace the image
with a working, stable tag from Docker Hub - Postgres.
The simplest configuration for PostgreSQL looks like this (excerpted from the example docker-compose.yml
):
|
|
Note:
Alternatively, you can use a managed PostgreSQL database. In that case, make sure to configure the Identity Server database.Redis
The configuration in this guide uses a single instance of Redis. Again, note that the volumes
need to be set up correctly so that the datastore is persisted on your server’s disk.
Note:
The Things Stack requires Redis version 6.2.In production, replace the image
with a working, stable tag from Docker Hub - Redis.
It is also possible (and even preferred) to use a managed Redis database. In this case, you will need to configure the managed database address with the redis-address
configuration option or TTN_LW_REDIS_ADDRESS
environment variable.
The simplest configuration for Redis looks like this (excerpted from the example docker-compose.yml
):
|
|
The Things Stack
After starting the PostgreSQL and Redis databases, Docker Compose starts The Things Stack.
Entrypoint and Dependencies
Docker Compose uses ttn-lw-stack -c /config/ttn-lw-stack-docker.yml
as the container entry point, so that ttn-lw-stack-docker.yml
configuration file is always loaded (more on the config file below).
In production, replace the image
with a working, stable tag from Docker Hub - The Things Industries for Enterprise, or Docker Hub - The Things Network for Open Source.
The default command is start
, which starts The Things Stack.
|
|
The depends_on
field tells Docker Compose that The Things Stack depends on PostgreSQL and Redis. With this, Docker Compose will wait for PostgreSQL and Redis to come online before starting The Things Stack.
|
|
Note:
If using a managed SQL or Redis database, these can be removed fromdepends_on
and the services do not need to be started in Docker.
Volumes
Under the volumes
section, volumes for the files that need to be persisted on the disk are defined. There are stored blob files (such as profile pictures) and certificate files retrieved with ACME (if required). Also, local ./config/stack/
directory is mounted on the container under /config
, so that The Things Stack can find the configuration file at /config/ttn-lw-stack-docker.yml
.
|
|
Note:
If yourttn-lw-stack-docker.yml
is in a directory other than ./config/stack
, you will need to change this volume accordingly.
Environment and Ports
The databases used by The Things Stack are configured in the environment
section. In this guide, these are set to the PostgreSQL and Redis instances that are mentioned above.
Note:
If using managed databases, theenvironment
ports need to be changed to the ports of the managed databases.
The ports
section exposes The Things Stack’s ports outside the Docker container. Port 80
and 443
are mapped to the internal HTTP and HTTPS ports. The other ports have a direct mapping. If you don’t need support for gateways and applications that don’t use TLS, you can remove ports starting with 188
:
|
|
Note:
Be sure to provide network access to these ports on the machine you are running The Things Stack.Understanding The Things Stack Configuration
Configuration options for running The Things Stack are specified in the ttn-lw-stack-docker.yml
file. This section points out the required configuration options.
The example ttn-lw-stack-docker.yml
file for The Things Stack Enterprise shown below contains details which help you follow this section. The example ttn-lw-stack-docker.yml
file is also available for download in the Example Configuration Files section.
Example ttn-lw-stack-docker.yml file
|
|
License
The Things Stack Enterprise requires a license, which can be purchased at the products page. This is specified in the license
field, and can be either a key
string, or a file
path. See the License configuration reference for more information.
|
|
The Things Stack sends emails to users, so the email
section of the configuration defines how these are sent.
You can use Sendgrid or an SMTP server. For development purposes, you can use the dir
provider that writes emails to a directory.
If you skip setting up an email provider, The Things Stack will print emails to the stack logs.
|
|
HTTP
In the http
section, HTTP server keys for encrypting and verifying cookies are configured, as well
as passwords for endpoints that you may want to keep for the internal use.
|
|
TLS
This example shows the configuration for using TLS with Let’s Encrypt. Since The Things Stack is being deployed on
thethings.example.com
in this guide, it is configured to only request certificates for that
host, and also to use it as the default host.
If using Let’s Encrypt, certificates will automatically be requested the first time you access The Things Stack. You will notice that the page takes some time to load while certificates are obtained in the background.
See the TLS Options configuration reference for more information.
Make sure that you use the correct tls
configuration depending on whether you are using Let’s Encrypt or your own certificate files.
If you are using your own certificate files, make sure to uncomment the lines that define source
type, root-ca
, certificate
and key
. The paths assigned to these do not need to be altered, because they point to the location of these files inside the Docker container, and not on your machine.
|
|
If you are using Let’s Encrypt in a multi-tenant The Things Stack environment, all tenant addresses have to be specified in the ttn-lw-stack-docker.yml
file using tls.acme.hosts
configuration option with *.thethings.example.com
wildcard.
|
|
Console Component URLs
The console
section configures the URLs for the Web UI and the secret used by the console client. These tell The Things Stack where all its components are accessible. Be sure to replace these, and all the other server addresses, with yours.
|
|
Warning:
Failure to correctly configure component URLs is a common problem that will prevent the stack from starting. Be sure to replace all instances ofthethings.example.com
with your domain name!
The client-secret
will be needed later when authorizing the Console. Be sure to set and remember it!
|
|
NOC
The noc
section configures the Network Operations Center.
Besides ui
and oauth
settings, storage settings need to be configured in the store
section. If you’re using Postgres read replicas to offload read requests or analytics traffic from the primary Postgres instance, you can configure it using the read-database-uri
. You’re also able to configure the batch window and size, as well as to set the retention period for raw data.
To authorize the NOC, be sure to set and remember the client secret.
|
|
To visualize data, configure the grafana
section.
|
|
Multi-tenancy
If running a multi-tenant environment, we need to configure the default tenant ID, and the base domain from which tenant IDs are inferred. See the tenancy
configuration reference.
|
|
For multi-tenant environments you’ll also need to configure tenant admin keys:
|
|
Next Step - Certificates
Once you have configured docker-compose.yml
and ttn-lw-stack-docker.yml
as shown in the instructions above, continue on to the Certificates section.
Running The Things Stack as localhost
Follow this section if you are configuring and running The Things Stack on a local machine with no public IP or DNS address.
In addition to the written instructions below, video instructions for installing on localhost
are available on The Things Network youtube channel.
Show video
localhost
has a different meaning on your machine than inside the Docker container where The Things Stack runs, which can cause problems if you use localhost
in your configuration.
localhost
addresses on your machine will resolve to your machine, while localhost
inside the Docker container will resolve inside the Docker container. In docker-compose.yml
, we forward requests on ports 80 and 443 to ports 1885 and 8885 inside the container, so visiting localhost
(which is really localhost:80
) on your machine actually takes you to localhost:1885
within the container.
If you configure your is.oauth.ui.canonical-url
as localhost
, this causes Token Exchange Refused errors when you try to log in to The Things Stack Console, because an authorization request generated from within the container will not be redirected to port 1885 or 8885, where The Things Stack is listening.
Solution 1: Use the IP address of your computer on your local network
The best solution is to configure and use a static IP address for your machine on your local network so that redirects from your machine, from the Docker container, or from anywhere inside your local network, all resolve at the same place, on your machine.
Follow instructions here for configuring a static IP address on your computer. Use that IP address as your server address, i.e replace thethings.example.com
with that IP address. You may also generate a self-signed certificate for that IP address by following instructions in the Certificates section.
Note:
ACME will not work onlocalhost
, so you must either generate custom certificates for your IP address as shown in the Custom Certificate Authority instructions, or use http
(unsecure) in your configuration.
This will still allow you to see The Things Stack Console by entering localhost
or your local IP address in your browser. It will also allow you to connect to The Things Stack from any machine inside your local network.
You will also need to configure the CLI, to use the static IP of your machine as the address of The Things Stack.
Solution 2: Specify the internal ports that The Things Stack listens on in your configuration files
By default, The Things Stack listens on ports 1885 and 8885 inside Docker. To make localhost
work both on your local machine and within the Docker container, append the port to localhost
and make sure port forwarding is enabled in your docker-compose.yml
for that port.
You must also remove ports 80 and 443 from your The Things Stack Docker configuration.
For example,
is:
oauth:
ui:
canonical-url: 'https://thethings.example.com/oauth'
is:
base-url: 'https://thethings.example.com/api/v3'
becomes
is:
oauth:
ui:
canonical-url: 'https://localhost:8885/oauth'
is:
base-url: 'https://localhost:8885/api/v3'
and in docker-compose.yml
, add the following port forwarding configuration (if it does not already exist), while removing ports 80 and 443:
services:
stack:
ports:
- "1885:1885"
- "8885:8885"
# - "80:80" # Do not forward port 80
# - "443:443" # Do not forward port 443
This will result in visits from both outside and inside the Docker container being received at the correct port by The Things Stack.