151 lines
5.8 KiB
Markdown
151 lines
5.8 KiB
Markdown
# Sawa Control Panel — Issues & Decisions
|
|
|
|
*Track open questions, known problems, and architectural decisions here.*
|
|
|
|
---
|
|
|
|
## Open Issues
|
|
|
|
### ISSUE-001 — sudo whitelist scope
|
|
**Status:** Open
|
|
**Priority:** Must resolve before Phase 1 complete
|
|
|
|
The backend needs to run `rc-service` commands without being root. A sudoers whitelist is required. The exact scope needs to be defined.
|
|
|
|
**Options:**
|
|
- Whitelist per service per action — most secure, most verbose sudoers file
|
|
- Whitelist `rc-service` for a named panel user with NOPASSWD — simpler, still scoped to that user
|
|
|
|
**Suggested resolution:** Create a dedicated `panel` system user. Grant NOPASSWD sudo access to `rc-service` only, for the specific whitelisted service names. Example:
|
|
```
|
|
panel ALL=(ALL) NOPASSWD: /sbin/rc-service nginx *, /sbin/rc-service mariadb *, ...
|
|
```
|
|
|
|
---
|
|
|
|
### ISSUE-002 — Client cert distribution to mobile
|
|
**Status:** Open
|
|
**Priority:** Must resolve before Phase 1 complete
|
|
|
|
Installing a client certificate on Android/iOS for nginx mTLS requires PKCS12 (.p12) format. The cert generation script must output `.p12` alongside `.pem`.
|
|
|
|
Safe transfer options to phone:
|
|
- Generate a one-time HTTPS download URL on the server (temporary endpoint, auto-deletes after download)
|
|
- AirDrop (iOS only)
|
|
- Manual transfer via USB cable
|
|
|
|
**Decision needed:** Which transfer method to implement in the cert script.
|
|
|
|
---
|
|
|
|
### ISSUE-003 — Service status parsing reliability
|
|
**Status:** Open
|
|
**Priority:** Should resolve before Phase 1 complete
|
|
|
|
`rc-service <n> status` returns inconsistent output formats across different services. Need to normalize into a consistent `started | stopped | crashed | unknown` enum.
|
|
|
|
**Suggested resolution:** Parse `rc-status` output instead of per-service status calls — it returns a structured view of all services in the current runlevel. More reliable and one call instead of N calls.
|
|
|
|
---
|
|
|
|
### ISSUE-004 — Build and deploy workflow
|
|
**Status:** Open
|
|
**Priority:** Needed for Phase 1
|
|
|
|
React app needs to be built locally then deployed to `/var/www/panel/` on the server. Need a repeatable deploy process.
|
|
|
|
**Options:**
|
|
- `npm run deploy` script — builds then SCPs to server using stored SSH key
|
|
- rsync watch mode for development iteration
|
|
- GitHub Actions CI/CD (Phase 3+)
|
|
|
|
**Suggested resolution for now:** Simple deploy script using scp. Keep it manual until the project stabilizes.
|
|
|
|
---
|
|
|
|
### ISSUE-005 — wlan0 fails on boot (server-side)
|
|
**Status:** Open — pre-existing server issue, not a panel issue
|
|
**Priority:** Low (eth0 works fine when server is docked at router)
|
|
|
|
wlan0 interface fails to come up during boot with `ifup: failed to change interface wlan0 state to up`. wpa_supplicant appears to start before the Intel WiFi 5100 hardware is fully initialized.
|
|
|
|
**Attempted fix:** Add `sleep 3` to pre-up in `/etc/network/interfaces` — not yet tested after reboot.
|
|
|
|
**Workaround:** Manual bring-up after boot:
|
|
```sh
|
|
wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant/wpa_supplicant.conf
|
|
ip route add default via 10.0.0.1 dev wlan0 metric 200
|
|
```
|
|
|
|
---
|
|
|
|
### ISSUE-006 — Diskless/RAM mode not yet configured
|
|
**Status:** Open — planned experiment
|
|
**Priority:** Medium (USB write wear reduction)
|
|
|
|
Currently running in `sys` mode — OS reads/writes directly to USB. Should convert to diskless mode to reduce USB wear. However the partition layout (separate ext4 boot partition sdb1, not vfat) is non-standard and the conversion is risky.
|
|
|
|
**Plan:** Test diskless conversion on a cloned spare USB first. Never attempt on the master image.
|
|
|
|
---
|
|
|
|
## Resolved Decisions
|
|
|
|
### DECISION-001 — Authentication mechanism
|
|
**Status:** Decided ✅
|
|
|
|
Use nginx mutual TLS (mTLS) with client certificates. No login page. Unauthorized devices get a TLS handshake failure — no HTTP response at all.
|
|
|
|
**Rationale:** Minimizes attack surface. No password to brute-force. No session management. Works seamlessly on authorized devices after one-time cert install. Accessible from outside LAN without VPN.
|
|
|
|
---
|
|
|
|
### DECISION-002 — Frontend framework
|
|
**Status:** Decided ✅
|
|
|
|
React with Vite and Tailwind CSS.
|
|
|
|
**Rationale:** Fast dev experience, small production build. Tailwind avoids CSS file management overhead. No SSR needed — the panel is not public-facing or SEO-sensitive.
|
|
|
|
---
|
|
|
|
### DECISION-003 — Backend language
|
|
**Status:** Decided ✅
|
|
|
|
Node.js with Express.
|
|
|
|
**Rationale:** Node.js is already installed on the server as part of the Sawa stack. No additional runtime needed. Express is minimal and well understood.
|
|
|
|
---
|
|
|
|
### DECISION-004 — Database stack convention
|
|
**Status:** Decided ✅
|
|
|
|
| Use case | Database |
|
|
|----------|----------|
|
|
| WordPress, Laravel | MariaDB |
|
|
| Node.js apps | PostgreSQL |
|
|
| Sessions, queues, app state | Redis (persistent, RDB+AOF) |
|
|
| Pure caching | Memcached |
|
|
|
|
---
|
|
|
|
### DECISION-005 — Panel not served on public internet directly
|
|
**Status:** Decided ✅
|
|
|
|
The control panel is accessible on LAN via its local IP and optionally via dynamic DNS from outside. It is not served on a named public domain. It runs on port 443 alongside other nginx virtual hosts, differentiated by the client certificate requirement.
|
|
|
|
---
|
|
|
|
## Technical Debt
|
|
|
|
These are known issues on the server that should be addressed before or alongside panel development:
|
|
|
|
- [ ] `noatime` not yet set on fstab — USB write reduction pending
|
|
- [ ] Diskless/RAM mode not yet configured — see ISSUE-006
|
|
- [ ] MariaDB still using deprecated binary names (`mysql` vs `mariadb`) — harmless but noisy in logs
|
|
- [ ] `resolv.conf` not protected from being overwritten by `networking restart`
|
|
- [ ] `firstboot.sh` lbu overlay rename logic not yet tested on a real clone
|
|
- [ ] Redis password currently passed on command line in some test calls — should use AUTH in config only
|
|
- [ ] SSH on port 22 — consider moving to non-standard port to reduce scan noise
|
|
- [ ] No log rotation configured — logs will grow unbounded on long-running servers
|