Sunil Saharan

Expose a Raspberry Pi IoT Dashboard Securely with IPv6, Caddy, and MQTT (Part 2)

Make a Raspberry Pi Zero W dashboard reachable beyond the home network. Learn how Dynu IPv6 DNS, router firewall rules, Caddy HTTPS, MariaDB page-load counts, a moderated guestbook, and a private MQTT broker fit together.

Live project: home-pi.freeddns.org. In Part 1, I built the local Raspberry Pi Zero W sensor dashboard. This second part explains how I made the site reachable from outside my home network and added a small visitor counter and guestbook service.

What this part covers. Dynamic DNS for a changing IPv6 address, HTTPS with Caddy, the difference between IPv4 port forwarding and an IPv6 firewall rule, a MariaDB-backed page-load counter, and a roadmap for adding ESP8266/ESP32 devices without exposing the MQTT broker to the public internet.

Remote access is a chain of separate checks

A domain name by itself does not make a home server reachable. The hostname must resolve to the current address, the router must allow the incoming traffic, the Pi must have a listener on the destination port, and the website must present a valid certificate. Troubleshooting got much easier when I checked those pieces in order instead of repeatedly changing Caddy.

Client on mobile data
        │ DNS AAAA lookup
        ▼
Dynu hostname → current global IPv6 address
        │ router IPv6 firewall allows HTTPS
        ▼
Caddy on Raspberry Pi :443
        ├── static website
        ├── /api/metrics → local Python service
        └── /api/community/* → local community service

Dynamic DNS with IPv6

My JioFiber connection assigned the Pi a global IPv6 address. I used Dynu's v2 API to maintain the hostname's AAAA record. The updater must read the Pi's current global IPv6 address, then update the intended DNS record when that address changes. I keep the API key in a root-readable file and never put it in an article, a public repository, or a command that leaves it in shell history.

After an update, verify the record from a different network. A successful API response confirms that Dynu accepted the update; it does not prove that inbound traffic can reach the Pi. DNS caches can also make a new address appear inconsistently for a short time.

IPv6 firewall rules are not IPv4 port forwarding

The router exposed separate IPv4 firewall, IPv6 firewall, and port-forwarding pages. My Pi had a global IPv6 address, so the relevant control was an IPv6 firewall allow rule for HTTPS to the Pi. An IPv4 port-forward rule would solve a different routing problem. I allowed the web service and kept SSH unavailable from the public network.

From Airtel mobile data, the hostname first resolved to the Pi's IPv6 address but an HTTPS request timed out. After adjusting the router's IPv6 firewall, the same external HTTPS check returned HTTP 200 from Caddy. SSH still did not work from Airtel, which is appropriate for this setup: the website is the public entry point, and administration remains a separate, restricted path. Results can vary by carrier, router firmware, and firewall state, so test from a network outside the home Wi-Fi.

Important: Do not expose SSH or an unauthenticated MQTT listener just to make remote access easier. Public web access should go through HTTPS. Use a VPN or another deliberately secured administration method for shell access.

Use Caddy as the single web entry point

Caddy serves the static pages and proxies only the API paths to services bound to loopback. MariaDB and the Python APIs are not exposed directly on the router. Caddy's file_server and reverse_proxy directives provide the basic pieces; the page routes and authentication rules must match the paths used by the frontend.

home-pi.freeddns.org {
    root * /var/www/home-pi

    handle /api/community/admin/* {
        # Add HTTP authentication here.
        reverse_proxy 127.0.0.1:8766
    }
    handle /api/community/* {
        reverse_proxy 127.0.0.1:8766
    }
    handle /api/* {
        reverse_proxy 127.0.0.1:8765
    }
    handle {
        file_server
    }
}

This is an architecture example, not a drop-in configuration: include the certificate setup, real authentication credentials, and page routes for your site. Validate the Caddyfile before reloading, then test local routes before testing over mobile data. I obtained the certificate using a DNS challenge because it lets certificate validation use DNS rather than relying on inbound HTTP port 80.

Count page loads without building a tracking profile

I added a small local MariaDB database for a daily aggregate page-view count. Each page load increments a date bucket. This is a count of page loads, not unique visitors: a refresh counts again, and automated traffic may count too. The design does not need to store visitor IP addresses or add tracking cookies.

The community Python service connects to MariaDB over loopback using a dedicated database account. The public site can request the count through Caddy, while the database port stays private. Give the application account only the SQL privileges it needs, use parameterized queries, and keep the database password in a protected environment file rather than in source code.

A guestbook needs moderation from the start

A guestbook is a useful small web project because it exercises forms, validation, a database, API routes, and moderation. New messages should enter a pending state. Only approved messages should appear publicly. Add a honeypot, basic rate limiting, strict length limits, safe text rendering, and an authenticated admin page with approve and delete actions.

Before publishing a guestbook, test the entire moderation path: submit a message, confirm that it stays pending, approve it, verify that it becomes public, and remove a test entry. Check that the admin page and admin API are both protected. A page that loads is not proof that its buttons or database permissions work.

Ideas for an embedded systems home lab

  • ESP sensor fleet: give each ESP8266 or ESP32 a device ID and publish JSON telemetry to a topic such as home/room1/temperature.
  • Device health board: display last-seen time, signal strength, firmware version, and battery voltage alongside sensor values.
  • Greenhouse monitor: combine temperature, humidity, and soil moisture; use an ESP32 for analog measurements and the Pi for storage and visualization.
  • Field telemetry experiment: use a low-power LoRa node and a home gateway to report pump status or tank level. Measure range on the actual site and follow local radio rules; terrain, antenna height, and antenna quality matter more than a headline range claim.
  • Control with feedback: start with a harmless LED or test load. Require authenticated commands, device acknowledgements, timeouts, and a safe local fallback before controlling equipment.

Keep MQTT local and design controls carefully

My intended architecture uses Mosquitto as a local message broker for ESP devices. Do not port-forward an unauthenticated MQTT port to the internet. Use broker authentication and topic ACLs on the LAN; if remote device access is required, use a VPN or a carefully designed TLS endpoint with authorization. The website should send an authenticated request to a backend service, which validates it before publishing a narrow command topic. A button click is not proof that a relay or pump changed state.

For pumps, mains equipment, or machinery, the web application must never replace electrical protection, interlocks, overload protection, a manual stop, or a safe local operating mode. Treat the Pi as a supervisory interface, not a safety controller.

What I would build next

The next useful increment is a device registry: give every node a name, expected topics, and a last-seen timestamp. Then add a history view and a simple alert when a reading is stale. After that, test commands with a low-voltage demo board and show the returned state separately from the requested state.

These projects are a practical way to learn embedded systems beyond blinking an LED: sensor interfaces, Linux device drivers, MQTT topic design, IPv6 networking, TLS, data persistence, and user interfaces all meet in one small, inspectable system.

Start at Part 1: Build the local Raspberry Pi Zero W IoT dashboard. The live demo is home-pi.freeddns.org.

References

– (0 ratings)

Your rating:

Comments (0)

Sign in or create an account to leave a comment.

No comments yet.