A self-hosted domain and SSL certificate monitoring application. Track registration expiry dates, SSL certificate validity, and receive email alerts when anything is about to expire.
  • JavaScript 83.7%
  • CSS 14.5%
  • Dockerfile 1.1%
  • HTML 0.7%
Find a file
2026-06-03 18:38:50 -07:00
backend Move persistent storage db to host via bind mount 2026-06-03 18:38:50 -07:00
data Move persistent storage db to host via bind mount 2026-06-03 18:38:50 -07:00
frontend initial commit 2026-06-03 16:47:51 -07:00
.dockerignore initial commit 2026-06-03 16:47:51 -07:00
docker-compose.yml Move persistent storage db to host via bind mount 2026-06-03 18:38:50 -07:00
Dockerfile initial commit 2026-06-03 16:47:51 -07:00
Dockerfile.backend initial commit 2026-06-03 16:47:51 -07:00
README.md Move persistent storage db to host via bind mount 2026-06-03 18:38:50 -07:00
screenshot1.png Move persistent storage db to host via bind mount 2026-06-03 18:38:50 -07:00
screenshot2.png Move persistent storage db to host via bind mount 2026-06-03 18:38:50 -07:00

Domain Watcher 🔍

A self-hosted domain and SSL certificate monitoring application. Track registration expiry dates, SSL certificate validity, and receive email alerts when anything is about to expire.

Created with Claude.ai

Features

  • WHOIS lookup — Registrar, creation, update, and expiry dates
  • SSL inspection — CN, SANs, issuer, protocol version, validity dates
  • Expiry highlighting — Red (≤15 days), Yellow (≤30 days)
  • Bulk actions — Watch, unwatch, or forget multiple domains at once
  • Email alerts — Configurable SMTP with customizable alert thresholds
  • Auto-recheck — Daily cron at 6AM UTC rechecks watched domains nearing expiry
  • UTC / Local time toggle — Switch date display in the top bar
  • Persistent storage — SQLite database stored in a Docker volume

Screenshots

Screenshot 1 Screenshot 2

Quick Start

Requirements

  • Docker and Docker Compose

Run

# Clone / copy this directory, then:
docker compose up -d

The app will be available at http://localhost:3001

To use a different port, edit docker-compose.yml:

ports:
  - "8080:3001"   # Change 8080 to your desired port

Build & run manually

docker build -t domain-watcher .
docker run -d \
  --name domain-watcher \
  -p 3001:3001 \
  -v domain-watcher-data:/data \
  --restart unless-stopped \
  domain-watcher

Usage

Adding Domains

  1. Click + Add Domains in the nav bar
  2. Paste one or more domains (one per line, or comma/space separated)
  3. Click Lookup Domains — WHOIS and SSL info will be fetched
  4. Select the domains you want to keep and click Save or Save + Watch

Domains are not saved automatically — you must explicitly save them.

Dashboard

  • The main table shows all saved domains with expiry status
  • Click any row to see full details
  • Use the bulk action dropdown + Apply button to watch/unwatch/delete domains
  • Use the Show dropdown to control how many rows appear per page

Domain Detail

Click any domain to see:

  • Full WHOIS registration info
  • Complete SSL certificate details including all SANs
  • Expiry warnings
  • Buttons to Refresh, Watch/Unwatch, or Remove

Settings

Configure:

  • Alert Days — How many days before expiry to send email alerts (default: 30)
  • Recheck Days — How many days before expiry to trigger a data re-fetch (default: 30)
  • SMTP — Server, port, credentials, from/to addresses
  • Use Test Alerts Now to trigger the alert check immediately

Data Persistence

The SQLite database is stored at /data/domains.db inside the container, mounted as a named Docker volume (domain-watcher-data). Your data survives container restarts and updates.

To back up the database:

docker cp domain-watcher:/data/domains.db ./domains-backup.db

To restore:

docker cp ./domains-backup.db domain-watcher:/data/domains.db

Updating

docker compose down
docker compose build --no-cache
docker compose up -d

Your data in the named volume is preserved.


Architecture

┌─────────────────────────────────┐
│         Docker Container        │
│                                 │
│  ┌─────────────┐  ┌──────────┐  │
│  │  React SPA  │  │  SQLite  │  │
│  │  (built)    │  │  /data/  │  │
│  └──────┬──────┘  └────┬─────┘  │
│         │              │        │
│  ┌──────▼──────────────▼─────┐  │
│  │   Express.js API :3001    │  │
│  │   + node-cron (daily)     │  │
│  └───────────────────────────┘  │
└─────────────────────────────────┘
  • Backend: Node.js + Express, port 3001
  • Frontend: React (served as static files by Express)
  • Database: SQLite via better-sqlite3
  • WHOIS: Raw TCP socket queries to TLD WHOIS servers
  • SSL: Node.js tls module direct TLS handshake
  • Scheduler: node-cron (daily at 6AM UTC)
  • Email: nodemailer

Environment Variables

Variable Default Description
PORT 3001 HTTP port
DATA_DIR /data SQLite database directory
NODE_ENV production Node environment

Notes

  • WHOIS lookups may be rate-limited by some registries for frequent queries
  • Up to 20 domains can be looked up in a single batch
  • Domains without WHOIS servers for their TLD will return partial results with errors noted
  • The SSL check connects directly to port 443; non-HTTPS domains will show SSL errors