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

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

VariablePurpose
SECRET_KEYSigns sessions and every emailed link. Never change it once live; the app refuses to start with the placeholder value.
APP_BASE_URLPublic URL used in emails, SSO redirect and signed links.
DATABASE_URLpostgresql://… (SQLite path for evaluation). DB_POOL_SIZE, DB_MAX_OVERFLOW, DB_POOL_RECYCLE tune the pool.
REDIS_URLOptional. 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_MBAttachment size cap (default 25).
SMTP_HOST/PORT/USER/PASS/FROM/SSL or NOVUHUB_EMAIL_PROVIDER + NOVUHUB_EMAIL_API_KEYOutbound email.
NOVUHUB_2FA_ENABLED, NOVUHUB_SESSION_DAYS, NOVUHUB_REMEMBER_DAYS, NOVUHUB_LOGIN_MAX_ATTEMPTSSign-in policy.
NOVUHUB_OIDC_*, NOVUHUB_SCIM_*Single sign-on and provisioning — see SSO & SCIM.
NOVUHUB_SHARD_RECORDS1 (default) stores hot collections one row each; 0 keeps the legacy single document.
NOVUHUB_SCHEDULER, NOVUHUB_ENGINE_MINUTES, NOVUHUB_ENGINE_IN_WEBBackground 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_VERSIONImpressum, legal pages and consent versions.
NOVUHUB_SECURITY_CONTACTPublished in /.well-known/security.txt.
NOVUHUB_SUPPORT_EMAILShown in the in-app Help & feedback panel.
SENTRY_DSN, NOVUHUB_VERSIONError 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

Health and monitoring

EndpointMeaning
GET /healthzProcess is up
GET /readyz200 only when the database and file storage respond; includes the version
GET /statusHuman status page reading /readyz
GET /api/ops/statusAdmin-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

See ops/RUNBOOK.md for the operational checklist.