| title | Security Checklist | ||||||||
|---|---|---|---|---|---|---|---|---|---|
| summary | Production security hardening checklist for the Pool Controller — default password change, OTA security, MQTT configuration, network isolation, and firmware integrity | ||||||||
| date | 2026-06-14 | ||||||||
| lastmod | 2026-06-14 | ||||||||
| draft | false | ||||||||
| toc | true | ||||||||
| type | docs | ||||||||
| tags |
|
||||||||
| menu |
|
⚠️ WARNING: Some security measures reference 230V AC mains voltage (relay testing, power supply verification). Always disconnect power before working on the circuit. If unsure, hire a qualified electrician.
This checklist covers security hardening measures for the Pool Controller. While the controller runs on a local network and operates pumps (not life-critical systems), following these recommendations prevents unauthorized access and reduces attack surface.
The factory-default web interface password must be changed before connecting the controller to any network.
- Default:
admin - Action: Web UI → Security & Update → Change Password
- Requirements:
- Minimum 8 characters
- Mix of uppercase, lowercase, digits, and special characters
- Not a reused password from other services
- Note: This same password protects the OTA update endpoints — there is no separate OTA password.
- Action: Configure MQTT username and password in controller settings
- Why: Unauthenticated MQTT allows anyone on the network to publish to controller topics
- Recommended: Create a dedicated MQTT user for the controller with minimal permissions
-
Action: Bind MQTT broker to local network interface only
-
Why: A publicly accessible MQTT broker can be discovered and abused
-
Mosquitto configuration:
listener 1883 192.168.1.10 allow_anonymous false password_file /etc/mosquitto/passwd
-
Do NOT expose port 1883 or 8883 to the internet
- The web interface listens on all interfaces by default
- Action: Ensure the controller is on a trusted local network
- Do NOT expose port 80/443 of the controller to the internet
- If remote access is needed, use a VPN (WireGuard, Tailscale, OpenVPN) or Home Assistant's secure remote access
- Action: Only flash firmware from official GitHub Releases
- Why: Unofficial firmware could contain backdoors or unsafe modifications
- Verification:
- Download from official releases
- Check the release tag matches the expected version
- Build from source yourself if you want full control
- Action: Save a screenshot or export of current configuration before updating firmware
- Why: OTA failures can corrupt the filesystem and require re-flashing
- Note: The controller's configuration is stored in NVS and survives re-flashing in most cases, but a backup is recommended
- Action: Verify relay operation with a multimeter before connecting 230V AC pumps
- Why: A malfunctioning relay could leave a pump permanently on, creating a safety hazard
- Procedure: See Hardware Guide → Relay Testing
For advanced setups:
- Place the ESP32 on an IoT VLAN with restricted internet access
- Allow only: MQTT broker, NTP server, Home Assistant
- Block all inbound connections from the internet
- Action: If you don't use OTA updates:
- To disable GitHub-based OTA only: Block outbound HTTPS (port 443) from the controller at your network firewall
- To fully disable OTA (including manual upload): Remove the OTA route
registrations in
src/WebPortal.cpp(lines 175–228) and rebuild the firmware; or block both inbound and outbound OTA at the firewall
- Action: If you don't need the web interface, restrict access via network firewall rules
- Why: Reducing attack surface reduces risk
Internet
│
│ (blocked)
▼
┌──────────────┐ ┌────────────┐ ┌──────────────────┐
│ Home Router │─────│ Local LAN │─────│ Pool Controller │
│ (Firewall) │ │ 192.168.x.x│ │ ESP32 │
└──────────────┘ └────────────┘ └──────────────────┘
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ MQTT Broker │ │ Home Assistant│
│ (local only) │ │ (local only) │
└──────────────┘ └──────────────┘
| Source | Destination | Port | Protocol | Action | Purpose |
|---|---|---|---|---|---|
| Controller | DNS Server | 53 | UDP/TCP | Allow | Name resolution |
| Controller | MQTT Broker | 1883 | TCP | Allow | MQTT communication |
| Controller | NTP Server | 123 | UDP | Allow | Time sync |
| Controller | Internet | 80 | TCP | Block | No web access needed |
| Controller | Internet | 443 | TCP | Allow | OTA update (GitHub) |
| Internet | Controller | any | any | Block | No inbound access |
| HA Server | Controller | 80 | TCP | Allow | Web UI / API |
Note: If you do not use OTA updates, port 443 can be blocked instead. The controller only uses HTTPS egress to check for and download firmware releases from GitHub.
| Credential | Storage | Encrypted? |
|---|---|---|
| WiFi password | NVS | No (ESP32 NVS is not encrypted by default) |
| MQTT password | NVS | No |
| Web UI password | NVS | SHA-256 hashed |
Note: NVS values are stored in plain text on the flash chip. Physical access to the device compromises all credentials. Enable Flash Encryption for production deployments.
For advanced security, enable ESP32 flash encryption:
- Enable in menuconfig:
Security features → Enable flash encryption - Burn efuse to permanently enable encryption
- Re-flash firmware
- All NVS data will be encrypted at rest
⚠️ Warning: Flash encryption is irreversible on most ESP32 modules. Once enabled, you cannot read the flash without the encryption key.
- Hardware Guide — Build and wiring instructions
- Software Guide — First-time setup and configuration
- MQTT Configuration — MQTT broker setup
- Troubleshooting Matrix — Common issues and fixes