Installation & upgrades
NovuHub is a single Python service (Flask behind gunicorn) with PostgreSQL, optional Redis, and file storage on local disk or any S3-compatible bucket. Everything is configured through environment variables, so a server or domain move never means editing code.
Requirements
- Linux host, Python 3.11+, Node.js 18+ (only for the front-end build step)
- PostgreSQL 14+ (SQLite works for evaluation)
- nginx (or any TLS-terminating reverse proxy)
- Optional: Redis 6+ (shared rate limits and real-time fan-out across workers)
- Optional: an S3-compatible bucket (Hetzner Object Storage, R2, S3, B2, MinIO)
- Outbound SMTP or a transactional email provider for invitations and resets
First installation (systemd)
sudo mkdir -p /var/www/novuhub && sudo chown $USER /var/www/novuhub
git clone <your-repo-url> /var/www/novuhub && cd /var/www/novuhub
python3 -m venv venv && venv/bin/pip install -r requirements.txt
cp .env.example .env # then edit: SECRET_KEY, APP_BASE_URL, DATABASE_URL, SMTP_*
bash build_frontend.sh # bundles, minifies and pre-compresses the front-end
sudo cp deploy/novuhub.service deploy/novuhub-worker.service /etc/systemd/system/
sudo cp deploy/nginx-novuhub.conf /etc/nginx/sites-available/novuhub
sudo ln -s /etc/nginx/sites-available/novuhub /etc/nginx/sites-enabled/
sudo systemctl daemon-reload && sudo systemctl enable --now novuhub novuhub-worker
sudo nginx -t && sudo systemctl reload nginx
Tables are created on first start; new columns added by later releases are applied automatically at boot (ensure_columns), so upgrades never need a manual migration.
The worker service runs the automation engine (workflow rules, reminders, webhook and email queues, weekly recap) every NOVUHUB_ENGINE_MINUTES (default 10). Keep NOVUHUB_ENGINE_IN_WEB=0 in the web service so the engine runs only in the worker. The optional novuhub-mailscan.timer scans the finance mailbox every 10 minutes.
Docker
docker compose up -d starts the app, PostgreSQL and Redis from the bundled docker-compose.yml; the same .env file applies.
Configuration reference
| Variable | Purpose |
|---|---|
SECRET_KEY | Signs sessions and every emailed link. Never change it once live; the app refuses to start with the placeholder value. |
APP_BASE_URL | Public URL used in emails, SSO redirect and signed links. |
DATABASE_URL | postgresql://… (SQLite path for evaluation). DB_POOL_SIZE, DB_MAX_OVERFLOW, DB_POOL_RECYCLE tune the pool. |
REDIS_URL | Optional. Enables shared API rate limits and real-time pub/sub across gunicorn workers and hosts. |
NOVUHUB_S3_* | Bucket, endpoint, region, key, secret, public URL. Empty bucket = local disk under NOVUHUB_UPLOAD_DIR. |
NOVUHUB_MAX_UPLOAD_MB | Attachment size cap (default 25). |
SMTP_HOST/PORT/USER/PASS/FROM/SSL or NOVUHUB_EMAIL_PROVIDER + NOVUHUB_EMAIL_API_KEY | Outbound email. |
NOVUHUB_2FA_ENABLED, NOVUHUB_SESSION_DAYS, NOVUHUB_REMEMBER_DAYS, NOVUHUB_LOGIN_MAX_ATTEMPTS | Sign-in policy. |
NOVUHUB_OIDC_*, NOVUHUB_SCIM_* | Single sign-on and provisioning — see SSO & SCIM. |
NOVUHUB_SHARD_RECORDS | 1 (default) stores hot collections one row each; 0 keeps the legacy single document. |
NOVUHUB_SCHEDULER, NOVUHUB_ENGINE_MINUTES, NOVUHUB_ENGINE_IN_WEB | Background engine placement and cadence. |
NOVUHUB_BILLING_* | Merchant-of-record billing (Paddle / Lemon Squeezy): provider, API key, webhook secret, plans, trial and grace days. |
NOVUHUB_COMPANY_*, NOVUHUB_LEGAL_*, NOVUHUB_PRIVACY_VERSION, NOVUHUB_TOS_VERSION | Impressum, legal pages and consent versions. |
NOVUHUB_SECURITY_CONTACT | Published in /.well-known/security.txt. |
NOVUHUB_SUPPORT_EMAIL | Shown in the in-app Help & feedback panel. |
SENTRY_DSN, NOVUHUB_VERSION | Error tracking and the version stamp reported by /readyz and /status. |
NOVUHUB_VAPID_* | Web-push keys. |
The full annotated list is in .env.example.
Upgrading
cd /var/www/novuhub
git pull
venv/bin/pip install -r requirements.txt
bash build_frontend.sh
sudo systemctl restart novuhub novuhub-worker
Read the changelog entry for the release first: it lists any new environment switch. Schema additions apply themselves on start-up. Roll back with git checkout <previous-tag> and the same four commands.
Backups and restore
ops/backup.shdumps the database and local uploads; setOFFSITE_S3orRCLONE_REMOTEin.envso dumps leave the machine. Schedule it nightly.ops/restore_verify.shrestores the newest dump into a scratch database and checks it — schedule weekly and alert on a non-zero exit.ops/restore.sh <dump.sql.gz>restores onto a server;ops/MIGRATION.mdcovers moving to a new host or domain (keepSECRET_KEY, re-pointDATABASE_URLand the bucket).
Health and monitoring
| Endpoint | Meaning |
|---|---|
GET /healthz | Process is up |
GET /readyz | 200 only when the database and file storage respond; includes the version |
GET /status | Human status page reading /readyz |
GET /api/ops/status | Admin-only detail: version, row counts, subsystems on/off |
Point your uptime monitor at /readyz. Logs go to journald (journalctl -u novuhub -u novuhub-worker); every request carries an X-Request-ID that appears in error logs and, when configured, in Sentry.
Scaling
- More gunicorn workers (
--workers) or more hosts behind the proxy: setREDIS_URLso rate limits, login throttling and live updates are shared. - Move PostgreSQL to a managed service with point-in-time recovery: only
DATABASE_URLchanges. - Object storage keeps uploads off the app host and makes the app stateless.
- The front-end ships as a core bundle (≈160 KB gzip) plus twelve lazily loaded chunks (finance, HR, portfolios, CRM, messages, calendar, people, mind map, docs, learning, settings, analysis), pre-compressed and served with immutable cache headers; a CDN in front of
/static/is optional.
See ops/RUNBOOK.md for the operational checklist.