EasyMonitor is a free, open source monitoring & observability project written in PHP and released under MIT. It has 75 GitHub stars, 7 forks and 0 open issues, and was last pushed 27 days ago. On this registry it ranks #94 of 97 tracked projects in Monitoring & Observability, with 5 head-to-head comparisons available.

What is EasyMonitor?

EasyMonitor is an open-source, self-hosted uptime and performance monitoring platform for websites and APIs, built for teams that want to run their own checks, alerts, and status pages on their own hardware instead of on a vendor's servers.

What it is

EasyMonitor is a full-stack monitoring application written in PHP on Laravel 12 and PHP 8.4, with a Livewire 3 interface and a separate Go 1.24 probe binary. It stores check results in PostgreSQL 18 with TimescaleDB 2.26, moving scheduling and result jobs across Redis 7 Streams, and it serves traffic through Caddy 2.10 in front of Nginx and PHP-FPM, with Supervisor and Laravel Horizon handling queues. The project is licensed under MIT. Users add a URL, choose a check interval, and receive alerts when a target goes down and when it recovers.

The concrete problem it solves is the recurring subscription behind hosted uptime services: instead of paying a vendor per monitor and per region, an operator runs the whole monitoring stack from a single docker compose up on hardware they control. Check history, projects, team membership, status page content, and alert routing all stay inside the self-hoster's own database and network. It also removes the operational guesswork around check intervals and false positives by pairing configurable intervals with a consecutive-failure threshold and optional probes in multiple regions.

Key capabilities

  • HTTP, ICMP, and TCP port checks, with a per-monitor interval between 30 seconds and 1 hour.
  • SSL certificate expiry monitoring captured during HTTPS checks, with alerts at 30, 14, and 7 days before expiry.
  • Multi-region probes distributed as lightweight Go binaries of roughly 10 MB, deployable anywhere with a network path back to the server's Redis.
  • Multi-channel alerting to email, Slack, Discord, Telegram, ntfy, generic webhooks signed with HMAC, and Pushover, selectable per user and per monitor for both down and recovery events.
  • Consecutive-failure thresholds configurable per monitor, so a single flaky failure does not trigger an alert.
  • Public, unlisted (secret link), or private status pages, supporting whole projects or individual monitors, hidden monitors, themes, custom CSS, logo upload, incidents, and scheduled maintenance with timeline updates.
  • Custom domains with automatic HTTPS through Caddy on-demand TLS, plus Teams with role-based access and Projects for grouping related monitors.
  • Infrastructure pieces aimed at operators: a TimescaleDB hypertable for check results, Redis Streams as the job bus, and a Laravel Horizon queue dashboard.

Who uses it and how

  • Small teams that need to publish live status to customers, using a public status page for the main site and an unlisted or private page for internal or staging monitors.
  • Operators who need to eliminate false positives from a single vantage point by deploying the Go probe binary in another region and connecting it to the server's Redis over a private tunnel such as Tailscale.
  • Organisations with data-ownership or compliance constraints that require check history and alert credentials to sit in their own PostgreSQL instance rather than a third-party service.
  • Operations staff who want queue and job visibility, served by the bundled Laravel Horizon dashboard.
  • Single-operator installs, where the registration policy can be set to first-user-only so the first account to register becomes the admin.

Getting started

Clone the repository, change into the easymonitor directory, and run ./setup.sh; the interactive installer covers mode, domain and admin email, database and Redis passwords, registration policy, email driver (log only, Amazon SES, or generic SMTP), Pushover, and object storage choices, then writes .env, builds and starts the containers, runs migrations, and builds frontend assets. Prerequisites are Docker with Docker Compose v2, roughly 2 GB of free RAM (4 GB is comfortable for production), and Linux, macOS, or WSL2.

How it compares

The facts provided name no comparable tools and no list of paid products that EasyMonitor replaces. On the evidence available, it stands alone in this registry.

When to use it — and when not to

A self-hoster takes on operating PostgreSQL 18 with TimescaleDB 2.26, Redis 7, and the Caddy, Nginx, and PHP-FPM stack, along with an email path through SMTP or Amazon SES and optional object storage on local disk, Cloudflare R2, or Amazon S3. Remote probes add another burden: Redis must never be exposed directly on the public internet, so a private tunnel such as Tailscale is required to reach it. It is a poor fit for teams that want zero-ops hosted monitoring or that will not run a Docker Compose stack, and its adoption is small at 75 stars and 7 forks, with no topics metadata listed in the facts.

project readme (upstream, from github) — read inline

EasyMonitor

Open-source, self-hosted uptime and performance monitoring you can run with one docker compose up.

GitHub tag License

EasyMonitor is a full-stack monitoring platform for your websites and APIs. Add a URL, pick an interval, and get alerted when something breaks. Group monitors into projects, share live status with your users via public status pages, and run probes in multiple regions to eliminate false positives.

Screenshot

EasyMonitor dashboard


Features

  • HTTP, ICMP, and TCP port checks — every 30 seconds to 1 hour per monitor
  • SSL certificate expiry monitoring — captured during HTTPS checks; alerts at 30/14/7 days before expiry
  • Multi-region probes — lightweight Go binaries (~10 MB) you can deploy anywhere
  • Consecutive-failure threshold — configurable per monitor; no alerts on flaky single failures
  • Multi-channel alerts — email, Slack, Discord, Telegram, ntfy, generic webhooks (HMAC-signed), and Pushover (per-user, per-monitor selection) on down and recovery
  • Projects — group related monitors (e.g. main site + APIs)
  • Teams — share monitors and projects with collaborators with role-based access
  • Status pages — public, unlisted (secret link), or private
    • Add projects (live link) or individual monitors
    • Hide specific monitors per page
    • Themes, custom CSS, logo upload
    • Incidents and scheduled maintenance with timeline updates
    • Custom domains with auto-HTTPS via Caddy on-demand TLS
  • TimescaleDB — efficient time-series storage for check results
  • Redis Streams — reliable job bus between scheduler, probes, and result consumer
  • Laravel Horizon — queue dashboard for ops visibility

Architecture

                       ┌──────────────────────────┐
                       │  Laravel + Livewire UI   │
                       │  (admin + public pages)  │
                       └────────────┬─────────────┘
                                    │
                XADD checks         │         consumes results
                ┌───────────────────┴───────────────────┐
                ▼                                       ▲
       ┌────────────────┐                       ┌──────┴────────┐
       │ Redis Streams  │ ◀──── XADD results ───┤ Probe nodes   │
       │ checks/results │    (HTTP, ICMP, TCP)  │ (Go, multi-r.)│
       └────────────────┘                       └───────────────┘
                │
                ▼
       ┌──────────────────────────┐
       │ PostgreSQL + TimescaleDB │
       │ (hypertable for checks)  │
       └──────────────────────────┘

Stack

  • Backend: Laravel 12, PHP 8.4, Livewire 3
  • Frontend: Tailwind CSS 4, DaisyUI 5, Alpine.js (bundled with Livewire)
  • Probe: Go 1.24 (separate binary, multi-architecture)
  • Database: PostgreSQL 18 + TimescaleDB 2.26
  • Message bus: Redis 7 Streams
  • Web: Caddy 2.10 (HTTPS) → Nginx → PHP-FPM (with Supervisor + Horizon)

Quick start

Prerequisites

  • Docker and Docker Compose v2
  • ~2 GB free RAM (4 GB comfortable for production)
  • Linux, macOS, or WSL2

One command

git clone https://github.com/easymonitordev/easymonitor.git
cd easymonitor
./setup.sh

The installer is interactive and walks through:

  1. Mode — local development or production
  2. Domain + admin email (production only) — auto-detects your server's public IP and verifies DNS
  3. Database — auto-generates strong password in production
  4. Redis password — optional
  5. Registration policy — open or first-user-only
  6. Email driver — log only, Amazon SES, or generic SMTP
  7. Pushover — optional; paste an application token to enable push alerts
  8. Object storage — local disk, Cloudflare R2, or Amazon S3

It then:

  • Writes .env
  • Patches docker/caddy/Caddyfile.production for production installs
  • Builds and starts all containers
  • Generates app key, JWT secret, probe token
  • Runs migrations
  • Builds frontend assets
  • Sets up the storage symlink

When it finishes, open the URL it prints. The first user can register and becomes the admin.

Adding a probe in another region

A local probe runs by default. To add probes in other regions, they need a network path to the server's Redis. Never expose Redis directly on the public internet — use a private network tunnel instead.

Supported options:

  • Tailscale (recommended) — two commands on server and probe, done
  • Cloudflare Tunnel — free, zero ports exposed
  • Manual — SSH tunnel, WireGuard, your own VPN

The setup.sh installer has a "Will you run probes on other machines?" prompt that auto-installs Tailscale on the server if you pick that option.

The probe node itself lives in a separate repo so you can deploy it on any host without cloning the full EasyMonitor app:

Full server-side tunnel setup (Tailscale / Cloudflare / manual) and probe-side docker run details are in PROBE_NODE_SETUP.md.

To disable the bundled local probe:

docker compose up -d --scale probe=0

Custom domains for status pages

When using the production Caddyfile (configured automatically by setup.sh for production installs), customers can point their own domain at your EasyMonitor instance:

  1. In the status page settings, they enter status.theircompany.com
  2. They add the displayed TXT record at their DNS provider for verification
  3. They CNAME their domain to your EasyMonitor host (gray cloud / DNS only on Cloudflare)
  4. Click Verify Domain in the UI

Caddy then provisions a Let's Encrypt certificate automatically on the first request via on-demand TLS. The app gates which domains are allowed via a /caddy/ask endpoint that checks the domain_verified_at flag.

Notifications

Each user chooses where their alerts go from Settings → Notifications. Every monitor picks a subset of the user's configured channels; new monitors default to the user's default channel.

Supported channels:

Channel Setup Per-user config
Email Configured by the admin via MAIL_MAILER (log, SES, SMTP) Uses the account email
Slack No admin setup — Slack-side only User adds one or more incoming webhooks, each labelled (e.g. #alerts-api, #alerts-frontend) — pick which ones to alert per monitor
Discord No admin setup — Discord-side only User adds one or more channel webhooks (Server Settings → Integrations → Webhooks), each labelled — pick which ones to alert per monitor
Webhook No admin setup User adds one or more HTTP endpoints (any URL) — each gets an auto-generated HMAC-SHA256 secret. Payloads are signed with X-EasyMonitor-Signature: sha256=… and tagged with X-EasyMonitor-Event: monitor.down|monitor.recovered|certificate.expiring. Pipe to PagerDuty, Zapier, n8n, custom services
Telegram No admin setup — Telegram-side only User creates a bot via @BotFather, then adds the bot token + chat id per chat/group, each labelled — pick which ones to alert per monitor
ntfy No admin setup User picks a topic on ntfy.sh or a self-hosted ntfy server (optional access token for protected topics), subscribes in the ntfy app — no account needed
Pushover Admin sets PUSHOVER_APP_TOKEN once (from pushover.net/apps/build) User pastes their user key (and optional device)

Send-test buttons on the Notifications page let each user verify their configuration end-to-end.

Webhook payload

Webhook deliveries are HTTP POST with Content-Type: application/json. Two events fire — one when a monitor crosses the failure threshold and one when it recovers.

Headers

Header Value
X-EasyMonitor-Event monitor.down, monitor.recovered, or certificate.expiring
X-EasyMonitor-Signature sha256= — HMAC-SHA256 of the raw body using your channel's secret
User-Agent EasyMonitor-Webhook/1.0

monitor.down body

{
  "event": "monitor.down",
  "monitor": {
    "id": 42,
    "name": "Production API",
    "url": "https://api.example.com/health",
    "check_type": "http"
  },
  "error": "Get \"https://api.example.com/health\": dial tcp: connection refused",
  "checked_at": "2026-05-14T13:42:07+00:00",
  "dashboard_url": "https://easymonitor.example.com/monitors/42"
}

error is

readme truncated — read the full docs on github

Frequently asked questions

Is EasyMonitor free to use?

EasyMonitor is open source under the MIT licence. There is no licence fee and no seat count — you can self-host it or, where the project offers one, pay a vendor for a managed version instead.

What does EasyMonitor do?

Self-hosted uptime monitoring that runs on your hardware, not their servers

What is EasyMonitor written in?

EasyMonitor is primarily written in PHP. Its source is publicly available at https://github.com/easymonitordev/easymonitor, and it has 75 GitHub stars.