After a power outage took out half my containers and I didn't notice for hours, I decided I needed proper uptime monitoring. Here's how I got it for free, without opening a single inbound port.

The problem

I run a home server I call "mother" — Fedora Linux, Podman, about 10 containers:
Home Assistant, Frigate NVR, AdGuard Home, Mosquitto MQTT, Nginx Proxy Manager and a few others.

For a long time I had zero visibility into whether things were actually running.
After a power outage I found out half my containers hadn't come back up — only discovered it when my automations stopped working hours later.

I looked at existing monitoring tools but hit the same wall every time: they're either cloud-only (can't reach 192.168.0.x private IPs) or they require you to open inbound ports to your network. Neither option worked for me.

The solution

I found Monitorion's private worker
— MIT licensed, runs in Docker, and flips the model entirely.

Instead of the cloud poking your services from outside, a lightweight agent runs
inside your network and pushes results outward. No inbound ports. No tunnels.
No VPN. Just outbound HTTPS to the platform.

[Home Network] [Monitorion Cloud] home-assistant:8123 ──┐ frigate:5000 ──┤ adguard:3000 ──┼──► dashboard + alerts router (192.168.0.1) ──┤ NAS (192.168.0.108) ──┘ ↑ all checks run from inside your network ↑ no inbound ports required 

Setup — under 5 minutes

1. Create a free account at app.monitorion.com

2. Go to Settings → Private Workers → Add Worker and copy your wkr_… key

3. Add this to your docker-compose.yaml:

monitorion-worker: image: ghcr.io/monitorion/monitorion-worker:latest container_name: monitorion-worker restart: unless-stopped cap_add: - NET_RAW # required for ping checks cap_drop: - ALL security_opt: - no-new-privileges:true read_only: true tmpfs: - /tmp:size=16m environment: - MONITORION_PLATFORM_URL=https://app.monitorion.com - MONITORION_API_KEY=wkr_xxxxxxxxxxxx # paste your key here - WORKER_NAME=mother 
  1. Run it:

docker compose up -d monitorion-worker

The worker registers itself with the platform, polls for jobs every 15 seconds,runs the checks, and pushes results out. Done.

What I'm monitoring now

All private IPs, all from inside the LAN:

HTTP checks:

  • AdGuard Home (:3000)
  • Home Assistant (:8123)
  • Frigate NVR (:5000)
  • Homepage dashboard (:3002)
  • Excalidraw (:3003)
  • Nginx Proxy Manager (:81)
  • Cockpit server admin (:9090)

Port checks:

  • SSH (:22)
  • MQTT / Mosquitto (:1883)
  • AdGuard DNS (:53)
  • Reolink entrance camera RTSP (:554)

Ping checks:

  • Main router (192.168.0.1)
  • Second AP / TP-Link (192.168.0.2)
  • Seagate NAS (192.168.0.108)
  • Reolink camera (192.168.0.173)
  • Somfy TaHoma smart blinds gateway (192.168.0.209)
  • Roborock S5 vacuum (192.168.0.248)

13 check types are supported in total — including SSL cert expiry, DNS, SMTP, WebSocket, and a JSON API checker that can assert on response field values.

What it caught immediately

Within the first few days:

  • Home Assistant went down for ~3 minutes during a container restart — would have missed it completely before
  • Nginx Proxy Manager had a brief hiccup after watchtower auto-updated it and recreated the container with a broken config — caught within 15 seconds

What I paid

Nothing. The free account covers the private worker and email alerts.

What I wish was better

The REST API doesn't let you assign the private worker to monitors programmatically — you have to open each monitor in the dashboard and set "Run from → your worker" manually. With 18 monitors this took a few minutes.
A bulk-assign option would be a big quality-of-life improvement.

Useful links

Happy to answer questions about the Podman setup, the cgroupv2 quirks I ran into, or the full compose stack.