Skip to main content

Deploying Chariot with Docker

Overview​

This page explains how to deploy Chariot using the official Docker image. By the end of this tutorial, you will have a running Chariot instance and understand how to configure it for your environment, from a quick local test to a production deployment with TLS and managed licensing.

Prerequisites​

Before you start, make sure you have:

  • Docker Engine 20.10+ or Docker Desktop installed and running.
  • Docker Compose v2 if you plan to use a Compose file. Docker Compose is recommended for anything beyond a quick test.
  • Network access to pull the Chariot image from Docker Hub.
  • A valid Chariot license key or license server address for production deployments. The image can be started without a license for evaluation purposes.
  • Outbound internet access from the container host if you are using online license activation.

How Configuration Works​

Chariot configuration is applied once, automatically, during the first startup of the container. The configure.sh script runs in the background alongside the Chariot process and applies configuration through the Chariot REST API.

A sentinel file at /Chariot/config-state/state.json records which configuration steps have completed. On subsequent restarts, completed steps are skipped.

Important: Changing an environment variable after the initial startup does not re-apply the corresponding configuration step. To apply a changed value, you must reset the relevant step in the sentinel file. See Re-applying configuration.

Configuration Order​

Configuration is applied in the following order:

  1. Accept EULA.
  2. Restore a backup, if BACKUP_FILE is set.
  3. Set the admin password.
  4. Activate the license.
  5. Apply MQTT server configuration.
  6. Upload IBSnow certificates.
  7. Create IBSnow servers.
  8. Apply IBSnow configuration.
  9. Create MQTT users.
  10. Configure TLS/SSL.
  11. Apply system configuration, including the server name and ports.

Backup and Environment Variable Precedence​

Backups are restored before the remaining configuration steps are applied. Environment variables applied afterward take precedence over settings restored from the backup.

For example, if the backup contains a different admin password, set ADMIN_PASSWORD to ensure you can log in after the restore.

ACCEPT_EULA=true is required for configuration. If this variable is not set to true, the configuration script exits immediately and no configuration is applied. The container starts with factory defaults only.

Quick Start: Running Chariot Locally​

The following command starts a Chariot instance suitable for local testing. This configuration is not recommended for production.

docker run -d \
--name chariot \
-p 8080:8080 \
-p 1883:1883 \
-e ACCEPT_EULA=true \
-e ADMIN_PASSWORD=mypassword \
cirruslink/chariot:latest

Once the container starts, wait approximately 60 seconds for Chariot to initialize, then open http://localhost:8080 in your browser.

Log in with:

  • Username: admin
  • Password: The value specified for ADMIN_PASSWORD

Important: If ADMIN_PASSWORD is not set, the default credentials (admin / password) remain active. Change the default password on any network-accessible instance before connecting devices.

To follow the configuration log as it runs:

docker logs -f chariot

Configuration log lines are prefixed with [configure.sh]. A successful configuration run ends with:

[configure.sh] Configuration complete. Logged out.

Production Deployment​

For production deployments, use Docker Compose with an .env file to keep configuration values out of the Compose file.

Step 1: Create the .env File​

Create a copy of the provided .env.example file:

cp .env.example .env

Edit .env and populate at minimum:

IMAGE_TAG=latest
ACCEPT_EULA=true
ADMIN_PASSWORD=your-strong-password-here

Important: Never commit your .env file to version control if it contains passwords or license keys.

Step 2: Create the Docker Compose File​

Create a docker-compose.yml file:

services:
chariot:
image: cirruslink/chariot:${IMAGE_TAG}
ports:
- "8080:8080" # HTTP Web UI and REST API
- "8443:8443" # HTTPS Web UI and REST API
- "1883:1883" # MQTT
- "8883:8883" # MQTT over TLS
- "8090:8090" # MQTT over WebSocket
- "8091:8091" # MQTT over Secure WebSocket
environment:
ACCEPT_EULA: "${ACCEPT_EULA}"
ADMIN_PASSWORD: "${ADMIN_PASSWORD}"
LICENSE_TYPE: "${LICENSE_TYPE:-}"
LICENSE_KEY: "${LICENSE_KEY:-}"
LICENSE_SERVER: "${LICENSE_SERVER:-}"
LICENSE_PRODUCT: "${LICENSE_PRODUCT:-}"
SERVER_CONFIG: "${SERVER_CONFIG:-}"
MQTT_USERS: "${MQTT_USERS:-}"
SETUP_SSL: "${SETUP_SSL:-}"
TLS_PRIVATE_KEY: "${TLS_PRIVATE_KEY:-}"
TLS_CERTIFICATE: "${TLS_CERTIFICATE:-}"
TLS_CA_CHAIN: "${TLS_CA_CHAIN:-}"
restart: unless-stopped

Step 3: Start the Service​

Start Chariot in detached mode:

docker compose up -d

Port Reference​

PortProtocolDescription
8080HTTPWeb UI and REST API
8443HTTPSSecure Web UI and REST API
1883MQTTStandard MQTT listener
8883MQTTSMQTT over TLS
8090WSMQTT over WebSocket
8091WSSMQTT over Secure WebSocket

Only expose the ports required for your deployment. For example, if you are not using WebSocket clients, you can omit ports 8090 and 8091.

Important: If you change a listener port through SERVER_CONFIG, update the corresponding ports mapping in the Compose file to match the new container-side port.

For example, if SERVER_CONFIG sets the MQTT listener port to 9999, the mapping should be "1883:9999" rather than "1883:1883".

Environment Variable Reference​

General​

VariableRequiredDefaultDescription
ACCEPT_EULAYes—Must be true for configuration to be applied. If unset or set to another value, no configuration is applied.
ADMIN_PASSWORDRecommendedpasswordPassword for the admin account.

MQTT Users​

Use MQTT_USERS to provision MQTT client accounts during the first startup. User definitions can be provided as inline JSON or as a path to a JSON file mounted into the container.

Inline JSON​

Inline JSON is suitable for a small number of users:

MQTT_USERS='[{"username":"myuser","password":"mypassword","acl":{"subscribeTopics":["#"],"publishTopics":["#"]}}]'

JSON File​

A JSON file is recommended when managing multiple users or keeping credentials out of the Compose file:

MQTT_USERS=/config/mqtt-users.json

Mount the file in the Compose service:

volumes:
- ./mqtt-users.json:/config/mqtt-users.json:ro

The JSON file uses the following structure:

[
{
"username": "myuser",
"password": "mypassword",
"acl": {
"subscribeTopics": ["devices/#"],
"publishTopics": ["devices/#"]
}
}
]

The acl object controls which MQTT topics each user can publish to and subscribe from. Use ["#"] to grant access to all topics, or restrict access using standard MQTT wildcard patterns such as + for a single level and # for multiple levels.

Licensing​

VariableRequired WhenDescription
LICENSE_TYPE—Set to online or floating. Omit this variable to skip license activation.
LICENSE_KEYLICENSE_TYPE=onlineLicense key for online activation. Requires outbound internet access.
LICENSE_SERVERLICENSE_TYPE=floatingAddress of the floating license server.
LICENSE_PRODUCTLICENSE_TYPE=floatingProduct identifier for the floating license: mqtt-server-ibsnow, mqtt-server, or ibsnow.

Choosing a License Type​

  • Online — Contacts the Cirrus Link license server at startup. This is the simplest option when outbound internet access is available.
  • Floating — Connects to a dedicated license server. Use this when managing multiple Chariot instances that share a license pool or when centralized license control is required.

MQTT Server Configuration​

SERVER_CONFIG accepts either an inline JSON object or an absolute path to a JSON file mounted into the container. Only include the fields you want to override.

FieldTypeDescription
portnumberMQTT listener port.
securePortnumberMQTT TLS listener port.
enableNonSecurebooleanEnables the non-secure MQTT listener.
enableSecurebooleanEnables the secure MQTT listener.
allowAnonymousbooleanAllows anonymous MQTT connections.
bindAddressstringBind address, such as 0.0.0.0.
webSocketEnablebooleanEnables MQTT over WebSocket.
webSocketPortnumberWebSocket listener port.
webSocketEnableSecurebooleanEnables secure WebSocket.
webSocketSecurePortnumberSecure WebSocket listener port.
enforceUniqueLwtTopicbooleanEnforces unique Last Will and Testament (LWT) topics.
uniqueLwtTopicFiltersstringLWT topic filter patterns.

Inline Configuration​

SERVER_CONFIG={"port":1883,"securePort":8883,"allowAnonymous":false}

Configuration File​

SERVER_CONFIG=/config/server-config.json

Mount the file using a volume:

volumes:
- ./server-config.json:/config/server-config.json:ro

If you change MQTT service ports through SERVER_CONFIG, update the container-side port mappings in the Compose file to match.

System Configuration​

VariableRequiredDefaultDescription
CHARIOT_SERVER_NAMENo—Display name shown in the Web UI.
HTTP_PORTNo8080HTTP listener port for the Web UI and REST API.
HTTPS_PORTNo8443HTTPS listener port.
HTTPS_ENABLEDNo—Set to true to enable HTTPS.

TLS/SSL Setup​

To enable TLS, mount your certificate files into the container and reference them using their container paths.

Step 1: Add Certificate Files to the Compose Volume​

volumes:
- ./certs:/certs:ro

Step 2: Set the TLS Environment Variables​

environment:
SETUP_SSL: "true"
TLS_PRIVATE_KEY: /certs/privkey.pem
TLS_CERTIFICATE: /certs/cert.pem
TLS_CA_CHAIN: /certs/chain.pem
VariableRequired WhenDescription
SETUP_SSL—Set to true to enable TLS configuration.
TLS_PRIVATE_KEYSETUP_SSL=trueContainer path to the private key file (.pem).
TLS_CERTIFICATESETUP_SSL=trueContainer path to the certificate file (.pem).
TLS_CA_CHAINSETUP_SSL=trueContainer path to the CA chain file (.pem).

All three TLS variables must be set together. If any are missing, the SSL configuration step logs an error and is skipped.

Once TLS is configured:

  • HTTPS is available on port 8443.
  • MQTT over TLS is available on port 8883.

Restoring from a Backup​

Chariot supports full configuration backups as .zip files exported from the Web UI. To restore a backup during the first startup:

Step 1: Mount the Backup File​

volumes:
- ./my-backup.zip:/backups/backup.zip:ro

Step 2: Set the Environment Variable​

environment:
BACKUP_FILE: /backups/backup.zip

The backup is restored before any other configuration step. Settings provided through environment variables, including ADMIN_PASSWORD, are applied afterward and override settings from the backup.

After a successful restore, the sentinel records the backup filename and timestamp. View this information with:

docker exec chariot cat /Chariot/config-state/state.json

IBSnow (Snowflake IoT Bridge)​

IBSnow connects Chariot to Snowflake for IoT data streaming. The following variables configure the integration during the first startup.

VariableDescription
IBSNOW_CONFIGJSON object containing the IBSnow configuration to merge with the default configuration, or an absolute path to a JSON file mounted into the container.
IBSNOW_SERVERSJSON array of MQTT server connections to create, or an absolute path to a JSON file.
IBSNOW_CERTSJSON array of absolute container paths to certificate files to upload, such as .p8 or .pem files.

Configuration Example​

The following example shows common IBSnow configuration fields:

{
"snowflake_application_enabled": true,
"ibsnow_instance_name": "prod-1",
"ibsnow_cloud_region": "us-east-1",
"streaming_profile_account": "xy12345",
"streaming_profile_host": "xy12345.snowflakecomputing.com",
"streaming_profile_database": "cl_bridge_stage_db",
"streaming_profile_schema": "stage_db",
"streaming_profile_warehouse": "cl_bridge_ingest_wh",
"streaming_profile_role": "cl_bridge_process_rl"
}

Inline Configuration​

IBSNOW_CONFIG={"snowflake_application_enabled":true,"ibsnow_instance_name":"prod-1","streaming_profile_account":"xy12345"}

Configuration File​

IBSNOW_CONFIG=/config/ibsnow-config.json

Mount the file using a volume:

volumes:
- ./ibsnow-config.json:/config/ibsnow-config.json:ro

IBSnow Servers​

Inline:

IBSNOW_SERVERS=[{"url":"tcp://localhost:1883","name":"Server1","subscriptions":"sub1,sub2","verifyHostname":false,"username":"user1","password":"password","clientId":"my-client"}]

File:

IBSNOW_SERVERS=/config/ibsnow-servers.json

Mount the file using a volume:

volumes:
- ./ibsnow-servers.json:/config/ibsnow-servers.json:ro

IBSnow Certificates​

Mount the certificate files and specify their container paths:

volumes:
- ./ibsnow-certs:/certs:ro

environment:
IBSNOW_CERTS: '["/certs/rsa_key.p8","/certs/cert.pem"]'

The configuration script verifies that all certificate files exist at their specified paths before attempting the upload. If any file is missing, the IBSnow certificate step is skipped and an error is logged.

Re-applying Configuration​

Configuration steps run only once. Changing an environment variable and restarting the container does not re-apply the corresponding configuration step.

To force a configuration step to run again:

Step 1: Open a Shell in the Running Container​

docker exec -it chariot sh

Step 2: Edit the Sentinel File​

vi /Chariot/config-state/state.json

The file lists each configuration step. Set the applied value to false for the step you want to re-run.

For example, to re-apply MQTT user configuration:

"mqttUsers": {
"applied": false
}

Step 3: Restart the Container​

docker compose restart chariot

The following table maps sentinel keys to their corresponding environment variables:

Sentinel KeyEnvironment Variable
backupBACKUP_FILE
adminPasswordADMIN_PASSWORD
licenseLICENSE_TYPE and related variables
serverConfigSERVER_CONFIG
ibsnowCertsIBSNOW_CERTS
ibsnowServersIBSNOW_SERVERS
ibsnowConfigIBSNOW_CONFIG
mqttUsersMQTT_USERS
sslSETUP_SSL and TLS_* variables
systemConfigCHARIOT_SERVER_NAME, HTTP_PORT, HTTPS_PORT, and HTTPS_ENABLED

Health Check​

The Docker image includes a built-in health check that polls the /eula REST endpoint every 30 seconds.

The health check includes:

  • A 60-second startup grace period.
  • A 10-second request timeout.
  • Three consecutive failures before Docker marks the container as unhealthy.

To check the current health status:

docker inspect --format='{{.State.Health.Status}}' chariot

You can also use the same endpoint manually to confirm that Chariot is responding:

curl -sf http://localhost:8080/eula -H "Accept: application/json;api-version=1.0"

A 200 response indicates that Chariot is responding. No response or a non-2xx response indicates that Chariot is still starting or has failed.

Troubleshooting​

Configuration Was Not Applied​

Symptom: Chariot starts, but no users, licenses, or settings were applied. The default admin / password credentials are still active.

Cause: ACCEPT_EULA was not set to true. The configuration script exits immediately if this check fails, before any other configuration step runs.

Fix: Confirm that the variable is set, then remove and recreate the container so the sentinel is initialized again:

docker rm -f chariot

docker run ... -e ACCEPT_EULA=true ...

I Changed an Environment Variable but Nothing Happened​

Cause: Configuration steps are applied only once. Once a step is marked applied: true in the sentinel file, it does not run again when environment variables change.

Fix: Reset the relevant step in the sentinel file and restart the container. See Re-applying Configuration.

Can't Log In — Credentials Rejected​

Possible causes and fixes:

Default password still active

If ADMIN_PASSWORD was not set, the password remains password.

Backup overrode the password

If BACKUP_FILE was used and ADMIN_PASSWORD was not set, the password from the backup is active. Set ADMIN_PASSWORD, reset the adminPassword sentinel step, and restart the container.

Admin password configuration failed

Check the logs for an error during the password configuration step:

docker logs chariot | grep -i "admin password"

MQTT Clients Cannot Connect​

Work through the following checks:

  1. Confirm that the correct port is exposed:

    docker inspect chariot | grep -A 10 Ports
  2. If allowAnonymous is false in SERVER_CONFIG, clients must provide credentials. Verify that the username and password match an entry in MQTT_USERS.

  3. If you changed a listener port in SERVER_CONFIG, ensure the ports mapping in the Compose file reflects the updated container-side port.

  4. For TLS connections on port 8883, verify that the client trusts the CA that signed the certificate.

  5. Check that the SSL configuration step completed:

    docker exec chariot cat /Chariot/config-state/state.json | grep ssl

TLS Setup Failed or HTTPS Is Not Available​

Symptom: The logs show an error during the SSL configuration step, or ports 8443 or 8883 are not responding.

Common causes:

  • One or more TLS variables (TLS_PRIVATE_KEY, TLS_CERTIFICATE, or TLS_CA_CHAIN) are missing. All three are required when SETUP_SSL=true.
  • A certificate file path is incorrect or the volume is not mounted correctly.

The configuration script logs an error when required TLS variables are missing or a certificate file cannot be found.

Fix: Verify the volume mount and container paths:

docker exec chariot ls /certs

Confirm that the file names match the values specified in TLS_PRIVATE_KEY, TLS_CERTIFICATE, and TLS_CA_CHAIN. Reset the ssl sentinel step and restart the container.

A Configuration Step Failed but the Container Is Still Running​

Cause: Configuration steps are independent. A failure in one step does not stop the remaining steps from running. Chariot continues starting up and logs a summary of any steps that failed.

Fix: Check the end of the configuration log for a summary of failed steps:

docker logs chariot | grep -A 10 "following steps failed"

Each failed step is listed by name. Cross-reference the failed step with the corresponding section above to diagnose the specific cause.