Skip to content

Commit 41e49ea

Browse files
committed
feat: initial release of Hora, a tiny self-hosted uptime monitor
A small Rust workspace that probes HTTP/TCP services, stores history in SQLite, alerts on outages and TLS-certificate expiry, and serves a server-rendered status page plus a JSON API (with a generated OpenAPI doc). Highlights: - Pluggable notifications (Notifier trait; Telegram built in), with a body snippet on failures and anti-flapping consecutive-failure thresholds. - Live config reload (file-watch + SIGHUP) with zero downtime; per-monitor retention and pruning. - Per-IP API rate limiting, strict security headers, redacted secrets. - Lock-free single-flight summary cache; parallel per-monitor queries. - Static musl binary in a ~25 MB Alpine image; CI + GHCR via GitHub Actions. Crates: hora-notify, hora-core, hora-web, hora.
0 parents  commit 41e49ea

35 files changed

Lines changed: 7219 additions & 0 deletions

.dockerignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/target
2+
/.git
3+
/.github
4+
*.db
5+
*.db-shm
6+
*.db-wal
7+
config.toml
8+
README.md

.github/workflows/ci.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
8+
env:
9+
CARGO_TERM_COLOR: always
10+
11+
jobs:
12+
check:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v6
16+
- uses: dtolnay/rust-toolchain@stable
17+
with:
18+
components: clippy, rustfmt
19+
- uses: Swatinem/rust-cache@v2
20+
- name: Install build dependencies (aws-lc-rs)
21+
run: sudo apt-get update && sudo apt-get install -y cmake clang libclang-dev
22+
- name: Format
23+
run: cargo fmt --all -- --check
24+
- name: Clippy
25+
run: cargo clippy --workspace --all-targets -- -D warnings
26+
- name: Test
27+
run: cargo test --workspace
28+
29+
deny:
30+
runs-on: ubuntu-latest
31+
steps:
32+
- uses: actions/checkout@v6
33+
- uses: EmbarkStudios/cargo-deny-action@v2

.github/workflows/docker.yml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: Docker
2+
3+
on:
4+
push:
5+
branches: [main]
6+
tags: ["v*"]
7+
8+
permissions:
9+
contents: read
10+
packages: write
11+
12+
jobs:
13+
build-push:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- uses: actions/checkout@v6
17+
18+
- uses: docker/setup-qemu-action@v3
19+
20+
- uses: docker/setup-buildx-action@v4
21+
22+
- name: Log in to GHCR
23+
uses: docker/login-action@v4
24+
with:
25+
registry: ghcr.io
26+
username: ${{ github.actor }}
27+
password: ${{ secrets.GITHUB_TOKEN }}
28+
29+
- name: Image metadata
30+
id: meta
31+
uses: docker/metadata-action@v6
32+
with:
33+
images: ghcr.io/${{ github.repository_owner }}/hora
34+
tags: |
35+
type=raw,value=latest,enable={{is_default_branch}}
36+
type=sha
37+
type=semver,pattern={{version}}
38+
type=semver,pattern={{major}}.{{minor}}
39+
40+
- name: Build and push
41+
uses: docker/build-push-action@v7
42+
with:
43+
context: .
44+
platforms: linux/amd64,linux/arm64
45+
push: true
46+
tags: ${{ steps.meta.outputs.tags }}
47+
labels: ${{ steps.meta.outputs.labels }}
48+
cache-from: type=gha
49+
cache-to: type=gha,mode=max

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/target
2+
3+
# Local runtime config and database
4+
/config.toml
5+
*.db
6+
*.db-shm
7+
*.db-wal

CHANGELOG.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Changelog
2+
3+
All notable changes to this project are documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [Unreleased]
9+
10+
## [0.1.0] - 2026-06-07
11+
12+
Initial release.
13+
14+
### Added
15+
16+
- **Monitors** — HTTP and TCP probes with per-monitor interval, timeout, expected
17+
status, a "degraded if slower than" threshold, and custom request headers.
18+
- **Status page** — server-rendered (no JS framework) compact, responsive grid:
19+
daily uptime bars, an inline SVG 24h latency chart, auto-refresh, Cal Sans
20+
branding and an SVG favicon.
21+
- **JSON API**`GET /api/summary` and `GET /api/monitors/{id}/latency`, plus a
22+
generated OpenAPI 3.1 document at `/api/openapi.json` (`utoipa`).
23+
- **TLS certificate expiry monitoring** with advance warnings.
24+
- **Notifications** — a pluggable `Notifier` trait with a built-in Telegram
25+
channel; alerts fire only after _N_ consecutive failures (anti-flapping),
26+
include a snippet of the failing response body, and a recovery message.
27+
- **Storage** — SQLite (sqlx) with per-monitor retention and automatic pruning.
28+
- **Live configuration reload** — file-watch and `SIGHUP`: monitors, thresholds,
29+
retention and notification channels are reconciled in place, with no downtime
30+
for unchanged monitors.
31+
- **API hardening** — per-IP rate limiting (`x-ratelimit-*` / `retry-after`
32+
headers), strict Content-Security-Policy, `X-Content-Type-Options` and
33+
`Referrer-Policy`.
34+
- **Performance** — a lock-free, single-flight summary cache (busted on config
35+
reload) and concurrent per-monitor queries keep responses fast under load.
36+
- **Packaging** — a static musl binary in a ~25 MB Alpine image (multi-arch
37+
amd64/arm64), with GitHub Actions for CI (fmt, clippy, tests, cargo-deny) and
38+
publishing to GHCR.
39+
40+
[Unreleased]: https://github.com/uplg/hora/compare/v0.1.0...HEAD
41+
[0.1.0]: https://github.com/uplg/hora/releases/tag/v0.1.0

0 commit comments

Comments
 (0)