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:
- Accept EULA.
- Restore a backup, if
BACKUP_FILEis set. - Set the admin password.
- Activate the license.
- Apply MQTT server configuration.
- Upload IBSnow certificates.
- Create IBSnow servers.
- Apply IBSnow configuration.
- Create MQTT users.
- Configure TLS/SSL.
- 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_PASSWORDis 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
.envfile 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
| Port | Protocol | Description |
|---|---|---|
8080 | HTTP | Web UI and REST API |
8443 | HTTPS | Secure Web UI and REST API |
1883 | MQTT | Standard MQTT listener |
8883 | MQTTS | MQTT over TLS |
8090 | WS | MQTT over WebSocket |
8091 | WSS | MQTT 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 correspondingportsmapping in the Compose file to match the new container-side port.For example, if
SERVER_CONFIGsets the MQTT listenerportto9999, the mapping should be"1883:9999"rather than"1883:1883".
Environment Variable Reference
General
| Variable | Required | Default | Description |
|---|---|---|---|
ACCEPT_EULA | Yes | — | Must be true for configuration to be applied. If unset or set to another value, no configuration is applied. |
ADMIN_PASSWORD | Recommended | password | Password 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
| Variable | Required When | Description |
|---|---|---|
LICENSE_TYPE | — | Set to online or floating. Omit this variable to skip license activation. |
LICENSE_KEY | LICENSE_TYPE=online | License key for online activation. Requires outbound internet access. |
LICENSE_SERVER | LICENSE_TYPE=floating | Address of the floating license server. |
LICENSE_PRODUCT | LICENSE_TYPE=floating | Product 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.
| Field | Type | Description |
|---|---|---|
port | number | MQTT listener port. |
securePort | number | MQTT TLS listener port. |
enableNonSecure | boolean | Enables the non-secure MQTT listener. |
enableSecure | boolean | Enables the secure MQTT listener. |
allowAnonymous | boolean | Allows anonymous MQTT connections. |
bindAddress | string | Bind address, such as 0.0.0.0. |
webSocketEnable | boolean | Enables MQTT over WebSocket. |
webSocketPort | number | WebSocket listener port. |
webSocketEnableSecure | boolean | Enables secure WebSocket. |
webSocketSecurePort | number | Secure WebSocket listener port. |
enforceUniqueLwtTopic | boolean | Enforces unique Last Will and Testament (LWT) topics. |
uniqueLwtTopicFilters | string | LWT 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
| Variable | Required | Default | Description |
|---|---|---|---|
CHARIOT_SERVER_NAME | No | — | Display name shown in the Web UI. |
HTTP_PORT | No | 8080 | HTTP listener port for the Web UI and REST API. |
HTTPS_PORT | No | 8443 | HTTPS listener port. |
HTTPS_ENABLED | No | — | 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
| Variable | Required When | Description |
|---|---|---|
SETUP_SSL | — | Set to true to enable TLS configuration. |
TLS_PRIVATE_KEY | SETUP_SSL=true | Container path to the private key file (.pem). |
TLS_CERTIFICATE | SETUP_SSL=true | Container path to the certificate file (.pem). |
TLS_CA_CHAIN | SETUP_SSL=true | Container 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.
| Variable | Description |
|---|---|
IBSNOW_CONFIG | JSON object containing the IBSnow configuration to merge with the default configuration, or an absolute path to a JSON file mounted into the container. |
IBSNOW_SERVERS | JSON array of MQTT server connections to create, or an absolute path to a JSON file. |
IBSNOW_CERTS | JSON 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 Key | Environment Variable |
|---|---|
backup | BACKUP_FILE |
adminPassword | ADMIN_PASSWORD |
license | LICENSE_TYPE and related variables |
serverConfig | SERVER_CONFIG |
ibsnowCerts | IBSNOW_CERTS |
ibsnowServers | IBSNOW_SERVERS |
ibsnowConfig | IBSNOW_CONFIG |
mqttUsers | MQTT_USERS |
ssl | SETUP_SSL and TLS_* variables |
systemConfig | CHARIOT_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:
-
Confirm that the correct port is exposed:
docker inspect chariot | grep -A 10 Ports -
If
allowAnonymousisfalseinSERVER_CONFIG, clients must provide credentials. Verify that the username and password match an entry inMQTT_USERS. -
If you changed a listener port in
SERVER_CONFIG, ensure theportsmapping in the Compose file reflects the updated container-side port. -
For TLS connections on port
8883, verify that the client trusts the CA that signed the certificate. -
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, orTLS_CA_CHAIN) are missing. All three are required whenSETUP_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.