Repository navigation
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
169 lines (156 loc) · 7.94 KB
/
Copy pathdocker-compose.yml
File metadata and controls
169 lines (156 loc) · 7.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# FTW — Home Energy Management System (Linux)
#
# Pulls the pre-built multi-arch image (linux/amd64 + linux/arm64) from
# GitHub Container Registry. No local build needed.
#
# Start: docker compose up -d
# Logs: docker compose logs -f
# Upgrade: docs/upgrade-paired-release.md (updater first, then Core).
# Do not `docker compose pull` both services together for 2.x → 3.x.
# Stop: docker compose down
#
# PLATFORM: This file uses `network_mode: host`, a Linux-kernel feature.
# It is the right file for a Raspberry Pi, an Ubuntu/Debian server, a
# NUC, or a Linux VM. On macOS (e.g. a Mac mini) host networking binds to
# the Docker Desktop VM, not to the Mac, so the dashboard is unreachable
# and discovery breaks silently — use docker-compose.macos.yml instead.
# Use docker-compose.macos.yml on Docker Desktop for Mac.
#
# Persistent state — config.yaml, state.db, battery models, cold/
# Parquet files — lives in ./data and survives image upgrades. The
# directory must be owned by uid 100 / gid 101 so the container's ftw
# user can write to it. If you set this up manually (instead of via
# scripts/install.sh), run:
#
# mkdir -p ./data && sudo chown -R 100:101 ./data
#
# In-app updates: the `ftw-updater` sidecar below is what the "Update" /
# "Restart" buttons in the web UI signal to pull a new image + recreate
# the main service. See docs/self-update.md. Remove the sidecar service
# (and the update-ipc volume) if you prefer to run upgrades by hand —
# the UI buttons will surface a non-2xx error (typically 502) and the
# version-check banner keeps working as a notify-only indicator.
name: ${COMPOSE_PROJECT_NAME:-ftw}
services:
ftw:
# Tag is variable so the ftw-updater sidecar can pin to a specific
# release on `update`. Manual `docker compose up -d` (no env set)
# falls through to :latest. See docs/self-update.md.
image: ghcr.io/srcfl/ftw:${FTW_IMAGE_TAG:-latest}
container_name: ftw
restart: unless-stopped
stop_grace_period: 60s
environment:
# Turns on the in-app self-update feature (version-check banner +
# Update/Restart buttons). Only meaningful alongside the ftw-updater
# sidecar below; native / OS-image deploys leave this unset so the
# UI hides the feature entirely. See docs/self-update.md.
FTW_SELFUPDATE_ENABLED: "1"
# Beta and stable point at one exact image digest. The image binds both
# allowed release identities; this immutable tag selects one of them.
# The updater pins it in .env after update.
FTW_IMAGE_TAG: ${FTW_IMAGE_TAG:-}
# Optional Bearer token for API mutations addressed through a public or
# fully-qualified hostname. Keep it in .env so updater-driven recreates
# retain it. Local LAN addresses continue to work without a token.
FTW_API_TOKEN: ${FTW_API_TOKEN:-}
# Host networking is required for:
# - Modbus TCP to inverters / meters on the LAN
# - MQTT brokers on the LAN (no port forwarding)
# - mDNS-based drivers (e.g. Sourceful Zap at zap.local)
#
# If you don't have any local hardware (e.g. you're just evaluating
# the UI) you can drop this line and add `ports: ["8080:8080"]`
# instead, at the cost of losing mDNS/broadcast driver discovery.
network_mode: host
volumes:
- ./data:/app/data
# Shared volume with the updater — the main app reads state.json from
# here to render update progress in the UI; it never writes to it.
- update-ipc:/run/ftw-update
# OPTIONAL — avahi-daemon's runtime directory. Host networking shares
# ports, not Unix sockets, so this is the only way in.
#
# With it, FTW asks the host's mDNS responder to resolve `.local` device
# names (and `getent hosts zap.local` works inside the container, via
# libnss-mdns). Without it FTW queries the LAN itself, which needs no
# host software and is why this stays commented out by default.
#
# Uncomment only if the host runs avahi-daemon, as Raspberry Pi OS
# does. Mount the DIRECTORY, not the socket inside it: if the path is
# missing Docker creates it, and an empty directory there is harmless,
# whereas a directory created where the *socket* belongs stops
# avahi-daemon from ever starting. Restarting avahi after the container
# detaches the mount, so restart FTW too if you do.
# - /run/avahi-daemon:/run/avahi-daemon:ro
ftw-updater:
# Normally follows :latest. The separate variable is only needed for
# bootstrapping a beta pair before the installed stable updater
# understands that prerelease's immutable tag.
image: ghcr.io/srcfl/ftw-updater:${FTW_UPDATER_IMAGE_TAG:-latest}
container_name: ftw-updater
restart: unless-stopped
# No network — the sidecar reaches the host daemon over its Unix
# socket and the main app reaches it over a Unix socket inside
# update-ipc. Nothing needs to leave this container.
network_mode: none
environment:
# Point the sidecar's internal `docker compose -f <path>` at the
# same absolute host path the user invoked compose with. This
# matters because the host daemon — not the sidecar — interprets
# the bind paths in the file, so they must be real host paths.
FTW_UPDATER_COMPOSE: ${PWD:-.}/docker-compose.yml
FTW_UPDATER_MAIN_SERVICE: ftw
# Without this the sidecar's internal compose would derive its
# project name from the -f file's parent dir and create a parallel
# set of containers/volumes instead of recreating the real ones.
# Defaults to `ftw` (matches the layout in
# operations.md); override at launch time if your deploy dir is
# named differently:
# COMPOSE_PROJECT_NAME=myhome docker compose up -d
COMPOSE_PROJECT_NAME: ${COMPOSE_PROJECT_NAME:-ftw}
volumes:
# The Docker socket is the ONE privileged resource the sidecar
# touches. Needed so it can `docker compose pull` + recreate the
# main service. If you want to harden this further, put
# tecnativa/docker-socket-proxy in front and swap the bind.
- /var/run/docker.sock:/var/run/docker.sock
# Bind the WHOLE project directory at its host path, read-only.
# Rationale: when the sidecar runs `docker compose up -d`, compose
# asks the host daemon to resolve `./data:/app/data` — which the
# daemon reads as an ABSOLUTE HOST PATH. If the path inside the
# sidecar doesn't match the host, the daemon binds a phantom
# directory and the recreated main container boots with empty
# state. ${PWD} comes from the shell at `docker compose up` time,
# which is the invocation flow documented in operations.md.
- ${PWD:-.}:${PWD:-.}:ro
# Shared with the main container so the update status survives the
# main app being recreated (volume contents outlive the container
# lifecycle of individual services that mount the same volume).
- update-ipc:/run/ftw-update
# ---------------------------------------------------------------------
# MQTT broker (Eclipse Mosquitto)
#
# Lets on-LAN devices — notably the Pixii PowerShaper's MQTT uplink —
# publish telemetry into FTW without us having to poll them
# over Modbus. The main app reaches the broker at localhost:1883 because
# it runs with host networking; the Pixii (and any other LAN device)
# reaches it at <host-ip>:1883.
#
# Config lives in ./mosquitto/config/mosquitto.conf (anonymous access,
# persistent queues). Remove this service block if you don't need an
# embedded broker — FTW drivers can just as well dial out
# to a broker somewhere else on the LAN.
# ---------------------------------------------------------------------
mosquitto:
image: eclipse-mosquitto:2
container_name: ftw-mosquitto
restart: unless-stopped
ports:
- "1883:1883"
volumes:
- ./mosquitto/config:/mosquitto/config:ro
- mosquitto-data:/mosquitto/data
volumes:
update-ipc:
mosquitto-data: