The Stack Behind
mynuggets.dev
A privacy-first, self-hosted platform built with modern tooling. Next.js, FastAPI, Docker, and PostgreSQL — deployed to an Unraid home-lab with security hardening and automated pipelines.
Why This Stack
Built for privacy & speed
Every architectural decision centres on protecting user data while maintaining developer experience and operational simplicity.
Unified Platform
10 isolated services — Main, Tech, Analytics, FitNuggys, Mental Health, Support, Admin, the Discord bot, and a Fastify middleware gateway, alongside the Diabetes CGM service — all on one shared Docker network.
Privacy by Design
No third-party analytics, ever. Every service is self-hosted on this stack — what each one stores server-side, and for how long, is listed per service below.
Security Hardened
HSTS, CSP, XFO, nosniff, CORS/CSRF protection, timing-safe auth. LibreLinkUp usernames and passwords are not logged; the password itself is encrypted at rest. Other services handle credentials per their own architecture — see below.
One-Command Deploy
Node-based deployer pushes to Unraid via SSH. Supports full or per-service incremental deploys with health checks.
System Overview
A layered architecture designed for separation of concerns, security boundaries, and operational simplicity.
Frontend Layer
App Router, static + dynamic rendering, strict typing across all apps.
Backend Services
Python microservice bridges LibreLinkUp API. Next.js API routes handle proxying and sanitization.
Data Layer
Postgres stores contact submissions, admin auth, diabetes users/accounts/readings, and the Analytics demo schema (seeded mock business data). No third‑party tracking; data stays self‑hosted.
Infrastructure
Multi-stage builds, unified stack, an internal Fastify gateway proxying service-to-service traffic with a constant-time-compared shared secret, self-hosted.
Defense in Depth
Multiple layers of protection at every level — from transport to storage, with privacy as the default, not an afterthought.
Encrypted Credential Storage
LibreLinkUp credentials are encrypted at rest and used only for periodic re-authentication with LibreLinkUp’s own API — never logged, never sent anywhere else.
Transport Security
HSTS max-age 1 year, strict CSP, X-Frame-Options DENY, X-Content-Type-Options nosniff, Referrer-Policy strict-origin.
CORS & CSRF
No wildcard origins with credentials. Same-origin enforcement for admin APIs. Proper preflight handling.
Data Sanitization
Responses from LibreLinkUp stripped of device metadata, internal IDs, and PII before reaching the client.
Per-Service Data Handling
What each service stores, and for how long, differs by service — see the table below rather than one blanket claim for the whole platform.
Container Isolation
Multi-stage builds, non-root runtime users, standalone Next.js output, service-level network isolation.
What each service actually stores
10 deployed applications — 7 public, 1 internal admin tool, 2 backend services with no web interface. Status and data handling per service, not one blanket claim for the whole platform.
| Service | Status | Stored server-side | Retention | Encryption |
|---|---|---|---|---|
| Main site | Live | Contact form submissions | Until manually cleared | None beyond standard DB access controls |
| Tech Stack (this page) | Live | Nothing — informational only | n/a | n/a |
| Diabetes Manager | Live | Account metadata, CGM readings, LibreLinkUp password | Until account deleted | LibreLinkUp password: AES-128 (Fernet), column-level. Readings: standard DB storage, not separately encrypted. |
| Mental Health Directory | Live | Public service-directory data only — no personal or user data | Ongoing (directory content) | n/a — not personal data |
| Support Hub | Live | Tickets, contact messages, community stories. IP hash (indefinite, rate-limiting); raw IP/user-agent on tickets only (welfare-check use) | Ticket raw IP/UA: 90 days, auto-purged. Everything else: until deleted on request. | None beyond standard DB access controls |
| FitNuggys | Live | Fitbit OAuth tokens, linked-account settings | Until disconnected | None beyond standard DB access controls |
| Analytics | Demo | Seeded mock business data (payroll, GST, accounts) — no real user or financial data | Demo dataset, reset periodically | n/a — not real data |
| Admin | Internal | Manages the data above; own data is one operator account + security event logs | Operator account: ongoing. Security logs: no scheduled purge (audit trail). | Password: bcrypt (12 rounds) |
| Discord bot | Internal | No independent storage — relays to/from the services above | n/a | n/a |
| Middleware gateway | Internal | No independent storage — internal request routing only | n/a | n/a |
“Live” means real users and real data. “Demo” means seeded/mock data only. “Internal” means not intended for public use, regardless of whether it has its own domain.
The Full Stack
Every tool chosen for a reason — performance, security, developer experience, or operational simplicity.
Interested in a similar stack?
Whether you need a privacy-focused application, a self-hosted solution, or help with Docker and DevOps — let's chat.