docs: add pos HOW-TO guide set (index + 8 category guides)
This commit is contained in:
@@ -10,6 +10,7 @@ CRITICAL: real guidance lives in DOC/. When you encounter a reference below, use
|
||||
- @DOC/DEV.md — conventions, verification, and the "Adding a new Feature/App/Tool" checklists. Read before creating or changing code/docs.
|
||||
- @DOC/POS.md — `pos` CLI reference (dispatcher + every command). Read when working on `bin/pos*` scripts or their docs.
|
||||
- @DOC/README.md — index of all docs. Read to find the right doc.
|
||||
- @DOC/HOWTO.md — hands-on per-category guides (network, docker, media, system, ssh, usb, communication, entertainment) with flags, recipes, and troubleshooting. Read when a task is about *using* `pos` day-to-day rather than extending it.
|
||||
|
||||
## Quick facts
|
||||
|
||||
|
||||
@@ -49,6 +49,10 @@ summary (newest last).
|
||||
|
||||
## Done (summary, newest last)
|
||||
|
||||
- 2026-08-06: `pos` HOW-TO guide set — `DOC/HOWTO.md` index + per-category
|
||||
`DOC/howto/*.md` (network, docker, media, system, ssh, usb, communication,
|
||||
entertainment) with flags, recipes, config, and troubleshooting; wired into
|
||||
DOC/README, root README, AGENTS.md.
|
||||
- 2026-08-06: Multi-platform alerting — `lib/notify.sh` routes via `NOTIFY_PLATFORM`
|
||||
(`notify.env`, default telegram; sender contract for Matrix/Synapse later),
|
||||
`system.env` shared config for health/backup, dynamic effective values in
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
# `pos` HOW-TO Guides
|
||||
|
||||
Hands-on, copy-paste guides for every `pos` category. These are the **tutorial**
|
||||
layer: flags, examples, configuration, recipes, and troubleshooting. For the
|
||||
authoritative one-line reference (every command + flag), see
|
||||
[DOC/POS.md](POS.md).
|
||||
|
||||
## Quick start — pick your category
|
||||
|
||||
| Category | What you can do | Guide |
|
||||
|----------|-----------------|-------|
|
||||
| `pos network` | IP info, hotspot, scan, port check | [network](howto/network.md) |
|
||||
| `pos docker` | Compose services, container dashboards, disposable VMs | [docker](howto/docker.md) |
|
||||
| `pos media` | Download audio/video via yt-dlp | [media](howto/media.md) |
|
||||
| `pos system` | Backups, firewall, health dashboard | [system](howto/system.md) |
|
||||
| `pos ssh` | Load keys into the agent | [ssh](howto/ssh.md) |
|
||||
| `pos usb` | Share USB devices over the network | [usb](howto/usb.md) |
|
||||
| `pos communication` | Send Telegram messages/files/alerts | [communication](howto/communication.md) |
|
||||
| `pos entertainment` | Scheduled auto-messages from public APIs | [entertainment](howto/entertainment.md) |
|
||||
|
||||
Every tool is `bin/pos-<category>-<command>`; run `pos <category> --help` to
|
||||
list a category, and any tool's `--help`/`--help`-style usage for full flags.
|
||||
|
||||
## Cross-cutting concepts (read once)
|
||||
|
||||
These apply to several categories at once.
|
||||
|
||||
### Config files — `~/.config/linux_post_install/`
|
||||
|
||||
Runtime tool config lives here as `<tool>.env` files (`chmod 600`). Precedence
|
||||
is always **flags > environment > config file**. `postinstall.sh` installs the
|
||||
templates (without overwriting an existing file):
|
||||
|
||||
| File | Used by | Keys |
|
||||
|------|---------|------|
|
||||
| `telegram.env` | `pos communication telegram`, everything that alerts | `TELEGRAM_BOT_TOKEN`, `TELEGRAM_CHAT_ID` |
|
||||
| `notify.env` | `lib/notify.sh` (all alerting) | `NOTIFY_PLATFORM` (e.g. `telegram,matrix`) |
|
||||
| `system.env` | `pos system health`, `pos system backup` | `BACKUP_SERVICE_ROOTS`, `HEALTH_BACKUP_MAX_AGE_DAYS` |
|
||||
| `compose.env` | `pos docker compose` | `TS_AUTHKEY`, `TZ`, `DNS_SERVER`, `SERVICES_BASE` |
|
||||
| `entertainment.env` | `pos entertainment *` | plugin keys (`WEATHER_LAT`…), `ENABLED` |
|
||||
|
||||
```bash
|
||||
pos communication telegram config set TELEGRAM_BOT_TOKEN=123:ABC
|
||||
pos communication telegram config set TELEGRAM_CHAT_ID=98765
|
||||
pos entertainment config set WEATHER_LAT=36.51 WEATHER_LON=40.75
|
||||
```
|
||||
|
||||
### The notify system — `lib/notify.sh`
|
||||
|
||||
Any tool that "announces" something calls `notify_send`, which delivers to every
|
||||
platform in `NOTIFY_PLATFORM` (default `telegram`). It is **silent-fail**: if no
|
||||
platform is configured it warns and never breaks the calling tool.
|
||||
|
||||
```bash
|
||||
# ~/.config/linux_post_install/notify.env
|
||||
NOTIFY_PLATFORM=telegram # comma-separated to send to all
|
||||
```
|
||||
|
||||
Adding a platform later (e.g. Matrix/Synapse) = create `bin/pos-communication-<p>`
|
||||
implementing `send <value> [--markdown]` and list it. See
|
||||
[DOC/DEV.md → Alerting](DEV.md) for the contract.
|
||||
|
||||
### Scheduling
|
||||
|
||||
- **Daily health digest** (`pos system health --send` at 08:00) — `systemd/pos-health.{service,timer}`,
|
||||
enabled by postinstall once `telegram.env` exists. See [system](howto/system.md).
|
||||
- **Entertainment auto-triggers** — per-plugin `pos entertainment enable <plugin> <interval>`,
|
||||
uses systemd user timers (or cron fallback). See [entertainment](howto/entertainment.md).
|
||||
|
||||
### Gotcha: run from anywhere
|
||||
|
||||
`install.sh` copies `bin/pos*` + `lib/*` to `/usr/local/bin`, so `pos` works
|
||||
after the repo is deleted. After pulling new changes, re-run `./install.sh` (or
|
||||
just copy the changed `bin/`/`lib/` files) to refresh the installed copies.
|
||||
|
||||
## How the guides relate to `DOC/POS.md`
|
||||
|
||||
- **`DOC/POS.md`** = reference. One table row per command, full flag lists,
|
||||
compose/ScaleTail config strategy. Use it when you need the exact flag.
|
||||
- **This guide set** = how-to. Examples, recipes, config walk-throughs, and
|
||||
troubleshooting, linking back to POS.md rather than duplicating it.
|
||||
@@ -4,6 +4,7 @@ Everything in this folder is reference material for the `Linux_post_install` pro
|
||||
|
||||
| Document | What it covers |
|
||||
|----------|----------------|
|
||||
| [HOWTO.md](HOWTO.md) | Hands-on guides per category (network, docker, media, system, ssh, usb, communication, entertainment): flags, recipes, config, troubleshooting |
|
||||
| [SCRIPTS.md](SCRIPTS.md) | Core installer scripts: `install.sh`, `preinstall.sh`, `postinstall.sh`, `lib/common.sh`, `lib/flags.sh`, `lib/entertainment-lib.sh`, `features/autostart.sh` — purpose, how each works, configuration |
|
||||
| [POS.md](POS.md) | The `pos` CLI: dispatcher, every `pos-*` command, Docker Compose / ScaleTail config, legacy wrappers, flag CLIs |
|
||||
| [APPS.md](APPS.md) | Optional apps: `apps/install.sh` picker, installer conventions, full app catalog |
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
# How-To: `pos communication`
|
||||
|
||||
Telegram messaging and alerts. Tools: `telegram`, `matrix`.
|
||||
|
||||
| Tool | What it does |
|
||||
|------|--------------|
|
||||
| `pos communication telegram` | Send messages/files, manage config, webhook state, message logs |
|
||||
| `pos communication matrix` | Matrix/Synapse sender (extensible; not yet implemented) |
|
||||
|
||||
`telegram` is the workhorse: it backs the whole **notify system** — health
|
||||
digests, backup alerts, firewall changes — and can be used directly.
|
||||
|
||||
---
|
||||
|
||||
## `pos communication telegram`
|
||||
|
||||
### One-time setup
|
||||
|
||||
```bash
|
||||
pos communication telegram config set TELEGRAM_BOT_TOKEN=123456:ABC...
|
||||
pos communication telegram config set TELEGRAM_CHAT_ID=987654321
|
||||
pos communication telegram config set TELEGRAM_DISABLE_WEBHOOK=true # if used with webhooks
|
||||
pos communication telegram config
|
||||
# config lives in ~/.config/linux_post_install/telegram.env (chmod 600)
|
||||
```
|
||||
|
||||
The bot token comes from @BotFather, the chat ID from @userinfobot (or by
|
||||
starting a chat and reading it). To set your display name once: message
|
||||
`/start` to your bot, then `pos communication telegram chat-id` prints it.
|
||||
|
||||
### Send
|
||||
|
||||
```bash
|
||||
pos communication telegram send "hello from my server" # plain text
|
||||
pos communication telegram send --markdown "**bold** ok" # parse as markdown
|
||||
pos communication telegram send --help # list all flags
|
||||
pos communication telegram file /path/to/report.pdf # send a document
|
||||
pos communication telegram broadcast "restarting in 5min" # to all known chat IDs
|
||||
```
|
||||
|
||||
### State & logs
|
||||
|
||||
```bash
|
||||
pos communication telegram getwebhookinfo # current webhook + pending count
|
||||
pos communication telegram setwebhook https://... # point a webhook URL (or "")
|
||||
pos communication telegram deletemenu # clear the bot menu
|
||||
pos communication telegram logs # recent send history (logs dir)
|
||||
pos communication telegram clear-logs # wipe message logs
|
||||
```
|
||||
|
||||
**Recipes:**
|
||||
- **Alert when a backup finishes** — automatic: `pos system backup` calls
|
||||
`notify_send` (below) on success *and* failure.
|
||||
- **Warn before a service update:**
|
||||
```bash
|
||||
pos communication telegram send "Maintenance: docker compose down in 2min"
|
||||
```
|
||||
- **On-call file drop:** `pos communication telegram file ~/log/nginx-error.log`
|
||||
|
||||
**Troubleshooting:**
|
||||
- "Not configured (no token or chat id)" → run `config set` for both values.
|
||||
- Send succeeds but nothing arrives → the chat must have started the bot
|
||||
(press `Start` / send `/start` once).
|
||||
- **Markdown silently empty** → Telegram uses its own MarkdownV2; unmatched
|
||||
syntax makes the message vanish. Use `--markdown` only when the text is
|
||||
Telegram-safe (the health digest output is).
|
||||
- **Webhook vs getUpdates:** if your bot has an active webhook, `send` may
|
||||
still work (we disable the webhook automatically when it owns it) — but if
|
||||
another process registered the webhook, polls fail; `deletemenu`/webhook
|
||||
state shows ownership. See `getwebhookinfo`.
|
||||
|
||||
---
|
||||
|
||||
## The notify system (`notify_send`)
|
||||
|
||||
Every tool that announces something sends through `lib/notify.sh` instead of
|
||||
hard-coding Telegram:
|
||||
|
||||
```bash
|
||||
# ~/.config/linux_post_install/notify.env
|
||||
NOTIFY_PLATFORM=telegram # default; comma-separated to fan out to all
|
||||
```
|
||||
|
||||
- `notify_send "msg"` → delivers to every platform in `NOTIFY_PLATFORM`
|
||||
(current senders: `telegram`).
|
||||
- **Silent-fail:** no platform configured → one WARN line, exit 0, never
|
||||
breaks the calling tool.
|
||||
- New platform (e.g. Matrix): implement `bin/pos-communication-<p> send
|
||||
<value> [--markdown]`, then list it in `NOTIFY_PLATFORM`. Details:
|
||||
[DOC/DEV.md → Alerting](../DEV.md).
|
||||
|
||||
---
|
||||
|
||||
## `pos communication matrix`
|
||||
|
||||
Sender contract exists (`send <value> [--markdown]`) and the dispatcher routes
|
||||
to it, but no implementation ships yet. When present, add `matrix` to
|
||||
`NOTIFY_PLATFORM` and configure it via `pos communication matrix config set …`.
|
||||
|
||||
---
|
||||
|
||||
## Related
|
||||
|
||||
- Reference + config file details: [DOC/POS.md → communication](../POS.md)
|
||||
- Alerting contract: [DOC/DEV.md → Alerting](../DEV.md)
|
||||
- Health digest (uses `--send --markdown`): [system.md](system.md)
|
||||
@@ -0,0 +1,137 @@
|
||||
# How-To: `pos docker`
|
||||
|
||||
Manage self-hosted services, watch containers, and spin up disposable VMs.
|
||||
Tools: `compose`, `ps`, `health`, `vbox`.
|
||||
|
||||
| Tool | What it does |
|
||||
|------|--------------|
|
||||
| `pos docker compose` | ScaleTail service manager (deploy/stop/logs/update) |
|
||||
| `pos docker ps` | Enhanced container overview (health, IPs, ports, uptime) |
|
||||
| `pos docker health` | One-glance health dashboard (exits 1 if unhealthy) |
|
||||
| `pos docker vbox` | Disposable Docker containers as lightweight VMs |
|
||||
|
||||
---
|
||||
|
||||
## `pos docker compose` — self-hosted services (ScaleTail)
|
||||
|
||||
Deploy 119+ self-hosted service templates (Jellyfin, Home Assistant, …) on
|
||||
Tailscale. Template set lives in
|
||||
`/usr/local/share/linux_post_install/scale-tail/services/`.
|
||||
|
||||
```bash
|
||||
pos docker compose ls # list available templates
|
||||
pos docker compose installed # what's deployed locally
|
||||
pos docker compose up jellyfin # deploy or start
|
||||
pos docker compose down actual-budget # stop + remove
|
||||
pos docker compose restart home-assistant
|
||||
pos docker compose logs jellyfin -f # follow logs
|
||||
pos docker compose update # pull latest templates + refresh deployments
|
||||
pos docker compose config # show global config
|
||||
pos docker compose config set TS_AUTHKEY=tskey-auth-xxxxx
|
||||
pos docker compose config set TZ=Asia/Tokyo
|
||||
pos docker compose config set SERVICES_BASE=/data
|
||||
pos docker compose config edit # open global config in $EDITOR
|
||||
```
|
||||
|
||||
### Config strategy (three layers, each overrides the one above)
|
||||
|
||||
1. **Template defaults** — `…/services/<name>/.env`
|
||||
2. **Global config** — `~/.config/linux_post_install/compose.env`
|
||||
keys: `TS_AUTHKEY` | `TZ` | `DNS_SERVER` | `SERVICES_BASE`
|
||||
3. **Per-service config** — `/srv/<service>/.env` (or `$SERVICES_BASE/<service>/.env`)
|
||||
|
||||
On first `up`, the per-service `.env` is generated from the template + your
|
||||
global config, and is **never overwritten** afterwards (not even by `update`).
|
||||
|
||||
### Quick start
|
||||
|
||||
```bash
|
||||
pos docker compose config set TS_AUTHKEY=tskey-auth-xxxxx # required
|
||||
pos docker compose up jellyfin
|
||||
# open https://jellyfin.tail-xxxxx.ts.net
|
||||
```
|
||||
|
||||
**Recipes:**
|
||||
- Change timezone once, applies everywhere: `pos docker compose config set TZ=Asia/Tokyo`
|
||||
- Store deployments on a bigger disk: `pos docker compose config set SERVICES_BASE=/data`
|
||||
- Tweak one service's options after deploy: edit `/srv/<service>/.env` directly
|
||||
(never clobbered).
|
||||
|
||||
**Troubleshooting:**
|
||||
- `up` fails with auth errors → `TS_AUTHKEY` missing/expired; re-set it.
|
||||
- Service reachable only on the host → Tailscale up/`tailscale up` not running;
|
||||
check `TS_AUTHKEY` in the service `.env`.
|
||||
- `update` doesn't change your customizations → expected; per-service `.env` is
|
||||
preserved by design.
|
||||
|
||||
---
|
||||
|
||||
## `pos docker ps` — better `docker ps`
|
||||
|
||||
```bash
|
||||
pos docker ps
|
||||
```
|
||||
|
||||
Enhanced overview: health status, uptime, IPs, port mappings.
|
||||
|
||||
**Recipe:** pair with the daily digest — the health report summarizes
|
||||
unhealthy/restarting containers; when it flags one, `pos docker ps` shows the
|
||||
details (IPs/ports/uptime) to investigate.
|
||||
|
||||
---
|
||||
|
||||
## `pos docker health` — is everything healthy?
|
||||
|
||||
```bash
|
||||
pos docker health
|
||||
```
|
||||
|
||||
Prints health + uptime per container; **exits 1 if any container is unhealthy**
|
||||
(useful for scripts/CI/monitoring).
|
||||
|
||||
**Recipe:** alert on failure in your own script:
|
||||
```bash
|
||||
pos docker health >/dev/null || notify_send "Docker unhealthy"
|
||||
```
|
||||
|
||||
**Troubleshooting:** a container shows no health status if its image has no
|
||||
`HEALTHCHECK` — that's fine, it counts as "no healthcheck configured" (exit 0),
|
||||
not unhealthy.
|
||||
|
||||
---
|
||||
|
||||
## `pos docker vbox` — disposable VMs
|
||||
|
||||
Docker containers with a bind-mounted host dir so files persist even after the
|
||||
container is removed. Great for labs, downloads, kali, throwaway services.
|
||||
|
||||
```bash
|
||||
pos docker vbox create lab1 # default dir ~/lab1
|
||||
pos docker vbox create lab1 --dir . # files land in cwd
|
||||
pos docker vbox create lab1 --dir /mnt/data/lab1
|
||||
pos docker vbox create kali kalilinux/kali-rolling # custom image
|
||||
pos docker vbox enter lab1
|
||||
pos docker vbox stop lab1
|
||||
pos docker vbox start lab1
|
||||
pos docker vbox rm lab1
|
||||
pos docker vbox ls
|
||||
```
|
||||
|
||||
**Recipe:** a disposable browsing/download box:
|
||||
```bash
|
||||
pos docker vbox create dl --dir /mnt/data/dl
|
||||
pos docker vbox enter dl # work inside; files persist in /mnt/data/dl
|
||||
pos docker vbox rm dl # container gone, files kept
|
||||
```
|
||||
|
||||
**Troubleshooting:**
|
||||
- `enter` needs a shell/SSH-capable image; `kalilinux/kali-rolling` works.
|
||||
- If files "disappear" after `rm`, check you used `--dir` on a real path — the
|
||||
container image changes are lost, only the mounted dir persists.
|
||||
|
||||
---
|
||||
|
||||
## Related
|
||||
|
||||
- Reference + compose config strategy: [DOC/POS.md → docker](../POS.md)
|
||||
- Container health in the daily digest: [system.md → health](system.md)
|
||||
@@ -0,0 +1,79 @@
|
||||
# How-To: `pos entertainment`
|
||||
|
||||
Auto-published fun messages from public APIs, with per-plugin scheduling.
|
||||
Tools: `config`, `enable`, `disable`, `send`, `status`.
|
||||
|
||||
| Tool | What it does |
|
||||
|------|--------------|
|
||||
| `pos entertainment send` | Fetch a plugin's message to stdout (dry-run) |
|
||||
| `pos entertainment enable <plugin> [interval]` | Schedule auto-sends |
|
||||
| `pos entertainment disable <plugin>` | Remove the schedule |
|
||||
| `pos entertainment status` | List plugins + their active schedules |
|
||||
| `pos entertainment config set|get` | Plugin keys in `entertainment.env` |
|
||||
|
||||
### Plugins
|
||||
|
||||
| Plugin | API | Config keys |
|
||||
|--------|-----|-------------|
|
||||
| `weather` | Open-Meteo (no key) | `WEATHER_LAT`, `WEATHER_LON` (req), `WEATHER_CITY` (opt) |
|
||||
| `joke` | icanhazdadjoke (no key) | — |
|
||||
| `gold` | goldprice.dev (no key) | — |
|
||||
|
||||
Interval (systemd time): `5m`, `10m`, `30m`, `1h`, `2h`, `6h`, `12h`, `daily`,
|
||||
`weekly`.
|
||||
|
||||
---
|
||||
|
||||
## First run — configure, test, schedule
|
||||
|
||||
```bash
|
||||
pos entertainment config set WEATHER_LAT=36.51 WEATHER_LON=40.75 WEATHER_CITY="Berlin"
|
||||
|
||||
pos entertainment send weather # stdout test — message for Telegram
|
||||
pos entertainment send joke
|
||||
pos entertainment send gold
|
||||
|
||||
pos entertainment enable weather daily # once a day
|
||||
pos entertainment enable joke 2h # every 2 hours
|
||||
pos entertainment disable gold
|
||||
|
||||
pos entertainment status # plugins + active schedules
|
||||
```
|
||||
|
||||
## How it works
|
||||
|
||||
- **Scheduling** uses systemd **user** timers (unit `pos-ent-<plugin>.timer`,
|
||||
fallback to cron when systemd user units are unavailable). Interval is
|
||||
resolved through the same systemd-time parser used by `.timer` units —
|
||||
invalid values are rejected with a clear message.
|
||||
- **Delivery** goes through `notify_send`, so the platform follows
|
||||
`NOTIFY_PLATFORM` (default Telegram). If no platform is configured, enable
|
||||
still works — the plugin fetches and tries to notify, silently no-ops when
|
||||
unconfigured.
|
||||
|
||||
**Recipes:**
|
||||
- **Morning weather + joke:** `enable weather daily`, `enable joke daily`; the
|
||||
08:00 health digest plus these make a nice wake-up.
|
||||
- **Add a plugin:** it's a `POS_PLUGIN` script in `entertainment/`; stdout is
|
||||
the message, `POS_KEYS` lines declare config keys. See
|
||||
[DOC/DEV.md → "Adding a plugin"](../DEV.md).
|
||||
|
||||
**Troubleshooting:**
|
||||
- `send weather` prints an error about coordinates → set `WEATHER_LAT`/
|
||||
`WEATHER_LON` (required keys) via `config set`.
|
||||
- `enable` fails on the interval → the value isn't valid systemd time; use one
|
||||
of: `5m 10m 30m 1h 2h 6h 12h daily weekly`.
|
||||
- Nothing arrives even though `status` shows the timer → check `notify.env`
|
||||
(`NOTIFY_PLATFORM`) and that `telegram.env` is configured (see
|
||||
[communication](communication.md)); confirm the timer fired:
|
||||
`systemctl --user list-timers pos-ent-*`.
|
||||
- Public-API flakiness → the plugin outputs a clear failure; the notify call is
|
||||
silent-fail by design.
|
||||
|
||||
---
|
||||
|
||||
## Related
|
||||
|
||||
- Reference + plugin list: [DOC/POS.md → entertainment](../POS.md)
|
||||
- Notify platform: [communication.md](communication.md)
|
||||
- Writing a plugin: [DOC/DEV.md](../DEV.md)
|
||||
@@ -0,0 +1,63 @@
|
||||
# How-To: `pos media`
|
||||
|
||||
Download audio and video from the web via `yt-dlp`. Tools: `mp3`, `mp4`.
|
||||
|
||||
| Tool | What it does |
|
||||
|------|--------------|
|
||||
| `pos media mp3` | Download audio, convert to MP3 |
|
||||
| `pos media mp4` | Download video with interactive format selection |
|
||||
|
||||
Requires `yt-dlp` (`sudo apt install yt-dlp`); the tools fail with a clean
|
||||
error message instead of a raw `command not found` if it's missing.
|
||||
|
||||
---
|
||||
|
||||
## `pos media mp3` — audio as MP3
|
||||
|
||||
```bash
|
||||
pos media mp3 <url>
|
||||
```
|
||||
|
||||
Extracts and converts the audio track to MP3 in the current directory.
|
||||
|
||||
```bash
|
||||
pos media mp3 https://youtube.com/watch?v=dQw4w9WgXcQ
|
||||
```
|
||||
|
||||
**Recipe:** batch — loop over a list of URLs:
|
||||
```bash
|
||||
while read -r url; do pos media mp3 "$url"; done < urls.txt
|
||||
```
|
||||
|
||||
**Troubleshooting:** MP3 conversion needs `ffmpeg`; if the tool errors about a
|
||||
missing postprocessor, `sudo apt install ffmpeg`. Single-song playlists: use the
|
||||
video URL directly, or a playlist entry.
|
||||
|
||||
---
|
||||
|
||||
## `pos media mp4` — video with format choice
|
||||
|
||||
```bash
|
||||
pos media mp4 <url>
|
||||
```
|
||||
|
||||
Lists the available formats (`yt-dlp -F`) and lets you pick interactively, then
|
||||
downloads to the current directory.
|
||||
|
||||
```bash
|
||||
pos media mp4 https://youtube.com/watch?v=dQw4w9WgXcQ
|
||||
```
|
||||
|
||||
**Recipe:** grab a 4K stream for later — pick the highest `video only` format +
|
||||
best audio; yt-dlp merges them (again needs `ffmpeg`).
|
||||
|
||||
**Troubleshooting:**
|
||||
- Format list is empty → the site/age-gate requires cookies/auth; yt-dlp can't
|
||||
access it — use a URL yt-dlp supports, or update yt-dlp (`sudo apt upgrade yt-dlp`).
|
||||
- Very large downloads: ensure free space; files land in the current directory.
|
||||
|
||||
---
|
||||
|
||||
## Related
|
||||
|
||||
- Reference: [DOC/POS.md → media](../POS.md)
|
||||
@@ -0,0 +1,116 @@
|
||||
# How-To: `pos network`
|
||||
|
||||
Networking day-to-day: IP/diagnostic info, Wi-Fi hotspots, host discovery, and
|
||||
port checks. Tools: `ip`, `hotspot`, `scan`, `checkport`.
|
||||
|
||||
| Tool | What it does |
|
||||
|------|--------------|
|
||||
| `pos network ip` | Interfaces, default route, public IP + location |
|
||||
| `pos network hotspot` | Wi-Fi AP via `create_ap` / `wihotspot-gui` |
|
||||
| `pos network scan` | Two-phase host discovery with `nmap` |
|
||||
| `pos network checkport` | Is a TCP port open on a host? |
|
||||
|
||||
---
|
||||
|
||||
## `pos network ip` — where am I, what's my IP
|
||||
|
||||
```bash
|
||||
pos network ip
|
||||
```
|
||||
|
||||
Shows local interfaces + addresses, the default route, and your public IP with
|
||||
its geolocation. Useful before `ssh`-ing home or opening ports.
|
||||
|
||||
**Recipe:** public IP on the go — this is the same value the health digest
|
||||
includes, so if your home IP changed you'll see it in the 08:00 report.
|
||||
|
||||
**Troubleshooting:** the public-IP lookup needs outbound HTTPS; if it prints
|
||||
"unreachable"/location unknown, your network or a firewall is blocking
|
||||
`api.ipify.org` / the geo provider.
|
||||
|
||||
---
|
||||
|
||||
## `pos network hotspot` — turn the machine into a Wi-Fi AP
|
||||
|
||||
Requires the precompiled `create_ap` + `wihotspot-gui` binaries shipped in
|
||||
`x64_bin/` (or `arm64_bin/`) and installed to `/usr/local/bin` by `install.sh`.
|
||||
The GUI needs a desktop session; the CLI needs a wireless NIC in AP mode.
|
||||
|
||||
```bash
|
||||
pos network hotspot # launch the wihotspot-gui
|
||||
pos network hotspot start wlan0 eth0 MyNet mypass # AP on wlan0, internet via eth0
|
||||
pos network hotspot start --foreground wlan0 eth0 MyNet mypass # block until Ctrl+C
|
||||
pos network hotspot stop # stop the running AP (auto-detected)
|
||||
pos network hotspot stop wlan0 # stop by interface/PID
|
||||
pos network hotspot status # list running APs
|
||||
```
|
||||
|
||||
Positional args: `<wifi-iface> [<internet-iface>] <ssid> [<passphrase>]`.
|
||||
Without `--foreground`, it asks whether to run in the background; daemonized APs
|
||||
log to `/var/log/linux_post_install_hotspot.log`.
|
||||
|
||||
**Recipes:**
|
||||
- Give guests internet while tethered: `pos network hotspot start wlan0 eth0 GuestNet secret`.
|
||||
- After starting, find who joined with `pos network scan 192.168.42.0/24` (create_ap
|
||||
default subnet) or `pos network checkport <phone-ip>:80`.
|
||||
|
||||
**Troubleshooting:**
|
||||
- `create_ap` not found → the precompiled binary wasn't installed; re-run
|
||||
`./install.sh` (Phase 2 copies `x64_bin/` → `/usr/local/bin`).
|
||||
- "No suitable AP mode" → your Wi-Fi card/driver doesn't support AP mode; use the
|
||||
GUI (wihotspot-gui) or a USB dongle.
|
||||
- Client has IP but no internet → check the `<internet-iface>` arg / NAT
|
||||
forwarding; `create_ap --daemon` logs to the hotspot logfile.
|
||||
|
||||
---
|
||||
|
||||
## `pos network scan` — find hosts on the LAN
|
||||
|
||||
Requires `nmap` (`sudo apt install nmap`).
|
||||
|
||||
```bash
|
||||
pos network scan 192.168.1.0/24 # fast discovery
|
||||
pos network scan 10.0.0.0/28 --full # + OS, ports, services, NSE scripts
|
||||
pos network scan 172.1.1.104 # single host
|
||||
pos network scan 192.168.1.0/24 --retries 3
|
||||
```
|
||||
|
||||
Two phases: fast ping-sweep discovery, then — only with `--full` — a detailed
|
||||
metadata scan on the alive hosts.
|
||||
|
||||
**Recipe:** after `pos network hotspot start`, find attached clients:
|
||||
`pos network scan 192.168.42.0/24`.
|
||||
|
||||
**Troubleshooting:** `nmap` missing → install it. Scanning a remote/hostile
|
||||
network without permission is not advisable; `--full` is slow — scope it to a
|
||||
`/24` or a single host.
|
||||
|
||||
---
|
||||
|
||||
## `pos network checkport` — is a port open?
|
||||
|
||||
```bash
|
||||
pos network checkport 192.168.1.1:80
|
||||
pos network checkport 10.0.0.5:443
|
||||
```
|
||||
|
||||
Exits non-zero if the port is closed/unreachable, so you can chain it:
|
||||
|
||||
**Recipe:** confirm a self-hosted service is up before alerting:
|
||||
```bash
|
||||
pos network checkport jellyfin.local:8096 && notify_send "Jellyfin reachable" \
|
||||
|| notify_send "Jellyfin DOWN"
|
||||
```
|
||||
(see [communication](communication.md) for `notify_send`).
|
||||
|
||||
**Troubleshooting:** a "closed" answer from a host that *is* up usually means a
|
||||
local firewall — check `sudo pos system firewall` rules and service binds
|
||||
(`ss -tlnp`).
|
||||
|
||||
---
|
||||
|
||||
## Related
|
||||
|
||||
- Reference tables: [DOC/POS.md → network](../POS.md)
|
||||
- Firewall that may block these: [system.md](system.md)
|
||||
- Public IP in the daily digest: [system.md → health](system.md)
|
||||
@@ -0,0 +1,41 @@
|
||||
# How-To: `pos ssh`
|
||||
|
||||
SSH agent key management. Tool: `load-keys`.
|
||||
|
||||
| Tool | What it does |
|
||||
|------|--------------|
|
||||
| `pos ssh load-keys` | Load all `~/.ssh/id_*` private keys into the ssh-agent |
|
||||
|
||||
---
|
||||
|
||||
## `pos ssh load-keys` — keys into the agent
|
||||
|
||||
```bash
|
||||
pos ssh load-keys
|
||||
```
|
||||
|
||||
Loads every `~/.ssh/id_*` private key into a shared ssh-agent. Skips `.pub`,
|
||||
`known_hosts`, `authorized_keys`, and `config`; validates keys before adding.
|
||||
|
||||
Requires the system-wide `ssh-agent.service` (socket `/run/ssh-agent/socket`),
|
||||
installed by `postinstall.sh`. `~/.bashrc` exports `SSH_AUTH_SOCK` to it, so
|
||||
agent-using tools (git, ssh, rsync) work from any session.
|
||||
|
||||
**Recipe:** after a fresh boot, before pushing to your server:
|
||||
```bash
|
||||
pos ssh load-keys && ssh -T git@gitea.skink-platy.ts.net
|
||||
```
|
||||
|
||||
**Troubleshooting:**
|
||||
- "Could not connect to agent" → `ssh-agent.service` isn't running:
|
||||
`sudo systemctl start ssh-agent && sudo systemctl enable ssh-agent`, then
|
||||
re-login or re-source `.bashrc` for `SSH_AUTH_SOCK`.
|
||||
- Key not loaded → confirm it's `~/.ssh/id_*` (non-`.pub`), perms `600`, and has
|
||||
no passphrase prompt issue; use `ssh-add -l` to list loaded keys.
|
||||
|
||||
---
|
||||
|
||||
## Related
|
||||
|
||||
- Service details: [DOC/SYSTEMD.md → ssh-agent.service](../SYSTEMD.md)
|
||||
- Reference: [DOC/POS.md → ssh](../POS.md)
|
||||
@@ -0,0 +1,148 @@
|
||||
# How-To: `pos system`
|
||||
|
||||
Host care: encrypted backups, firewall, and the health dashboard. Tools:
|
||||
`backup`, `firewall`, `health`.
|
||||
|
||||
| Tool | What it does |
|
||||
|------|--------------|
|
||||
| `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 health` — host health dashboard
|
||||
|
||||
```bash
|
||||
pos system health # console report; exits 1 if any check FAILs
|
||||
pos system health --send # also send the summary via notify platforms
|
||||
pos system health --markdown # same, markdown parse mode (implies --send)
|
||||
```
|
||||
|
||||
Checks: disk per mount (>90% = FAIL), RAM/swap, failed systemd units, backup
|
||||
age, fail2ban, docker containers. Header shows hostname, uptime, load, public IP.
|
||||
|
||||
`--help` prints the **effective** config values (env > `system.env` > default),
|
||||
e.g.:
|
||||
|
||||
```
|
||||
Environment (effective values):
|
||||
NOTIFY_PLATFORM telegram
|
||||
HEALTH_BACKUP_MAX_AGE_DAYS 2
|
||||
BACKUP_SERVICE_ROOTS /srv /home/you/srv
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
```bash
|
||||
# ~/.config/linux_post_install/system.env
|
||||
BACKUP_SERVICE_ROOTS=/srv /home/you/srv # where backup-age is checked
|
||||
HEALTH_BACKUP_MAX_AGE_DAYS=3 # WARN if newest backup older
|
||||
# ~/.config/linux_post_install/notify.env
|
||||
NOTIFY_PLATFORM=telegram
|
||||
```
|
||||
|
||||
### Daily digest (automated)
|
||||
|
||||
`systemd/pos-health.{service,timer}` run `pos system health --send --markdown`
|
||||
at 08:00 as the installing user. Enable it (re-run postinstall after Telegram
|
||||
is configured):
|
||||
|
||||
```bash
|
||||
./postinstall.sh # enables timer once telegram.env exists
|
||||
systemctl list-timers | grep pos-health
|
||||
systemctl start pos-health.service # run once now, check status
|
||||
```
|
||||
|
||||
**Recipes:**
|
||||
- Watch the backup age without email: enable the digest; if the backup check
|
||||
turns WARN you'll see it in the morning report.
|
||||
- Exit code in a cron/scheduled check:
|
||||
`pos system health >/dev/null 2>&1 || notify_send "health FAIL"`.
|
||||
|
||||
**Troubleshooting:**
|
||||
- `[WARN] fail2ban installed but not running` → expected unless you have it
|
||||
active; start it (`sudo systemctl enable --now fail2ban`) or ignore.
|
||||
- `[FAIL] services: nbd-server.service …` → a failed unit; inspect with
|
||||
`systemctl status <unit>`.
|
||||
- `--send` prints a warn and exits 0 when no platform is configured — by design
|
||||
(see [communication](communication.md)).
|
||||
|
||||
---
|
||||
|
||||
## `pos system backup` — encrypted folder snapshots
|
||||
|
||||
```bash
|
||||
pos system backup <folder-path> # encrypt to ./<name>_<date>.tar.gz.gpg
|
||||
pos system backup --service # pick a folder from /srv + ~/srv
|
||||
```
|
||||
|
||||
Uses `sudo tar` + gpg AES-256. The password is prompted **twice and never
|
||||
stored**; the artifact is `chmod 600`. On success (and on failure, via ERR
|
||||
trap) a `notify_send` alert is sent.
|
||||
|
||||
`--service` lists folders under the roots in `BACKUP_SERVICE_ROOTS`
|
||||
(default `/srv $HOME/srv`; override via `system.env` or env) and lets you pick.
|
||||
|
||||
### Recipes
|
||||
|
||||
- **Nightly service backup + health check:**
|
||||
```bash
|
||||
cd ~/backups && pos system backup --service
|
||||
pos system health # "backup: 0d old" turns OK
|
||||
```
|
||||
- **Cron it and get alerted:**
|
||||
```bash
|
||||
30 3 * * * cd ~/backups && pos system backup --service >> ~/backups/backup.log 2>&1
|
||||
```
|
||||
Success/failure are sent to Telegram automatically.
|
||||
|
||||
**Troubleshooting:**
|
||||
- "Root not found: …" → the default roots don't exist; set `BACKUP_SERVICE_ROOTS`
|
||||
in `system.env`.
|
||||
- Forgot the password → backups are unrecoverable; keep the passphrase in a
|
||||
password manager. Nothing is stored anywhere else.
|
||||
- `sudo tar` prompt: ensure the user has sudo rights for the source dir.
|
||||
|
||||
---
|
||||
|
||||
## `pos system firewall` — interactive UFW ("UFW POWER")
|
||||
|
||||
**Must run as root:**
|
||||
|
||||
```bash
|
||||
sudo pos system firewall
|
||||
```
|
||||
|
||||
Interactive menu: add rule (port/service/IP/directional), delete by number or
|
||||
text, status (simple/verbose/numbered), enable/disable/reset, default policies,
|
||||
and an executed-command history. Supports `--dry-run`:
|
||||
|
||||
```bash
|
||||
sudo pos system firewall --dry-run
|
||||
```
|
||||
|
||||
Every command is **previewed and confirmed** before execution. Executed
|
||||
mutating changes are announced via `notify_send` (read-only `ufw status` is
|
||||
not).
|
||||
|
||||
### Recipes
|
||||
- Open SSH + a service:
|
||||
`add rule → port/service → 22/tcp`, then `8080/tcp`; finish with `enable`.
|
||||
- See current rules for deletion: menu `3) Show status → numbered`.
|
||||
- `--dry-run` to rehearse a rule batch safely.
|
||||
|
||||
**Troubleshooting:**
|
||||
- "Please run as root" → you need `sudo pos system firewall` (the notify config
|
||||
still uses your user's `$HOME`, so alerts keep working).
|
||||
- Accidentally locked yourself out of SSH → console into the host,
|
||||
`sudo ufw allow 22/tcp`, then `sudo ufw reload`.
|
||||
- `ufw reset` requires typing `RESET` — deliberate.
|
||||
|
||||
---
|
||||
|
||||
## Related
|
||||
|
||||
- Reference: [DOC/POS.md → system](../POS.md)
|
||||
- Notify platform config: [communication.md](communication.md)
|
||||
- Backup roots shared with health: `system.env` ([DOC/POS.md](../POS.md))
|
||||
@@ -0,0 +1,66 @@
|
||||
# How-To: `pos usb`
|
||||
|
||||
Share USB devices over the network with the USB Redirector server. Tool:
|
||||
`server`.
|
||||
|
||||
| Tool | What it does |
|
||||
|------|--------------|
|
||||
| `pos usb server` | Control `usbsrv`: share devices, manage clients, callbacks, nicknames |
|
||||
|
||||
Requires `usbsrv` (the USB Redirector server binary) — a **manual** install from
|
||||
incentivespro.com, not an apt package. Point to it and it's picked up by
|
||||
`command -v usbsrv`; `install.sh` copies any precompiled `x64_bin/`/`arm64_bin/`
|
||||
binaries to `/usr/local/bin`.
|
||||
|
||||
---
|
||||
|
||||
## `pos usb server` — share + manage
|
||||
|
||||
```bash
|
||||
pos usb server --ls # host devices + connected clients
|
||||
pos usb server --ls-shared # only shared/in-use devices
|
||||
pos usb server --share # interactive picker
|
||||
pos usb server --share 0-1 3 # share device 0-1 to client 3
|
||||
pos usb server --unshare 0-1 # stop sharing a device
|
||||
pos usb server --auto-share on|off # auto-share new devices
|
||||
pos usb server --callback 192.168.1.5:8080 # callback connection to a client
|
||||
pos usb server --close-callback 192.168.1.5:8080 # close it
|
||||
pos usb server --auto-connect on|off [client] # remote auto-connect
|
||||
pos usb server --disconnect 0-1 # disconnect a device from clients
|
||||
pos usb server --disconnect all
|
||||
pos usb server --nickname 0-1 myprinter # friendly name (empty = remove)
|
||||
pos usb server --timeout 0-1 300 # auto-unshare after inactivity (0=off)
|
||||
pos usb server --port 32032 # server TCP port (restart to apply)
|
||||
pos usb server --info # server info
|
||||
pos usb server --version # server version
|
||||
```
|
||||
|
||||
Subcommands that need input (e.g. `--share`) prompt interactively when args are
|
||||
omitted.
|
||||
|
||||
**Recipes:**
|
||||
- **Attach a device and connect to one client, in one step:**
|
||||
```bash
|
||||
pos usb server --ls # note device + client IDs
|
||||
pos usb server --share 0-1 3
|
||||
```
|
||||
- **Keep the USB printer always available:** `--auto-share on` + a nickname
|
||||
(`--nickname 0-1 printer`) so clients see a friendly name.
|
||||
- **Dedicated USB-over-network box:** set `--port` once, then clients connect
|
||||
to that port.
|
||||
|
||||
**Troubleshooting:**
|
||||
- `usbsrv: command not found` → the binary isn't installed; get it from
|
||||
incentivespro.com and drop it in `x64_bin/` (or `arm64_bin/`) then re-run
|
||||
`./install.sh`, or `sudo install -m 755 usbsrv /usr/local/bin/`.
|
||||
- Device shared but client can't see it → check the client connects to the
|
||||
right `host:port` (see `--info`/`--port`); verify a callback/auto-connect is
|
||||
not required for your topology.
|
||||
- Nickname/timeout don't apply → `usbsrv` persists them on the server; restart
|
||||
the server after `--port` changes.
|
||||
|
||||
---
|
||||
|
||||
## Related
|
||||
|
||||
- Reference + full flag table: [DOC/POS.md → usb](../POS.md)
|
||||
@@ -43,6 +43,7 @@ cd Linux_post_install
|
||||
| Topic | Where |
|
||||
|-------|-------|
|
||||
| Docs index | [DOC/README.md](DOC/README.md) |
|
||||
| `pos` HOW-TO guides (recipes + troubleshooting) | [DOC/HOWTO.md](DOC/HOWTO.md) |
|
||||
| Core scripts (installer, libs, features) — how they work + config | [DOC/SCRIPTS.md](DOC/SCRIPTS.md) |
|
||||
| `pos` CLI reference (all commands, compose config, wrappers) | [DOC/POS.md](DOC/POS.md) |
|
||||
| Optional apps (picker + full catalog) | [DOC/APPS.md](DOC/APPS.md) |
|
||||
|
||||
Reference in New Issue
Block a user