# yaml-language-server: $schema=https://schema.zeabur.app/template.json
apiVersion: zeabur.com/v1
kind: Template
metadata:
    name: TeslaMate
spec:
    description: A powerful, self-hosted data logger for your Tesla — track drives, charges, efficiency, and more with rich Grafana dashboards.
    coverImage: https://docs.teslamate.org/screenshots/web_interface.png
    icon: https://docs.teslamate.org/img/logo.svg
    variables:
        - key: PUBLIC_DOMAIN
          type: DOMAIN
          name: TeslaMate Domain
          description: The public domain for accessing the TeslaMate web UI (port 4000).
        - key: GRAFANA_DOMAIN
          type: DOMAIN
          name: Grafana Domain
          description: The public domain for accessing Grafana dashboards (port 3000). Default login is admin / admin — change it on first sign-in.
        - key: ENCRYPTION_KEY
          type: STRING
          name: Encryption Key
          description: A long, strong random secret used to encrypt your Tesla API tokens at rest. Must be at least 16 characters. Save this somewhere safe — you'll need the same value to restore from a backup.
        - key: TESLAMATE_USERNAME
          type: STRING
          name: Web UI Username
          description: HTTP Basic Auth username for the TeslaMate web UI (enforced by the Caddy reverse proxy).
        - key: TESLAMATE_PASSWORD
          type: STRING
          name: Web UI Password
          description: HTTP Basic Auth password for the TeslaMate web UI. Pick a strong one — this is the only thing protecting your driving history and Tesla token management page from the public internet.
        - key: TZ
          type: STRING
          name: Timezone
          description: IANA timezone name (e.g. "America/Los_Angeles", "Asia/Shanghai", "Europe/Berlin"). Leave as "UTC" if you're unsure.
    tags:
        - Vehicle
        - Tesla
        - Monitoring
        - Dashboard
        - Database
    readme: |-
        # TeslaMate

        [TeslaMate](https://github.com/teslamate-org/teslamate) is a powerful, self-hosted data logger for your Tesla. It records detailed information about your drives, charges, efficiency, sleep states, software updates, and more — and visualizes everything through beautifully prepared Grafana dashboards.

        ## Features

        - **Drive & Charge Logs** — Distance, duration, consumption, costs
        - **Efficiency Analysis** — Energy usage by temperature, route, and driving style
        - **Charge Statistics** — Where, when, how much, and what it cost
        - **Software Update Tracking** — Full history of firmware versions
        - **Geofencing** — Auto-tag drives by named locations (Home, Work, etc.)
        - **MQTT Streaming** — Real-time vehicle state for home automation
        - **Pre-built Grafana Dashboards** — 15+ ready-to-use visualizations

        ## What's deployed

        This template provisions the full TeslaMate stack with security hardening:

        1. **Caddy** — reverse proxy in front of TeslaMate, enforces HTTP Basic Auth (the only public entry point on `PUBLIC_DOMAIN`)
        2. **TeslaMate** — the main web app, **internal-only**, reachable only via Caddy
        3. **PostgreSQL 18** — internal-only, stores all vehicle data
        4. **Grafana** — pre-loaded with TeslaMate's official dashboards, exposed on `GRAFANA_DOMAIN` with its own login
        5. **Mosquitto MQTT** — internal-only broker for real-time state updates

        ## Quick Start

        1. **Deploy** — Click deploy, fill in the variables (including the Web UI username / password), and bind both domains
        2. **Sign in to TeslaMate** at your `PUBLIC_DOMAIN` — the browser will prompt for the Basic Auth credentials you set, then TeslaMate's own setup flow asks for your Tesla API tokens
        3. **Open Grafana** at your `GRAFANA_DOMAIN` (default `admin` / `admin` — change immediately)
        4. **Drive your car** — TeslaMate will start recording automatically

        ## Security

        - **TeslaMate has no built-in login**, so this template puts a Caddy reverse proxy with HTTP Basic Auth in front of it. The TeslaMate container itself is **not exposed to the public internet** — only Caddy is.
        - **Postgres and Mosquitto are internal-only** by default. **Do not enable Port Forwarding** on them in the Zeabur dashboard unless you fully understand the consequences — Mosquitto runs without authentication, so exposing 1883 publicly leaks real-time GPS coordinates of your car.
        - **Save your `ENCRYPTION_KEY`** outside Zeabur. Restoring a database backup requires the exact same key.
        - **Grafana** uses its own admin login (`admin` / `admin` on first launch). Change it immediately the first time you sign in.
        - The Basic Auth credentials are bcrypt-hashed at container start using `caddy hash-password` — the plaintext password is only stored in Zeabur's env vars, never in the container's filesystem.

        ## Links

        - [Documentation](https://docs.teslamate.org)
        - [GitHub](https://github.com/teslamate-org/teslamate)
        - [Discord](https://discord.gg/PHhDBpW3vt)
    services:
        - name: database
          icon: https://raw.githubusercontent.com/zeabur/service-icons/main/marketplace/postgresql.svg
          template: PREBUILT_V2
          spec:
            id: database
            source:
                image: postgres:18-trixie
            ports:
                - id: database
                  port: 5432
                  type: TCP
            volumes:
                - id: data
                  dir: /var/lib/postgresql/data
            env:
                PGDATA:
                    default: /var/lib/postgresql/data/pgdata
                POSTGRES_DB:
                    default: teslamate
                    expose: true
                POSTGRES_HOST:
                    default: ${CONTAINER_HOSTNAME}
                    expose: true
                POSTGRES_PASSWORD:
                    default: ${PASSWORD}
                    expose: true
                POSTGRES_PORT:
                    default: ${DATABASE_PORT}
                    expose: true
                POSTGRES_USER:
                    default: teslamate
                    expose: true
            healthCheck:
                type: TCP
                port: database
            portForwarding:
                enabled: false
        - name: mosquitto
          icon: https://mosquitto.org/images/mosquitto-text-side-28.png
          template: PREBUILT_V2
          spec:
            id: mosquitto
            source:
                image: eclipse-mosquitto:2
                command:
                    - mosquitto
                    - -c
                    - /mosquitto-no-auth.conf
            ports:
                - id: mqtt
                  port: 1883
                  type: TCP
            volumes:
                - id: config
                  dir: /mosquitto/config
                - id: data
                  dir: /mosquitto/data
            env:
                MQTT_HOST:
                    default: ${CONTAINER_HOSTNAME}
                    expose: true
                MQTT_PORT:
                    default: "1883"
                    expose: true
            healthCheck:
                type: TCP
                port: mqtt
            portForwarding:
                enabled: false
        - name: teslamate
          icon: https://docs.teslamate.org/img/logo.svg
          dependencies:
            - database
            - mosquitto
          template: PREBUILT_V2
          spec:
            id: teslamate
            source:
                image: teslamate/teslamate:latest
            ports:
                - id: web
                  port: 4000
                  type: TCP
            volumes:
                - id: import
                  dir: /opt/app/import
            env:
                CHECK_ORIGIN:
                    default: "true"
                DATABASE_HOST:
                    default: database
                DATABASE_NAME:
                    default: teslamate
                DATABASE_PASS:
                    default: ${POSTGRES_PASSWORD}
                DATABASE_PORT:
                    default: "5432"
                DATABASE_USER:
                    default: teslamate
                DISABLE_MQTT:
                    default: "false"
                ENCRYPTION_KEY:
                    default: ${ENCRYPTION_KEY}
                MQTT_HOST:
                    default: mosquitto
                MQTT_PORT:
                    default: "1883"
                PORT:
                    default: "4000"
                SECRET_KEY_BASE:
                    default: ${PASSWORD}${PASSWORD}${PASSWORD}${PASSWORD}
                SIGNING_SALT:
                    default: ${PASSWORD}
                TZ:
                    default: ${TZ}
                VIRTUAL_HOST:
                    default: ${PUBLIC_DOMAIN}
            healthCheck:
                type: TCP
                port: web
            portForwarding:
                enabled: false
        - name: caddy
          icon: https://user-images.githubusercontent.com/1128849/210187356-dfb7f1c5-ac2e-43aa-bb23-fc014280ae1f.svg
          dependencies:
            - teslamate
          template: PREBUILT_V2
          spec:
            id: caddy
            source:
                image: caddy:2
                command:
                    - sh
                    - -c
                    - |
                      set -e
                      caddy version
                      if [ -z "$TESLAMATE_USERNAME" ]; then
                        echo "ERROR: TESLAMATE_USERNAME is empty. Set it in template variables." >&2
                        exit 1
                      fi
                      if [ -z "$TESLAMATE_PASSWORD" ]; then
                        echo "ERROR: TESLAMATE_PASSWORD is empty. Set it in template variables." >&2
                        exit 1
                      fi
                      TESLAMATE_PASSWORD_HASH=$(caddy hash-password --plaintext "$TESLAMATE_PASSWORD" 2>/dev/null || true)
                      if [ -z "$TESLAMATE_PASSWORD_HASH" ]; then
                        TESLAMATE_PASSWORD_HASH=$(printf '%s\n%s\n' "$TESLAMATE_PASSWORD" "$TESLAMATE_PASSWORD" | caddy hash-password 2>/dev/null || true)
                      fi
                      if [ -z "$TESLAMATE_PASSWORD_HASH" ]; then
                        echo "ERROR: failed to generate password hash via both --plaintext and stdin methods" >&2
                        caddy hash-password --help >&2 || true
                        exit 1
                      fi
                      export TESLAMATE_PASSWORD_HASH
                      echo "Password hash generated (length=${#TESLAMATE_PASSWORD_HASH})"
                      exec caddy run --config /etc/caddy/Caddyfile --adapter caddyfile
            ports:
                - id: web
                  port: 80
                  type: HTTP
            env:
                TESLAMATE_PASSWORD:
                    default: ${TESLAMATE_PASSWORD}
                TESLAMATE_USERNAME:
                    default: ${TESLAMATE_USERNAME}
            configs:
                - path: /etc/caddy/Caddyfile
                  template: |
                    {
                        admin off
                        auto_https off
                        servers {
                            trusted_proxies static private_ranges
                        }
                    }

                    :80 {
                        @ws {
                            header Connection *Upgrade*
                            header Upgrade websocket
                        }

                        handle /healthz {
                            respond "ok" 200
                        }

                        handle @ws {
                            reverse_proxy teslamate:4000 {
                                header_up Host {host}
                            }
                        }

                        handle {
                            basic_auth {
                                {$TESLAMATE_USERNAME} {$TESLAMATE_PASSWORD_HASH}
                            }
                            reverse_proxy teslamate:4000 {
                                header_up Host {host}
                                header_up X-Real-IP {remote_host}
                            }
                        }
                    }
                  permission: null
                  envsubst: null
            healthCheck:
                type: HTTP
                port: web
                http:
                    path: /healthz
          domainKey: PUBLIC_DOMAIN
        - name: grafana
          icon: https://grafana.com/media/docs/grafana-cloud/infrastructure/grafanalogo.svg
          dependencies:
            - database
          template: PREBUILT_V2
          spec:
            id: grafana
            source:
                image: teslamate/grafana:latest
            ports:
                - id: web
                  port: 3000
                  type: HTTP
            volumes:
                - id: data
                  dir: /var/lib/grafana
            env:
                DATABASE_HOST:
                    default: database
                DATABASE_NAME:
                    default: teslamate
                DATABASE_PASS:
                    default: ${POSTGRES_PASSWORD}
                DATABASE_PORT:
                    default: "5432"
                DATABASE_USER:
                    default: teslamate
                GF_AUTH_ANONYMOUS_ENABLED:
                    default: "false"
                GF_AUTH_BASIC_ENABLED:
                    default: "true"
                GF_SECURITY_ADMIN_PASSWORD:
                    default: admin
                GF_SECURITY_ADMIN_USER:
                    default: admin
                GF_SERVER_ROOT_URL:
                    default: ${ZEABUR_WEB_URL}
                TZ:
                    default: ${TZ}
            healthCheck:
                type: HTTP
                port: web
                http:
                    path: /api/health
          domainKey: GRAFANA_DOMAIN
localization:
    zh-CN:
        description: 强大的自托管 Tesla 数据记录器 —— 跟踪行程、充电、效率等数据，并通过 Grafana 仪表板进行可视化。
        readme: |
            # TeslaMate

            [TeslaMate](https://github.com/teslamate-org/teslamate) 是一个强大的自托管 Tesla 数据记录器。它会记录你的行程、充电、能效、休眠状态、固件升级等详细数据，并通过精心设计的 Grafana 仪表板进行可视化。

            ## 功能特性

            - **行程与充电日志** —— 距离、时长、能耗、费用
            - **能效分析** —— 按温度、路线、驾驶风格分析能耗
            - **充电统计** —— 在哪里、什么时候、充了多少、花了多少
            - **固件升级跟踪** —— 完整的固件版本历史
            - **地理围栏** —— 用命名位置（家、公司等）自动标记行程
            - **MQTT 推流** —— 实时车辆状态，方便接入家庭自动化
            - **预置 Grafana 仪表板** —— 15+ 个开箱即用的可视化面板

            ## 部署内容

            此模板会部署经过安全加固的完整 TeslaMate 技术栈：

            1. **Caddy** —— TeslaMate 前置反向代理，强制 HTTP Basic Auth（公网上唯一可访问的入口，绑定 `PUBLIC_DOMAIN`）
            2. **TeslaMate** —— 主 Web 应用，**仅内网访问**，必须通过 Caddy 访问
            3. **PostgreSQL 18** —— 仅内网访问，存储所有车辆数据
            4. **Grafana** —— 预装 TeslaMate 官方仪表板，对外暴露在 `GRAFANA_DOMAIN`，自带独立登录
            5. **Mosquitto MQTT** —— 仅内网访问的实时状态消息代理

            ## 快速开始

            1. **部署** —— 点击部署，填写所有变量（含 Web UI 用户名和密码），并绑定两个域名
            2. **访问 TeslaMate** —— 打开 `PUBLIC_DOMAIN`，浏览器会弹窗要求输入你设置的 Basic Auth 账号密码，然后再走 TeslaMate 自己的 Tesla token 配置流程
            3. **打开 Grafana** —— 访问 `GRAFANA_DOMAIN`（默认 `admin` / `admin`，请立即修改）
            4. **开车** —— TeslaMate 会自动开始记录数据

            ## 安全说明

            - **TeslaMate Web UI 自身没有登录功能**，因此本模板在它前面挂了一层带 HTTP Basic Auth 的 Caddy 反代。TeslaMate 容器**不直接对外暴露**，只有 Caddy 对外。
            - **Postgres 和 Mosquitto 默认仅内网访问**。**请勿在 Zeabur 控制台为这两个服务启用 Port Forwarding**，除非你清楚后果 —— 特别是 Mosquitto 是无密码的，开了 1883 公网端口等于把车辆的实时 GPS 位置直接公开。
            - **请把 `ENCRYPTION_KEY` 保存到 Zeabur 之外**，恢复数据库备份时必须使用同一把密钥。
            - **Grafana 自带独立登录**（首次 `admin` / `admin`，登录后会要求立即修改）。
            - Basic Auth 密码在容器启动时由 `caddy hash-password` 自动 bcrypt 加密，明文只存于 Zeabur 的环境变量，不会落到容器文件系统。

            ## 相关链接

            - [官方文档](https://docs.teslamate.org)
            - [GitHub](https://github.com/teslamate-org/teslamate)
            - [Discord](https://discord.gg/PHhDBpW3vt)
    zh-TW:
        description: 強大的自架 Tesla 資料記錄器 —— 追蹤行程、充電、能效等資料，並透過 Grafana 儀表板視覺化。
        readme: |
            # TeslaMate

            [TeslaMate](https://github.com/teslamate-org/teslamate) 是一個強大的自架 Tesla 資料記錄器。它會記錄你的行程、充電、能效、休眠狀態、韌體更新等詳細資料，並透過精心設計的 Grafana 儀表板進行視覺化。

            ## 功能特色

            - **行程與充電紀錄** —— 距離、時長、能耗、費用
            - **能效分析** —— 依溫度、路線、駕駛風格分析能耗
            - **充電統計** —— 在哪裡、何時、充了多少、花了多少
            - **韌體更新追蹤** —— 完整的韌體版本歷史
            - **地理圍欄** —— 用命名地點（家、公司等）自動標記行程
            - **MQTT 串流** —— 即時車輛狀態，方便接入家庭自動化
            - **預載 Grafana 儀表板** —— 15+ 個開箱即用的視覺化面板

            ## 部署內容

            此模版會部署經過安全強化的完整 TeslaMate 技術堆疊：

            1. **Caddy** —— TeslaMate 的前置反向代理，強制 HTTP Basic Auth（公網上唯一可存取的入口，綁定 `PUBLIC_DOMAIN`）
            2. **TeslaMate** —— 主 Web 應用，**僅內網存取**，必須透過 Caddy 進入
            3. **PostgreSQL 18** —— 僅內網存取，儲存所有車輛資料
            4. **Grafana** —— 預載 TeslaMate 官方儀表板，對外暴露於 `GRAFANA_DOMAIN`，內建獨立登入
            5. **Mosquitto MQTT** —— 僅內網存取的即時狀態訊息代理

            ## 快速開始

            1. **部署** —— 點擊部署，填寫所有變數（含 Web UI 帳號密碼），並綁定兩個網域
            2. **存取 TeslaMate** —— 開啟 `PUBLIC_DOMAIN`，瀏覽器會跳出視窗要求輸入你設定的 Basic Auth 帳密，接著再走 TeslaMate 自己的 Tesla token 設定流程
            3. **開啟 Grafana** —— 造訪 `GRAFANA_DOMAIN`（預設 `admin` / `admin`，請立即修改）
            4. **開車** —— TeslaMate 會自動開始記錄資料

            ## 安全說明

            - **TeslaMate Web UI 本身沒有登入機制**，因此本模版在它前面掛了一層帶 HTTP Basic Auth 的 Caddy 反向代理。TeslaMate 容器**不直接對外暴露**，只有 Caddy 對外。
            - **Postgres 與 Mosquitto 預設僅內網存取**。**請勿在 Zeabur 控制台為這兩個服務啟用 Port Forwarding**，除非你完全清楚後果 —— Mosquitto 是無密碼的，公開 1883 連接埠等同於把車輛即時 GPS 位置直接公開。
            - **請把 `ENCRYPTION_KEY` 保存到 Zeabur 之外**，還原資料庫備份時必須使用同一把金鑰。
            - **Grafana 內建獨立登入**（首次 `admin` / `admin`，登入後會要求立即修改）。
            - Basic Auth 密碼在容器啟動時由 `caddy hash-password` 自動 bcrypt 加密，明文僅存於 Zeabur 的環境變數，不會落到容器檔案系統。

            ## 相關連結

            - [官方文件](https://docs.teslamate.org)
            - [GitHub](https://github.com/teslamate-org/teslamate)
            - [Discord](https://discord.gg/PHhDBpW3vt)
