How TeslaMate is Deployed: Complete Docker Architecture Guide
TeslaMate is deployed as a multi-container Docker stack comprising four services—the Elixir application, PostgreSQL, Grafana, and Mosquitto—built from a multi-stage Dockerfile and orchestrated via Docker Compose with persistent volumes and environment-based configuration.
TeslaMate is a self-hosted Tesla data logger maintained by the teslamate-org community. Understanding how TeslaMate is deployed requires examining its containerized architecture, which packages the Elixir application and its dependencies into a production-ready Docker environment. This approach ensures consistent deployments across any Docker-compatible host while maintaining data persistence and security isolation.
Container Architecture Overview
TeslaMate's deployment consists of four distinct containers that communicate over a private Docker network:
- TeslaMate: The core Elixir application (
teslamate/teslamate:latest) that polls the Tesla API, stores telemetry, and serves a web interface on port 4000. - PostgreSQL: Database backend (
postgres:18-trixie) storing all vehicle data, events, and configuration in persistent volumes. - Grafana: Visualization layer (
teslamate/grafana:latest) providing pre-configured dashboards accessible on port 3000. - Mosquitto: MQTT broker (
eclipse-mosquitto:2) enabling real-time vehicle topic publication for integration with Home Assistant and Node-RED.
Multi-Stage Docker Build Process
The deployment image is constructed using the Dockerfile located in the repository root. This multi-stage build separates compilation from runtime to minimize attack surface and image size.
Builder Stage: Compiles the Elixir Release using mix release, bundles frontend assets, and prepares the application code.
App Stage: Copies only the compiled release to /opt/built, installs runtime dependencies, and creates a non-root user (nonroot) for security. According to the Dockerfile source, the release builds with mix release --path /opt/built during the build process.
Docker Compose Deployment Configuration
Production deployments rely on docker-compose.yml to orchestrate the four services. The configuration defines specific environment variables, network settings, and volume mounts.
Environment Variables
Service connectivity relies on standardized environment variables:
- ENCRYPTION_KEY: Encrypts stored Tesla API tokens (must be set to a strong, unique value)
- DATABASE_USER, DATABASE_PASS, DATABASE_NAME, DATABASE_HOST: PostgreSQL connection parameters (typically
DATABASE_HOST=database) - MQTT_HOST: Points to the Mosquitto container (typically
MQTT_HOST=mosquitto) - POSTGRES_PASSWORD: Must match
DATABASE_PASSfor the TeslaMate application to authenticate
Persistent Volumes
Data survives container restarts through named volumes:
teslamate-db: PostgreSQL data at/var/lib/postgresqlteslamate-grafana-data: Grafana SQLite database and dashboard configurations at/var/lib/grafanamosquitto-confandmosquitto-data: MQTT broker configuration and retained messages./import: Host-mounted directory for CSV import/export operations mapped to/opt/app/import
Network Security
All services communicate over Docker's default compose network. The TeslaMate container reaches PostgreSQL via the hostname database and Mosquitto via mosquitto. Only ports 4000 (TeslaMate UI) and 3000 (Grafana) are exposed externally, while PostgreSQL and MQTT remain isolated on the internal network.
Runtime Startup and Entrypoint
When containers start, the entrypoint.sh script initializes the runtime environment before launching the application. This script prepares configuration and executes bin/teslamate start to run the compiled Elixir Release. The release was built during the Docker image creation using mix release, with production-specific settings defined in config/prod.exs and dependencies managed in mix.exs.
Security Hardening
The deployment implements several security best practices:
- Non-root execution: The container runs as a
nonrootuser created during the Dockerfile build process - Capability dropping: Uses
cap_drop: - allto remove unnecessary Linux capabilities - No external database exposure: PostgreSQL and MQTT ports are not mapped to the host
- Reverse proxy requirement: TLS termination and external HTTPS access should be handled by Traefik, Caddy, or Apache as recommended in the official documentation
Deployment Example
A minimal docker-compose.yml configuration demonstrating the architecture:
services:
teslamate:
image: teslamate/teslamate:latest
restart: always
environment:
- ENCRYPTION_KEY=super-secret-key
- DATABASE_USER=teslamate
- DATABASE_PASS=change-me
- DATABASE_NAME=teslamate
- DATABASE_HOST=database
- MQTT_HOST=mosquitto
ports:
- "4000:4000"
volumes:
- ./import:/opt/app/import
cap_drop:
- all
database:
image: postgres:18-trixie
restart: always
environment:
- POSTGRES_USER=teslamate
- POSTGRES_PASSWORD=change-me
- POSTGRES_DB=teslamate
volumes:
- teslamate-db:/var/lib/postgresql
grafana:
image: teslamate/grafana:latest
restart: always
environment:
- DATABASE_USER=teslamate
- DATABASE_PASS=change-me
- DATABASE_NAME=teslamate
- DATABASE_HOST=database
ports:
- "3000:3000"
volumes:
- teslamate-grafana-data:/var/lib/grafana
mosquitto:
image: eclipse-mosquitto:2
restart: always
command: mosquitto -c /mosquitto-no-auth.conf
volumes:
- mosquitto-conf:/mosquitto/config
- mosquitto-data:/mosquitto/data
volumes:
teslamate-db:
teslamate-grafana-data:
mosquitto-conf:
mosquitto-data:
Execute docker compose up -d to start the stack, then access TeslaMate at http://<host-ip>:4000 and Grafana at http://<host-ip>:3000 (default credentials: admin/admin).
Summary
- TeslaMate is deployed via Docker Compose using four containerized services: the Elixir application (
teslamate/teslamate:latest), PostgreSQL (postgres:18-trixie), Grafana (teslamate/grafana:latest), and Mosquitto (eclipse-mosquitto:2). - The multi-stage Dockerfile compiles an Elixir Release in a builder stage, then copies it to a minimal runtime image with a non-root user.
- Environment variables configure database connections (
DATABASE_HOST=database), MQTT integration (MQTT_HOST=mosquitto), and API token encryption viaENCRYPTION_KEY. - Persistent volumes ensure data survives container restarts, storing PostgreSQL data, Grafana dashboards in
teslamate-grafana-data, and MQTT configuration. - The entrypoint.sh script initializes the runtime environment and launches the compiled release with
bin/teslamate start. - Security features include cap_drop: all, non-root execution, and internal-only networking for database and MQTT services.
Frequently Asked Questions
What Docker images are required to deploy TeslaMate?
TeslaMate requires four official images: teslamate/teslamate:latest for the application, postgres:18-trixie for the database, teslamate/grafana:latest for visualization, and eclipse-mosquitto:2 for MQTT messaging. These images are pulled automatically when running docker compose up according to the architecture defined in the repository's Docker installation guide.
How does TeslaMate handle database migrations during deployment?
Database schema migrations are managed through Elixir's Ecto framework. When the TeslaMate container starts via entrypoint.sh, it runs the compiled release which automatically executes pending migrations located in priv/repo/migrations/ against the PostgreSQL database specified in DATABASE_HOST.
Can TeslaMate be deployed without Docker?
While Docker is the officially supported deployment method, TeslaMate can technically run as a standalone Elixir application compiled from source using mix release. However, this requires manual installation of Erlang/Elixir, PostgreSQL, and Node.js, plus configuration of the services defined in config/prod.exs—making Docker the recommended approach for production use.
What ports need to be exposed when deploying TeslaMate?
Only two ports require external exposure: port 4000 for the TeslaMate web interface and port 3000 for Grafana dashboards. PostgreSQL and MQTT ports should remain unexposed and accessible only via the internal Docker network, with TLS termination handled by a reverse proxy like Traefik or Caddy for secure external access.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →