-
Notifications
You must be signed in to change notification settings - Fork 0
Installing on Windows
A first-class Windows deployment: Breeze Core runs as a hardened Windows service (via the bundled NSSM), with an optional guided Caddy reverse proxy for public HTTPS and a fail2ban-style IP banner. There's a click-through NSIS installer, or you can drive the same PowerShell scripts by hand.
Contents: 1. Prerequisites · 2. Guided installer · 3. Manual install · 4. Day to day · 5. Caddy / public HTTPS · 6. Tripwire · 7. Hardening notes · 8. Uninstall · 9. Build it yourself
What you get, and the trade-off. The service runs unprivileged (
LOCAL SERVICE), keeps its state in a locked-down%ProgramData%\breeze-core, and is firewalled to the LAN. Windows has no equivalent of the systemd kernel sandbox (syscall filter,IPAddressDeny), so for an internet-facing box a systemd Linux host or a container is still the stronger option — but the pieces below recover the important parts (privilege drop, filesystem confinement, TLS, XFF-overwrite, and IP banning). See HARDENING.md sec. 7.
Everything here targets Windows 10/11 / Server 2019+, amd64. Run the elevated (Administrator) steps from PowerShell.
-
Python 3.11+ on
PATH(py -3 --version). If missing:winget install Python.Python.3.12(or grab it from python.org — tick Add to PATH). The installer/scripts build a private virtualenv from it; they don't touch your global Python. - Administrator rights (registering a service + firewall rules).
- Your Midea units already on WiFi (via the NetHome Plus app).
- Internet access at install time (to download Python deps and, if you use it, Caddy).
-
Download
Breeze-Core-Setup.exefrom the latest release — or from the package host, bolero.salataputarica.hr.eu.org/windows/, which publishes a.sha256next to each build — and run it (it asks for elevation).Or install it with winget
Breeze Core isn't in the public winget-pkgs repository (yet), so this goes through a manifest — which Windows gates behind an admin setting. In an elevated PowerShell, once:
winget settings --enable LocalManifestFilesThen, as yourself:
mkdir breeze-core-3.0.2; cd breeze-core-3.0.2 'Breeze.BreezeCore.yaml','Breeze.BreezeCore.installer.yaml','Breeze.BreezeCore.locale.en-US.yaml' | % { iwr "https://bolero.salataputarica.hr.eu.org/winget/3.0.2/$_" -OutFile $_ } winget install --manifest .
winget downloads the installer from the GitHub release and verifies it against the SHA256 in the manifest. The manifests live in
packaging/winget/<version>/;InstallerType: nullsoftis what tells winget the silent switch is/S.A private winget source (
winget source add) isn't possible against bolero — winget sources are a REST API, and bolero serves static files only. -
On the Components page:
-
Breeze Core server (Windows service) — required. Copies the app, builds
the venv, installs dependencies, and registers the hardened
BreezeCoreservice (LAN-first bind,LOCAL SERVICE, LocalSubnet firewall rule). - Caddy reverse proxy (guided setup) — optional and separate. Tick it only if you're exposing Breeze Core to the internet; it just opts you into running the Caddy wizard at the end (you can also run it any time later from the Start menu).
-
Breeze Core server (Windows service) — required. Copies the app, builds
the venv, installs dependencies, and registers the hardened
-
On the Finish page:
-
Pair my AC units now — opens a console that runs discovery, writes
config.json, and prints your API key once (save it!). - Set up the Caddy reverse proxy now — launches the Caddy wizard (only pre-ticked if you chose that component).
-
Pair my AC units now — opens a console that runs discovery, writes
After pairing, start the service if it isn't already:
nssm start BreezeCore # or: Start-Service BreezeCoreThen open http://<this-PC-LAN-IP>:8420 on the LAN, enter the API key, and pair
a client. Start-menu shortcuts are installed for pairing, the Caddy wizard, and
editing the service.
Get the code (git clone or copy the tree) to e.g. C:\Program Files\Breeze Core,
then from an elevated PowerShell in deploy\windows:
# 1. fetch the bundled service wrapper (NSSM) into .\vendor
powershell -ExecutionPolicy Bypass -File .\fetch-vendor.ps1
# 2. build the venv + register the hardened BreezeCore service (LAN-first)
powershell -ExecutionPolicy Bypass -File .\install-service.ps1 `
-Action Install -InstallDir "C:\Program Files\Breeze Core" -Nssm .\vendor\nssm.exe
# 3. pair your units (writes config.json, prints the API key once)
$env:AC_CONFIG = "$env:ProgramData\breeze-core\config.json"
& "C:\Program Files\Breeze Core\venv\Scripts\python.exe" `
"C:\Program Files\Breeze Core\setup_device.py"
# 4. start it
nssm start BreezeCoreinstall-service.ps1 flags: -BindHost <ip> (default: auto-detected LAN IP),
-Port 8420, -BehindProxy (bind loopback + --proxy-headers + AC_BEHIND_PROXY=1),
-LockEgress (best-effort outbound lockdown, see sec. 7),
-NoFirewall, and -Action Uninstall [-Purge].
BreezeCore is an auto-start service wrapping
venv\Scripts\uvicorn.exe meow_ac.app:app:
nssm start BreezeCore
nssm stop BreezeCore
nssm restart BreezeCore
nssm edit BreezeCore # GUI: account, args, environment
Get-Service BreezeCore-
Account:
NT AUTHORITY\LocalService(low privilege, no password). -
State/logs:
%ProgramData%\breeze-core\—config.json,devices.json,programs.json, andlogs\service.log(rotated). The folder's ACL is stripped of inheritance and granted only to SYSTEM, Administrators, and LOCAL SERVICE — the Windows analogue ofchmod 600/750. - Restart: NSSM restarts the process automatically if it exits.
The service errors (HTTP 500) until you've paired — it needs
config.json. Pair first (step 3 above or the installer's finish page), then start it.
The Caddy wizard is the Windows counterpart of the Linux
deploy/reverse-proxy-wizard.sh. Caddy is a single binary with automatic
HTTPS (Let's Encrypt) — no certbot, no manual renewal.
# preview everything first — writes nothing, downloads nothing:
powershell -ExecutionPolicy Bypass -File .\caddy-wizard.ps1 `
-Domain breeze.example.com -Email you@example.com -DryRun
# then for real (add -SetupTripwire to also install the IP banner):
powershell -ExecutionPolicy Bypass -File .\caddy-wizard.ps1 `
-Domain breeze.example.com -Email you@example.com -SetupTripwireWhat it does:
- Downloads the official Caddy binary (the reverse-proxy step is deliberately not bundled — it's a separate, optional choice).
- Renders a hardened Caddyfile (
%ProgramData%\breeze-core\Caddyfile) andcaddy validates it:- Automatic HTTPS + HTTP→HTTPS redirect.
- HSTS +
nosniff+X-Frame-Options: DENY+Referrer-Policy+ COOP; theServerheader is stripped. (The app sends its own strict CSP — Caddy never adds a second one.) -
X-Forwarded-For is the real client. With no
trusted_proxiesconfigured, Caddy drops any client-sent (forged)X-Forwarded-Forand sets it to the real peer — the overwrite HARDENING.md requires so nobody can fake a "LAN" client. Don't add public ranges totrusted_proxies. -
Admin endpoints (
/api/auth/enroll/approve,/api/auth/devices) are403'd unless the caller is on the LAN — defence in depth with the app's own check, and the signal the tripwire watches.
-
Rebinds
BreezeCoreto127.0.0.1with--proxy-headersandAC_BEHIND_PROXY=1(so only Caddy can reach it). Pass-KeepLanBindto also keep it directly reachable on the LAN. - Registers
BreezeCaddyas an auto-start service and opens inbound TCP 80/443. - With
-SetupTripwire, installs the banner (next section).
Point your domain's A/AAAA record at the host and forward 80/443 at your
router. Browse to https://breeze.example.com — Caddy fetches the certificate
on first hit. Walk the go-live checklist
before you announce the hostname.
A static reference config is in
deploy/windows/Caddyfile.example if you
prefer to hand-edit.
Windows has no fail2ban, so deploy/windows/breeze-tripwire.ps1 fills the gap.
It tails Caddy's JSON access log and bans abusive source IPs with Windows
Firewall block rules — the Windows analogue of the
HARDENING.md sec. 3 jails:
-
General: ≥ 5
4xx/5xxfrom one IP within 10 min → 24 h ban. -
Tripwire: any
403on an admin endpoint is hostile → 7-day ban. - LAN is never banned (so you can't lock yourself out); bans expire automatically.
Enable it with the wizard's -SetupTripwire, or install it standalone as the
BreezeTripwire service. It needs rights to manage the firewall, so it runs as
LocalSystem (NSSM's default) — the only component that isn't LocalService.
Get-NetFirewallRule -DisplayName "BreezeBan *" # see who's currently banned
Get-Content "$env:ProgramData\breeze-core\logs\tripwire.log" -Tail 20Tunable via parameters (-MaxRetry, -FindWindowSec, -BanSec,
-TripwireBanSec, -LanCidr).
| systemd protection (Linux) | Windows equivalent here |
|---|---|
Unprivileged User=
|
Service runs as LOCAL SERVICE
|
ProtectSystem / mode 600 |
%ProgramData%\breeze-core ACL: inheritance off, SYSTEM/Admins/LocalService only |
| Inbound restricted to LAN | LocalSubnet-only firewall rule on the port (LAN mode) |
| TLS + HSTS + XFF-overwrite | Caddy auto-HTTPS + headers + default XFF overwrite |
| fail2ban jails | the BreezeTripwire watcher |
IPAddressDeny=any (egress) |
weak point — see below |
Egress lockdown is the one thing Windows can't do cleanly per-app. The
optional install-service.ps1 -LockEgress adds an outbound block rule for the
service's python.exe to RemoteAddress Internet, allowing only LAN/Intranet —
but Windows' "Internet" classification depends on the network-location profile
and isn't as tight as IPAddressDeny. Treat it as best-effort; verify your
units still respond after enabling it. For strict egress control, run Breeze
Core in a container or on a systemd Linux host.
Via Apps & features → Breeze Core, the Start-menu Uninstall shortcut, or
the scripts. Uninstalling removes the BreezeCore / BreezeCaddy /
BreezeTripwire services, their firewall rules, and the program files — but
keeps %ProgramData%\breeze-core (your config + device tokens). Delete that
folder by hand to wipe everything, or:
powershell -ExecutionPolicy Bypass -File .\install-service.ps1 -Action Uninstall -PurgeRequires NSIS (makensis) and internet (for the
bundled NSSM). From the repo root:
powershell -ExecutionPolicy Bypass -File .\deploy\windows\fetch-vendor.ps1 # -> vendor\nssm.exe
.\deploy\windows\build-installer.ps1 # -> Breeze-Core-Setup.exebuild-installer.ps1 reads the version from meow_ac/__init__.py and passes it
to makensis, so the installer can't claim a version the package doesn't have.
Pass -OutDir <dir> to also drop a versioned copy (Breeze-Core-Setup-<v>.exe)
somewhere; it prints the SHA256 either way.
This is the one release artifact CI can't produce — makensis needs
Windows. Build it on a Windows box at release time and attach it to the tag;
packaging/repo/build-bsd-repo.sh stages it for the package host from
WINDOWS_EXE=<path>, the same way the Android APK is staged.
vendor\ and build output are git-ignored — no binaries are committed.
For a testing-only quick run without a service, see the short Windows note in INSTALL.md. Next: the threat model and go-live checklist in HARDENING.md.
Breeze Core · Breeze for Android · Packages · AGPL-3.0
Start here
Install it
Use it
Reference
Run it safely
Develop and port