- Full UI redesign: GitHub-dark palette, custom CSS vars, better contrast, card layout, cleaner tables and typography - Dashboard auto-refresh every 30s (was 60s) - Remove Quotas tab; each share row now has a Quota button that opens a modal pre-filled with the share's valid users (SMB) or path (NFS) - Replace all alert() with Bootstrap toast notifications - Add Users tab: list system users (uid >= 1000) with SMB status, create user (useradd + smbpasswd), delete user, change SMB password - Backend: /api/users GET/POST, /api/users/<name> DELETE, /api/users/<name>/password POST Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4.9 KiB
MicroNAS — Planning
A lightweight web GUI to manage file shares on a single home server — like a minimal NAS control panel for a Proxmox LXC/VM. Manages SMB shares, NFS exports, and quotas by editing the host config files and reloading the daemons.
Design principle: keep it small. Single box, home/LAN use only, no database, no auth framework, dependency-light. If a feature needs heavy machinery, it's out of scope.
Deployment decision
Run directly on the LXC/VM as a systemd service (Flask behind gunicorn).
Not Docker.
Reason: this app's whole job is to manipulate host services (smbd, nfsd,
/etc/exports, exportfs, setquota). Containerizing it means bind-mounting
host config, running privileged, and fighting the kernel NFS server — all the
downsides of running on the host with none of the isolation benefit. Docker is
kept only as an optional dev/test sandbox.
Network: LAN-only. Never expose to the internet. Reach it via local network or Tailscale. Auth is a safety net, not an internet-facing defense.
Backups: Out of scope. Handled at the Proxmox layer (Proxmox Backup Server on a second client). This app does not implement backup.
Current state (baseline)
app.py— Flask API: list/create SMB & NFS shares, set quotas.index.html— Bootstrap UI with SMB / NFS / Quotas tabs.docker-compose.yml— test sandbox.
Known issues to fix
parse_smb()is called (app.py:13) but never defined →/api/shares500s.subprocess.run(cmd, shell=True)with f-string input (app.py:82) → command injection as root.add_smb_sharewrites raw user input intosmb.conf→ config injection via newlines.- No authentication on any route.
- Config is append-only (
open(..., 'a')) → no working delete/edit; UI Delete buttons are wired to nothing. - No input validation on names or paths (path traversal, share of
/).
Roadmap
Phase 1 — Correctness & safety (must-have)
- Implement
parse_smb()so/api/sharesworks. - Remove all
shell=True; use argument-listsubprocesscalls. - Validate input:
- share/user names:
^[A-Za-z0-9_-]+$ - paths must resolve under
/srv - reject anything else with a clear error.
- share/user names:
- Simple login: HTTP Basic Auth, single user + password from env var, protecting all routes.
systemdunit +gunicorn, plus README run instructions.
Phase 2 — Dashboard & health (the main goal)
A landing page that shows the state of the server at a glance:
- Daemon status — is
smbdrunning? isnfsdrunning? (green/red). - Disk usage — free / used / total for
/srv. - All shares in one view — every SMB share and NFS export, their paths, and who can access them.
- Per-share data used — size on disk of each share's path (
du). - Quota usage — for each user with a quota: used vs limit, with a progress bar.
- Auto-refresh every 30 seconds + manual refresh button.
Phase 2.5 — UX improvements (next up)
Improvements identified after first real test:
- UI redesign — GitHub-dark palette, better contrast, card layout, breathing room. Custom CSS variables, no extra dependencies.
- Inline quota management — removed dedicated Quotas tab. Each SMB share and NFS export row has a "Quota" button that opens a modal. For SMB: lists valid_users with individual GB inputs. For NFS: manual user + GB. Submits one API call per user in parallel.
- Toast notifications — replaced all
alert()with Bootstrap toasts. - Auto-refresh every 30 s (was 60 s).
- User management tab — create, delete, and change the SMB password
of NAS users without touching the command line:
- List all system users (uid ≥ 1000), show whether they have a Samba
account.
- Create user:
useradd -M -s /usr/sbin/nologin+smbpasswd -a. - Delete user:smbpasswd -x+userdel. - Change SMB password:smbpasswd -svia modal. - Backend:/api/usersGET/POST,/api/users/<name>DELETE,/api/users/<name>/passwordPOST.
Phase 3 — Full management (complete the CRUD)
- Working delete for SMB & NFS (parse config into blocks, rewrite the whole file — not append-only).
- Edit existing shares (path, valid users).
- Enable/disable a share without deleting it.
Phase 4 — Nice-to-have
- WebDAV support. Preferred approach: don't build it in Flask — have the app drop an Apache/nginx WebDAV config snippet, same pattern as SMB/NFS, so it reuses the existing architecture.
- Simple in-browser file browser for
/srv.
Out of scope (intentionally)
- Backups (Proxmox Backup Server handles this).
- Multi-user accounts / roles (single admin login is enough).
- Database (config files are the source of truth).
- Internet exposure / TLS termination (LAN + Tailscale only).
- Clustering / multi-host management.