Grylli is a secure, self-hosted message delivery platform that automatically sends pre-configured notifications if a user fails to check in within a defined time period.
- Features
- Security Checklist
- Lighthouse Audit Results
- Testing & Quality Assurance
- Backups & Maintenance
- Screenshots
- Docker Compose Configuration
- Credits & Key Dependencies
- Recommended Third-Party Services
- Self-hosted Flask web application with user authentication
- Responsive UI built with Tailwind CSS
- Frontend interactivity powered by Stimulus.js for minimal, CSP-compliant JavaScript
- Light and dark mode support with DaisyUI components integrated for consistent theme application
- Local timezone support
- Multilingual interface with automatic translation via GPT-PO Translator
- Status endpoint for healthcheck and version
- Integrated version check with GitHub release comparison and automated scheduler updates
- Language selection toggle with per-user preference and locale-aware interface
- Fixed sidebar and header layout with scrollable main content for consistent UX
- Table/Card view preference is saved per module via localStorage for persistent view selection (e.g., Messages, Emails, Reminders, & Users)
- Modular partial layout: all list views (emails, messages, reminders, Apprise, webhooks) use shared
table_view.html,card_view.html,actions.html, andhelp_panel.htmlpartials for maintainability - Context-sensitive help panels for each major module
- Dashboard with equal-height cards showing reminders, emails, messages, Apprise, webhooks, and SMTP at a glance
- Dedicated Schedule tab showing all enabled items and their configured run times
- Activity tab displaying filtered logs of recent user actions and system events
- Shared UI components and actions ensure consistency across table and card views
- Progressive Web App (PWA) support: installable manifest, service worker registration, offline metadata caching, and mobile/desktop home screen integration. Requires HTTPS and a public certificate.
- Seamless navigation and interaction using HTMX:
- All sidebar and profile dropdown links use HTMX for dynamic content loading
- Add/edit/delete/cancel actions update only affected content via HTMX
- Buttons for test/send/enable/disable are handled dynamically via HTMX and fully CSP-compliant
- Grylli has undergone a thorough accessibility audit using pa11y and manual contrast verification.
- Main pages (login, signup, dashboard, reminders, emails, messages, settings) have been remediated for WCAG 2.1 AA compliance
- All forms include semantic labels, ARIA feedback, and keyboard-accessible controls
- High-contrast themes and visible focus styles are built-in
- No inline JavaScript or event handlers (CSP-compliant)
- No CAPTCHAs or visual-only barriers; public routes are rate-limited instead
⚠️ Minor, non-blocking color contrast issues (e.g. emoji/icons) are acknowledged
- Configurable notification and check-in system
- Deliver Messages using Apprise, with support for dozens of services
- Execute webhooks when notification grace period for checkin has expired
- Customizable emails with optional attachments
- Attach multiple files to emails
- Files are loaded from /uploads at send time (edit outside Grylli)
- Create reminders with labels, subjects, and rich scheduling options
- Assign email, webhook, and Apprise destinations to each reminder
- Optional test-send for validation of all linked services
- Schedule single or recurring reminders (daily, weekly, monthly, etc.)
- Toggle reminders on/off dynamically from the UI
- Multi-admin and multi-user support
- Role-based access control (RBAC) with user/admin privileges
- MFA using TOTP apps (e.g. Google Authenticator) with recovery codes
- MFA reset and recovery options for both users and admins
- Admin protection from self-demotion and critical privilege changes
- Sign-up with registration code
- Forgot username and password recovery flows
- User actions to export their data and delete their account
- Global SMTP settings for system-level notifications
- User-specific SMTP settings for personalized delivery
- All application events are logged with context, including:
- check-in attempts, enable/disable actions, task execution, test runs, and validation errors
- internal exceptions are captured with full tracebacks and categorized by severity
- Logs are written to both stdout and
data/grylli.logby default - Admin panel includes a filterable and sortable log viewer:
- Filter by log level, text content, and timestamp (before/after)
- Sort by timestamp or severity column
- HTMX-powered for live interaction without full page reload
- Dedicated Activity tab shows recent user-facing log events tied to current user
- CSP violation reports are captured, parsed, and logged for debugging front-end policy violations
- Debug layout view captures DOM structure, controller bindings, loaded styles/scripts, and page metadata
- All logging is structured for human readability and system integration
- Debug-friendly logging helpers (
log_info_message,log_exception_with_traceback) used across all routes for consistent traceability
- Admin-only UI available under Tasks for executing one-time system actions
- First task available: Manual Version Check
- Triggers the same logic used in the scheduled update check
- Confirms if a new Grylli release is available on GitHub
- Fully CSP-compliant task execution and feedback via flash messages
- Admin-only dashboard with real-time reports and usage summaries
- Tabbed UI with HTMX-based dynamic content loading (no full page reloads)
- Currently available reports:
- Accounts: Overview of all users, roles, MFA status, activity flags, and lockouts
- Scheduler Activity: Displays execution history for scheduled items (reminders, emails, messages)
- Uses modular partial templates and consistent DaisyUI styling
- Reports are automatically updated with the latest activity and user status changes
- Table views support sortable and accessible column headers
- Email integrity is enforced on login: only users can change their own email address, preventing backend tampering
- Sensitive credentials (e.g., SMTP passwords, Apprise tokens) and user-defined data (e.g., message subjects, email recipients, reminder text, etc.) are encrypted at rest using Fernet symmetric encryption
- Fully Content Security Policy (CSP) compliant: dynamic nonces, no inline scripts or handlers, no
.innerHTML - Frontend entirely refactored to use Stimulus.js controllers instead of Alpine.js or inline JavaScript
- Password and token reveal functionality is CSP-safe with strict event handling
- Admin routes are tightly permission-controlled with automatic role enforcement
- All public forms and inputs validated server-side using secure WTForms
- App-level logging captures all sensitive operations, errors, and admin events without exposing secrets
- Enforces complex passwords
- Runs as non-root using PUID/PGID
- Reverse proxy ready (
base_urlsupport) - Runs in a minimal distroless container for production, reducing attack surface and image size
- Python sources are precompiled to
.pycfiles for faster startup and to reduce accidental code exposure in the image - Rate limiting on failed logins and sign up
- Additional HTTP security headers: X-Content-Type-Options: nosniff, X-Frame-Options: DENY, frame-ancestors: 'none' to mitigate common web vulnerabilities
- Account lockout enforced after repeated failed login attempts, with automatic unlock after a delay
- Modular view architecture using partials for cleaner maintenance and CSP compliance
- CAPTCHA-free signup flow with soft rate limiting for better UX and accessibility
- Grylli performs a secure file integrity check on startup to ensure application files have not been tampered with.
- A
file_hashes.sha256manifest is generated at build time, containing SHA-256 hashes for all.py,.html, and.jsfiles in the source tree. - At runtime, a built-in Python script verifies these hashes against the actual files on disk.
- If any file has been modified or added, startup is aborted, and the failure is logged.
- This ensures administrators or malicious actors cannot modify core logic or templates without detection.
- A scheduler task re-validates file integrity and exits if any tampering is detected.
- Grylli is designed with privacy and control in mind.
- Users retain full control over their check-in schedules, messages, and delivery methods.
- All sensitive user data — including email passwords, Apprise tokens, and webhook URLs — is encrypted before being stored.
- Administrators cannot view stored credentials or plaintext tokens.
- No external telemetry, analytics, or phone-home behavior is present.
- Users can export or delete their data at any time
- Passwords and secrets encrypted at rest
- CSP-compliant templates and JavaScript (no inline scripts or handlers)
- Rate-limited login, signup, and reset flows
- MFA with TOTP and recovery support
- Role-based route protections (admin vs. user)
- Admin safeguards (no self-demotion)
- Secure form validation with CSRF and ARIA feedback
- Optional backup and deletion workflows
- Automatic account lockout after repeated failed logins
- CSP Violation Reporting: Server now captures and logs CSP violations
⬆ Back to Table of Contents Grylli has been tested with Google Lighthouse across all major modules, achieving:
| Metric | Average Score |
|---|---|
| Performance | 96 |
| Accessibility | 99 |
| Best Practices | 93 |
| SEO | 100 |
All primary user-facing and administrative pages meet or exceed Lighthouse guidelines.
Installability was validated using Lighthouse PWA audits.
⬆ Back to Table of Contents Grylli has a comprehensive test suite covering the platform's core features, ensuring the stability, security, and functionality of all workflows.
| Module | Coverage |
|---|---|
| Auth Routes | 83% |
| Admin Panels | 84% |
| Reminder Logic | 78% |
| Email Workflows | 82% |
| Apprise & Webhooks | 78% |
| Backup & Restore | 85% |
| MFA Setup & Reset | 84% |
| Account Management | 68% |
| CSP Compliance | 100% |
| Public Pages | 100% |
| Version Metadata | 100% |
| Route Permissions | 100% |
Total Coverage: 81%
(4977 statements, 933 currently not covered)
- Written using pytest
- Uses SQLAlchemy 2.x-style
db.session.get()methods - Mocks all external calls (email, encryption, login state) for safe, fast test runs
- Enforces role-based access control through simulated admin/user scenarios
- Coverage includes flash messages, status codes, and failure paths
- Automated daily database backups (7-day retention)
- On-demand backup option
⬆ Back to Table of Contents
docker-compose.sample.yml
If you prefer not to use Docker Compose, you can run Grylli with a single command:
Show Docker Run Command
docker run -d \
--name grylli \
-p 5069:5069 \
-v $(pwd)/grylli/data:/data \
-v $(pwd)/grylli/uploads:/uploads \
-e TZ=America/Chicago \
-e PUID=1000 \
-e PGID=1000 \
-e GRYLLI_DATA_DIR=/data \
-e DEBUG=False \
-e FQDN=http://your.domain.com:5069 \
-e BASE_URL=/grylli \
-e FLASK_APP_PORT=5069 \
-e FLASK_APP_KEY=changeme-supersecret-key \
-e FERRET_KEY=changeme-fernet-key \
-e SIGNUP_CODE=YourSuperSecretCode123! \
-e DEFAULT_LANGUAGE=en \
-e SMTP_HOST=smtp.example.com \
-e SMTP_PORT=587 \
-e SMTP_USE_TLS=1 \
-e [email protected] \
-e [email protected] \
-e SMTP_PASS=your_password_or_app_token \
--restart unless-stopped \
ghcr.io/samcro1967/grylli
Show Environment Variables
| Variable | Description | Example/Notes |
|---|---|---|
TZ |
Timezone for the container | America/Chicago |
PUID |
User ID for container process (for volume permissions) | 1000 |
PGID |
Group ID for container process | 1000 |
GRYLLI_DATA_DIR |
Directory for persistent data inside the container | /data |
DEBUG |
Enable or disable debug mode | False (use True for debugging) |
FQDN |
Public base URL of your Grylli instance | http://your.domain.com:5069 |
BASE_URL |
Base URL path for Grylli (use /grylli or /) |
/grylli |
FLASK_APP_PORT |
Port Grylli listens on inside the container | 5069 |
FLASK_APP_KEY |
Secret key for Flask session security | (generate a secure random string) |
FERRET_KEY |
Encryption key for sensitive data (Fernet, 32-byte base64 string) | (generate with Fernet) |
SIGNUP_CODE |
Registration code required for new sign-ups | YourSuperSecretCode123! |
DEFAULT_LANGUAGE |
Default language code | en |
SMTP_HOST |
SMTP server hostname | smtp.example.com |
SMTP_PORT |
SMTP server port | 587 (for TLS), 465 (for SSL) |
SMTP_USE_TLS |
Use TLS for SMTP connection (1 for yes, 0 for no) | 1 |
EMAIL_FROM |
Default sender email address | [email protected] |
SMTP_USER |
SMTP authentication username | [email protected] |
SMTP_PASS |
SMTP authentication password or app token | your_password_or_app_token |
Note: See
docker-compose.sample.ymlfor instructions on how to generate your ownFLASK_APP_KEYandFERRET_KEY.
- Flask — Python web framework
- Flask-WTF — Secure web forms with CSRF protection
- Flask-Login — User session and authentication management
- Flask-Migrate — Database migrations powered by Alembic
- Flask-Babel — Internationalization (i18n) and localization
- APScheduler — Advanced Python scheduling
- email-validator — Email address validation
- cryptography — Secure encryption for sensitive data at rest
- PyOTP — Time-based one-time passwords for MFA
- python-dateutil — Advanced datetime parsing and timezone handling
- polib — PO file management for localization workflows
- GPT-PO Translator — Automated PO file translation with GPT
- Stimulus — Lightweight JavaScript framework for CSP-compliant interactivity
- HTMX — Dynamic HTML-over-the-wire interactivity without custom JavaScript
- Tailwind CSS — Utility-first CSS framework for responsive, accessible UI
- DaisyUI — Plugin for TailwindCSS that provides pre-designed components
- SVGBackgrounds — Open-source SVG background patterns used in the theme-aware background selector
- PostCSS — CSS transformation engine used in Tailwind’s build pipeline
- Autoprefixer — Adds vendor prefixes to CSS rules automatically
- Apprise — Notification delivery to dozens of services
- htmx-extensions: safe-nonce — HTMX extension for CSP nonce propagation
- Critical — Extracts and inlines critical-path CSS for faster first paint
- Pa11y — Automated accessibility testing and validation
- gunicorn — Production Python WSGI server
- Docker — Containerized application deployment (distroless)
- Clean-CSS CLI — CSS minifier for optimized production output
- Terser — JavaScript minifier used in production builds
- pytest — Python test framework
- pytest-cov — Coverage reporting plugin for pytest
- black — Opinionated Python code formatter
- isort — Python import sorter
- pylint — Static code analysis for Python
- djlint — Linter and formatter for Jinja2 templates
- Lighthouse — Performance, accessibility, and SEO auditing for web apps
- OWASP ZAP — Automated security scanning and penetration testing
Special thanks to these libraries and their maintainers for powering Grylli.
- webhook (adnanh/webhook) — Simple webhook server


















