docs(history,wip,todo): 2026-05-27 evening — peertube + photoprism + WAF unblocking

HISTORY.md: new 2026-05-27 (afternoon/evening) section capturing the
second leg's work — 8 new PRs (#388-395), substantial live-fixes on
gk2.

  - 2 new LXC containers (peertube 10.100.0.120, photoprism 10.100.0.130)
    with LXC-template alignment fix (debian.common.conf, drop strict
    common+userns+apparmor) so postgres-15 + podman CNI work.
  - PhotoPrism LIVE via podman --network=host. Photo-shared dir
    /data/shared/photos bind-mounted into both NC and PhotoPrism.
  - IP forwarding root-fixed: 99-secubox-hardening.conf was setting
    ip_forward=0, overrode our 90-* (alphabetical loss); renamed to
    99-secubox-zz-* so we win. Added explicit lan0 masquerade.
  - 4 GB more swap (8 GB total).
  - NC SSO removal #394 so mobile clients work; NC bf disabled +
    table truncated; CrowdSec allowlist created.
  - WAF cred-004 false-positive on NC mobile login-poll fixed #395.
  - nextcloud.gk2.secubox.in URL aliased (mitmproxy route + nginx
    server_name).
  - mitmproxy live-config drift discovered (host vs LXC copies of
    haproxy-routes.json + secubox_waf.py).

WIP.md: bumped to "2026-05-27 (evening)" with current done-state +
carry-overs.

TODO.md: six new P0 follow-ups:
  - Peertube install completion check + URL verify
  - NC bruteforce re-enable command (after mobile reconnect confirmed)
  - PhotoPrism admin password rotation
  - PhotoPrism auto-index timer for new NC-synced photos
  - LXC template bootstrap fixes (DNS, template choice, bind-mount chown)
  - mitmproxy/WAF live-config drift bind-mount fix
  - IP-forward + lan0-masquerade backport to secubox-system-tuning
  - CrowdSec public-IP allowlist (operator's home/cellular IP TBD)
This commit is contained in:
CyberMind-FR 2026-05-27 16:47:17 +02:00
parent d20aacf8cf
commit 02528cbc85
3 changed files with 266 additions and 3 deletions

View File

@ -1,6 +1,145 @@
# HISTORY — SecuBox-DEB Migration Log
*Tracking completed milestones with dates*
---
## 2026-05-27 (afternoon/evening session — peertube + photoprism + mail + WAF)
Continuation of the morning consolidation session. Operator-driven
work on three fronts: peertube package + container + URL, photoprism
LXC + Nextcloud-shared photos folder, and mail/WAF/SSO unblocking
mobile clients. Eight new PRs (#388#395) and substantial live-fix
work on gk2.
### Container infra (gk2)
* **2 new LXC containers** at `/data/lxc/{peertube,photoprism}/`,
each at 10.100.0.{120,130}. Both started life with the strict
`common.conf + userns.conf + apparmor.profile=generated` template
default, which blocked unprivileged operations (postgres-15
postinst chown, podman CNI bridge iptables, even basic apt). Fixed
by aligning their config with the working `matrix` LXC template:
single `lxc.include = /usr/share/lxc/config/debian.common.conf`,
drop the apparmor lines, keep the `lxc.idmap` UID mapping.
* **Bind-mount UID ownership pattern** captured the hard way: bind
mounts default to host-root ownership which the LXC root (UID
100000 outside) cannot chown. Both peertube postgres + photoprism
storage failed with "Operation not permitted" until host-side
`chown -R 100000:100000 /data/<service>/` opened the dirs for the
LXC. Recipe should ship in the LXC template wiki.
### IP forwarding / NAT (gk2)
* **All LXC containers were silently cut off from external internet**
(apt update inside any container → DNS Temporary failure → fail).
Root cause: `99-secubox-hardening.conf` sets `ip_forward = 0`; my
`90-secubox-lxc-forward.conf` from the consolidation session was
alphabetically earlier and lost. Renamed to
`99-secubox-zz-lxc-forward.conf` so it wins. Also added
`net.ipv4.conf.all.forwarding = 1` explicitly (the legacy
`ip_forward` key alone isn't enough on modern Debian).
* **Masquerade rule targeted `eth2`** which is DOWN — real WAN is
`lan0` (192.168.1.200/24, default route via 192.168.1.254). Added
`oif lan0 masquerade` to `inet nat postrouting`, traffic now
egresses correctly. Should backport to `secubox-system-tuning`.
### Swap (gk2)
* Added `/data/swapfile2` (4 GB) bringing total swap to **8 GB**
(was 4 GB from session #391).
### PhotoPrism — LIVE (#388 follow-up)
* `secubox-photoprism` LXC running podman → official
`docker.io/photoprism/photoprism:latest` (Ubuntu 26.04 / 2.59 GB
image) with `--network=host` (CNI bridge can't add iptables rules
in unprivileged LXC), `PHOTOPRISM_HTTP_PORT=2342`, sqlite DB.
* Bind mounts: `/var/lib/photoprism/originals``/data/shared/photos`
(shared with NC), `/var/lib/photoprism/{storage,import}`
`/data/photoprism/{storage,import}`.
* Public URL `https://photoprism.gk2.secubox.in/` wired:
- nginx vhost `/etc/nginx/sites-available/photoprism.conf` → 9080 →
`10.100.0.130:2342`
- HAProxy ACL `host_photoprism_gk2_secubox_in` added to both
http-in + https-in frontends → `nginx_vhosts` backend
- URL returns 307 (PhotoPrism login redirect) ✓
- login: `admin` / `secubox-CHANGE-ME` (must rotate)
### Nextcloud — bind mount + URL alias + SSO removal (#394)
* **Photo sync ready**: `/data/shared/photos` bind-mounted into NC at
`/var/www/nextcloud/data/Photos` (NC LXC config edit, requires
restart). Smartphone NC client → "Photos" folder → PhotoPrism
auto-indexes via the shared dir.
* **URL `nextcloud.gk2.secubox.in` worked end-to-end** by:
- mitmproxy haproxy-routes.json entry added
(`nextcloud.gk2.secubox.in → 192.168.1.200:9080`) — **TWICE**,
once on host's `/srv/mitmproxy/haproxy-routes.json` and once on
the LXC's separate copy (live config drift — see TODO).
- nginx vhost `server_name` aliased: `nc.gk2.secubox.in
nextcloud.gk2.secubox.in;`
- mitmproxy LXC service restarted to pick up the new routes
* **SSO removed from NC vhost** so official Nextcloud mobile client
(which uses HTTP Basic + app-password, not browser cookies) can
authenticate. Comment-out preserves the four
`auth_request` / `error_page 401` / `auth_request_set` /
`proxy_set_header X-Forwarded-User` lines for revert symmetry.
Source backport in #394`secubox-nextcloud 1.3.5`.
* **NC bruteforce protection disabled at runtime** + table truncated.
The SSO loop had triggered NC's own bf throttle; operator
re-enables via `occ config:system:set
auth.bruteforce.protection.enabled --value=true` after confirming
mobile reconnect.
### WAF cred-004 false-positive (#395)
* After SSO unblock, NC mobile client hit a NEW 403 wall: WAF rule
`cred-004` ("JWT/token in URL", severity=critical) matches NC's
legitimate `/index.php/login/v2/poll?token=…` polling, banning the
client IP after `BAN_THRESHOLD=3` polls (every ~1-2 sec).
* Fix: path-based early-return skip in
`packages/secubox-waf/mitmproxy/secubox_waf.py check_request()`
for `/index.php/login/v2/` and `/ocs/v2.php/core/login`. Source
bumped to `secubox-waf 1.1.3`; live patch applied to gk2's
`/data/lxc/mitmproxy/rootfs/srv/mitmproxy/secubox_waf.py`.
* Verified: 0 new 403s in 60+ sec post-fix vs 1/sec before.
### CrowdSec allowlist (gk2)
* Created `cscli allowlist secubox-trusted` with 4 internal nets
(192.168.1.0/24, 192.168.255.0/24, 10.100.0.0/24, 10.0.3.0/24).
Operator's public IP not added (would need user input).
### LXC DNS systemd-resolved gotcha
* Fresh download-template LXCs default to systemd-resolved stub
resolv.conf (127.0.0.53) that has no actual nameservers
configured. Both peertube + photoprism failed apt with
"Temporary failure resolving 'deb.debian.org'" until I overwrote
/etc/resolv.conf with `nameserver 1.1.1.1 / 8.8.8.8`. The fix
doesn't persist across LXC restarts (systemd-resolved rewrites
it). Should ship a stable resolv.conf in the LXC template
bootstrap.
### Peertube — install in flight at session end
* LXC up at 10.100.0.120, all bind mounts + network OK, podman/
postgres prerequisites unblocked by the template fix + bind-mount
chown. Install script at `/root/install-peertube.sh` running step
6/8 (`yarn install --production --pure-lockfile`, ~10000 packages
on arm64). Monitor armed; service expected active in ~15-25 min.
* Pre-emptively rewired host nginx `peertube.conf` `proxy_pass →
10.100.0.120:9000` (was 127.0.0.1:9001 from the earlier Podman
attempt). HAProxy ACL was already in place from #390.
### Live config drift discovered (mitmproxy)
* `/srv/mitmproxy/haproxy-routes.json` on the host is NOT
bind-mounted into the mitmproxy LXC. Each has its own copy,
edits to one don't reach the other. Tripped me up when adding
the nextcloud.gk2.secubox.in route. Recipe: also bind-mount
the LXC's `/srv/mitmproxy/` from host. Same applies to
`secubox_waf.py`. Filed in TODO.
---
## 2026-05-27

View File

@ -1,10 +1,81 @@
# TODO — SecuBox-DEB Backlog
*Mis à jour : 2026-05-27*
*Mis à jour : 2026-05-27 (evening)*
---
## 🔥 P0 — Immediate (in flight)
### Session 2026-05-27 evening follow-ups (peertube + photoprism + WAF)
- [ ] **Peertube install monitoring**: still at step 6/8
(`yarn install --production`) in the LXC at 10.100.0.120 at session
end. When complete, verify https://peertube.gk2.secubox.in/ returns
PeerTube content (was 502; nginx vhost already rewired to
`10.100.0.120:9000`). If yarn install fails, fall back to PeerTube
Docker image inside the LXC (similar pattern to PhotoPrism with
`--network=host`).
- [ ] **NC bruteforce protection re-enable** after operator confirms
mobile NC client reconnects successfully:
```sh
ssh root@192.168.1.200 lxc-attach -n nextcloud -P /data/lxc -- \
sudo -u www-data php /var/www/nextcloud/occ \
config:system:set auth.bruteforce.protection.enabled \
--value=true --type=boolean
```
- [ ] **PhotoPrism admin password rotation**: still `secubox-CHANGE-ME`
from the initial systemd unit env. Operator should:
1. Login at https://photoprism.gk2.secubox.in/
2. Settings → Account → change password
3. Edit `/data/lxc/photoprism/rootfs/etc/systemd/system/photoprism.service`
`PHOTOPRISM_ADMIN_PASSWORD=` line to match (so future restarts
don't fight the DB)
- [ ] **PhotoPrism auto-index of new photos**: NC client syncs to
`/data/shared/photos`; PhotoPrism only picks up new files on
`/library/index` API call or manual UI button. Add a systemd timer
inside the photoprism LXC that calls
`photoprism index` (or the HTTP API) every N minutes. Or
inotifywait-based watcher.
- [ ] **LXC template bootstrap fixes** (capture lessons-learned):
1. **DNS**: fresh download-template LXCs ship a
systemd-resolved stub with no nameservers. Workaround: overwrite
`/etc/resolv.conf` with `nameserver 1.1.1.1 / 8.8.8.8`. Should
bake into the LXC template or a one-shot first-boot script.
2. **Template choice**: `lxc-create -t download -- -d debian` uses
`common.conf + userns.conf + apparmor=generated` by default,
which breaks postgres-15 postinst + podman CNI. Use
`debian.common.conf` (matrix template). Document in
wiki.
3. **Bind-mount UID ownership**: bind-mounted dirs default to host
root, LXC root (UID 100000 outside) can't chown across. Recipe:
`chown -R 100000:100000 /data/<svc>/` on host BEFORE first
container start. Document.
- [ ] **mitmproxy + WAF live-config drift**: host's
`/srv/mitmproxy/haproxy-routes.json` and `secubox_waf.py` are NOT
bind-mounted into the mitmproxy LXC. Each has its own copy →
source-side edits don't propagate. Fix: add
`lxc.mount.entry = /srv/mitmproxy srv/mitmproxy none bind,create=dir`
to `/data/lxc/mitmproxy/config` so edits flow either way. Beware:
the LXC currently has `mitmproxy:mitmproxy` ownership; host owns
by root. Need to align UIDs first.
- [ ] **IP-forward + lan0-masquerade backport to
`secubox-system-tuning`**: live fix on gk2 used
`99-secubox-zz-lxc-forward.conf` (alphabetical win) + manual
`nft add rule inet nat postrouting oif lan0 masquerade`. Backport
both as part of the tuning package so other boards inherit it on
apt install. Bump secubox-system-tuning to 1.1.0.
- [ ] **CrowdSec public-IP allowlist**: operator's home/cellular IP
not in `secubox-trusted` allowlist (would need them to run
`curl ifconfig.me`). Without it they may hit external bf
scenarios. Add when known.
### Session 2026-05-27 follow-ups (consolidation pass)
- [ ] **`secubox-daemon` arm64 cross-build + deploy** so the

View File

@ -1,9 +1,62 @@
# WIP — Work In Progress
*Mis à jour : 2026-05-27*
*Mis à jour : 2026-05-27 (evening)*
---
## 🔄 2026-05-27: Consolidation pass — audit + 2 real merges + 5 naming sweeps + gk2 deploy
## 🔄 2026-05-27 (evening): peertube + photoprism + mail + WAF unblocking
### ✅ Done (this leg)
* **PhotoPrism LIVE** at https://photoprism.gk2.secubox.in/
(login: admin / secubox-CHANGE-ME). Podman-based, LXC 10.100.0.130,
`--network=host` (CNI bridge unprivileged-LXC workaround).
* **Photos shared folder** `/data/shared/photos` bind-mounted into both
PhotoPrism (`/var/lib/photoprism/originals`) and Nextcloud
(`/var/www/nextcloud/data/Photos`). Smartphone NC client → "Photos"
→ PhotoPrism auto-indexes.
* **nextcloud.gk2.secubox.in URL** wired (was only `nc.gk2`):
mitmproxy route entry added (host + LXC copies, see drift in TODO);
nginx `server_name` aliased.
* **#394 NC SSO removal** so official mobile clients can authenticate
(HTTP Basic + app-password don't carry Authelia cookie). NC bf
protection disabled at runtime + table truncated.
* **#395 WAF cred-004 false-positive** on NC mobile login-poll
(`/index.php/login/v2/poll?token=...`) fixed live + source-side.
* **CrowdSec allowlist** `secubox-trusted` with 4 internal nets.
* **8 GB swap** total (was 4 GB).
* **IP forwarding** root-fixed: `99-secubox-hardening.conf` set
`ip_forward=0`, overrode our `90-secubox-lxc-forward.conf`
(alphabetical loss). Renamed to `99-secubox-zz-…` so it wins.
Also added explicit `lan0 masquerade` rule (real WAN, eth2 is
down).
* **LXC template fix** for peertube + photoprism: replaced strict
`common.conf + userns.conf + apparmor` defaults with matrix's
working `debian.common.conf` template; otherwise postgres-15
postinst and podman CNI both fail in unprivileged-LXC sandbox.
* **Bind-mount UID-mapping recipe**: host-side `chown -R
100000:100000 /data/<service>/` to allow LXC root (UID 100000
outside) to manage them.
### 🔄 In flight
* **Peertube install** in container at 10.100.0.120, step 6/8
(yarn install ~10000 packages on arm64). Monitor armed. When
done, URL https://peertube.gk2.secubox.in/ will serve real
content (nginx vhost already rewired to `10.100.0.120:9000`).
### 📋 Carry-overs (filed in TODO.md)
* Mail backup gap + URL fix (still deferred from earlier today)
* IP-forward + lan0-masquerade + sysctl-ordering backport to
`secubox-system-tuning` package
* mitmproxy + WAF script live-config drift (host vs LXC copies)
* LXC template wiki: DNS resolv.conf, bind-mount chown UID 100000,
template choice (debian.common vs strict)
* Release bump after everything lands (per user)
---
## 🔄 2026-05-27 (morning): Consolidation pass — audit + 2 real merges + 5 naming sweeps + gk2 deploy
### ✅ Done (this session)