Initial setup

The BlueRange server and additional services required for logging, updating and monitoring are installed from the setup package available at BlueRange Setup@GitHub. Following is a walk-through of the installation steps outlined in the Readme.

Clone the setup

The installation files are downloaded:

$ cd /opt
$ sudo git clone
Cloning into 'bluerange-setup'...
$ cd bluerange-setup/docker

Further steps are carried out in the folder /opt/bluerange-setup/docker.

Configuring the server

Edit the configuration file:

$ hostname
$ pwd
$ sudo editor server.env

The server.env file consists of a number of KEY=VALUE pairs. As a minimum the hostname must be set as HOST variable. Ideally the server properly displays its name:[1]

$ hostname --all-fqdns localhost.localdomain
$ hostname --fqdn

The name given as e.g. must match the server certificate.

Check if the host is reachable by its name. Ping the host, for example, 'ping'. On local machines it can sometimes happen that the shown hostname is not part of your (local) DNS. In this case use the ip address instead (for test installations only).

For some features like requesting a password reset the server requires access to an SMTP email server:

The SMTP configuration is recommended but not strictly required. When omitted features depending on it may not be available.

By default, the installation picks up the passwords defined in the .env file:

$ cat .env

Please keep the COMPOSE_PROJECT_NAME as is. The remaining passwords should be overwritten in the server.env. Passwords may be generated using the command:

$ pwgen -snc 48 5
The file uses shell escaping so that special characters in passwords may need to be escaped!

The minimal server.env file should look like this:

$ sudo cat server.env
Except the organization administrator’s password these passwords do not need to be entered by a human so there is no reason to use weak passwords.

The SYSTEM_ADMIN_PASSWORD=admin123 and ORGA_ADMIN_PASSWORD=iot12345 are used for initialization only and may be changed at any time later on in the UI of the server. The MINIO_ACCESS_KEY=mender-deployments may be chosen arbitrarily and need not be changed.

Configure certificates

The installation expects the following certificate-related files to be provided:

  • server.pem: certificate used for HTTPS which must match the HOST variable setting being the host machine name registered with DNS

  • server.key: private key for issuing the HTTPS certificate

  • ca.pem: additional CA certificate(s) used for signing the server.pem so that all of those PEMs form a full chain of trust

For using self-signed certificates the command discussed below provides provisioning that commences automatically when the certificate files above are not found. Following is a walk-through of the self-signed certificate provisioning process for demonstration purposes only that should be skipped when using your own certificates:

$ sudo ./
$ openssl genrsa -out ca.key 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
e is 65537 (0x010001)
$ openssl req -new -x509 -key ca.key -out ca.crt
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
Country Name (2 letter code) [XX]:DE
State or Province Name (full name) []:Germany
Locality Name (eg, city) [Default City]:Stuttgart
Organization Name (eg, company) [Default Company Ltd]:M-Way Solutions GmbH
Organizational Unit Name (eg, section) []:BlueRange
Common Name (eg, your name or your server's hostname) []:CA
Email Address []:
$ openssl x509 -in ca.crt -out ca.pem
$ openssl req -new -out cert.csr -config cert.conf
Generating a RSA private key
writing new private key to 'cert.key'
$ openssl ca -config ca.conf -extfile cert.conf -out cert.crt -infiles cert.csr
Using configuration from ca.conf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName           :PRINTABLE:'DE'
stateOrProvinceName   :ASN.1 12:'Germany'
localityName          :ASN.1 12:'Stuttgart'
organizationName      :ASN.1 12:'M-Way Solutions GmbH'
organizationalUnitName:ASN.1 12:'BlueRange'
commonName            :ASN.1 12:''
Certificate is to be certified until Apr  8 07:31:10 2022 GMT (365 days)
Sign the certificate? [y/n]:y

1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
$ openssl x509 -in newcerts/01.pem -out cert.pem
$ openssl verify -CAfile ca.crt cert.crt
cert.crt: OK
$ openssl rsa -inform PEM -in server.key -out server.rsa
writing RSA key

The certificate files generated are:

$ cat ca.pem
$ cat server.pem
$ cat server.key

The use of self-signed certificates is strongly discourages as it requires installation of the ca.pem CA certificate as a root certification authority on every client connecting to the server, incl. the BlueRange App and BlueRange Gateways.

The auto-provisioning above serves demonstration purposes only. If you already ran the commands above, in order to use your own certificates, firstly clean up the files created above:

$ sudo rm -rf ca.* cert.* serial* fullchain.pem newcerts anchors/* server.pem server.key server.rsa index.txt*

Now place the files ca.pem, server.pem and server.key in X.509 PEM format as shown above. Notice, the server.rsa and fullchain.pem files are generated by the script on first startup automatically for you.

Start BlueRange

This compose file defines the services: bluerange, database, mongodb, nginx, mosquitto, nodered, prometheus and grafana. The nodered service serves as an example of an IoT add-on middleware service and may be removed for production purposes.

To start BlueRange you can now use to start all the Docker containers defined in the yaml file:

$ sudo ./
-> docker-compose -p bluerange -f docker-compose.yml -f docker-compose.elasticsearch.yml -f docker-compose.mender.yml up -d
Creating network "bluerange_default" with the default driver
Creating volume "bluerange_mysql" with default driver
Creating volume "bluerange_mongodb" with default driver
Creating volume "bluerange_nodered" with default driver
Creating volume "bluerange_elasticsearch" with default driver
Creating volume "bluerange_redis" with default driver
Creating volume "bluerange_mender-artifacts" with default driver
Pulling mender-gui (mendersoftware/gui:1.7.0)...
Pulling elasticsearch (amazon/opendistro-for-elasticsearch:1.1.0)...
Pulling database (mariadb:10.4.8)...
Pulling minio (minio/minio:RELEASE.2018-09-25T21-34-43Z)...
Pulling mongodb (mongo:latest)...
Pulling bluerange (bluerange/bluerange:latest)...
Pulling mosquitto (relution/relution-mosquitto:latest)...
Pulling nginx (nginx:latest)...
Creating bluerange_database_1      ... done
Creating bluerange_mongodb_1       ... done
Creating bluerange_bluerange_1          ... done
Creating bluerange_mosquitto_1          ... done
Creating bluerange_nginx_1              ... done

-> mender-useradm$ useradm create-user --password=admin123

    BlueRange:  (admin / admin123)
       Mender:  ( / admin123)
      Grafana: (admin / admin123)
       Kibana: (admin / admin)
        Minio: (mender-deployments / cSfn7EzlD1UWXJd9ugJYM2UaLE7tBtHzVaZzxunKjM2pNFFS)
ElasticSearch: (admin / admin)

This will download the Docker image of each service defined in the docker-compose.yml file before starting a Docker container for each service. Images are cached on the local machine, so future starts will be faster.

The compose files force using as a replacement of docker-compose. Running docker-compose directly will not work and issue an error instead.

It will take some time for the services to start up once the downloads complete. To see the log output of a specific container use the following command:

$ sudo ./ logs --follow bluerange
Attaching to bluerange_bluerange_1
bluerange_1 Certificate was added to keystore
bluerange_1 Temp directory does not exist. It will be created.
bluerange_1 Expected configuration found in './application.yml' or environment variables
bluerange_1  ________  ___       ___  ___  _______   ________  ________  ________   ________  _______           ___  ___  ___
bluerange_1 |\   __  \|\  \     |\  \|\  \|\  ___ \ |\   __  \|\   __  \|\   ___  \|\   ____\|\  ___ \         |\  \|\  \|\  \
bluerange_1 \ \  \|\ /\ \  \    \ \  \\\  \ \   __/|\ \  \|\  \ \  \|\  \ \  \\ \  \ \  \___|\ \   __/|        \ \  \ \  \ \  \
bluerange_1  \ \   __  \ \  \    \ \  \\\  \ \  \_|/_\ \   _  _\ \   __  \ \  \\ \  \ \  \  __\ \  \_|/__       \ \  \ \  \ \  \
bluerange_1   \ \  \|\  \ \  \____\ \  \\\  \ \  \_|\ \ \  \\  \\ \  \ \  \ \  \\ \  \ \  \|\  \ \  \_|\ \       \/  /\/  /\/  /|
bluerange_1    \ \_______\ \_______\ \_______\ \_______\ \__\\ _\\ \__\ \__\ \__\\ \__\ \_______\ \_______\      /  ///  ///  //
bluerange_1     \|_______|\|_______|\|_______|\|_______|\|__|\|__|\|__|\|__|\|__| \|__|\|_______|\|_______|     /_ ///_ ///_ //
bluerange_1                                                                                                    |__|/|__|/|__|/

The log output can be stopped by pressing Ctrl-C.

After first startup, please check your container is all fine by rerunning the command. The command will retry restarting any failed containers. If all is well no container should be restarted:

$ sudo ./
$ docker-compose -p bluerange -f docker-compose.yml -f docker-compose.elasticsearch.yml -f docker-compose.mender.yml up -d
bluerange_elasticsearch_1 is up-to-date
bluerange_mongodb_1 is up-to-date
bluerange_minio_1 is up-to-date
bluerange_mender-redis_1 is up-to-date
bluerange_database_1 is up-to-date
bluerange_mender-gui_1 is up-to-date
bluerange_logagent_1 is up-to-date
bluerange_kibana_1 is up-to-date
bluerange_mender-useradm_1 is up-to-date
bluerange_mender-inventory_1 is up-to-date
bluerange_mender-device-auth_1 is up-to-date
bluerange_mender-deployments_1 is up-to-date
bluerange_mender-conductor_1 is up-to-date
bluerange_bluerange_1 is up-to-date
bluerange_mosquitto_1 is up-to-date
bluerange_nginx_1 is up-to-date
bluerange_mender-api-gateway_1 is up-to-date

mender-useradm$ useradm create-user --password=admin123
creating user failed: user with a given email already exists

    BlueRange:  (admin / admin123)
       Mender:  ( / admin123)
       Kibana: (admin / admin)
        Minio: (mender-deployments / cSfn7EzlD1UWXJd9ugJYM2UaLE7tBtHzVaZzxunKjM2pNFFS)
ElasticSearch: (admin / admin)

In case of any failed container, try the log command above to find out why things went wrong. A common source of issues is in DNS and HTTPS certificates which can be checked for validity, e.g.:

$ openssl s_client -connect
depth=1 C = DE, ST = Germany, L = Stuttgart, O = M-Way Solutions GmbH, OU = BlueRange, CN = CA
verify error:num=19:self signed certificate in certificate chain
verify return:1
depth=1 C = DE, ST = Germany, L = Stuttgart, O = M-Way Solutions GmbH, OU = BlueRange, CN = CA
verify return:1
depth=0 C = DE, ST = Germany, O = M-Way Solutions GmbH, OU = BlueRange, CN =
verify return:1
Certificate chain
 0 s:C = DE, ST = Germany, O = M-Way Solutions GmbH, OU = BlueRange, CN =
   i:C = DE, ST = Germany, L = Stuttgart, O = M-Way Solutions GmbH, OU = BlueRange, CN = CA
 1 s:C = DE, ST = Germany, L = Stuttgart, O = M-Way Solutions GmbH, OU = BlueRange, CN = CA
   i:C = DE, ST = Germany, L = Stuttgart, O = M-Way Solutions GmbH, OU = BlueRange, CN = CA
Server certificate
subject=C = DE, ST = Germany, O = M-Way Solutions GmbH, OU = BlueRange, CN =

issuer=C = DE, ST = Germany, L = Stuttgart, O = M-Way Solutions GmbH, OU = BlueRange, CN = CA

No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Server Temp Key: X25519, 253 bits
SSL handshake has read 2587 bytes and written 406 bytes
Verification error: self signed certificate in certificate chain
New, TLSv1.2, Cipher is ECDHE-RSA-AES128-GCM-SHA256
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES128-GCM-SHA256
    Session-ID: F63586BD4D75D65DF7FC1154AEB7440AE588488925F86B2FFC960BBD91B16331
    Master-Key: 899DA4E9386093FC55064056A2D5BD48468CBA2C6DADA798AF437B4C572C45A1D83E1EDB132CECA0136F1BEFE3029AC0
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket lifetime hint: 300 (seconds)
    TLS session ticket:
    0000 - ce 31 29 2f 28 04 3a 69-02 ca 8e 36 27 c3 45 6d   .1)/(.:i...6'.Em
    00b0 - ef 08 99 63 09 61 a6 43-ab 81 d8 43 12 dc 05 5a   ...c.a.C...C...Z

    Start Time: 1617874016
    Timeout   : 7200 (sec)
    Verify return code: 19 (self signed certificate in certificate chain)
    Extended master secret: yes

As can be seen from the output above, the self-signed certificate from the previous chapter is in use. For a public certificate the return code reported should be 0, of course. The SSL check can be done for each of the services listed by as all of them are set up to TLS.

As a final check of the BlueRange server the health status can be queried:

$ curl --cacert ca.pem

The health status endpoint is available for integration into monitoring systems.

When fetching the health status providing server administrator credentials using basic-auth or an api-key further details are made available.

As a last step in server installation rebooting the host machine is recommended ensuring a properly configured networking environment and that all the services come up automatically.

Stopping the server

For maintenance, it might become necessary to stop all the services temporarily. This can be done by shutting down the composition without destroying volumes:

$ sudo ./ down
Stopping bluerange_nginx_1              ... done
Stopping bluerange_mosquitto_1          ... done
Stopping bluerange_bluerange_1          ... done
Stopping bluerange_mongodb_1            ... done
Stopping bluerange_database_1           ... done
Removing bluerange_nginx_1              ... done
Removing bluerange_mosquitto_1          ... done
Removing bluerange_bluerange_1          ... done
Removing bluerange_mongodb_1            ... done
Removing bluerange_database_1           ... done
Removing network bluerange_default

This will not remove the downloaded images and preserves database data.

When you shut down a Docker container, data inside the container is potentially lost. This means data that needs to be persisted must be stored outside the container (e.g. on a mounted volume). The default configuration maps the data directories of MariaDB and MongoDB to Docker volumes named mysql and mongodb respectively.

BlueRange stores all of its data in the database, so no additional configuration should be needed. Make sure to include MariaDB and MongoDB in your backup strategy though.

1. In case hostname --fqdn does not display the correct hostname, chances are that DNS is not set up correctly.