# Executive Summary # 00 — Executive Summary NAS Modernization Project — Phase 1: Discovery / As-Built Inventory (Digital Twin) - Audit date: 2026-08-21 - Auditor host: Golden-Eye (Ubuntu 26.04, orchestrator/compute) → reached NAS read-only over SSH (Tailscale 100.90.167.88, port 54321) - Audit mode: READ-ONLY. No files, containers, packages, users, tasks, settings, network config, or storage were modified. No secrets were read or recorded. - Scope: Complete as-built inventory of the Synology NAS (NGAGED_CLOUD) in its current state, per the Phase 1 directive. --- ## 1. What Exists Hardware / System - Model: Synology DS220+ (2-bay), platform geminilake, x86_64 - CPU: Intel Celeron J4025 (2c/2t) - RAM: 17 GB (12 GB swap: 2 GB /dev/md1 + 2× zram) - DSM: 7.3.2-86009 (build 2026/06/18) - Storage: 2× Synology HAT3300-4T (4 TB HDD) in SHR RAID-1 (md3/md2), LVM → single 3.5 TB btrfs volume1 - External: 1× 2 TB USB drive (usbshare1, ext4, 1.8 TB) - Disk health: Both drives report normal SMART, 0 bad sectors, temp ~35°C. No failing-disk risk currently. Data (volume1, 3.5T — 2.5T used, 1.1T free — 70%) - vMix Recordings — 752 GB (church service recordings) - homes — 823 GB (6 users; shaconann 321G, vidalstephen 202G, sadevidal 141G, rore-admin 114G) - docker — 594 GB (primarily /volume1/docker/data/media = 534 GB of media: TV 282G, Anime-TV 155G, Movies 88G) - projects — 11 GB, media share — 21 GB, Shared Documents — 3.8 GB, music — 422 MB - USB drive: 760 GB used (Hyber Backup homes target + DSM_HOMES_BACKUP) Containers (Docker 24.0.2 / Container Manager) - 23 running, ~28 stopped/exited. Total 255 images (162 dangling), 23 volumes. - Biggest running groups: - media-platform (~21 containers): Jellyfin, Plex, Sonarr/Radarr/Prowlarr/Bazarr (+anime variants), Overseerr, Tautulli, Deemix, TubeArchivist (kids), qmutorrent/gluetun, rdt-client, FlareSolverr, Recyclarr, CleanUpArr - platform: Traefik v3 (reverse proxy), cloudflared (tunnel 6f717a56, serves *.nsystems.live + *.vectorhost.net), cf-ddns - monitoring: Gatus + Gotify - homelab: vaultwarden (password manager), rustdesk (hbbs+hbbr), devshell - hosted: scrapline2, crimson-haven, skybreaker-transform, ghostline-command Packages (installed, Synology + community) - Data-facing: Hyper Backup, Synology Drive, Synology Photos, Snapshot (share snapshots on all shares), Storage Analyzer, MailPlus-Server (+ MailClient, Contacts, Calendar), Chat, Audio Station, Codec Pack - Container Manager 24.0.2, Git, Node.js 18/20, PHP 8.2, Python 2/3.9/3.10, Tailscale, Secure SignIn, QuickConnect, Active/ActiveInsight --- ## 2. Where the Important Data Lives | Share | Size | Nature | Protection | |---|---|---|---| | vMix Recordings | 752 GB | Church services video (LOSS-HIGH) | Single copy; NOT in Hyper Backup job; small/empty btrfs snapshot | | homes (esp. shachonn/vidal) | 836 GB | Personal/family photos & files | In Hyper Backup "Local Copy 1" → USB only (see §6) | | docker/data/media | 534 GB | Media library (Plex/Jellyfin/arr) | NO backup — voluminous, low-value, re-downloadable | | projects, Shared Documents, music | ~15 GB | Business/work docs | In USB backup? (partial) | | USB usbshare | 760 GB | Backup target + DSM_HOMES_BACKUP | Itself un-backed-up | --- ## 3. What Depends on What - All public web services depend on: cloudflared (tunnel) → Traefik (routing/TLS) → container. Authelia (auth) is exited/down, so exposed services may lack SSO enforcement (verify). - All media containers bind-mount /volume/data/media (the media library). Jellyfin & Plex bind /volume/docker/data/media-library. - devshell container bind-mounts /var/run/docker.sock, /volume1, and .ssh — a powerful container. - homes are served via Synology Drive/FileStation and are the subject of the only configured Hyper Backup job. ## 4. What Is Currently Protected - One Hyper Backup job ("Local;1") → USB drive (usbshare1, target NGAGED_CLOUD_1), daily 03:00, enabled. But state=disabled in the schedule task, and the job's folder list is homes only. Last backup ~2025-11 (from target dir listing). - btrfs snapshots available (share snapshot service on all shares) — only vMix Recordings has an actual snapshot (empty/1 file). - Syncthing/ActiveInsight/SynologyDrive present. ## 5. What Is NOT Adequately Protected (top risks) 1. CRITICAL — No verified restore. No Hyper Backup restore has been tested; job last ran ~Nov 2025. Cannot prove recoverability. 2. CRITICAL — vMix Recordings (752 GB) has NO backup. Not in the Hyper Backup folder list; snapshots essentially empty. Single copy on a 2-bay RAID1 (protects against disk failure, not against deletion/corruption/fire). 3. HIGH — Docker/container config is not centrally backed up. /volume1/docker (compose files + stack configs) are inside the docker share (594 GB, mostly data). Many containers have no reproduceable-config backup outside the host. 255 images and 23 anonymous volumes suggest a lot of un-tracked state. 4. HIGH — No offsite/off-NAS backup. USB target sits on the same NAS. No cloud/offsite copy. 5. MEDIUM/HIGH — Authelia (access control) is DOWN while services are internet-exposed via tunnel. 6. MEDIUM — 4 service accounts + broad permissions (see §3): devshell has docker.sock + full /volume1 + ssh access. ## 6. What Appears Safe - Disk health good (both drives normal, 0 bad sectors). - NAS RAID1 mirror functional. - DSM up-to-date on recent minor. - Structured compose directories (/volume1/docker/platform, /stacks, /data). ## 7. What Concerns Me - The only existing backup is a stale (~9-month-old) local USB backup of homes only. Not restore-tested, not offsite, excludes the two largest/high-value directories (media, vMix). - 42 containers exited, many months old — configuration fragility if lost. - 155 dangling images / anonymous volumes — storage + restore clutter. - Exposed public ports on 0.0.0.0: Plex(32400), RustDesk(21115-21119), Jellyfin(8096), phpmyadmin(8086), freightline-dev(3001). - Authelia (SSO) is down at a time when 28+ subdomains route through the tunnel. - vMix Recordings is the single largest, un-backed-up, irreplaceable dataset. - SMB shares are guest-writable (including homes and docker) — mitigated only by the firewall confining SMB to Tailscale/LAN. - SSH password authentication is enabled — brute-force surface on the known port. ## 8. What Remains UNKNOWN / REQUIRES MANUAL REVIEW - Hyper Backup restore state — never verified. - Exact Hyper Backup retention policy (version counts) — GUI-only detail. - Router port-forwarding state — the DSM firewall allows DSM web/Drive/SSH from any source, but whether the router actually forwards those ports (5000/5001/54321) to the NAS is external to the NAS. - Syncthing/ActiveInsight/ActiveInsight exact job configs (GUI-only). - Who "ryan" is (empty home; deny-ACL on docker, allow on vMix). - Whether Authelia was deliberately decommissioned or just crashed. > Resolved during the admin-access pass (no longer unknown): firewall rules (DSM INPUT_FIREWALL), SSHD hardening (password auth enabled), per-share ACLs (enumerated), SMB guest access (all shares guest-open but Tailscale-only at firewall), DSM config backup (exists at /volume1/@config_backup, 61 KB, dated 2026-08-16), storage pool layout (SHR RAID-1, LVM 3.63 T). ## 9. What I Recommend Next 1. Proceed to PHASE 2 — BACKUP, INTEGRITY VERIFICATION & RESTORE TESTING (see below), with priorities: - P0: Design + implement a verified, off-NAS backup for vMix Recordings (and homes) — using golden-eye/srv1388017/edge as target, not the same-NAS USB. - P0: Restore-test the existing USB homes backup (pick one user's dir) to prove recoverability — do NOT trust it. - P1: Back up all compose configs + env-file NAMES (/volume1/docker/platform, /stacks, /nsystems-monitoring, plus any stack-config/ under the media stack) to a safe, reproducibly-restorable location; enable restore-test. - P1: Record container config to a reproducibility manifest (inventory already produced; next is a docker inspect dump). - P2: Offsite (edge) copy of critical small datasets. 2. During Phase 2 you may want to enable SSH sudo or share the DSM admin password with the agent for firewall/SSHD/task-reads — OR provide those directly to complete the UNKNOWN section. --- ## Final Gate This document and its 12 companions constitute the Phase-1 as-built inventory / digital twin. Discovery is complete and I am STOPPING here as directed. I request authorization to proceed to PHASE 2 — BACKUP, INTEGRITY VERIFICATION & RESTORE TESTING, with the priorities above. No destructive operation has been performed or is authorized by this directive. # System Inventory # 01 — System Inventory NAS: NGAGED_CLOUD · Model: Synology DS220+ (2-bay) · Platform: geminilake · Arch: x86_64 | Attribute | Value | |---|---| | Hostname | NGAGED_CLOUD | | DSM version | 7.3.2-86009 (build 2026/06/18, GM, smallfix 4) | | Kernel | 4.4.302+ synology_geminilake_220+ | | CPU | Intel Celeron J4025 @ 2.00 GHz (2 cores / 2 threads) | | RAM | 17 GiB total (6.8 used / 9.7 avail) | | Swap | 12 GiB total (2 GB /dev/md1 + 2× zram 5.5 GB), ~1.4 GiB used | | Uptime | 41 days, 11h (at audit); load ~2.9 (IO-heavy) | | Timezone (log evidence) | UTC-5 (US Central) | | Enclosure health | Good — both drives SMART normal, 0 bad sectors | ## Network Interfaces | Interface | State | Address | |---|---|---| | eth0 | UP | 192.168.0.164/24 (LAN, primary) | | eth1 | DOWN | 169.254.67.66/16 (unused) | | tailscale0 | UP | 100.90.167.88/32 (Tailscale) | | docker0 + 11 docker bridges | mix | 172.x/192.168.x docker subnets | - Gateway: 192.168.0.1 - DNS: 8.8.8.8 / 8.8.4.4 - Public/DDNS: ngaged.synology.me (Synology DDNS enabled) - Tailscale: v1.58.2 package, node ngaged-cloud, IP 100.90.167.88 ## Storage Pools / RAID / Volumes The NAS uses SHR (Synology Hybrid RAID) over a 2-disk RAID-1 arrangement with LVM on top. | Device | Role | Filesystem | Size | Used / Free | |---|---|---|---|---| | /dev/md0 | System (/) | ext4 | 7.9 GB | 3.9 / 3.9 G (50%) | | /dev/md1 | Swap | — | 2 GB | — | | /dev/md2 | SHR data part 1 (member) | btrfs (LVM PV) | 1.93 TB | — | | /dev/md3 | SHR data part 2 (member) | btrfs (LVM PV) | 1.95 TB | — | | /dev/vg1/volume_1 → /volume1 | Main volume | btrfs | 3.5 TB | 2.5 used / 1.1 free (70%) | | /dev/usb1p1 | USB drive → /volumeUSB1/usbshare | ext4 | 1.8 TB | 760 G used / 1.1 free (42%) | - md arrays (all RAID-1, [2/2] [UU] healthy): md0, md1, md2, md3. - LVM (confirmed via lvs/vgs/pvs): vg1 = 3.63 T across PVs /dev/md2 (1.81 T) + /dev/md3 (1.82 T); LV volume_1 = 3.63 T (thin volume syno_vg_reserved_area 12 M also present). SHR RAID-1 confirmed. - Filesystem: btrfs with synoacl, space_cache=v2, subvol per shared folder under /volume1/@syno. - Encryption: Volume/share encryption supported by DSM but volume is NOT encrypted (LVM thin volume not listed as encrypted; no encrypted-mount in /proc/mounts). support_share_encryption=yes, support_volume_encryption=yes, lock_encrypted_storage=no. - SSD cache: None. No SSD cache md devices; support_m2_pool=no. ## Physical Disks | Disk | Path | Model | Firmware | Size | Serial | Type | Temp | SMART | |---|---|---|---|---|---|---|---|---| | Bay 2 | /dev/sata1 | Synology HAT3300-4T | PL01 | 4.0 TB | ZW62LVN1 | HDD | 35°C | normal | | Bay 1 | /dev/sata2 | Synology HAT3300-4T | PL01 | 4.0 TB | ZW61Z06C | HDD | — | normal | | USB | /dev/usb1 | (USB drive) | — | 2.0 TB | — | HDD | — | n/a | SMART / health detail (from /var/log/diskprediction/data-2026-08-21.json): - overview_status=normal, smart=normal, smart_test=normal, bad_sec_ct=0, below_remain_life_thr=0. - No failing-disk indicators. Safe to run a large backup at present (both drives healthy). ## Encryption Configuration - Volume + share encryption supported but the primary volume is not encrypted (drive data at rest unencrypted). - /usr/syno/etc/keymanager present (key management service) — no encrypted volume mounted. ## Storage Utilization Flags - Main volume at 70% (1.1 TB free). Large backup of docker/data/media (534 GB) onto same volume would not fit (534 GB > 1.1 TB free — but would still fit off-NAS). - Health is good; no immediate backup-blocking hardware risk. ## Discovery Commands (sanitized) bash ssh -p 54321 msn0624c@100.90.167.88 cat /etc.defaults/VERSION cat /proc/cpuinfo | grep -E "model name|cpu cores" free -h; cat /proc/swaps cat /proc/mdstat lsblk; df -hT cat /var/log/diskprediction/data-.json | python3 -m json.tool # disk health # Storage & Shares # 02 — Storage & Shared Folders Primary volume /volume1 (btrfs, 3.5 T, 70% used). Each DSM shared folder is a btrfs subvolume under /volume1/@syno. A USB drive mounts at /volumeUSB1/usbshare (ext4). ## Shared Folder Table | Share | Size | Path | Purpose (inferred) | Snapshot | Recycle bin | Key users | Classification | |---|---|---|---|---|---|---|---| | vMix Recordings | 752 GB | /volume1/vMix Recordings | Church services video (largest, irreplaceable) | btrfs snapshot present (essentially empty) | yes (#recycle 6.3G) | — | KEEP (critical, needs backup) | | homes | 823 GB | /volume1/homes | Per-user home dirs (photos/files) | available | yes (#recycle 7.2G) | all users | KEEP | | docker | 594 GB | /volume1/docker | Docker compose configs + data/media (534 GB) | — | yes | msn0624c | REVIEW (config KEEP, media is data) | | media | 21 GB | /volume1/media | Legacy media staging (seedbox-data 15G, temp) | — | yes | — | MIGRATE/REVIEW (largely redundant with docker/data/media) | | projects | 11 GB | /volume1/projects | Project files (vps 6G, ZeroArcade) | — | yes (5G) | — | MIGRATE/REVIEW | | Shared Documents | 3.8 GB | /volume1/Shared Documents | Office/docs (Synology Office) | — | — | — | KEEP | | music | 422 MB | /volume1/music | Audio library | — | — | — | REVIEW (vs docker/data/media/Music) | | chat | 324 KB | /volume1/chat | Synology Chat data | — | — | — | REVIEW | | MailPlus | 1.7 MB | /volume1/MailPlus | MailPlus server mail data | — | — | — | REVIEW | | web | 4.0 K | /volume1/web | Web root (DSM web station) | — | — | — | REVIEW | | web_packages | 0 | /volume1/web_packages | Package web files | — | — | — | REVIEW | | gitea-share | 0 | /volume1/gitea-share | Gitea container share (empty) | — | — | — | REVIEW | | backups | 1 MB | /volume1/backups | Docker inventory + romm backups | — | — | msn0624c | KEEP (small, admins) | ### USB drive /volumeUSB1/usbshare (1.8 TB, 760 G used, ext4) - NGAGED_CLOUD_1/ — Hyper Backup "Local;1" target (homes backup) - DSM_HOMES_BACKUP/ — separate manual homes archive (Nov 2025) - Un-backed-up itself. ## Major Storage Consumers ### /volume1/docker/data/media — 534 GB - TV — 282 GB - Anime-TV — 155 GB - Movies — 88 GB - Instrumentals — 4.5 GB, Music — 2.5 GB - (Empty: Stems, MusicVideos, Anime-Movies) ### /volume1/docker/data/media-library — 22 GB - YouTube-Kids — 22 GB (TubeArchivist) ### /volume1/docker/data/torrents — 9.3 GB (active download area) ### /volume1/homes — 823 GB (per user) | User | Size | Top folders | |---|---|---| | shaconann | 321 GB | Photos 106G, "all images" 60G, USA TRIP 23G, sd-card 20G, Family videos 8G | | vidalstephen | 202 GB | Photos 98G, Assets 44G, My Shared Folders 19G, Business Projects 12G | | sadevidal | 141 GB | (n/i) | | rore-admin | 114 GB | (n/i) | | rore-worship | 14 GB | | | mskeete | 14 GB | | | msn0624c | 12 GB | | ### /volume1/vMix Recordings — 752 GB - archive 136 GB, many 4–57 GB .mp4/.avi single-service files; #recycle 6.3 GB. ## Notes - Recycle bin is enabled on homes, docker, media, projects, vMix Recordings — deleted files remain reclaimable; good for safety, but inflates size (e.g. #recycle in homes 7.2G). - media share is largely redundant with docker/data/media — candidates for consolidation during Phase 2+. - Container data (docker/data/media) has NO backup — re-downloadable from *arr indexers (lowest priority to back up). - vMix + homes are the irreplaceable, high-value data. ## Snapshot Configuration - Share-snapshot service enabled on all shares (/usr/syno/etc/sharesnap/sharesnap.conf lists every share). - Actual snapshot: only /volume1/@sharesnap/vMix Recordings/ exists and it contains just a desktop.ini (effectively empty). No usable snapshots protect any share today. ## Discovery Commands bash sudo du -sh /volume1/ du -sh /volume1/vMix\ Recordings/* | sort -rh | head du -sh /volume1/homes/*/ | sort -rh | head du -sh /volume1/docker/data/media/* | sort -rh | head cat /usr/syno/etc/sharesnap/sharesnap.conf # Users, Groups & Permissions # 03 — Users, Groups & Permissions > NOTE: Full fine-grained ACLs and share-permission matrices require synoacltool/DSM admin (sudo). Values below are from /etc/passwd, /etc/group, and filesystem ownership (read-only). Fine-grained ACLs not dumped — UNKNOWN / REQUIRES MANUAL REVIEW for exact per-user ACLs. ## Local Users (/etc/passwd, non-system) | User | UID | Home | Notes | |---|---|---|---| | admin | 1024 | /var/services/homes/admin | DSM default admin account (system) | | msn0624c | 1026 | /var/services/homes/msn0624c | NAS SSH/operator account (used by agent) | | postgres | 55 | /var/services/pgsql | service account (PostgreSQL) | | root | 0 | /root | OS root (ash) | > Other DSM users exist as home dirs: shaconann, vidalstephen, sadevidal, rore-admin, rore-worship, mskeete, ryan — visible via /volume1/homes/* even though not all are in passwd excerpt. ryan has an empty home (possible orphan). ## Groups (abridged, non-system) | Group | Members / purpose | |---|---| | administrators | admin, msn0624c — full DSM admin | | users | default user group (members via homes) | | docker (65538) | msn0624c — docker group access | | ngaged-cloud (65537) | sadevidal, shaconann, vidalstephen, rore-admin, mskeete — shared family group | | roreccelsia (65536) | rore-admin | | Many package service groups | (ContainerManager, HyperBackup, MailPlus-Server, SynologyPhotos, SynologyDrive, FileStation, etc.) | ## Permission Observations / Findings 1. Two full administrators (admin + msn0624c). msn0624c is the automation/SSH account with admin + docker group. 2. msn0624c is a very broad account: in administrators, in docker, and it owns /volume1/backups, /volume1/docker. This is the agent's operational account — broad but intentional. 3. devshell container is exceptionally privileged: bind-mounts /var/run/docker.sock, the entire /volume1, and ~/.ssh. Anyone with that container's console = full NAS control. 4. nfs/nobody sharing groups exist but NFS exports file was empty (NFS not obviously exporting). 5. Service accounts for packages (postgres, mysql, mailplus, chat, etc.) — expected. 6. ryan home exists but empty — possible orphaned/incomplete user. 7. Fine-grained share ACLs are the DSM default rwxrwxrwx+ on most shares (the + indicates extended ACL). Exact per-user access NOT enumerated (needs sudo synoacltool). ## Excessive / Unnecessary Privilege Flags (for Phase 2+ review — no changes made) - devshell container: docker.sock + /volume1 + .ssh = effectively root-equivalent. Restrict or gate. - msn0624c as full admin + docker — acceptable for the migration operator but should be least-privileged once migration is done. - Confirm admin account is needed vs. a dedicated admin (defense-in-depth). ## SMB / NFS (now read with admin access) - SMB service installed (SMBService). Nearly all shares are configured guest ok=yes, valid users=nobody,nobody, writeable=yes — i.e. guest-accessible SMB on chat, docker, gitea-share, homes, MailPlus, media, music, projects, usbshare1, web, web_packages. This is a significant finding: SMB shares (including homes and docker) accept guest/write. However, the DSM firewall only allows SMB (445/139/137/138) from the Tailscale subnet (100.0.0.0/8), so LAN/Tailscale-only exposure is the mitigating factor. - NFS: /etc/exports empty → NFS not exported. ## Fine-Grained ACLs (now enumerated with admin access) | Share | Owner | ACL highlights | |---|---|---| | homes | root | group:administrators rwx, group:users rwx, user:ContainerManager rwx, everyone r-x | | docker | msn0624c | user:msn0624c rwx, user:ryan deny, group:users rwx, user:ContainerManager rwx, everyone r-x | | vMix Recordings | root | user:mskeete deny, group:administrators rwx, user:ryan rwx, user:vidalstephen rwx, user:rore-admin rwx | | projects | root | group:administrators rwx only | - user:ryan appears with a deny on docker and allow on vMix Recordings — inconsistent; review whether the ryan account is still needed. ## Discovery Commands bash grep -vE "nologin|/bin/false|daemon|/sbin/" /etc/passwd cat /etc/group ls -la /volume1/homes/ # Fine ACLs (need sudo): sudo /usr/syno/sbin/synoacltool --enumerate # REQUIRES MANUAL (sudo) # Containers & Services # 04 — Containers & Services (Docker / Container Manager) Engine: Docker 24.0.2 (Container Manager 24.0.2-1606) · Compose v2.20.1 · storage driver btrfs · cgroup v1 · logging db Totals: 23 running, ~28 exited/stopped · 255 images (162 dangling ) · 23 volumes · 16 networks ## Running Containers ### Platform Layer | Container | Image | Status | Ports | Compose source | Purpose | |---|---|---|---|---|---| | traefik | traefik:v3 | Up 5w | expose 8080 | /platform/traefik/ | Reverse proxy + TLS (CF DNS-01) | | cloudflared | cloudflare/cloudflared:latest | Up 5w (healthy) | — | /platform/cloudflared/ | Tunnel 6f717a56 → serves *.nsystems.live + *.vectorhost.net | | cf-ddns-nsystems | favonia/cloudflare-ddns:latest | Up 5w | — | /platform/ddns/ | Cloudflare DDNS updater | ### Media Platform (/volume1/docker/stacks/media/media-platform/) | Service | Image | Notes | |---|---|---| | jellyfin | lscr.io/linuxserver/jellyfin | 0.0.0.0:8096 exposed | | plex | lscr.io/linuxserver/plex | 0.0.0.0:32400 exposed + DLNA/UPnP | | sonarr, sonarr-anime | linuxserver/sonarr | anime variant | | radarr, radarr-anime | linuxserver/radarr | anime variant | | prowlarr | linuxserver/prowlarr | indexer manager | | bazarr, bazarr-anime | linuxserver/bazarr | subtitles | | overseerr | linuxserver/overseerr | requests/Discovered | | tautulli | linuxserver/tautulli | Plex stats | | deemix | bockiii/deemix | music download | | recyclarr | ghcr.io/recyclarr/recyclarr | Arr config sync | | cleanuparr | ghcr.io/cleanuparr/cleanuparr | Arr cleanup | | rdt-client | rogerfar/rdtclient | 192.168.0.164:6500 (debrid client) | | flaresolverr | flaresolverr/flaresolverr | proxy solver | | tubearchivist-kids + tak-redis + tak-elasticsearch | (separate docker-compose-tak.yml) | YouTube archiving (media-library/YouTube-Kids) | ### Torrent/VPN sub-stack (docker-compose.torrent.yml) | Service | Image | Notes | |---|---|---| | gluetun | qmcgaw/gluetun | WireGuard VPN sidecar | | qbittorrent | linuxserver/qbittorrent | via gluetun | | rutorrent | crazy-max/rtorrent-rutorrent | legacy torrent UI (has anonymous volumes) | ### Platform/Homelab | Service | Image | Port | Notes | |---|---|---|---| | nsystems-gatus | twinproduction/gatus | 100.90.167.88:8081 | uptime monitoring | | nsystems-gotify | gotify/server | 100.90.167.88:8082 | notifications | | vaultwarden | vaultwarden/server | (80 int) | password manager (config in /volume1/docker/stacks/homelab/vault/config) | | hbbs, hbbr | rustdesk/rustdesk-server | 0.0.0.0:21115-21119 | RustDesk relay | | devshell | ghcr.io/vidalstephen/devshell | 127.0.0.1:2222→22 | remote dev shell (docker.sock + /volume1 + .ssh) | ### Hosted apps (static nginx / game services) | Service | Image | Port | Notes | |---|---|---|---| | scrapline2 | scrapline2:production | 8080/tcp | game | | crimson-haven | nginx:alpine | 80/tcp | static | | skybreaker-transform | nginx:alpine | 80/tcp | static | | ghostline-command | nginx:alpine | 80/tcp | static | ## Exited / Stopped Containers (~28) — notable scrapline (old), aethrix-wordpress + -phpmyadmin (0.0.0.0:8086), wordpress + wordpress-db (mariadb:11), druglord-dev, freightline, freightline-dev (0.0.0.0:3001), starforge, agent-zero, reactive-resume(+db+printer), calcom(+db+redis), uptime-kuma, dsm-router, dozzle, dungeon-generator, template-myapp-1, buildx_buildkit_synobuilder0, plus Invidious tasks (disabled). > These exited containers represent significant un-backupped configuration fragility and storage clutter (images/volumes). ## Volumes (23) - Named: devshell-vscode-server, scrapline2_scrapline2-data, starforge_starforge-data, uptime-kuma_uptime-kuma-data, nsystems-gatus-data, nsystems-gotify-data, druglord_druglord_node_modules, freightline_freightline_node_modules, scrapline-shell_*, aethrix_wordpress_*, skybreaker-drone-strike-node-modules, sessioncraft_*, buildx_buildkit_*. - 11 anonymous hash volumes (hex IDs) — likely from docker compose on manually-run containers (rutorrent, flaresolverr, calcom, etc.). Unknown owner/content — flag. ## Networks proxy (shared Traefik ingress net), bridge, host, plus per-project: media-platform_ta-internal, media-platform_tak-internal, calcom_*, reactive-resume_*, rustdesk_default, ddns_default, docker_default, freightline_default, sessioncraft_*, wordpress_*, socket-proxy, nsystems-monitoring_default. ## Published / Exposed Ports (risk-relevant) - 0.0.0.0 (all interfaces): Plex 32400, RustDesk 21115-21119, Jellyfin 8096, phpmyadmin 8086, freightline-dev 3001 - LAN IP: rdt-client 192.168.0.164:6500 - Tailscale-only: gatus 100.90.167.88:8081, gotify 100.90.167.88:8082, devshell 127.0.0.1:2222 - Traefik/cloudflared expose the tunnel layer (28+ subdomains) — internal service ports mostly not directly public (good), but phpmyadmin/Jellyfin/Plex/RustDesk ARE directly exposed. ## Bind-Mounts (data locality) - Media stack reads /volume1/docker/data (media, torrents, media-library). - devshell: /var/run/docker.sock, /volume1 (whole volume), .ssh. - vaultwarden: /volume1/docker/stacks/homelab/vault/config (password vault — backup priority). - scrapline2: named volume scrapline2_scrapline2-data. - Traefik: docker.sock (ro) + acme.json + config. - cloudflared: tunnel cred JSON (6f718a56-….json) + config. ## Dependencies - All web apps depend on cloudflared → traefik → app; authelia (auth) is exited/down. - Media stack depends on /volume1/docker/data/media and (for torrent) gluetun VPN. - RustDesk needs both hbbs+hbbr running for relay (both up). - DDNS (cf-ddns) depends on a valid CF token + IP detection. ## Provisional Classification | Workload | Classification | |---|---| | Traefik, cloudflared, ddns | KEEP on NAS (network/edge layer; could move to VPS) | | Authelia | REVIEW (down; decide fix vs replace/remove) | | Media stack (Jellyfin, Plex, *arr, Overseerr, Tautulli, Deemix, TubeArchivist) | KEEP ON NAS (data-local to media share) — but streamers can later move to compute if desired | | qBittorrent/gluetun/rutorrent/rdt-client | REVIEW (data flows; keep on NAS near media) | | Gatus, Gotify | MOVE TO COMPUTE (monitoring belongs on golden-eye) | | vaultwarden | KEEP ON NAS or MOVE TO COMPUTE/VPS (decide in Phase 2; data must be backed up) | | RustDesk (hbbs/hbbr) | MOVE TO VPS/EDGE (public-facing, wants a stable always-up host) | | devshell | REPLACE (dev shell should live on compute; restrict) | | scrapline2, crimson-haven, skybreaker-transform, ghostline-command | MOVE TO COMPUTE/VPS (static/hosted apps need not be on NAS) | | Exited containers (wordpress, aethrix, reactive-resume, calcom, uptime-kuma, dozzle, etc.) | RETIRE/REVIEW (old; decide per project) | | Upk Keep everything mounted to /volume1/docker/data/media | KEEP (data-centric) | > These are provisional recommendations only — no migration performed in Phase 1. ## Discovery Commands bash /usr/local/bin/docker ps -a --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}" /usr/local/bin/docker inspect --format '{{ index .Config.Labels "com.docker.compose.project" }}' /usr/local/bin/docker inspect --format '{{range .Mounts}}{{.Type}}:{{.Source}}:{{.Destination}} {{end}}' /usr/local/bin/docker network ls; docker volume ls; docker images # Packages # 05 — Synology Packages Installed packages enumerated from /var/packages/. Grouped by role. ## Data / Backup / Sync | Package | Version | Role | Active? | Data location | Essential? | |---|---|---|---|---|---| | Hyper Backup | 4.2.1-4228 | Backup engine | Yes (1 job → USB) | /var/packages/HyperBackup/ | ESSENTIAL (only backup path) | | Synology Drive | 4.0.3-27892 | File sync/Drive | Yes | /volume1/@syno Drive subvols | Important | | Synology Photos | 1.9.0-10924 | Photo management | Yes | homes/Photos | Important (consumer) | | Snapshot (share snap) | — | btrfs snapshots | enabled all shares | /volume1/@sharesnap | Important (no real snapshots today) | | Storage Analyzer | 2.1.1-0641 | Usage analysis | Yes | — | No | | ActiveInsight | 3.0.5-24122 | Cloud monitoring/support | Yes | — | No | | SynoAnalytics | 1.0.4-20014 | Analytics | — | — | No | | HybridShare | 1.5.2-1832 | C2 cloud file mgmt | — | — | No | | USBCopy | 2.2.1-1306 | USB auto-copy | — | — | No (but used for backup target?) | | Tailscale | 1.58.2-700058002 | VPN mesh | Yes (agent access) | — | Essential for remote mgmt | ## Communications / Collaboration | Package | Role | Essential? | |---|---|---| | MailPlus-Server 4.0.0-31657 | mail server | Yes if email in use (has data) | | MailClient 4.0.0-22251 | webmail | No | | Contacts 1.0.10 | address book | No | | Calendar 3.0.2 | CalDAV | No | | Chat 2.4.6 | chat server | No (has data) | | Synology Office (Spreadsheet) | docs | No | | UniversalViewer 1.4.0 | preview | No | ## Media | Package | Purpose | Essential? | |---|---|---| | Audio Station 7.2.0 | audio | No (docker deems used) | | CodecPack/AME 4.0.0 | codecs | Yes for native video | | Synology Photos | (above) | — | ## Runtime / App frameworks | Package | Version | Essential? | |---|---|---| | Container Manager | 24.0.2-1606 | Yes (all Docker) | | Node.js_v18 / v20 | 18.18.2 / 20.19.5 | No (dev) | | PHP 8.2 | 8.2.28 | No (web station) | | Python2 / 3.9 / 3.10 | 2.7.18 / 3.9.22 / 3.10.20 | No | | Git / git | 2.39 / 2.53 | No (dev) | | Perl 5.34 | — | No | ## Security / Auth / Access | Package | Purpose | Essential? | |---|---|---| | SecureSignIn 1.1.6 | passwordless/2FA | Yes (if used) | | OAuthService 1.2.0 | OAuth2 | framework | | QuickConnect 1.0.10 | internet connect | Exists; DDNS enabled | | ActiveInsight | (above) | — | ## Core DSM services (always present) FileStation, StorageManager, SMBService, ScsiTarget (iSCSI/SAN), LogCenter, SynoFinder, SynologyApplicationService, SynoOnlinePack_v2, SupportService, AIConsole, StorageAnalyzer, TextEditor. ## Package attention (per directive) - Hyper Backup — present, 1 job (see 06). Critical to NAS operation. - Snapshot Replication — snapshot capability present (share snap), but no meaningful snapshots exist. - Synology Drive — active, homes-centric. - Container Manager / Docker — core (see §04). - Synology Photos — active, home photos. - Active Backup — NOT installed (no "ActiveBackup" package seen). No client backup to NAS. - VPN packages — none (only Tailscale). - Media services — Audio Station, CodecPack, Photos; plus Docker media stack (Plex/Jellyfin/*arr). - File-sharing — SMB, QuickConnect, Synology Drive, FileStation. ## Classification summary (for later) - Keep/Essential: Container Manager, Hyper Backup, Synology Drive, Photos, Storage Manager, FileStation, Tailscale, SecureSignIn, SMB. - Review: Chat, MailPlus, Calendar, Contacts, HybridShare, USBCopy, Analjyics, AIConsole, ActiveInsight — enable/retire decision. - Retire candidates (bloat): Python2, Perl (legacy), redundant runtimes. ## Discovery Commands bash ls /var/packages/ for p in $(ls /var/packages/); do cat /var/packages/$p/INFO 2>/dev/null | grep -E "^version=|^package=|^description=" ; done # Backup & Recovery # 06 — Backup & Recovery Audit > Critical finding: The only configured backup is stale (~9 months old), targets the same-NAS USB drive, covers homes only, and has never been restore-tested. BACKUP EXISTS ≠ RESTORE VERIFIED. ## Backup Mechanisms ### 1. Hyper Backup — "Local;1" → USB | Attribute | Value | |---|---| | Job name | Local Copy 1 (task id 10) | | Engine | Hyper Backup 4.2.1-4228 | | Source folders | /homes/mskeete, /homes/msn0624c, /homes/rore-admin, /homes/rore-worship, /homes/sadevidal, /homes/vidalstephen (homes only) | | Destination | Local USB usbshare1 → target dir NGAGED_CLOUD_1 | | Transport | trans_type=local (same-NAS USB) | | Schedule | task id 10: daily 03:00 (from crontab), but task state=disabled | | Retention | enable_delete=true (version deletion on) — retention policy not fully captured | | Encryption | not indicated | | Last successful run | ~2025-11-02/04 (target dir mtime + DSM_HOMES_BACKUP 2025-11). Stale ~9 months. | RESTORE VERIFIED | NO — no evidence of a restore test | Evidence of staleness: USB NGAGED_CLOUD_1 last modified Nov 2025; synobkpinfo.db dated Nov 4 2025; DSM_HOMES_BACKUP Nov 2025. No recent Hyper Backup activity log. ### 2. Manual homes copy — DSM_HOMES_BACKUP (USB) - Separate homes archive on USB (admin, mskeete, msn0624c, rore-admin, rore-worship, sadevidal, shaconann, vidalstephen). - Dated 2025-11. Not automated, not verified. ### 3. Docker config backups (ad-hoc) - /volume1/docker/backups/ — manual snapshots: media-platform-20251112, traefik-20260420, wordpress/, stacks-inactive-20260501, 20250929. - /volume1/docker/_archive/traefik-old-platform/ — old Traefik config. - /volume1/docker/_backups/pre-kvm1-alignment-20260420/. - These are manual, not scheduled, not verified. ### 4. Container/app-level backups - backups/romm (small), backups/docker-inventory. - No automated container config backup detected (no dsmbackup-driven docker backup; state=disabled on backup task). ### 5. DSM configuration backup (auto) - DSM maintains an automatic config backup at /volume1/@config_backup (61 KB, dated 2026-08-16) — this captures DSM settings/account/network config. Good, but it lives on the same volume/NAS, so it protects against config drift, not NAS loss. Include in any off-NAS backup. ## Snapshot Protection - Share-snapshot service enabled on all shares, but only vMix Recordings has a snapshot, and it is empty (single desktop.ini). - Effectively zero snapshot protection today. ## Protection Gaps (BACKUP EXISTS vs RESTORE VERIFIED) | Dataset | Backup exists? | Restore verified? | Notes | |---|---|---|---| | homes (all users) | Yes (Hyper Backup → USB, stale) | NO | Only non-offsite backup; stale 9 mo | | vMix Recordings (752 GB) | NO | — | CRITICAL GAP — irreplaceable, largest dataset | | docker/data/media (534 GB) | NO | — | Re-downloadable; low priority | | Docker compose configs | Partial manual (stale) | NO | Fragile | | Vaultwarden data | NO (within docker share) | — | Priority — password manager | | Synology packages/config | not captured | — | DSM config not exported | | projects, Shared Documents | Not in Hyper Backup job | — | Gap | | Offsite/cloud copy | NO | — | No off-NAS backup anywhere | ## Conclusion - Only the homes directories are nominally backed up, and only to a USB drive on the same physical NAS (protects against disk failure within the box, but not against fire/theft/whole-NAS loss, and is 9 months stale and unverified). - vMix Recordings, media config, projects, vaultwarden have no effective backup. - No restore has ever been tested → cannot assume any backup is recoverable. ## Phase-2 Priorities (proposal — not executed) 1. P0 — Add an off-NAS backup for vMix Recordings + homes (target: golden-eye / srv1388017 VPS / edge; rsync/rclone/rsnapshot). 2. P0 — Restore-test the existing USB homes backup (restore one user dir to scratch, verify hashes) before trusting it. 3. P1 — Back up all compose configs + env-file names under /volume1/docker (platform/, stacks/, nsystems-monitoring/) to a restorable location. 4. P1 — Export DSM config (Control Panel → config backup) + Hyper Backup task config. 5. P2 — Offsite copy of vaultwarden + key small datasets. ## Discovery Commands bash cat /var/packages/HyperBackup/etc/synobackup.conf ls -la /volumeUSB1/usbshare/NGAGED_CLOUD_1/ ls -la /volumeUSB1/usbshare/DSM_HOMES_BACKUP/ ls -la /volume1/backups/ /volume1/docker/backups/ cat /usr/syno/etc/sharesnap/sharesnap.conf # Network & Security # 07 — Network & Security > NOTE: Firewall rules, SSH daemon hardening, and reverse-proxy internal rules could not be read without privileged (sudo) access. Items marked UNKNOWN / REQUIRES MANUAL REVIEW need DSM admin or the sudo password. ## IP & Interfaces | Interface | State | Address | Notes | |---|---|---|---| | eth0 | UP | 192.168.0.164/24 | LAN primary | | eth1 | DOWN | 169.254.67.66/16 | unused | | tailscale0 | UP | 100.90.167.88/32 | Tailscale node ngaged-cloud | - Gateway: 192.168.0.1 - DNS: 8.8.8.8 / 8.8.4.4 - DDNS: Synology DDNS enabled, ngaged.synology.me (→ public IP). QuickConnect package present. - Tailscale package v1.58.2 — remote admin path for the agent. ## Public Exposure - Cloudflare tunnel 6f717a56-… (cloudflared container) serves: - *.nsystems.live + nsystems.live - *.vectorhost.net + vectorhost.net - Ingress → http://traefik:8080 → internal services (28+ subdomains) - Directly exposed ports (0.0.0.0): - Plex 32400 - RustDesk 21115-21119 - Jellyfin 8096 - phpmyadmin 8086 (container exited but port defined) - freightline-dev 3001 (container exited) - LAN: rdt-client 192.168.0.164:6500 - Tailscale-only: gatus 100.90.167.88:8081, gotify 100.90.167.88:8082 - Loopback: devshell 127.0.0.1:2222 ## Exposure flags (unnecessarily exposed?) - phpmyadmin and freightline-dev are exposed on 0.0.0.0 even though their containers are exited — if they ever start they'd be internet-facing without auth. Flag. - Jellyfin + Plex directly bound to 0.0.0.0 in addition to the tunnel — double exposure. Prefer tunnel-only (no direct bind). - RustDesk on 0.0.0.0 (public relay) — intentional but should be confirmed desired. ## SSH Configuration - SSH access confirmed on port 54321 (custom) from golden-eye via key. - From admin inspection: PubkeyAuthentication yes, PasswordAuthentication yes (password auth is enabled), ChallengeResponseAuthentication no. The sshd listener runs on the standard DSM config (/usr/bin/sshd -D [listener]). - Finding: password auth is enabled for SSH. Combined with a high but known port, this is an exposure to brute-force. Recommend key-only auth + disable password auth during Phase 2 hardening. ## Firewall (DSM firewall — now read with admin access) - DSM's firewall is the INPUT_FIREWALL chain (96 total rules). Key allow rules: - 1 ACCEPT lo - 2 ACCEPT state RELATED,ESTABLISHED - 3 RETURN tcp 0.0.0.0/0 -> dports 5000,5001,6690,54321,22 — DSM web (5000/5001), Synology Drive (6690), SSH (54321/22) are allowed from ANY source (internet-facing if the router forwards them). - Rules 4–16 RETURN many services (NFS, SMB, FTP, media ports 8096/32400/6500, iSCSI, etc.) only from the Tailscale subnet 100.0.0.0/8 — so SMB, Jellyfin(8096), Plex(32400), rdt-client(6500) are Tailscale/LAN-only at the firewall even though Docker publishes them on 0.0.0.0 (the firewall blocks non-Tailscale access to those). - Net effect: the DSM firewall confines most services to Tailscale; but DSM web + Drive + SSH are open to the internet if the router port-forwards them. The cloudflared tunnel plus exposed Plex/RustDesk ports remain the primary internet paths. ## Firewall / NFS / SMB - iptables INPUT: INPUT_FIREWALL chain (see above). Default action for unlisted traffic is effectively drop (only RETURN/ACCEPT rules exist; unreturned packets fall to the chain policy). - NFS: /etc/exports empty → NFS not exported. - SMB: nearly all shares guest ok=yes (see §03), but SMB port 445/139/137/138 is RETURN-allowed only from 100.0.0.0/8 → SMB is Tailscale/LAN-only. Mitigates the guest-open shares. ## Reverse Proxy / TLS / Certificates - Traefik v3 is the reverse proxy: entrypoints, ACME (Let's Encrypt), CF DNS-01 challenge using CF_DNS_API_TOKEN (value REDACTED/SECRET). Certs stored in acme.json (/volume1/docker/platform/traefik/acme/). - Authelia (SSO/2FA for proxied apps) is exited/down → auth middleware dashboard-auth@file still referenced by Traefik dashboard; proxied services may lack enforced SSO while Authelia is down. Verify exposure. ## Certificates - /usr/syno/etc/certificate/ contains system, ReverseProxy, _archive certs (DSM + reverse proxy certs). ## Security posture summary | Area | Status | |---|---| | Public exposure path | Cloudflare tunnel (good) but with direct port binds (reduce) | | SSO / Authelia | DOWN (gap) | | SSH | custom port + key auth (good) BUT password auth enabled (tighten) | | Firewall | DSM INPUT_FIREWALL: DSM-web/Drive/SSH open to all; most services Tailscale-only | | SMB | guest-writable on most shares (Tailscale/LAN-only via firewall) | | Malware/AV | BitDefenderForMailPlus group exists (MailPlus AV); no general AV | | SecureSignIn | installed (2FA/passwordless) — usage UNKNOWN | | ActiveInsight | cloud monitoring enabled | ## Phase-2 recommendations (no change now) - Remove/disable direct 0.0.0.0 binds for Jellyfin, Plex, phpmyadmin, freightline-dev (keep tunnel-only). - Restore/replace Authelia OR confirm Cloudflare Access is enforced for exposed apps. - Obtain SSH/firewall config via sudo to complete the UNKNOWN section. - Consider binding RustDesk to Tailscale/LAN only if remote relay is not strictly required. ## Discovery Commands bash ip -br addr; ip route; cat /etc/resolv.conf ss -tlnp # (needs sudo on Synology) # Firewall (needs sudo): sudo iptables -L INPUT -n sudo cat /etc/ssh/sshd_config cat /volume1/docker/platform/cloudflared/config.yaml # tunnel ingress map grep -iE "entryPoints|providers|acme|endpoint|email" /volume1/docker/platform/traefik/traefik.yml # Scheduled Tasks # 08 — Scheduled Tasks & Automation Tasks enumerated from /etc/crontab, /usr/syno/etc/synoschedule.d/root/*.task, and the Docker scripts/ automation tree. All are read-only observations; nothing changed. ## DSM Scheduled Tasks (/usr/syno/etc/synoschedule.d/root/) | ID | Name | Type | State | Command (decoded) | Purpose | |---|---|---|---|---|---| | 1 | DSM Auto Update | weekly (Sun 04:45) | enabled | /usr/syno/sbin/synoupgrade --autoupdate | Auto-apply DSM hotfixes | | 2 | Run security advisor | weekly (Sun 01:49) | enabled | bash synowebapi …SecurityScan… update/start items=ALL | Scheduled security scan | | 3 | Update spamassassin rules | daily 04:15 | enabled | /var/packages/MailPlus-Server/target/scripts/SpamRuleUpdate.sh all | MailPlus spam rules | | 4 | Security check | daily (hourly) | enabled | …/SecurityCheck.sh all | MailPlus security | | 5 | do_regular_op | daily 02:00 | enabled | /var/packages/MailClient/target/tool/regular_op --all | MailPlus housekeeping | | 7 | Docker Cleaner | once | disabled | bash /volume1/docker/dockerprune.sh | Docker prune (disabled) | | 8 | Invidious Stop | daily | disabled | synowebapi …Docker.Container stop Invidious | stop Invidious (disabled) | | 9 | Invidious Start | daily | disabled | docker container start Invidious | start Invidious (disabled) | | 10 | Local Copy 1 (Hyper Backup) | daily 03:00 | disabled | /var/packages/HyperBackup/target/bin/dsmbackup --backup 1 | Backup job — DISABLED (stale) | > Key finding: the only backup task (id 10) is disabled, matching the stale USB backup. DSM auto-update + security scans are enabled. Docker-prune and Invidious tasks are disabled (so nothing is auto-pruning/overwriting today — safe). ## /etc/crontab (system) - MailPlus clean-junk, clamav update, and synoschedtask dispatcher entries (mirror tasks above). No destructive crons found. ## Custom Docker automation (/volume1/docker/scripts/) Automation helpers (present but not necessarily scheduled): - nasops (14 KB bash CLI), stackctl.sh, stack-update.sh, stack-status.sh, compose-all-down.sh - network-watchdog.sh, dnscheck.sh, portcheck.sh, tlscheck.sh, routercheck.sh, preflight.sh, validate-traefik-config.sh - email-notify.sh/.py, fix-postgres-perms.sh, add-authelia-labels.py, lib.sh, boot-startup.sh - /volume1/docker/update-all-stacks.sh (deprecated → points to stack-update.sh) - /volume1/docker/dockerprune.sh — referenced by disabled task 7; not present at /volume1/docker/dockerprune.sh (only referenced). Verify in Phase 2. - Makefile (/volume1/docker/Makefile) — deployment/ops targets (dns, preflight, tls, deploy, etc.) — not a cron, dev tooling. ## What these do / depend on - Auto-update depends on network + Synology update server. - Security scan depends on DSM Security Advisor. - MailPlus tasks depend on MailPlus server; relate to mail data. - Backup task (disabled) would call dsmbackup --backup 1 → the USB Hyper Backup job. - Prune task (disabled) — would delete Docker junk — currently not running (good; nothing being pruned now). ## Anything capable of deleting/moving/syncing/overwriting? - No enabled task does deletion today. The prune task and backup task are both disabled. - Docker *arr/media stack performs its own moves/hardlinks but that is application behavior, not a scheduled destructive task. - CleanUpArr / Recyclarr (running containers) manage *arr data (cleanup/config sync) — could delete media if misconfigured; note but they are healthy and user-configured. ## Discovery Commands bash cat /etc/crontab for f in /usr/syno/etc/synoschedule.d/root/*.task; do echo "--$f--"; grep -E "^(id|name|type|state|action|cmd)=" "$f"; done ls -la /volume1/docker/scripts/ # Hermes Current State # 09 — Hermes Current State (on NAS) > Finding: There is no Hermes installation running on the NAS today. The mission brief said "Hermes currently exists on this NAS" — the evidence indicates it does not currently run there. What exists is a staging artifact (an empty Ollama data directory), not a live agent. Nothing was migrated. ## Evidence | Check | Result | |---|---| | which hermes on NAS | not found | | ~/.hermes on NAS | does not exist | | docker ps -a --filter name=hermes | no container | | find /volume1 -iname "*hermes*" | no matches | | /volume1/docker/ollama/ | exists but contains only empty logs + a 4 KB model blob stub (see below) | ## /volume1/docker/ollama/ — the only NAS artifact - logs/ollama.log — logs from an Ollama process run 2026-07-02 … 2026-07-07 (last entry 2026-07-07T05:39). Shows an Ollama server was run on the NAS ~2 weeks in July, fetching model recommendations, then stopped. - models/blobs/sha256-6528… — 4 KB blob (a tiny placeholder/stub, not a real model). Manifest for glm-5.2:cloud present (a cloud-sized pointer, no local weights). - Conclusion: Someone staged a Cloud-Ollama mount (ollama dir) on the NAS, ran it briefly in early July, and it is no longer running and has no usable model weights. This is a leftover staging artifact, not an active Hermes. ## Why it matters for the target architecture - The target: Primary Hermes Orchestrator → Compute/Laptop (golden-eye), with an optional lightweight NAS Domain Agent (storage/DSM operator, read-only by default, least-privilege, reports to orchestrator). - The NAS currently has no agent — clean slate. The /volume1/docker/ollama dir should be treated as review (likely remove or repurpose as a future NAS-agent data mount during migration — Phase 2+, not now). ## Data needed to (re)build a NAS Domain Agent later (NOT migrated now) 1. NAS SSH account (msn0624c) + key access (present). 2. Read-only DSM API/tool access (synoshare, synouser, synostgpool, synosharesnapshot — via sudo). 3. A lightweight container/runtime for the agent (Ollama dir could host it). 4. Connection back to golden-eye orchestrator (Tailscale 100.90.167.88 ↔ 100.112.235.92). 5. Least-privilege operator identity (dedicated NAS-agent user, not full admin). ## Dependencies - The future NAS agent depends on: golden-eye orchestrator (orchestration), Tailscale (connectivity), DSM API (management), and read-only access to shares/volumes/snapshots (storage ops). None of these are provisioned for Hermes yet. ## Secrets - No Hermes credentials exist on the NAS to document (none found). Any future agent credentials must be stored in SOPS/Vaultwarden/broker, never in the wiki or chat. ## Recommendation - Treat NAS Hermes as not present; plan the NAS Domain Agent from scratch in the target architecture. The /volume1/docker/ollama dir is a REVIEW item (likely retire/repurpose). Confirm with Stephen whether a prior partial Hermes/Ollama setup was abandoned. ## Discovery Commands bash which hermes; ls ~/.hermes /usr/local/bin/docker ps -a --filter name=hermes find /volume1 -maxdepth 3 -iname "*hermes*" ls -la /volume1/docker/ollama; du -h /volume1/docker/ollama/models/blobs/* cat /volume1/docker/ollama/logs/ollama.log | tail # Dependency Map # 10 — Dependency Map Map of relationships among NAS shares, containers, packages, users, backups, and external infrastructure. Focus: hidden dependencies that could break after a factory reset. ## External machines / services | External node | Relationship to NAS | |---|---| | golden-eye (100.112.235.92) | Orchestrator; SSH operator to NAS (port 54321); future primary Hermes host | | srv1388017 VPS | (documented sibling; may be backup target in Phase 2) | | Cloudflare | Tunnel 6f717a56 + DNS for nsystems.live/vectorhost.net; Traefik CF DNS-01 token for TLS | | Tailscale | VPN mesh; agent/NAS connectivity (100.90.167.88) | | Ollama cloud | (nas-guestory) — NAS had staged Ollama cloud mount (glm-5.2:cloud), no local model | | Internet indexers | *arr uses Prowlarr + FlareSolverr + debrid (rdt-client) — external API deps | | USB drive | local backup target (Hyper Backup) | ## Share → Service dependencies - docker/data/media ← all *arr, Jellyfin, Plex, rdt-client, bazarr, deemix (bind mounts) - docker/data/media-library ← Jellyfin, Plex (read), TubeArchivist-kids (write) - docker/data/torrents ← qBittorrent/rutorrent/cleanuparr - docker/stacks/…/stack-config/* ← all media containers (config; reproduceability) - docker/platform/{traefik,cloudflared,ddns} ← all public web services (proxy/tunnel/DNS) - homes ← Synology Drive, FileStation, Photos, Hyper Backup source - vMix Recordings ← only filesystem/DSM (no container depends; no backup) ## Container → Container - Traefik ↔ all web apps (routing) - cloudflared → Traefik (tunnel → ingress) - Authelia (exited) → proxied apps (auth middleware) — down = SSO gap - qBittorrent/rutorrent → gluetun (VPN network namespace) - rdt-client → *arr (download client via fake qBit API) - Plex → tautulli (stats), overseerr → sonarr/radarr (requests) - Prowlarr → sonarr/radarr/lidarr (indexer sync) - TubeArchivist → tak-redis + tak-elasticsearch ## Users / service accounts - msn0624c (admin + docker) → all compose stacks, SSH, backups - ngaged-cloud group (5 family users) → homes shares - shaconann/vidalstephen/sadevidal/rore-admin → largest homes data - package service accounts (postgres, mysql, mailplus, etc.) ## Backup - Hyper Backup job (homes → USB) depends on USB drive + job enabled (currently disabled). - No container/app config backup → hidden fragility for any container. ## Hidden-dependency risks after a factory reset 1. All DNS/TLS breaks unless Cloudflare tunnel creds (6f717a56-….json) + CF DNS token are recovered. Stored in /volume1/docker/platform/{cloudflared,traefik} — inside the docker share. 2. All compose stacks lose their config if /volume1/docker/stacks + /platform + /nsystems-monitoring are not backed up. 3. Vaultwarden (password manager) — if /volume1/docker/stacks/homelab/vault/config is lost, all vault credentials are lost. 4. Media library is re-downloadable but huge; vMix Recordings is irreplaceable and has no backup. 5. ACL/permission model is DSM-native; recreated cleanly only if config exported. 6. Package list (MailPlus, Photos, Drive) must be reinstalled + re-licensed. 7. Docker images (255, 162 dangling) — re-pullable but config labels are in the exited containers. 8. Anonymous volumes (11 hex volumes) — content/ownership unknown; may hold unreproducible data. ## Dependencies of external on NAS - Cloudflare tunnel depends on the NAS's cloudflared container staying up (if NAS down, 28+ subdomains go dark). - RustDesk relay (hbbs/hbbr) — clients depend on NAS. - Plex/Jellyfin clients depend on NAS media + streaming containers. - Synology Drive/Photos clients depend on NAS. ## Diagram (text) Internet │ (DNS: nsystems.live / vectorhost.net) ▼ Cloudflare Tunnel (6f717a56) ──► cloudflared (NAS) │ ▼ Traefik (:80/443) │ ├─(CF DNS-01 cert) ▼ Authelia [DOWN] ── SSO gate (gap) │ ┌──────────────┬───────────┴──────┬───────────────┐ ▼ ▼ ▼ ▼ Jellyfin *arr stack static apps monitoring Plex Sonarr/Radarr/ (scrapline2, (gatus/gotify) Prowlarr/Bazarr crimson, ...) │ │ │ ▼ ▼ ▼ /docker/data/ /docker/data/ /volume1 (docker.sock media-library media via devshell) # Risk Register # 11 — Risk Register Prioritized risks with Evidence → Impact → Remediation (not executed in Phase 1). ## CRITICAL ### R1. No verified restore — backup may be unrecoverable - Evidence: Hyper Backup job "Local;1" is disabled (task id 10 state=disabled); USB target NGAGED_CLOUD_1 + synobkpinfo.db last modified 2025-11 (~9 months stale); no restore test on record. - Impact: Even the homes data cannot be guaranteed recoverable. A perceived backup may be a false sense of security. - Remediation: Phase 2 P0 — restore-test the USB backup (restore a user dir to scratch, verify hashes) before proceeding; do not rely on it. ### R2. vMix Recordings (752 GB) has NO backup - Evidence: Not in Hyper Backup folder list (backup_folders = homes only); snapshot empty (desktop.ini only); largest single dataset (752 GB, mostly >4 GB church service videos). - Impact: Total loss of irreplaceable recordings on any deletion/corruption/fire. Highest-value single dataset. - Remediation: Phase 2 P0 — off-NAS backup (rsync/rclone/rsnapshot to golden-eye/srv1388017/edge) + enable snapshot scheduling + periodic integrity check. ### R3. Only backup targets the SAME NAS (no offsite) - Evidence: Hyper Backup trans_type=local → USB usbshare1 physically attached to the NAS; no cloud/offsite job. - Impact: Whole-NAS loss (theft, fire, power surge) destroys data AND backup together. - Remediation: Add off-NAS/offsite backup (rclone to object storage, edge VPS, or a second site). ## HIGH ### R4. Docker/container config not reproducibly backed up - Evidence: Compose files + stack-config live inside /volume1/docker (no automated backup; manual snapshots stale). 255 images / 162 dangling / 11 anonymous volumes. - Impact: Factory reset or volume loss = all stack configs gone; containers cannot be rebuilt from memory. - Remediation: Back up /volume1/docker/{platform,stacks,nsystems-monitoring} + .env/env-file names to a restorable location; dump docker inspect for every container; snapshot named volumes. ### R5. Vaultwarden (password manager) data not backed up - Evidence: vaultwarden config at /volume1/docker/stacks/homelab/vault/config; inside docker share; no backup job. - Impact: Loss of the password vault = total credential loss. - Remediation: Phase 2 P1 — include vaultwarden config/ in backup (ideally offsite) + enable Bitwarden built-in backups if available. ### R6. Authelia (SSO/access control) is DOWN while services are internet-exposed - Evidence: authelia container exited; compose labels reference authelia.nsystems.live; tunnel serves 28+ subdomains. - Impact: Exposed web apps may lack enforced SSO/2FA; dashboard-auth middleware may fail open. - Remediation: Restore or replace Authelia, or enforce Cloudflare Access on tunnel routes; confirm every exposed route requires auth. ### R7. Container config / anonymous volumes unowned - Evidence: 11 anonymous hex volumes; several exited containers (calcom, reactive-resume, etc.) with DB volumes; no owner map. - Impact: Unknown data, can't reproduce; storage + restore clutter; potential orphaned DBs. - Remediation: Map each anonymous volume to its container in Phase 2; decide keep/retire; back up any needed. ## MEDIUM ### R8. Internet-exposed services on 0.0.0.0 - Evidence: Plex 32400, RustDesk 21115-21119, Jellyfin 8096, phpmyadmin 8086, freightline-dev 3001 all bound to 0.0.0.0. - Impact: Direct internet exposure beyond the tunnel; phpmyadmin/freightline are exited but would expose if started. - Remediation: Bind to 127.0.0.1/LAN/Tailscale or keep tunnel-only; disable the exited exposure. ### R9. Stale/unsupported runtimes & old containers - Evidence: Python2, Perl, old wordpress:6.8.3/mariadb:11, agent-zero, calcom, uptime-kuma, etc. exited; 162 dangling images. - Impact: Attack surface (unpatched images), storage bloat, restore clutter. - Remediation: Retire/archive stopped containers + prune dangling images (with approval). ### R10. Undocumented/partial Docker prune task + Invidious tasks - Evidence: tasks 7/8/9 (dockerprune.sh, Invidious stop/start) exist but disabled. - Impact: If enabled accidentally, could delete Docker data (prune) or toggle a container. - Remediation: Document; keep disabled; remove stale task 8/9 if Invidious not in use. ## LOW ### R11. Broad operator permissions - Evidence: msn0624c = full admin + docker; devshell container mounts docker.sock + /volume1 + .ssh. - Impact: If compromised, full NAS control. - Remediation: Create least-privilege operator for migration; restrict/remove devshell docker.sock & /volume1. ### R12. Data with unclear ownership - Evidence: ryan home empty; legacy media share redundant with docker/data/media; anonymous volumes. - Impact: Can't confidently archive/retire. - Remediation: Confirm ownership in Phase 2 before any removal. ### R13. Single copies of important data - Evidence: vMix (752G) & vaultwarden & compose configs have single copies. - Impact: any local failure = loss. - Remediation: (covered by R2/R4/R5 backup actions) ### R14. SSH/firewall hardening unverified - Evidence: sshd_config + iptables not readable without sudo; SSH on custom port 54321. - Impact: unknown whether root login/password auth permitted. - Remediation: Obtain sudo/DSM admin, review SSHD + firewall, enforce key-only, restrict root. > Admin-pass update: This is now RESOLVED (firewall + SSHD + ACLs + SMB enumerated). Two new findings from the privileged pass: ### R15 (MEDIUM→HIGH). SMB shares are guest-writable - Evidence: smb.conf shows nearly all shares (homes, docker, media, projects, music, web, chat, MailPlus, usbshare1, etc.) with guest ok=yes, valid users=nobody,nobody, writeable=yes. - Impact: Any LAN/Tailscale client can access these shares without authentication, including homes (personal data) and docker (container configs/media). Mitigated only by the DSM firewall confining SMB to 100.0.0.0/8 (Tailscale) — so exposure is Tailnet/LAN, not internet. - Remediation: Restrict SMB shares to named users/groups (remove guest ok), especially homes and docker. Enable SMB auth. During Phase 2, audit and lock down each share. ### R (MEDIUM). SSH password authentication enabled - Evidence: sshd_config has PasswordAuthentication yes. - Impact: Brute-force risk on the known SSH port (54321) for any account with password auth. - Remediation: Disable password auth (key-only), enforce for all users; ideally restrict SSH to Tailscale/LAN. ## Risk summary counts - CRITICAL: 3 (no-verified-restore, vMix no backup, no offsite) - HIGH: 4 (docker config not reproducible, vault not backed up, authelia down + exposure, SMB guest-writable) - MEDIUM: 4 (0.0.0.0 exposure, stale/unsupported images, undocumented disabled automation, SSH password auth) - LOW: 4 (broad perms, unclear ownership, single copies, unverified hardening) > No remediation performed in Phase 1. All items pending Phase 2 authorization. # Keep / Move / Retire / Replace # 12 — Keep / Move / Retire / Replace (Migration Classification) Intended architecture principle: - Synology NAS = storage, snapshots, backup, replication, and carefully selected data-centric services. - Compute/Laptop (golden-eye) = Hermes orchestration, AI/agent workloads, automation, dev tools, monitoring, databases, compute-heavy services. - VPS/Edge = services needing public internet accessibility. - NAS Domain Agent = lightweight, read-only-by-default, least-privilege storage/DSM operator reporting to the primary orchestrator. Provisional classification for each significant workload. No migration performed in Phase 1. ## Storage / Shares | Item | Class | Rationale | |---|---|---| | vMix Recordings | KEEP on NAS (+ backup offsite) | Data-centric, irreplaceable, huge | | homes | KEEP on NAS (+ backup offsite) | Personal data, Synology Drive/Photos native | | docker/data/media | KEEP on NAS | Media library, re-downloadable, near streamers | | projects | MOVE (to compute) | Dev/project files belong with compute | | media (legacy share) | RETIRE/REVIEW | Redundant with docker/data/media | | Shared Documents | KEEP | Office docs | | music | REVIEW | vs docker/data/media/Music | | chat, MailPlus, Calendar, Contacts | REVIEW/RETIRE | decide if actively used | | web, web_packages | RETIRE/REVIEW | not used for hosted apps (they're Docker now) | | gitea-share | REVIEW | empty | | backups | KEEP | admin/backup staging | ## Containers | Workload | Class | Target host | |---|---|---| | Traefik (reverse proxy) | KEEP (or MOVE) | NAS (data-local) or VPS/edge | | cloudflared (tunnel) | KEEP | NAS (or move to always-up edge) | | cf-ddns | KEEP | NAS | | Authelia | REPLACE/REVIEW | resolve SSO gap | | media-platform (Jellyfin, Plex, *arr, Overseerr, Tautulli, Deemix, TubeArchivist) | KEEP ON NAS | data-local | | qBittorrent/gluetun/rutorrent/rdt-client | REVIEW | near media; VPN sidecar on NAS | | Gatus, Gotify | MOVE to COMPUTE | monitoring/notifications belong on golden-eye | | Vaultwarden | KEEP or MOVE to VPS | decide; must be backed up | | RustDesk (hbbs/hbbr) | MOVE to VPS/EDGE | public relay wants always-up host | | devshell | REPLACE | dev shell on compute; restrict | | scrapline2, crimson-haven, skybreaker-transform, ghostline-command | MOVE to COMPUTE/VPS | static/hosted apps | | Exited: wordpress(+db), aethrix(+phpmyadmin), reactive-resume(+db+printer), calcom(+db+redis), uptime-kuma, dozzle, dsm-router, dungeon-generator, template-myapp, agent-zero, druglord, freightline(+dev), starforge, scrapline(old) | RETIRE/REVIEW | old project containers; keep only if needed | ## Packages | Package | Class | |---|---| | Container Manager, Hyper Backup, Synology Drive, Photos, Storage Manager, FileStation, SMB, Tailscale, SecureSignIn | KEEP (essential) | | Synology Photos/Drive | KEEP | | Chat, MailPlus(+Server/MailClient), Calendar, Contacts, HybridShare, USBCopy, Analytics, AIConsole, ActiveInsight | REVIEW/RETIRE (if unused) | | Python2, Perl, redundant runtimes | RETIRE (bloat) | | (None) — no Active Backup, no VPN packages installed | — | ## Hermes / Agent | Item | Class | Notes | |---|---|---| | Hermes on NAS | NOT PRESENT (no migration needed) | Only staging /volume1/docker/ollama stub | | NAS Domain Agent (future) | ADD | read-only by default, least privilege, reports to golden-eye orchestrator | | Primary Hermes Orchestrator | KEEP on golden-eye | target architecture | | /volume1/docker/ollama dir | REVIEW (likely retire/repurpose) | abandoned staging | ## Summary of target placement - On NAS: storage (all shares), media stack, torrent/VPN, Traefik/cloudflared/ddns (or edge), Synology data packages. - On Compute (golden-eye): Hermes orchestrator, monitoring (gatus/gotify), dev tooling, static/hosted apps, project files. - On VPS/Edge: RustDesk relay, any truly-public services, offsite backup target. - NAS Domain Agent: lightweight read-only DSM/storage operator reporting to orchestrator (Phase 2+ design). > All classifications are provisional recommendations. No migration or removal performed in Phase 1. Decision required from Stephen before Phase 2 moves any workload.