feat: add pos system nfs-server and nfs-client (systemd persistent mounts)

This commit is contained in:
Your Name
2026-08-06 03:19:42 -04:00
parent aac3c5266a
commit 03e9d4c8e6
8 changed files with 390 additions and 14 deletions
+20 -14
View File
@@ -10,19 +10,19 @@
<!-- GEN:START docmap -->
| ## 1. Project Overview | 2843 |
| ## 2. Directory Structure | 44165 |
| ## 3. Installation Flow | 166217 |
| ## 4. The `pos` CLI System | 218275 |
| ## 5. Shared Library — `lib/common.sh` | 276306 |
| ## 6. Docker Compose / ScaleTail | 307349 |
| ## 7. Optional Apps (`apps/`) | 350379 |
| ## 8. Entertainment Module | 380393 |
| ## 9. Systemd Services | 394404 |
| ## 10. Configuration Files | 405428 |
| ## 11. Coding Conventions | 429461 |
| ## 12. Development Workflow | 462513 |
| ## 13. Key File Quick Reference | 514556 |
| ## 14. Common Tasks for Agents | 557581 |
| ## 2. Directory Structure | 44167 |
| ## 3. Installation Flow | 168219 |
| ## 4. The `pos` CLI System | 220279 |
| ## 5. Shared Library — `lib/common.sh` | 280310 |
| ## 6. Docker Compose / ScaleTail | 311353 |
| ## 7. Optional Apps (`apps/`) | 354383 |
| ## 8. Entertainment Module | 384397 |
| ## 9. Systemd Services | 398408 |
| ## 10. Configuration Files | 409432 |
| ## 11. Coding Conventions | 433465 |
| ## 12. Development Workflow | 466517 |
| ## 13. Key File Quick Reference | 518562 |
| ## 14. Common Tasks for Agents | 563587 |
<!-- GEN:END docmap -->
## 1. Project Overview
@@ -77,6 +77,8 @@ Linux_post_install/
│ ├── pos-system-backup # Encrypted (AES-256) folder snapshots (tar + gpg)
│ ├── pos-system-firewall # Interactive UFW management
│ ├── pos-system-health # Host health dashboard (disk, RAM, services, backup age, fail2ban, docker); exit 1 if any FAIL
│ ├── pos-system-nfs-client # Mount NFS shares (ephemeral or persistent systemd mount units)
│ ├── pos-system-nfs-server # Manage the NFS kernel server (status, share/unshare exports, enable/disable)
│ ├── pos-usb-server # USB Redirector server control (--ls, --share; prompts when args omitted)
<!-- GEN:END tree -->
│ ├── flag-reader # Inspect feature flags (list/status/--raw)
@@ -254,6 +256,8 @@ All non-interactive `pos` commands log output to `~/.local/share/linux_post_inst
| system | backup | `pos-system-backup` | Encrypted (AES-256) folder snapshots (tar + gpg) |
| system | firewall | `pos-system-firewall` | Interactive UFW management |
| system | health | `pos-system-health` | Host health dashboard (disk, RAM, services, backup age, fail2ban, docker); exit 1 if any FAIL |
| system | nfs-client | `pos-system-nfs-client` | Mount NFS shares (ephemeral or persistent systemd mount units) |
| system | nfs-server | `pos-system-nfs-server` | Manage the NFS kernel server (status, share/unshare exports, enable/disable) |
| usb | server | `pos-usb-server` | USB Redirector server control (--ls, --share; prompts when args omitted) |
<!-- GEN:END dispatch -->
@@ -526,7 +530,7 @@ Use conventional prefixes: `feat:`, `fix:`, `docs:`, `refactor:`, `chore:`
| `bin/flag-clear` | 21 | Unset a flag |
| `features/autostart.sh` | 14 | Boot-time feature (moved from `bin/`, flag-gated service) |
<!-- GEN:START filetable -->
| `bin/pos` | 213 | CLI dispatcher with smart arg matching + logging + category help |
| `bin/pos` | 216 | CLI dispatcher with smart arg matching + logging + category help |
| `bin/pos-communication-telegram` | 274 | Send Telegram messages/files/links/stickers via Bot API (send, test, config set) |
| `bin/pos-docker-compose` | 364 | Docker Compose service manager (ls/up/down/restart/logs/update/config) |
| `bin/pos-docker-health` | 110 | One-glance container health dashboard (exits 1 if unhealthy) |
@@ -547,6 +551,8 @@ Use conventional prefixes: `feat:`, `fix:`, `docs:`, `refactor:`, `chore:`
| `bin/pos-system-backup` | 125 | Encrypted (AES-256) folder snapshots (tar + gpg) |
| `bin/pos-system-firewall` | 291 | Interactive UFW management |
| `bin/pos-system-health` | 243 | Host health dashboard (disk, RAM, services, backup age, fail2ban, docker); exit 1 if any FAIL |
| `bin/pos-system-nfs-client` | 138 | Mount NFS shares (ephemeral or persistent systemd mount units) |
| `bin/pos-system-nfs-server` | 134 | Manage the NFS kernel server (status, share/unshare exports, enable/disable) |
| `bin/pos-usb-server` | 218 | USB Redirector server control (--ls, --share; prompts when args omitted) |
| `completions/pos.bash` | 189 | Dynamic bash completion |
<!-- GEN:END filetable -->
+2
View File
@@ -155,6 +155,8 @@ The standalone `vbox` command still works and forwards to `pos docker vbox` (see
| `pos system backup <folder-path>` | `bin/pos-system-backup` | Create a gpg-encrypted (AES-256) `tar.gz` snapshot of a folder and verify it | Prompts twice for a password (never stored). Uses `sudo tar`; needs `gnupg` (in `preinstall.sh` PACKAGES). Artifact `<name>_<date>.tar.gz.gpg` in the current directory, `chmod 600`. Success/failure are announced via `lib/notify.sh` |
| `pos system backup --service` | `bin/pos-system-backup` | Lists folders under `/srv` and `~/srv`, lets you pick one, then runs the same backup | Roots via `BACKUP_SERVICE_ROOTS` (space-separated, default `/srv $HOME/srv`) or `~/.config/linux_post_install/system.env` |
| `pos system health [--send] [--markdown]` | `bin/pos-system-health` | Host health dashboard: disk per mount, RAM/swap, failed systemd units, backup age, fail2ban, docker containers. Exits 1 if any check FAILs | `--send`/`--markdown` send the summary via `lib/notify.sh` to every platform in `NOTIFY_PLATFORM`. `HEALTH_BACKUP_MAX_AGE_DAYS` (default 2) and `BACKUP_SERVICE_ROOTS` come from `~/.config/linux_post_install/system.env`; `--help` shows the effective values. Platform list from `~/.config/linux_post_install/notify.env` |
| `pos system nfs-server <cmd>` | `bin/pos-system-nfs-server` | Manage the NFS kernel server: `status`, `share <path> [client]`, `unshare <path>`, `list`, `reload`, `enable`, `disable` | Requires `nfs-kernel-server` (added to `preinstall.sh` PACKAGES). Exports live in `/etc/exports`; `share` is idempotent (replaces any existing line for the path) and runs `exportfs -ra`. Default client `*(rw,sync,no_subtree_check)` — the tool warns you to restrict it; help prints Tailscale CGNAT (`100.64.0.0/10`), WireGuard (`10.10.0.0/24`) and LAN examples. Mutating commands announce via `lib/notify.sh` |
| `pos system nfs-client <cmd>` | `bin/pos-system-nfs-client` | Mount and manage NFS shares: `mount <server:export> <local-dir>`, `unmount <local-dir>`, `list`, `persist <server:export> <local-dir>`, `unpersist <local-dir>` | Requires `nfs-common` (added to `preinstall.sh` PACKAGES). `persist` writes a systemd `.mount` unit (`systemd-escape --path --suffix=mount`) with `After=network-online.target` / `Wants=network-online.target` — mounts only once all interfaces are up, no fstab edits to break boot — then `daemon-reload` + `enable --now`. `unpersist` stops/disables/removes the unit. `mount`/`persist` announce via `lib/notify.sh` |
`systemd/pos-health.service` + `systemd/pos-health.timer` run `pos system health --send --markdown` daily at 08:00 as the installing user. `postinstall.sh` enables the timer automatically once `~/.config/linux_post_install/telegram.env` exists — re-run postinstall after configuring a notify platform to pick it up. The service also loads `system.env` + `notify.env` via `EnvironmentFile=`.
+86
View File
@@ -8,6 +8,8 @@ Host care: encrypted backups, firewall, and the health dashboard. Tools:
| `pos system health` | Host health dashboard (disk, RAM, services, backup age, fail2ban, docker) |
| `pos system backup` | gpg-encrypted (AES-256) folder snapshots |
| `pos system firewall` | Interactive UFW ("UFW POWER") management |
| `pos system nfs-server` | Manage the NFS kernel server (exports, enable/disable) |
| `pos system nfs-client` | Mount NFS shares (ephemeral or persistent systemd units) |
---
@@ -143,6 +145,90 @@ not).
---
## `pos system nfs-server` — NFS kernel server
Requires `nfs-kernel-server` (in `preinstall.sh` PACKAGES). Writes to
`/etc/exports` and reloads via `exportfs -ra`; mutating commands announce via
`notify_send`.
```bash
pos system nfs-server status # server active? + current exports
pos system nfs-server share /mnt/hdd # export (generic, warns)
pos system nfs-server share /mnt/hdd '100.64.0.0/10(rw,sync,no_subtree_check)'
pos system nfs-server list # exportfs -v
pos system nfs-server unshare /mnt/hdd # remove the export
pos system nfs-server reload # re-apply /etc/exports after hand edits
pos system nfs-server enable # start + boot-persist the server
pos system nfs-server disable
```
`share <path> [client]` is idempotent: an existing line for the same path is
replaced. With no client it uses `*(rw,sync,no_subtree_check)` and **warns you
to restrict it** — print the restricted form:
- Tailscale (CGNAT): `pos system nfs-server share /mnt/hdd '100.64.0.0/10(rw,sync,no_subtree_check)'`
- WireGuard: `pos system nfs-server share /mnt/hdd '10.10.0.0/24(rw,sync,no_subtree_check)'`
- LAN: `pos system nfs-server share /mnt/backups '192.168.1.0/24(ro,sync,no_subtree_check)'`
**Recipes:**
- **Share the media drive to the tailnet:**
```bash
pos system nfs-server share /mnt/hdd '100.64.0.0/10(rw,sync,no_subtree_check)'
pos system nfs-server enable
```
- **Read-only backups to a LAN host:** use `(ro,sync,no_subtree_check)` and only
`enable` the server where it's needed.
**Troubleshooting:**
- "exportfs not found" → `nfs-kernel-server` isn't installed; `sudo apt install nfs-kernel-server`
- Client sees "mount.nfs: Permission denied" → your `/etc/exports` client rule
doesn't cover the client's IP (check with `pos system nfs-server list`); use
`showmount -e <server>` on the client to see what's exported
- After editing `/etc/exports` by hand, run `pos system nfs-server reload`
- NFS is blocked → allow the ports in `pos system firewall` (or `ufw`)
- Changes to `/etc/exports` are root-required → the tool uses `sudo`
---
## `pos system nfs-client` — mount NFS shares
Requires `nfs-common` (in `preinstall.sh` PACKAGES).
```bash
pos system nfs-client mount <server:export> <local-dir> # one-shot (mkdir -p first)
pos system nfs-client persist <server:export> <local-dir> # persistent systemd mount
pos system nfs-client list # active NFS mounts
pos system nfs-client unmount <local-dir>
pos system nfs-client unpersist <local-dir> # remove the systemd unit
```
**Persistent mounts use systemd, not fstab.** `persist` writes a
`/etc/systemd/system/<mnt-nfs-name>.mount` unit ordered after
`network-online.target`, so the share is mounted only once all interfaces are
up — a down/unreachable NFS server can't break boot (with fstab it could).
`enable --now` mounts it immediately too.
**Recipes:**
- **Mount the server's media share and keep it across reboots:**
```bash
pos system nfs-client persist 100.100.100.1:/mnt/hdd /mnt/nfs/media
pos system nfs-client list
```
- **One-off mount (no persistence):**
`pos system nfs-client mount 10.0.0.5:/srv/data /mnt/data`
**Troubleshooting:**
- "mount.nfs not found" → `nfs-common` isn't installed; `sudo apt install nfs-common`
- Mount hangs → check the server export (`pos system nfs-server list` on the
server) and that the client IP is allowed; `showmount -e <server>` lists
exports; NFS timeouts take ~2min by default, add `timeo=50,retrans=2` via the
unit if needed
- Persistent mount fails at boot when the server is off → intended: the unit
waits for network-online and fails cleanly, and boot continues (unlike fstab);
`pos system nfs-client unpersist` removes it
---
## Related
- Reference: [DOC/POS.md → system](../POS.md)