Uptime monitoring dashboard for tracking service health, response times, and incidents.
- Ruby 4.0.5 (see
.ruby-version) - SQLite3
- RVM (recommended for Ruby version management)
# Clone and enter project
git clone https://github.com/binilsn/up-timer.git
cd up-timer
# Configure admin emails (copy and edit)
cp .env.example .env
# Edit .env with your email to get admin access:
# ADMIN_EMAILS=you@example.com
# Activate Ruby (RVM users)
rvm use
# Install dependencies
bundle install
# Setup database
rails db:create
rails db:migrate
rails db:seed
# Start development server
bin/devbin/dev starts:
- Web server (Puma) on
http://localhost:3000 - CSS watcher (Tailwind CSS v4)
- Job worker (SolidQueue) for background jobs
Use Docker Compose with Traefik for HTTPS. Only docker-compose.yml and a .env file are needed:
Let's Encrypt (wildcard):
# .env
DOMAIN=uptime.example.com
WILDCARD_DOMAIN=*.example.com
DNS_PROVIDER=cloudflare
CF_DNS_API_TOKEN=your-token
LETSENCRYPT_EMAIL=you@example.com
# App config (see table above)
ADMIN_EMAILS=admin@example.com,manager@example.com
docker compose up -dCloudflare SSL (no cert management):
# .env
DOMAIN=uptime.example.com
ENTRYPOINT=web
# App config (see table above)
ADMIN_EMAILS=admin@example.com
docker compose up -dIf ENTRYPOINT is not set, Traefik defaults to websecure (HTTPS) with automatic Let's Encrypt DNS challenge. Supported DNS providers
docker run -d -p 3000:80 \
-e ADMIN_EMAILS=admin@example.com \
-e MAIL_PROVIDER=resend \
-e RESEND_API_KEY=re_xxxxxx \
binilsn/up-timer:latestOpens at http://localhost:3000.
See Mailer for email configuration.
| Variable | Required | Default | Description |
|---|---|---|---|
ADMIN_EMAILS |
❌ | — | Comma-separated emails that get admin role on registration |
MAIL_PROVIDER |
❌ | — | Email delivery provider: resend or mailgun (no value = disabled) |
MAIL_FROM |
❌ | noreply@example.com |
From address for all outgoing emails |
RESEND_API_KEY |
* | — | Required when MAIL_PROVIDER=resend |
MAILGUN_API_KEY |
* | — | Required when MAIL_PROVIDER=mailgun |
MAILGUN_DOMAIN |
* | — | Required when MAIL_PROVIDER=mailgun |
APP_HOST |
❌ | example.com |
Host used for links in email templates |
SOLID_QUEUE_IN_PUMA |
❌ | true (baked in) |
Runs background jobs in the web process |
Repository: hub.docker.com/r/binilsn/up-timer
Authentication is handled by Rodauth.
| Route | Description |
|---|---|
/login |
Sign in |
/create-account |
Register new user |
/logout |
Sign out |
After login, users are redirected to /dashboard.
Set ADMIN_EMAILS environment variable with a comma-separated list:
ADMIN_EMAILS=admin@example.com docker compose up -dUsers registering with those emails get the admin role. Everyone else defaults to viewer.
| Role | Access |
|---|---|
| viewer | Dashboard, Nodes (view), Alerts (view), Public status page |
| collaborator | Everything viewer can + Nodes (CRUD), Alerts (create/resolve) |
| admin | Everything above + Integrations, Settings, user promotion |
Set ADMIN_EMAILS env var with a comma-separated list of emails:
ADMIN_EMAILS=alice@example.com,bob@example.com rails serverUsers registering with these emails are auto-assigned the admin role. Everyone else defaults to viewer.
SolidQueue powers all background processing with a recurring schedule defined in config/recurring.yml.
| Task | Environment | Frequency |
|---|---|---|
MonitorSchedulerJob |
dev + prod | Every 30 seconds |
DataRetentionJob |
dev + prod | Every day at 3am |
SolidQueue::Job.clear_finished_in_batches |
prod only | Every hour at minute 12 |
| Job | File | Purpose |
|---|---|---|
MonitorSchedulerJob |
app/jobs/monitor_scheduler_job.rb |
Iterates all monitors and enqueues a MonitorCheckJob for any whose last check is older than its configured check_interval |
MonitorCheckJob |
app/jobs/monitor_check_job.rb |
Performs an HTTP GET against a monitor's URL; records response time, status code, and up/down state; manages Incident lifecycle (creates on first failure, resolves all open incidents on recovery) |
DataRetentionJob |
app/jobs/data_retention_job.rb |
Purges MonitorCheck records older than 30 days and resolved Incident records older than 90 days |
Start the worker with bin/jobs (already included in bin/dev).
- Login and navigate to
/nodes - Click Create Node
- Fill in name, URL, check interval (seconds), and timeout (seconds)
- The scheduler picks it up within 30 seconds
Emails open in browser via letter_opener. No SMTP configuration needed.
Email supports Resend and Mailgun. Set MAIL_PROVIDER and the provider's credentials via environment variables. If no provider is configured, email delivery is silently disabled — no errors will be raised.
| Variable | Required | Default | Description |
|---|---|---|---|
MAIL_PROVIDER |
❌ | — | resend or mailgun |
MAIL_FROM |
❌ | noreply@example.com |
From address for all outgoing emails |
RESEND_API_KEY |
* | — | Required when MAIL_PROVIDER=resend |
MAILGUN_API_KEY |
* | — | Required when MAIL_PROVIDER=mailgun |
MAILGUN_DOMAIN |
* | — | Required when MAIL_PROVIDER=mailgun |
APP_HOST |
❌ | example.com |
Host used for links in email templates |
Required when using that provider.
See DESIGN.md for the full design token specification (colors, typography, components).
Built with:
- Tailwind CSS v4 — utility-first CSS
- Lucide — icon library (CDN)
- Chartkick + Chart.js — bar/column charts
- Stimulus — JavaScript sprinkles (sidebar toggle, dropdown menu, password toggle)
| Layer | Technology |
|---|---|
| Framework | Rails 8.1 |
| Ruby | 4.0.5 |
| Database | SQLite3 |
| Auth | Rodauth with RBAC (viewer / collaborator / admin) |
| CSS | Tailwind CSS v4 |
| JS | Stimulus + Turbo |
| Charts | Chartkick + Chart.js |
| Jobs | SolidQueue |
| Mailer | letter_opener (dev), Action Mailer with AlertMailer |
| Feature Flags | Flipper (email_notifications toggle) |
| Icons | Lucide |
| Tools | Tippy.js (tooltips), Pagy (pagination) |
# Tag and push — CI builds and pushes to Docker Hub
git tag v1.0.0
git push origin v1.0.0Or create a GitHub Release via the UI — same result.
rails test