Repository navigation
Platforms
The same image name works everywhere, but each host has one thing you must get right. These are the differences that actually break setups.
| Platform | Base image | Timezone | Mount owner | Watch out for |
|---|---|---|---|---|
linux/amd64 |
ASP.NET runtime (Debian) |
TZ, IANA id |
uid 1654 | Leave Controller__TimeZone empty |
linux/arm64 |
ASP.NET runtime (Debian) |
TZ, IANA id |
uid 1654 | Enable cgroup memory accounting first |
nanoserver ltsc2022 |
ASP.NET runtime (Nano Server) |
Controller__TimeZone, Windows id
|
n/a | No ICU; TZ is ignored; amd64 only |
The straightforward case — nothing platform-specific beyond the uid 1654 ownership covered in Configuration. The command in Docker works as written.
Raspberry Pi OS ships with cgroup memory accounting disabled — the firmware prepends
cgroup_disable=memory to the kernel command line, so it appears in /proc/cmdline while no file on
the boot partition mentions it. Without it every mem_limit is silently ignored: docker inspect
records Memory=0 and docker stats shows 0B / 0B for every container. On a 1 GB board that is
the difference between one container being killed and the whole box thrashing; on a 4 GB one you
mainly lose the per-container figures you need to diagnose a leak. Required on every board whatever
its memory — what you append below lands after the firmware's copy, and the later parameter wins.
sudo cp /boot/firmware/cmdline.txt /boot/firmware/cmdline.txt.bak
# cmdline.txt is ONE single line. The bootloader reads only the first line,
# so appending a second line leaves the parameters completely inert.
sudo sh -c '
line=$(tr "\n" " " < /boot/firmware/cmdline.txt | tr -s " " | sed "s/[[:space:]]*$//")
case $line in
*cgroup_enable=memory*) ;;
*) line="$line cgroup_enable=memory cgroup_memory=1" ;;
esac
printf "%s\n" "$line" > /boot/firmware/cmdline.txt
'
wc -l /boot/firmware/cmdline.txt # MUST print 1
cat /boot/firmware/cmdline.txt # check it before rebooting
sudo rebootCheck the file before rebooting: a mangled cmdline.txt means a Pi that will not boot, and fixing
that needs the storage in another machine. After the reboot, confirm what the kernel actually
booted with — that is the authoritative answer.
cat /proc/cmdline | tr ' ' '\n' | grep cgroup
docker info 2>&1 | grep -i "memory limit" # note 2>&1 — warnings go to stderrNote
Two things that look wrong but aren't. cgroup_disable=memory stays visible in
/proc/cmdline — the Pi firmware injects it and it exists in no file you can edit. Firmware
parameters come first, so your cgroup_enable=memory is processed later and wins. Both being
present is the normal working state. Separately, WARNING: No swap limit support is expected and
harmless — swap accounting is a different facility and nothing here asks for it. Only
No memory limit support matters.
On Bullseye and older the file is /boot/cmdline.txt instead — /boot/firmware/ is the
Bookworm-and-later layout, where /boot/cmdline.txt is a stub that says not to edit it.
The Windows image is built on Nano Server ltsc2022, which runs on both Windows Server 2022 and 2025
hosts. Your Docker daemon must be in Windows containers mode.
Warning
You must set the timezone explicitly. .NET on Windows ignores the TZ environment variable
entirely, so an unconfigured container runs in UTC and stamps every recorded charging session
with the wrong day. Nano Server also ships no ICU, so the IANA-to-Windows zone mapping is
unavailable — you must give a Windows zone id, not an IANA one.
docker run -d --name solax-controller --restart on-failure ^
-e Controller__TimeZone="Central Europe Standard Time" ^
-e Solax__Inverter__Host=192.168.2.10 ^
-e Solax__EvCharger__Host=192.168.2.6 ^
-v C:\solax\data:C:\app\data ^
-v C:\solax\logs:C:\app\logs ^
ghcr.io/mpospisil/solax-controller:latestUse Central Europe Standard Time, not Europe/Prague. An id that cannot be resolved stops the
worker at startup rather than quietly reverting to UTC — that failure is deliberate, and it is the
good outcome.
The published images are cross-compiled rather than emulated, so no QEMU is involved. You only need this to test an unreleased change.
docker build --platform linux/arm64 -t solax-controller .
docker build --platform linux/amd64 -t solax-controller .
# Windows needs its own Dockerfile — a Dockerfile targets one OS,
# and a Windows runtime stage only assembles on a Windows daemon.
docker build -f Dockerfile.windows -t solax-controller:nanoserver .Previous: Docker · Next: Deployment
Runs entirely on your LAN · Full configuration reference in README.md · Pi preparation and backup in deploy/README.md
- Home
- Get started — build & run
- Configuration
- Solcast
- Weather
- Troubleshooting
Advanced
- Docker
- Platforms
- Deployment — Pi, two workflows
- MQTT
Images: ghcr.io/mpospisil/solax-controller