- 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>
117 lines
4.9 KiB
Markdown
117 lines
4.9 KiB
Markdown
# 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/shares` 500s.
|
|
- `subprocess.run(cmd, shell=True)` with f-string input (`app.py:82`) → command
|
|
injection as root.
|
|
- `add_smb_share` writes raw user input into `smb.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/shares` works.
|
|
- [ ] Remove all `shell=True`; use argument-list `subprocess` calls.
|
|
- [ ] Validate input:
|
|
- share/user names: `^[A-Za-z0-9_-]+$`
|
|
- paths must resolve under `/srv`
|
|
- reject anything else with a clear error.
|
|
- [ ] Simple login: HTTP Basic Auth, single user + password from env var,
|
|
protecting all routes.
|
|
- [ ] `systemd` unit + `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:
|
|
- [x] **Daemon status** — is `smbd` running? is `nfsd` running? (green/red).
|
|
- [x] **Disk usage** — free / used / total for `/srv`.
|
|
- [x] **All shares in one view** — every SMB share and NFS export, their paths,
|
|
and who can access them.
|
|
- [x] **Per-share data used** — size on disk of each share's path (`du`).
|
|
- [x] **Quota usage** — for each user with a quota: used vs limit, with a
|
|
progress bar.
|
|
- [x] Auto-refresh every 30 seconds + manual refresh button.
|
|
|
|
### Phase 2.5 — UX improvements (next up)
|
|
Improvements identified after first real test:
|
|
|
|
- [x] **UI redesign** — GitHub-dark palette, better contrast, card layout,
|
|
breathing room. Custom CSS variables, no extra dependencies.
|
|
- [x] **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.
|
|
- [x] **Toast notifications** — replaced all `alert()` with Bootstrap toasts.
|
|
- [x] **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 -s` via modal.
|
|
- Backend: `/api/users` GET/POST, `/api/users/<name>` DELETE,
|
|
`/api/users/<name>/password` POST.
|
|
|
|
### 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.
|