A single-binary domain monitor that checks DNS, SSL, HTTP, and content changes on a schedule, sends alert emails via SMTP, and writes a structured uptime log.
- Set up your
data/directory:
mkdir data
cp example.env data/env
vi data/env # fill in your SMTP credentials- Add your domains (CSV format, 8 columns — extra columns from the portal are ignored):
cat > data/domains.csv <<EOF
# domain,recipient,interval,status,date,stripe,key,created_at
example.com,ops@example.com,1h
shop.example.com,ops@example.com,30m
EOF- Run:
docker run --rm -v ./data:/data ghcr.io/dyanet/uptime:latestConfig, domains, baselines, and uptime logs all live in ./data/. The container reads data/env on startup automatically.
cargo build --release
./target/release/uptime \
--domains domains.csv \
--baseline baselines.json \
--log-file uptime.jsonl \
--sender monitor@example.com \
--recipient ops@example.com \
--smtp-host email-smtp.us-east-1.amazonaws.com \
--smtp-user your-smtp-user \
--smtp-pass your-smtp-passwordOr set the UPTIME_* env vars and run ./target/release/uptime with no flags.
Every option works as a CLI flag or an environment variable.
| CLI Flag | Env Var | Default | Description |
|---|---|---|---|
--domains |
UPTIME_DOMAINS |
(required) | Path to domain list file (CSV or plain text) |
--interval |
UPTIME_INTERVAL |
1h |
Default check interval: 30m, 1h, 3h, 24h |
--baseline |
UPTIME_BASELINE |
/data/baselines.json |
Baseline persistence file |
--sender |
UPTIME_SENDER |
(required) | From email address |
--recipient |
UPTIME_RECIPIENT |
(required) | Default To email address |
--smtp-host |
UPTIME_SMTP_HOST |
(required) | SMTP server hostname |
--smtp-port |
UPTIME_SMTP_PORT |
587 |
SMTP server port |
--smtp-user |
UPTIME_SMTP_USER |
(required) | SMTP username |
--smtp-pass |
UPTIME_SMTP_PASS |
(required) | SMTP password |
--smtp-tls |
UPTIME_SMTP_TLS |
true |
Enable TLS (port 465 = implicit, port 587 = STARTTLS) |
--log-file |
UPTIME_LOG_FILE |
/data/uptime.jsonl |
JSONL uptime log path |
--error-log |
UPTIME_ERROR_LOG |
/data/errors.jsonl |
JSONL error log path |
CSV, one domain per line. Comments (#) and blank lines are ignored. The monitor reads the first 4 columns and ignores the rest (columns 5–8 are managed by the portal).
# domain,recipient,interval,status,date,stripe,key,created_at
# Production — alerts go to ops team, check every 30 minutes
example.com,ops@example.com,30m,Paid,2025-07-10,sub_123,abc123,2025-01-01
# Staging — use global defaults
staging.example.com
# Marketing site — different recipient, check every 3 hours
blog.example.com,marketing@example.com,3h
The monitor skips rows with status Disabled or Lapsed. All other statuses (Free, Paid, Verifying, Internal) are monitored. Multiple rows for the same domain (different watchers) are handled correctly — each gets independent checks.
The monitor re-reads the domain file every 30 minutes. If the file has changed, it rebuilds its interval groups and starts/stops monitoring domains accordingly. No container restart needed.
Each check appends a JSON line to the log file:
{"timestamp":"2026-03-31T14:22:01Z","domain":"example.com","up":true,"dns_ok":true,"http_status":200,"ssl_error":null,"response_size":45230,"error":null}| Field | Type | Description |
|---|---|---|
timestamp |
string | RFC 3339 UTC |
domain |
string | Domain checked |
up |
bool | true if DNS ok, no SSL/connection error, HTTP 2xx/3xx |
dns_ok |
bool | DNS resolution succeeded |
http_status |
int | null | HTTP status code |
ssl_error |
string | null | SSL error detail |
response_size |
int | null | Body size in bytes (2xx only) |
error |
string | null | Connection/timeout error |
Quick uptime percentage with jq:
jq -s 'group_by(.domain) | map({domain: .[0].domain, pct: (map(select(.up)) | length) / length * 100})' uptime.jsonl- Startup/shutdown emails — sent to the global recipient when the monitor starts and stops
- Error emails — DNS failure, SSL error, HTTP 4xx/5xx, timeout/refused (sent to per-domain recipient if configured)
- Warning emails — home page content changed (sent to per-domain recipient if configured)
Send failures are logged but never stop monitoring.
docker build -t uptime .
docker run --rm -v ./data:/data uptimeThe container sources /data/env on startup if it exists. Multi-stage build: compiles a release binary in the Rust image, copies it into a slim Debian runtime.