diff --git a/.env.example b/.env.example deleted file mode 100644 index f57b2e3..0000000 --- a/.env.example +++ /dev/null @@ -1,17 +0,0 @@ -# ================= 核心配置 ================= -TM_ENCRYPTION_KEY=your_secure_encryption_key_here -TM_DB_USER=teslamate -TM_DB_PASSWORD=Abcd1234__TM # 需修改为强密码 -TM_DB_NAME=teslamate -TM_DB_HOST=database - -# ================= 网络配置 ================= -TM_PORT=4000 # TeslaMate 访问端口 -GF_PORT=3000 # Grafana 访问端口 -TM_MQTT_HOST=mosquitto - - -# ================= 可选优化 ================= -BD_MAP_AK= -BD_MAP_SK= -TZ=Asia/Shanghai \ No newline at end of file diff --git a/README.md b/README.md index 1dcebaf..558ad40 100644 --- a/README.md +++ b/README.md @@ -20,77 +20,135 @@ ## 🚀 快速启动 Quick Start -### 云服务器一键部署 +### 本地内网部署步骤 Deployment -#### 准备工作 +本项目提供两种部署方式: -1. 购买腾讯云服务器 -推荐购买腾讯云新加坡轻量应用服务器: -配置: 1核2GB,99元/年 -地区: 新加坡(海外节点,访问 Tesla API 更稳定) -购买链接: 腾讯云活动 -服务器规格建议: -内存: 2GB 以上 -存储: 40GB 以上 -系统:Ubuntu 24.04 LTS -2. 购买域名 -在腾讯云购买域名: - - 进入腾讯云控制台 -3. 选择"域名注册" - - 搜索并购买一个便宜的域名(如 .top、.xyz 等后缀) - - 完成实名认证 -4. 配置 DNS 解析 - - 添加 A 记录 - - 在腾讯云 DNS 解析控制台: - - 主机记录: teslamate(或您喜欢的子域名) - - 记录类型: A - - 记录值: 您的服务器公网 IP - - TTL: 600 +| 版本 | 文件 | 说明 | +|------|------|------| +| **普通版本** | `docker-compose.yml` | 基础版本,包含 TeslaMate + Grafana | +| **Mytesla 版本** | `docker-compose-with-mytesla.yml` | 集成 Mytesla Dash,现代化看板替代 Grafana | -#### 一键部署脚本 +--- -我们提供了一个交互式安装脚本,可以自动完成所有配置: -登录腾讯云控制台,找到您购买的服务器 -远程登录 免密登录 -执行以下命令根据提示操作即可 +## 📊 Mytesla Dash - Grafana 替代方案 -```sh -bash -c "$(curl -sSL https://s.mytesla.cc/install.sh)" +[Mytesla Dash](https://dash.mytesla.cc) 是一个现代化的 Tesla 数据看板,可以完美替代 Grafana 作为日常使用的数据展示界面。 + +### 为什么选择 Mytesla Dash? + +- **现代化 UI** - 简洁美观的界面设计,移动端友好 +- **开箱即用** - 无需复杂的 Grafana 仪表盘配置 +- **实时监控** - 车辆状态、充电进度实时展示 +- **数据分析** - 行程记录、能耗统计、充电费用一目了然 +- **地理围栏** - 支持自定义地理围栏,自动识别充电地点 +- **分时计费** - 峰谷电价自动计算,精确统计充电成本 + +### 授权说明 + +> **注意**:Mytesla Dash 需要一次性授权才能使用,首次访问时会引导完成授权流程。 +> +> 获取授权码:[小红书 Mytesla 授权](https://www.xiaohongshu.com/goods-detail/688dbe5f02d7b00001179ed2) + +### 界面预览 + + +![Dashboard 主界面](images/923shots_so.png) + + +![记录](images/650shots_so.png) + + +![统计](images/148shots_so.png) + +--- + +## 🔐 反向代理与认证安全 + +`docker-compose-with-mytesla.yml` 采用 **Traefik + ForwardAuth** 架构,提供企业级的安全防护: + +### 架构说明 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ 用户请求 │ +└─────────────────────────┬───────────────────────────────────┘ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ Traefik (反向代理) │ +│ - 统一入口 (端口 80) │ +│ - 路由分发 │ +│ - 中间件处理 │ +└─────────────────────────┬───────────────────────────────────┘ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ Auth Service (认证服务) │ +│ - Cookie-based 会话认证 │ +│ - 登录/登出管理 │ +│ - ForwardAuth 中间件 │ +└─────────────────────────┬───────────────────────────────────┘ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ 后端服务 │ +│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ +│ │TeslaMate │ │ Dash │ │ Grafana │ │ API │ │ +│ │/teslamate│ │ / │ │ /grafana │ │ /panel │ │ +│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ +└─────────────────────────────────────────────────────────────┘ ``` -脚本功能特性 -* 自动安装 Docker 和 Docker Compose -* 交互式配置环境变量 -* 自动生成安全密码 -* 配置 SSL 证书(Let's Encrypt) -* 基础认证保护 -* 使用 Mytesla 优化镜像 -* 支持百度地图精确定位 -* 自动启动服务 -* 支持更新服务 -* 支持备份以及恢复数据 +### 安全特性 -#### Mytesla UI推荐 +| 组件 | 作用 | +|------|------| +| **Traefik** | 反向代理,统一管理所有服务的入口,隐藏内部服务端口 | +| **Auth Service** | 提供统一的登录认证,保护敏感数据不被未授权访问 | +| **ForwardAuth** | 每个请求都会先经过认证服务验证,确保只有登录用户才能访问 | +| **路径隔离** | 不同服务使用不同路径,互不干扰 | -在成功部署 TeslaMate 后,强烈推荐您使用 [Mytesla UI](https://mytesla.cc), 现代化新数据看板日常使用可以替换掉 grafana: +### 访问路径 -Mytesla UI 特色功能 -* **实时车辆监控** 电池状态实时显示 充电进度跟踪 位置信息监控 -* **数据分析** 详细的行驶数据分析 能耗统计报告 充电费用统计 峰谷用电充电自动计费 -* **通知提醒** 充电完成通知 行程完成通知 周期数据统计 更新提醒 +- `/` - Mytesla Dash 主界面(需要登录) +- `/teslamate` - TeslaMate 管理界面(需要登录) +- `/grafana` - Grafana 仪表盘 +- `/login` - 登录页面 +- `/logout` - 登出 +- `/settings` - 设置页面 +--- -### 本地内网部署步骤 Deployment +## 🚀 部署指南 + +### 方式一:普通版本(TeslaMate + Grafana) ```bash # 克隆仓库 git clone https://github.com/gococonut/teslamate-cn-docker.git cd teslamate-cn-docker -# 配置环境变量 -cp .env.example .env -nano .env # 修改环境变量 +# 启动服务 +docker compose up -d +``` + +### 方式二:Mytesla 版本(推荐) + +```bash +# 克隆仓库 +git clone https://github.com/gococonut/teslamate-cn-docker.git +cd teslamate-cn-docker # 启动服务 -docker-compose up -d +docker compose -f docker-compose-with-mytesla.yml up -d ``` + +### 访问服务 + +- **普通版本**: + - TeslaMate: `http://your-ip:4000` + - Grafana: `http://your-ip:3000` + +- **Mytesla 版本**: + - 统一入口: `http://your-ip` (默认跳转到 Dashboard) + - TeslaMate: `http://your-ip/teslamate` + - Grafana: `http://your-ip/grafana` + - 默认登录: 用户名 `admin` / 密码 `admin123`(可在 `http://your-ip/settings` 设置页面修改) diff --git a/docker-compose-with-mytesla.yml b/docker-compose-with-mytesla.yml new file mode 100644 index 0000000..577d460 --- /dev/null +++ b/docker-compose-with-mytesla.yml @@ -0,0 +1,197 @@ +services: + # ForwardAuth service for Cookie-based authentication + auth: + image: docker.1ms.run/mytesla/auth:latest + restart: unless-stopped + environment: + - AUTH_USERNAME=admin + - AUTH_PASSWORD=admin123 + - SECRET_KEY=mytesla-secret-key-change-me + - CONFIG_PATH=/data/config.json + volumes: + - auth-data:/data + labels: + - "traefik.enable=true" + - "traefik.http.services.auth.loadbalancer.server.port=8080" + # Login/Logout routes + - "traefik.http.routers.auth-login.rule=PathPrefix(`/login`) || PathPrefix(`/logout`)" + - "traefik.http.routers.auth-login.entrypoints=web" + - "traefik.http.routers.auth-login.priority=100" + # Settings route + - "traefik.http.routers.auth-settings.rule=PathPrefix(`/settings`)" + - "traefik.http.routers.auth-settings.entrypoints=web" + - "traefik.http.routers.auth-settings.priority=100" + # ForwardAuth middleware definition + - "traefik.http.middlewares.forward-auth.forwardauth.address=http://auth:8080/auth" + - "traefik.http.middlewares.forward-auth.forwardauth.authResponseHeaders=X-Forwarded-User" + + traefik: + image: docker.1ms.run/traefik:v3.6 + restart: unless-stopped + command: + - --api.dashboard=true + - --providers.docker=true + - --providers.docker.exposedbydefault=false + - --entrypoints.web.address=:80 + - --log.level=INFO + ports: + - "80:80" + volumes: + - /var/run/docker.sock:/var/run/docker.sock + labels: + - "traefik.enable=true" + depends_on: + - auth + + teslamate: + image: docker.1ms.run/mytesla/teslamate:v2.2 + restart: always + depends_on: + - database + - mosquitto + environment: + - DATABASE_USER=teslamate + - DATABASE_PASS=teslamate + - DATABASE_NAME=teslamate + - DATABASE_HOST=database + - MQTT_HOST=mosquitto + - ENCRYPTION_KEY=your-encryption-key-change-me + - TZ=Asia/Shanghai + - CHECK_ORIGIN=false + - URL_PATH=/teslamate + - MYTESLA_SELF_HOST=true + volumes: + - ./data/teslamate/import:/opt/app/import + cap_drop: + - all + labels: + - "traefik.enable=true" + - "traefik.http.services.teslamate.loadbalancer.server.port=4000" + - "traefik.http.middlewares.teslamate-strip.stripprefix.prefixes=/teslamate" + # Public routes (no auth) + - "traefik.http.routers.teslamate-public.rule=PathPrefix(`/teslamate/static`) || PathRegexp(`^/teslamate/.*\\.(png|jpg|jpeg|gif|ico|svg|webp|css|js)$$`)" + - "traefik.http.routers.teslamate-public.entrypoints=web" + - "traefik.http.routers.teslamate-public.middlewares=teslamate-strip" + - "traefik.http.routers.teslamate-public.priority=20" + # WebSocket routes (no auth) + - "traefik.http.routers.teslamate-ws.rule=PathPrefix(`/teslamate/live/websocket`)" + - "traefik.http.routers.teslamate-ws.entrypoints=web" + - "traefik.http.routers.teslamate-ws.middlewares=teslamate-strip" + - "traefik.http.routers.teslamate-ws.priority=15" + # Protected routes (with ForwardAuth) + - "traefik.http.routers.teslamate.rule=PathPrefix(`/teslamate`)" + - "traefik.http.routers.teslamate.entrypoints=web" + - "traefik.http.routers.teslamate.middlewares=forward-auth,teslamate-strip" + - "traefik.http.routers.teslamate.priority=10" + + database: + image: docker.1ms.run/postgres:18-trixie + restart: always + environment: + - POSTGRES_USER=teslamate + - POSTGRES_PASSWORD=teslamate + - POSTGRES_DB=teslamate + volumes: + - postgres-data:/var/lib/postgresql/data + + grafana: + image: docker.1ms.run/mytesla/grafana:v2.2 + restart: always + depends_on: + - database + environment: + - DATABASE_USER=teslamate + - DATABASE_PASS=teslamate + - DATABASE_NAME=teslamate + - DATABASE_HOST=database + - GRAFANA_PASSWD=admin123 + - GF_SECURITY_ADMIN_USER=admin + - GF_SECURITY_ADMIN_PASSWORD=admin123 + - GF_AUTH_ANONYMOUS_ENABLED=false + - GF_USERS_DEFAULT_LANGUAGE=zh-CN + - GF_SERVER_SERVE_FROM_SUB_PATH=true + - GF_SERVER_ROOT_URL=%(protocol)s://%(domain)s:%(http_port)s/grafana/ + volumes: + - grafana-data:/var/lib/grafana + labels: + - "traefik.enable=true" + - "traefik.http.services.grafana.loadbalancer.server.port=3000" + - "traefik.http.routers.grafana.rule=PathPrefix(`/grafana`)" + - "traefik.http.routers.grafana.entrypoints=web" + + mosquitto: + image: docker.1ms.run/eclipse-mosquitto:2 + restart: always + command: mosquitto -c /mosquitto-no-auth.conf + volumes: + - ./data/mosquitto/config:/mosquitto/config + - ./data/mosquitto/data:/mosquitto/data + + teslamateapi: + image: docker.1ms.run/mytesla/teslamateapi:latest + restart: unless-stopped + ports: + - "3030:8080" + depends_on: + - database + - teslamate + - mosquitto + environment: + - DATABASE_USER=teslamate + - DATABASE_PASS=teslamate + - DATABASE_NAME=teslamate + - DATABASE_HOST=database + - ENCRYPTION_KEY=your-encryption-key-change-me + - MQTT_HOST=mosquitto + volumes: + - teslamateapi-data:/opt/app/data + labels: + - "traefik.enable=true" + - "traefik.http.services.teslamateapi.loadbalancer.server.port=8080" + - "traefik.http.middlewares.teslamateapi-panel-rewrite.replacepathregex.regex=^/panel(.*)" + - "traefik.http.middlewares.teslamateapi-panel-rewrite.replacepathregex.replacement=/api/panel$${1}" + - "traefik.http.routers.teslamateapi-panel.rule=PathPrefix(`/panel`)" + - "traefik.http.routers.teslamateapi-panel.entrypoints=web" + - "traefik.http.routers.teslamateapi-panel.middlewares=teslamateapi-panel-rewrite" + + dash: + image: docker.1ms.run/mytesla/dash:latest + restart: unless-stopped + depends_on: + - teslamateapi + - env-adapter + labels: + - "traefik.enable=true" + - "traefik.http.services.dash.loadbalancer.server.port=3000" + # Public routes (no auth) - PWA assets + - "traefik.http.routers.dash-public.rule=Path(`/manifest.json`) || PathPrefix(`/images`) || PathRegexp(`^/.*\\.(png|jpg|jpeg|gif|ico|svg|webp)$$`)" + - "traefik.http.routers.dash-public.entrypoints=web" + - "traefik.http.routers.dash-public.priority=20" + - "traefik.http.middlewares.dash-redirect.redirectregex.regex=^/$$" + - "traefik.http.middlewares.dash-redirect.redirectregex.replacement=/dashboard" + # Protected routes (with ForwardAuth) + - "traefik.http.routers.dash.rule=PathPrefix(`/`)" + - "traefik.http.routers.dash.entrypoints=web" + - "traefik.http.routers.dash.middlewares=forward-auth,dash-redirect" + - "traefik.http.routers.dash.priority=1" + + env-adapter: + image: docker.1ms.run/mytesla/env-adapter:latest + restart: unless-stopped + volumes: + - /etc/machine-id:/etc/machine-id:ro + - /proc/cpuinfo:/proc/cpuinfo:ro + - env-adapter-data:/app/storage:rw + depends_on: + - teslamateapi + +volumes: + auth-data: + teslamateapi-data: + grafana-data: + postgres-data: + env-adapter-data: + +networks: + default: + name: teslamate-network diff --git a/docker-compose.yml b/docker-compose.yml index d2b8c65..0951dc2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,16 +3,14 @@ services: image: docker.1ms.run/mytesla/teslamate:v2.2 restart: always environment: - - ENCRYPTION_KEY=${TM_ENCRYPTION_KEY} - - DATABASE_USER=${TM_DB_USER} - - DATABASE_PASS=${TM_DB_PASSWORD} - - DATABASE_NAME=${TM_DB_NAME} - - DATABASE_HOST=${TM_DB_HOST} - - MQTT_HOST=${TM_MQTT_HOST} - - BD_MAP_AK=${BD_MAP_AK} - - BD_MAP_SK=${BD_MAP_SK} + - ENCRYPTION_KEY=your-encryption-key-change-me + - DATABASE_USER=teslamate + - DATABASE_PASS=teslamate + - DATABASE_NAME=teslamate + - DATABASE_HOST=database + - MQTT_HOST=mosquitto ports: - - "${TM_PORT}:4000" + - "4000:4000" volumes: - ./import:/opt/app/import cap_drop: @@ -22,9 +20,9 @@ services: image: docker.1ms.run/postgres:18-trixie restart: always environment: - - POSTGRES_USER=${TM_DB_USER} - - POSTGRES_PASSWORD=${TM_DB_PASSWORD} - - POSTGRES_DB=${TM_DB_NAME} + - POSTGRES_USER=teslamate + - POSTGRES_PASSWORD=teslamate + - POSTGRES_DB=teslamate volumes: - teslamate-db:/var/lib/postgresql/data @@ -32,12 +30,12 @@ services: image: docker.1ms.run/mytesla/grafana:v2.2 restart: always environment: - - DATABASE_USER=${TM_DB_USER} - - DATABASE_PASS=${TM_DB_PASSWORD} - - DATABASE_NAME=${TM_DB_NAME} - - DATABASE_HOST=${TM_DB_HOST} + - DATABASE_USER=teslamate + - DATABASE_PASS=teslamate + - DATABASE_NAME=teslamate + - DATABASE_HOST=database ports: - - "${GF_PORT}:3000" + - "3000:3000" volumes: - teslamate-grafana-data:/var/lib/grafana diff --git a/images/.gitkeep b/images/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/images/148shots_so.png b/images/148shots_so.png new file mode 100644 index 0000000..5e2e027 Binary files /dev/null and b/images/148shots_so.png differ diff --git a/images/650shots_so.png b/images/650shots_so.png new file mode 100644 index 0000000..5e44dc8 Binary files /dev/null and b/images/650shots_so.png differ diff --git a/images/923shots_so.png b/images/923shots_so.png new file mode 100644 index 0000000..4b01288 Binary files /dev/null and b/images/923shots_so.png differ