Codebase cleanup: remove dead code, fix docker, update docs
app.py: - Remove 'raw' field from export dict entries (only comment/blank kinds need raw; export entries are always reconstructed from path/rest/enabled when writing back) - Remove extra blank line shares.js: - Remove unused pathJson variable in SMB row (was only needed for the quota button, which was removed) docker-compose.yml: - Deleted entirely: was missing templates/ and static/ mounts so the Flask app couldn't serve pages; SYS_ADMIN cap_add was only needed for quotas; deployment is systemd, not Docker README.md: - Remove quota package from apt install command - Remove quota setup section (feature removed) - Remove docker-compose from Dev section CLAUDE.md / PLANNING.md: - Remove docker-compose.yml references and quotas.js from file tree .gitignore: - Remove redundant micronas.env entry (already covered by *.env) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
bf7daf1c2c
commit
96055e6375
7 files changed
+7
-73
No files matched your search
@@ -3,5 +3,4 @@ __pycache__/
|
|||||||
venv/
|
venv/
|
||||||
.venv/
|
.venv/
|
||||||
*.env
|
*.env
|
||||||
micronas.env
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
@@ -20,7 +20,6 @@ daemons. Home/LAN use only.
|
|||||||
- `static/js/users.js` — user CRUD + password modal.
|
- `static/js/users.js` — user CRUD + password modal.
|
||||||
- `static/js/main.js` — page init and 30 s auto-refresh.
|
- `static/js/main.js` — page init and 30 s auto-refresh.
|
||||||
- `micronas.service` — systemd unit (gunicorn, reads `/etc/micronas.env`).
|
- `micronas.service` — systemd unit (gunicorn, reads `/etc/micronas.env`).
|
||||||
- `docker-compose.yml` — dev/test sandbox only, not for production.
|
|
||||||
|
|
||||||
## How it runs
|
## How it runs
|
||||||
Directly on the LXC/VM as a `systemd` service, Flask behind `gunicorn`.
|
Directly on the LXC/VM as a `systemd` service, Flask behind `gunicorn`.
|
||||||
|
|||||||
+1
-3
@@ -44,11 +44,9 @@ MicroNAS/
|
|||||||
│ ├── utils.js esc(), showToast(), apiFetch()
|
│ ├── utils.js esc(), showToast(), apiFetch()
|
||||||
│ ├── dashboard.js loadDashboard()
|
│ ├── dashboard.js loadDashboard()
|
||||||
│ ├── shares.js SMB/NFS CRUD + edit/delete/toggle
|
│ ├── shares.js SMB/NFS CRUD + edit/delete/toggle
|
||||||
│ ├── quotas.js Quota modal
|
|
||||||
│ ├── users.js User CRUD + password modal
|
│ ├── users.js User CRUD + password modal
|
||||||
│ └── main.js Init + auto-refresh
|
│ └── main.js Init + auto-refresh countdown
|
||||||
├── micronas.service systemd unit
|
├── micronas.service systemd unit
|
||||||
├── docker-compose.yml Dev/test sandbox only
|
|
||||||
├── README.md
|
├── README.md
|
||||||
└── PLANNING.md
|
└── PLANNING.md
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ Run everything below **inside the LXC container** as root.
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
apt update
|
apt update
|
||||||
apt install -y git samba nfs-kernel-server quota python3 python3-venv
|
apt install -y git samba nfs-kernel-server python3 python3-venv
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. Clone the repo
|
### 2. Clone the repo
|
||||||
@@ -59,46 +59,6 @@ Open `http://<lxc-ip>:5000` in your browser.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Quota setup (one-time, per filesystem)
|
|
||||||
|
|
||||||
Quotas are a **filesystem feature** — they must be enabled on the partition that holds your shares (usually `/srv`) before MicroNAS can set them.
|
|
||||||
|
|
||||||
### Step 1 — Enable quota mount options
|
|
||||||
|
|
||||||
Edit `/etc/fstab`. Find the line for the partition that contains `/srv` and add `usrquota`:
|
|
||||||
|
|
||||||
```
|
|
||||||
# Example — your device path and options may differ
|
|
||||||
/dev/sdb1 /srv ext4 defaults,usrquota 0 2
|
|
||||||
```
|
|
||||||
|
|
||||||
Remount to apply without rebooting:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
mount -o remount /srv
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 2 — Initialise quota database
|
|
||||||
|
|
||||||
```bash
|
|
||||||
quotacheck -ugm /srv
|
|
||||||
quotaon /srv
|
|
||||||
```
|
|
||||||
|
|
||||||
This creates `/srv/aquota.user`. You only need to run this once; `quotaon` is automatically called on boot via the quota init script.
|
|
||||||
|
|
||||||
### Step 3 — Verify
|
|
||||||
|
|
||||||
```bash
|
|
||||||
repquota -u /srv
|
|
||||||
```
|
|
||||||
|
|
||||||
If it prints a header and user list (even if empty), quotas are active. MicroNAS reads this output for the dashboard.
|
|
||||||
|
|
||||||
> **Note:** if `/srv` is not a separate partition (e.g. it lives on the root `/` filesystem), add `usrquota` to the `/` entry in fstab instead and run `quotacheck`/`quotaon` on `/`. The Quota button in MicroNAS detects the correct filesystem automatically via `df`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Updates
|
## Updates
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -118,13 +78,12 @@ LAN or Tailscale only — never expose to the internet.
|
|||||||
## Dev / test
|
## Dev / test
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Quick local run (no gunicorn needed):
|
# Quick local run (no gunicorn needed, must have flask installed):
|
||||||
MICRONAS_USER=admin MICRONAS_PASS=secret flask --app app.py run --debug --host=0.0.0.0
|
MICRONAS_USER=admin MICRONAS_PASS=secret flask --app app.py run --debug --host=0.0.0.0
|
||||||
|
|
||||||
# Or with docker-compose (UI only — systemctl/samba calls won't work):
|
|
||||||
docker compose up
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note: SMB/NFS/user management calls require root and the relevant daemons — run on the actual LXC for full testing.
|
||||||
|
|
||||||
## Auth
|
## Auth
|
||||||
|
|
||||||
All routes require a login session. Go to `http://<lxc-ip>:5000` — you will be redirected to the login page automatically. Credentials come from `MICRONAS_USER` / `MICRONAS_PASS` in `/etc/micronas.env`. If `MICRONAS_PASS` is not set the app starts unprotected and logs a warning — do not do this in production.
|
All routes require a login session. Go to `http://<lxc-ip>:5000` — you will be redirected to the login page automatically. Credentials come from `MICRONAS_USER` / `MICRONAS_PASS` in `/etc/micronas.env`. If `MICRONAS_PASS` is not set the app starts unprotected and logs a warning — do not do this in production.
|
||||||
@@ -157,15 +157,13 @@ def _parse_exports():
|
|||||||
if inner.startswith('/'):
|
if inner.startswith('/'):
|
||||||
parts = inner.split(None, 1)
|
parts = inner.split(None, 1)
|
||||||
entries.append({'kind': 'export', 'enabled': False,
|
entries.append({'kind': 'export', 'enabled': False,
|
||||||
'path': parts[0], 'rest': parts[1] if len(parts) > 1 else '',
|
'path': parts[0], 'rest': parts[1] if len(parts) > 1 else ''})
|
||||||
'raw': raw})
|
|
||||||
else:
|
else:
|
||||||
entries.append({'kind': 'comment', 'raw': raw})
|
entries.append({'kind': 'comment', 'raw': raw})
|
||||||
continue
|
continue
|
||||||
parts = stripped.split(None, 1)
|
parts = stripped.split(None, 1)
|
||||||
entries.append({'kind': 'export', 'enabled': True,
|
entries.append({'kind': 'export', 'enabled': True,
|
||||||
'path': parts[0], 'rest': parts[1] if len(parts) > 1 else '',
|
'path': parts[0], 'rest': parts[1] if len(parts) > 1 else ''})
|
||||||
'raw': raw})
|
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
pass
|
pass
|
||||||
return entries
|
return entries
|
||||||
@@ -562,7 +560,6 @@ def _shares_with_usage():
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/dashboard', methods=['GET'])
|
@app.route('/api/dashboard', methods=['GET'])
|
||||||
@require_auth
|
@require_auth
|
||||||
def get_dashboard():
|
def get_dashboard():
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
version: '3'
|
|
||||||
services:
|
|
||||||
share-manager:
|
|
||||||
image: python:3.11-slim
|
|
||||||
volumes:
|
|
||||||
- ./app.py:/app/app.py
|
|
||||||
- /etc/samba:/etc/samba
|
|
||||||
- /etc/exports:/etc/exports
|
|
||||||
- /srv:/srv
|
|
||||||
ports:
|
|
||||||
- "5000:5000"
|
|
||||||
working_dir: /app
|
|
||||||
command: >
|
|
||||||
sh -c "pip install flask &&
|
|
||||||
python app.py"
|
|
||||||
cap_add:
|
|
||||||
- SYS_ADMIN
|
|
||||||
@@ -13,7 +13,6 @@ async function loadShares() {
|
|||||||
// esc() HTML-encodes JSON so " inside onclick="..." doesn't break the attribute
|
// esc() HTML-encodes JSON so " inside onclick="..." doesn't break the attribute
|
||||||
const shareJson = esc(JSON.stringify(s));
|
const shareJson = esc(JSON.stringify(s));
|
||||||
const nameJson = esc(JSON.stringify(s.name));
|
const nameJson = esc(JSON.stringify(s.name));
|
||||||
const pathJson = esc(JSON.stringify(s.path));
|
|
||||||
return `<tr style="${enabled ? '' : 'opacity:.55'}">
|
return `<tr style="${enabled ? '' : 'opacity:.55'}">
|
||||||
<td>${esc(s.name)}</td>
|
<td>${esc(s.name)}</td>
|
||||||
<td><code>${esc(s.path)}</code></td>
|
<td><code>${esc(s.path)}</code></td>
|
||||||
|
|||||||
Reference in new issue
Block a user