52 KiB
| title | description | published | date | tags | editor | dateCreated |
|---|---|---|---|---|---|---|
| Pocket Clips | Integrating Stash | true | 2026-02-22T05:20:31.865Z | markdown | 2026-02-20T04:48:11.191Z |
Pocket Grimoire - Stash Integration Guide
Adding Stash media library manager to Pocket Grimoire using two-instance architecture with ZFS replication
Overview
This guide extends the Pocket Grimoire deployment to include Stash using a two-instance architecture:
- Stash-Main on Netgrimoire watches your entire media library
- Stash-Pocket on Netgrimoire watches only curated personal content (GREEN drive)
- Stash-Pocket replicates to Pocket Grimoire's GREEN drive for offline access
This approach provides:
- Full library management at home (Stash-Main)
- Curated personal subset with independent database (Stash-Pocket)
- Automatic synchronization via existing ZFS replication to GREEN drive
- Read-only browsing on travel with all previews pre-generated
- Zero CPU load on travel Pi (no scanning/generation)
Key Principle: All intensive operations happen on Netgrimoire. Pocket Grimoire just serves pre-generated content in read-only mode.
Important: Stash data lives on the GREEN drive (personal media), NOT on VAULT. VAULT is for backups only.
Architecture
┌─────────────────────────────────────────────────────┐
│ NETGRIMOIRE (Home) │
├─────────────────────────────────────────────────────┤
│ │
│ Stash Instance #1: "Stash-Main" (Port 9999) │
│ ├─ Watches: ALL media libraries │
│ ├─ Config: /export/vault/stash-main/config │
│ ├─ Generated: /export/vault/stash-main/generated │
│ ├─ Blobs: /export/vault/stash-main/blobs │
│ ├─ Database: 1-5GB (full library) │
│ └─ Does NOT sync to Pocket │
│ │
│ Stash Instance #2: "Stash-Pocket" (Port 9998) │
│ ├─ Watches: ONLY Green/Pocket (personal content) │
│ ├─ Location: /export/Green/Pocket/ │
│ │ ├── media/library/ (personal media) │
│ │ └── stash/ (Stash-Pocket data) │
│ │ ├── config/ (database) │
│ │ ├── generated/ (previews) │
│ │ └── blobs/ (markers) │
│ ├─ Database: 200MB-1GB (personal subset) │
│ └─ SYNCS to Pocket GREEN drive via ZFS │
│ │
└─────────────────────────────────────────────────────┘
↓ ZFS Send (syncoid)
(vault/Green/Pocket → greenpg/Pocket)
↓
┌─────────────────────────────────────────────────────┐
│ POCKET GRIMOIRE (Travel) │
├─────────────────────────────────────────────────────┤
│ │
│ GREEN Drive (greenpg pool): │
│ └─ /srv/greenpg/Pocket/ (dataset from sync) │
│ ├─ media/library/ (media files) │
│ └─ stash/ (Stash data) │
│ │
│ Stash Instance: "Stash-Pocket" (Port 9999) │
│ ├─ Watches: GREEN media only (read-only) │
│ ├─ Location: /srv/greenpg/Pocket/ │
│ │ ├── media/library/ (synced media) │
│ │ └── stash/ (synced, read-only) │
│ │ ├── config/ (synced database) │
│ │ ├── generated/ (synced previews) │
│ │ └── blobs/ (synced markers) │
│ ├─ Same database as Netgrimoire Stash-Pocket │
│ └─ Browse only - no scanning or generation │
│ │
└─────────────────────────────────────────────────────┘
Why Two Instances?
Benefits of Two-Instance Architecture
✅ Stash-Main (Port 9999):
- Manages your entire home media library
- Heavy operations (scanning, tagging, preview generation)
- Full featured - edit, organize, tag anything
- Stays on Netgrimoire (doesn't sync to Pocket)
✅ Stash-Pocket (Port 9998 at home, 9999 on travel):
- Manages only curated personal content (GREEN drive)
- Smaller database (faster, lighter)
- Independent from main library
- Syncs to Pocket Grimoire's GREEN drive automatically
- Preview personal setup before trips
✅ Separation of Concerns:
- Main library can be massive (thousands of videos)
- Personal subset is manageable (hundreds of videos)
- No confusion about what's available where
- Changes to main library don't affect travel copy
- Faster sync times (only GREEN data replicates)
Storage Requirements
On Netgrimoire
Stash-Main (Does NOT sync):
Location: /export/vault/stash-main/
Database: 1-5GB (depends on library size)
Generated previews: 50-200GB (depends on settings)
Blobs/markers: 5-20GB
─────────────────────────────────────────────
Total: ~56-225GB (stays on Netgrimoire)
Stash-Pocket (DOES sync to GREEN drive):
Location: /export/Green/Pocket/stash/
Database: 200MB-1GB (smaller subset)
Generated previews: 5-20GB
Blobs/markers: 1-5GB
─────────────────────────────────────────────
Total: ~6-26GB (syncs to Pocket GREEN)
Personal Media (syncs to GREEN drive):
Location: /export/Green/Pocket/media/
Content: 500GB-1TB (curated for travel)
─────────────────────────────────────────────
Total Green/Pocket: ~506GB-1TB (vault/Green/Pocket dataset)
On Pocket Grimoire (GREEN Drive)
Location: /srv/greenpg/Pocket/
Stash data: ~6-26GB (synced from Netgrimoire)
Media files: ~500GB-1TB (synced from Netgrimoire)
─────────────────────────────────────────────
Total: ~506GB-1TB on GREEN SSD
This fits comfortably on a 2TB+ GREEN SSD.
Note: VAULT drive contains backups only (no Stash, no media).
Resource Impact
Updated Resource Profile (With Stash)
Netgrimoire (Running Two Instances):
Idle:
Stash-Main: ~400MB RAM
Stash-Pocket: ~300MB RAM (smaller database)
────────────────────────────
Total: ~700MB RAM
CPU: <5%
During operations:
Stash-Main (scanning): ~1-2GB RAM, 80%+ CPU
Stash-Pocket (scanning): ~500MB RAM, 40% CPU
Note: Run intensive tasks one at a time
Pocket Grimoire (Single Instance, Read-Only):
Idle:
Wiki.js + PostgreSQL: ~250MB RAM
Jellyfin (idle): ~150MB RAM
Stash-Pocket: ~200MB RAM
ZFS ARC: ~512MB RAM
System: ~200MB RAM
─────────────────────────────────
Total: ~1.3GB / 8GB RAM ✓
CPU: <10%
Temperature: Cool
Browsing Stash:
Stash-Pocket (active): ~300MB RAM
Other services: ~1.1GB RAM
─────────────────────────────────
Total: ~1.4GB / 8GB RAM ✓
CPU: <15%
Temperature: Cool to Warm
Media playback + Stash:
Jellyfin (serving): ~200MB RAM
Stash (browsing): ~300MB RAM
Wiki.js + PostgreSQL: ~250MB RAM
ZFS ARC: ~512MB RAM
System: ~200MB RAM
─────────────────────────────────
Total: ~1.5GB / 8GB RAM ✓
Still plenty of headroom
Installation: Netgrimoire (Home)
1. Create Directory Structure
# Create Stash-Main directories (NOT in Green folder - won't sync)
sudo mkdir -p /export/vault/stash-main/{config,generated,blobs,cache}
sudo chown -R 1000:1000 /export/vault/stash-main
sudo chmod -R 755 /export/vault/stash-main
# Stash-Pocket directories in existing Green/Pocket dataset
# Your dataset: vault/Green/Pocket mounted at /export/Green/Pocket
sudo mkdir -p /export/Green/Pocket/stash/{config,generated,blobs,cache}
sudo mkdir -p /export/Green/Pocket/media/library/{movies,tv}
sudo chown -R 1000:1000 /export/Green/Pocket
sudo chmod -R 755 /export/Green/Pocket
Verify structure:
tree -L 2 /export/vault/stash-main
tree -L 3 /export/Green/Pocket
# Should show:
# /export/Green/Pocket/
# ├── stash/
# │ ├── config/
# │ ├── generated/
# │ ├── blobs/
# │ └── cache/
# └── media/
# └── library/
2. Curate Pocket Media Content
Copy or move curated travel content to Pocket location:
# Example: Copy favorite movies to Pocket
cp /export/vault/media/library/movies/favorites/*.mp4 \
/export/vault/Green/Pocket/media/library/movies/
# Example: Copy specific TV show seasons
cp -r /export/vault/media/library/tv/ShowName/Season01 \
/export/vault/Green/Pocket/media/library/tv/
# Or organize a dedicated travel collection
mkdir -p /export/vault/Green/Pocket/media/library/travel-collection
# ... add curated content ...
Important: This is your travel media library. Keep it manageable (500GB-1TB).
3. Stash-Main Docker Compose
Create directory:
mkdir -p /srv/netgrimoire/stacks/stash-main
File: /srv/netgrimoire/stacks/stash-main/docker-compose.yml
services:
stash-main:
image: stashapp/stash:latest
container_name: netgrimoire_stash_main
environment:
- STASH_STASH=/data/
- STASH_GENERATED=/generated/
- STASH_CACHE=/cache/
- STASH_BLOBS=/blobs/
- TZ=America/Chicago
volumes:
# Stash-Main data (NOT in Pocket directory - won't sync)
- /export/vault/stash-main/config:/root/.stash
- /export/vault/stash-main/generated:/generated
- /export/vault/stash-main/blobs:/blobs
- /export/vault/stash-main/cache:/cache
# Watch ALL media libraries
- /export/vault/media:/data:ro
# Optionally also include Pocket media in main view
# - /export/vault/Green/Pocket/media:/data/pocket:ro
ports:
- "9999:9999"
restart: unless-stopped
Start Stash-Main:
cd /srv/netgrimoire/stacks/stash-main
docker compose up -d
# Check logs
docker logs -f netgrimoire_stash_main
# Access: http://netgrimoire.local:9999
4. Stash-Pocket Docker Compose
Create directory:
mkdir -p /srv/netgrimoire/stacks/stash-pocket
File: /srv/netgrimoire/stacks/stash-pocket/docker-compose.yml
services:
stash-pocket:
image: stashapp/stash:latest
container_name: netgrimoire_stash_pocket
environment:
- STASH_STASH=/data/
- STASH_GENERATED=/generated/
- STASH_CACHE=/cache/
- STASH_BLOBS=/blobs/
- TZ=America/Chicago
volumes:
# Stash-Pocket data (IN Pocket directory - will sync)
- /export/vault/Green/Pocket/stash/config:/root/.stash
- /export/vault/Green/Pocket/stash/generated:/generated
- /export/vault/Green/Pocket/stash/blobs:/blobs
- /export/vault/Green/Pocket/stash/cache:/cache
# Watch ONLY Pocket media
- /export/vault/Green/Pocket/media:/data:ro
ports:
- "9998:9999" # Different external port to avoid conflict
restart: unless-stopped
Note: Container uses port 9999 internally, but exposed as 9998 externally to avoid conflict with Stash-Main.
Start Stash-Pocket:
cd /srv/netgrimoire/stacks/stash-pocket
docker compose up -d
# Check logs
docker logs -f netgrimoire_stash_pocket
# Access: http://netgrimoire.local:9998
Verify both running:
docker ps | grep stash
# Should show:
# netgrimoire_stash_main (port 9999)
# netgrimoire_stash_pocket (port 9998)
5. Configure Stash-Main
Access: http://netgrimoire.local:9999
-
Initial Setup Wizard:
- Set admin password
- Configure paths (default /data should work)
- Complete setup
-
Add Libraries:
- Settings → Library
- Add folder:
/data/library(or your structure) - Save
-
Run Initial Scan:
- Tasks → Scan
- Wait for completion (can take hours for large libraries)
-
Configure Preview Generation:
- Settings → Tasks → Generate
- Video encoding: VP9 or H.264
- Resolution: 720p (good quality, reasonable size)
- Preview duration: 20-60 seconds
- Enable image previews
- Enable sprites
-
Generate Previews:
- Tasks → Generate → Previews
- This is CPU intensive - let run overnight
- Can take many hours for large libraries
-
Organize and Tag:
- Tag performers, studios, scenes
- Create collections, galleries
- Add markers, metadata
- This is your full-featured home library
6. Configure Stash-Pocket
Access: http://netgrimoire.local:9998
-
Initial Setup Wizard:
- Set admin password (can be same as Stash-Main)
- Configure paths (default /data should work)
- Complete setup
-
Add Library:
- Settings → Library
- Add folder:
/data/library - Save
-
Run Initial Scan:
- Tasks → Scan
- Should be much faster (smaller library)
- Wait for completion
-
Configure Preview Generation:
- Use same settings as Stash-Main
- Settings → Tasks → Generate
- Resolution: 720p
- Preview duration: 20-60 seconds
-
Generate Previews:
- Tasks → Generate → Previews
- Much faster than Stash-Main (fewer videos)
- Let complete before first trip
-
Organize (Optional):
- Tag travel-specific content
- Create "Travel Favorites" collections
- Can copy/import tags from Stash-Main if desired
- Or keep separate organization
Why configure Stash-Pocket separately?
- Independent database from Stash-Main
- Travel-specific organization
- Can have different preview settings (optimize for size)
- Preview what will be available on travel
7. Verify Data in Pocket Directory
# Check Stash-Pocket database exists
ls -lh /export/vault/Green/Pocket/stash/config/
# Should show: stash-go.sqlite (database file)
# Check previews generated
ls -lh /export/vault/Green/Pocket/stash/generated/
# Should show: many .webp or .mp4 preview files
# Check media is present
ls -lh /export/vault/Green/Pocket/media/library/movies/
# Should show: your curated travel media
Installation: Pocket Grimoire (Travel)
1. Wait for Initial Sync
Your existing ZFS sync handles everything:
# This already exists in your sync script:
syncoid --no-sync-snap --recursive \
--sshkey "${SSH_KEY}" \
"root@${NETGRIMOIRE}:vault/Green/Pocket" \
"vaultpg/Green/Pocket"
This syncs:
- ✅ Stash-Pocket database
- ✅ Stash-Pocket previews
- ✅ Stash-Pocket blobs/markers
- ✅ Pocket media files
- ✅ Wiki, photos, documents (already syncing)
Initial sync time:
- Stash data: 10-30 minutes
- Media files: 1-4 hours (depending on size)
- Total: 1-5 hours for first sync
Check sync status:
# On Pocket Grimoire
tail -f /var/log/pocketgrimoire-sync.log
# Verify data arrived
ls /srv/vaultpg/Green/Pocket/stash/
ls /srv/vaultpg/Green/Pocket/media/
2. Verify Synced Data
# SSH into Pocket Grimoire
ssh user@pocket-grimoire.local
# Check Stash database
ls -lh /srv/vaultpg/Green/Pocket/stash/config/
# Should show: stash-go.sqlite
# Check previews
ls /srv/vaultpg/Green/Pocket/stash/generated/ | wc -l
# Should show: hundreds of preview files
# Check media
du -sh /srv/vaultpg/Green/Pocket/media/
# Should show: 500GB-1TB
3. Create Stash Docker Compose
Create directory:
mkdir -p /srv/pocket-grimoire/stacks/stash
mkdir -p /srv/pocket-grimoire/data/stash/cache
File: /srv/pocket-grimoire/stacks/stash/docker-compose.yml
services:
stash:
image: stashapp/stash:latest
container_name: pocketgrimoire_stash
environment:
- STASH_STASH=/data/
- STASH_GENERATED=/generated/
- STASH_CACHE=/cache/
- STASH_BLOBS=/blobs/
- TZ=America/Chicago
volumes:
# Point to synced Pocket directory on GREEN drive (READ-ONLY)
- /srv/greenpg/Pocket/stash/config:/root/.stash:ro
- /srv/greenpg/Pocket/stash/generated:/generated:ro
- /srv/greenpg/Pocket/stash/blobs:/blobs:ro
# Local cache only (writable, not synced)
- /srv/pocket-grimoire/data/stash/cache:/cache
# Media location on GREEN drive (read-only)
- /srv/greenpg/Pocket/media:/data:ro
ports:
- "9999:9999" # Standard port on Pocket (no conflict)
restart: unless-stopped
Note the :ro flags - Everything except local cache is read-only.
4. Start Stash on Pocket Grimoire
cd /srv/pocket-grimoire/stacks/stash
docker compose up -d
# Check logs
docker logs -f pocketgrimoire_stash
# Verify running
docker ps | grep stash
5. Access and Verify
Access: http://pocket-grimoire.local:9999
Should see:
- Same library as Netgrimoire Stash-Pocket
- All previews available
- All scene markers working
- All metadata present
- Works fully offline
Verify read-only mode:
- Try to edit a scene → Should fail with permission error
- Try to scan library → Should fail
- Try to generate previews → Should fail
- This confirms read-only mode is working
6. Disable Background Tasks
In Stash UI:
- Settings → Tasks
- Disable all automatic tasks:
- ❌ Auto-scan
- ❌ Auto-tag
- ❌ Auto-preview generation
- ❌ Auto-cleanup
- Save settings
Why? Even though filesystem is read-only, these tasks will try to run and fail. Better to disable.
ZFS Replication Configuration
Your Existing Sync Script Already Works!
File: /usr/local/sbin/pocketgrimoire-zfs-pull.sh
Current sync (should already include this):
#!/usr/bin/env bash
set -euo pipefail
SRC_HOST="netgrimoire.local"
SSH_KEY="/srv/pocket-grimoire/keys/zfs_pull_ro"
# Sync vault/Green/Pocket to GREEN drive (greenpg/Pocket)
syncoid --no-sync-snap \
--sshkey "${SSH_KEY}" \
"root@${SRC_HOST}:vault/Green/Pocket" \
"greenpg/Pocket"
# This single command syncs:
# - /export/Green/Pocket/stash/ → Stash-Pocket data
# - /export/Green/Pocket/media/ → Media files
# All Pocket data syncs to GREEN drive automatically
No additional sync commands needed! ✅
Stash-Main data does NOT sync (it's in /export/vault/stash-main/, outside Pocket directory).
Note: The sync destination is greenpg/Pocket on the GREEN drive, NOT vaultpg. Stash and media data live on GREEN, not VAULT.
Sync Frequency
Your existing timer: Every 6 hours
This is perfect for Stash:
- Database changes sync regularly
- New previews sync automatically
- New media syncs when added
To sync immediately (before trips):
sudo systemctl start pocketgrimoire-sync.service
tail -f /var/log/pocketgrimoire-sync.log
Workflow
At Home: Adding Content for Travel
1. Curate new content:
# On Netgrimoire
cp /export/vault/media/library/movies/new-favorites/*.mp4 \
/export/vault/Green/Pocket/media/library/movies/
2. Scan Stash-Pocket:
Open: http://netgrimoire.local:9998
Tasks → Scan
Wait for completion
3. Generate previews (if needed):
Tasks → Generate → Previews
Wait for completion
4. Let sync happen (automatic):
- Next 6-hour sync cycle picks up changes
- Or trigger manually:
sudo systemctl start pocketgrimoire-sync.service
5. Verify on Pocket Grimoire:
Open: http://pocket-grimoire.local:9999
Should show new content after sync
At Home: Previewing Travel Setup
Access Stash-Pocket on Netgrimoire:
http://netgrimoire.local:9998
This shows exactly what will be available on Pocket Grimoire:
- Same library
- Same previews
- Same organization
- Test before traveling
While Traveling: Browsing Content
On Pocket Grimoire:
http://pocket-grimoire.local:9999
Features available offline:
- ✅ Browse entire Pocket library
- ✅ View all previews
- ✅ See scene markers
- ✅ Search and filter
- ✅ View performer/studio info
- ❌ Cannot edit or tag (read-only)
- ❌ Cannot scan or generate (read-only)
Play media:
- Click video in Stash
- Opens in browser player
- Or copy path and open in Jellyfin
- Or use StashApp on Onn boxes
If You Need to Edit While Traveling
VPN back to Netgrimoire:
- Connect Beryl AX to hotel WiFi
- WireGuard VPN connects to Netgrimoire
- Access Netgrimoire Stash-Pocket:
http://netgrimoire.local:9998 - Make edits there
- Changes sync on next cycle
Accessing Stash
From Web Browser
At Home (Netgrimoire):
Stash-Main (Full Library): http://netgrimoire.local:9999
Stash-Pocket (Travel Subset): http://netgrimoire.local:9998
While Traveling (Pocket Grimoire):
Stash-Pocket (Travel Subset): http://pocket-grimoire.local:9999
From Laptop (via browser):
- Connect to portapotty WiFi
- Open browser to above URLs
- Works same as Netgrimoire
From Onn Streaming Boxes
Install StashApp for Android TV:
- See "Onn 4K Streaming Box Setup Guide" for detailed instructions
- Download APK: https://github.com/damontecres/StashAppAndroidTV/releases
- Sideload onto Onn boxes
Configure StashApp:
Server URL: http://pocket-grimoire.local:9999
Or: http://10.0.0.10:9999 (if .local doesn't resolve)
API Key: (if required - found in Stash settings)
Features on Onn:
- Browse Stash library
- View previews and scene markers
- Play videos directly
- Search and filter
- Full touch/remote control
From Phone/Tablet
Via Web Browser:
Connect to portapotty WiFi
Open: http://pocket-grimoire.local:9999
Mobile-responsive interface works well
Service Access Summary
Updated with Stash:
When connected to portapotty network:
Wiki.js: http://pocket-grimoire.local:3000
Jellyfin: http://pocket-grimoire.local:8096
Stash: http://pocket-grimoire.local:9999 ← NEW
File Browser: http://pocket-grimoire.local:8080
Dozzle: http://pocket-grimoire.local:8888
SSH: ssh user@pocket-grimoire.local
NFS Media: nfs://pocket-grimoire.local/srv/mediapg
Router Admin: http://192.168.8.1
At Home (Netgrimoire):
Stash-Main: http://netgrimoire.local:9999
Stash-Pocket: http://netgrimoire.local:9998
Troubleshooting
Stash Won't Start on Pocket Grimoire
Check Docker container status:
docker ps | grep stash
docker logs pocketgrimoire_stash
Common issues:
-
ZFS datasets not mounted:
zfs list | grep Pocket sudo zfs mount -a -
Permissions denied:
ls -ld /srv/vaultpg/Green/Pocket/stash/ # Should show ownership 1000:1000 sudo chown -R 1000:1000 /srv/vaultpg/Green/Pocket/stash/ -
Port conflict:
sudo netstat -tlnp | grep 9999 # If another service is using port 9999, change in docker-compose.yml
Stash Shows "Database is locked"
This is expected - read-only mode is working correctly.
The database file is mounted read-only (:ro flag), so Stash cannot write to it.
If you need to make changes:
- VPN to Netgrimoire
- Access:
http://netgrimoire.local:9998 - Edit on Netgrimoire Stash-Pocket
- Changes sync on next cycle
Previews Not Showing on Pocket Grimoire
Verify previews synced:
ls /srv/vaultpg/Green/Pocket/stash/generated/
# Should show many .webp or .mp4 files
du -sh /srv/vaultpg/Green/Pocket/stash/generated/
# Should show several GB
If empty:
- Previews not generated on Netgrimoire yet
- Generate:
http://netgrimoire.local:9998→ Tasks → Generate
- Generate:
- Sync hasn't completed
- Check:
tail -f /var/log/pocketgrimoire-sync.log
- Check:
- Sync failed
- Check logs for errors
- Manually trigger:
sudo systemctl start pocketgrimoire-sync.service
Media Files Not Found
Check media synced:
ls /srv/vaultpg/Green/Pocket/media/library/movies/
# Should show video files
du -sh /srv/vaultpg/Green/Pocket/media/
# Should show 500GB-1TB
If empty:
- Media not in Pocket directory on Netgrimoire
- Check:
/export/vault/Green/Pocket/media/
- Check:
- Sync hasn't completed (media takes longest)
- Wait or trigger manual sync
- Check progress:
zfs list vaultpg/Green/Pocket
Verify Docker volume mount:
docker inspect pocketgrimoire_stash | grep -A 10 Mounts
# Should show /srv/vaultpg/Green/Pocket/media mounted as /data
Sync Takes Too Long
Check what's being synced:
# Watch sync progress
tail -f /var/log/pocketgrimoire-sync.log
# Check dataset sizes
zfs list | grep Pocket
Optimization tips:
-
Reduce preview quality on Netgrimoire:
- Stash-Pocket settings: Lower resolution (480p instead of 720p)
- Smaller files = faster sync
-
Sync less frequently:
- Change timer from 6h to 12h or 24h
- Edit:
/etc/systemd/system/pocketgrimoire-sync.timer
-
Compress during sync:
syncoid --compress=lz4 \ "root@${SRC_HOST}:vault/Green/Pocket" \ "vaultpg/Green/Pocket" -
Bandwidth limit (if needed):
syncoid --bwlimit=50M \ "root@${SRC_HOST}:vault/Green/Pocket" \ "vaultpg/Green/Pocket"
Stash API Key Issues (StashApp)
If StashApp asks for API key:
On Netgrimoire Stash-Pocket:
http://netgrimoire.local:9998
Settings → Security → API Key
Generate key if not present
Copy key
API key is in config file (synced to Pocket):
# On Netgrimoire
cat /export/vault/Green/Pocket/stash/config/config.yml | grep api_key
# On Pocket (after sync)
cat /srv/vaultpg/Green/Pocket/stash/config/config.yml | grep api_key
Configure StashApp:
- Settings → Server → API Key
- Paste key
- Connect
Note: API key syncs with config, so should be same on both systems.
Two Instances Conflict on Netgrimoire
Problem: Both Stash instances try to use same port
Solution: Already handled - different external ports
- Stash-Main: External 9999 → Internal 9999
- Stash-Pocket: External 9998 → Internal 9999
Verify no conflict:
sudo netstat -tlnp | grep 9999
# Should show: netgrimoire_stash_main
sudo netstat -tlnp | grep 9998
# Should show: netgrimoire_stash_pocket
Optimization Tips
Reduce Storage Usage
On Netgrimoire (affects Pocket via sync):
-
Lower preview quality for Stash-Pocket:
http://netgrimoire.local:9998 Settings → Tasks → Generate - Video resolution: 480p (instead of 720p) - Lower bitrate - Shorter duration (20s instead of 60s) -
Disable sprite generation:
Settings → Tasks → Generate - Disable sprite generation - Just use video previews - Saves significant space -
Selective preview generation:
Don't generate previews for everything Only generate for favorites or frequently viewed
Speed Up Initial Sync
First sync only:
# Use compression
syncoid --compress=lz4 \
--sshkey "${SSH_KEY}" \
"root@${NETGRIMOIRE}:vault/Green/Pocket" \
"vaultpg/Green/Pocket"
Subsequent syncs are incremental (much faster).
Reduce Preview Generation Load
On Netgrimoire:
- Generate previews during off-hours (overnight)
- Use Stash Task Scheduler
- Limit concurrent preview generation
- Lower thread count for generation
- Settings → System → Parallel Tasks: 4 (instead of 8+)
Maintenance
Weekly (While at Home)
On Netgrimoire:
# Check both Stash instances running
docker ps | grep stash
# Verify Pocket directory health
du -sh /export/vault/Green/Pocket/
zfs list | grep Pocket
# Check for database integrity (optional)
# Stash-Main: http://netgrimoire.local:9999 → Tasks → Optimize Database
# Stash-Pocket: http://netgrimoire.local:9998 → Tasks → Optimize Database
On Pocket Grimoire:
# Verify sync is working
tail -n 100 /var/log/pocketgrimoire-sync.log
# Check Stash accessible
curl -s http://localhost:9999 | grep -i stash
# Check storage usage
df -h /srv/vaultpg
Monthly
On Netgrimoire:
# Run manual scan if auto-scan disabled
# Stash-Pocket: Tasks → Scan
# Clean up orphaned files (if any)
# Tasks → Clean
# Check database integrity
# Tasks → Optimize Database
# ZFS scrub
sudo zfs scrub vault/Green/Pocket
On Pocket Grimoire:
# Verify dataset health
sudo zpool status vaultpg
# Check for errors in sync logs
grep -i error /var/log/pocketgrimoire-sync.log
# Test Stash browsing and preview playback
Before Each Trip
On Netgrimoire:
- Curate new content to Pocket media directory
- Scan Stash-Pocket to pick up new files
- Generate previews for new content
- Verify previews completed:
http://netgrimoire.local:9998 - Manually trigger sync:
sudo systemctl start pocketgrimoire-sync.service - Wait for sync completion (check logs)
- Verify on Pocket:
http://pocket-grimoire.local:9999
On Pocket Grimoire:
- Test Stash loads and browses correctly
- Test preview playback
- Test StashApp on Onn boxes connects
- Verify media files accessible
After Trips
On Pocket Grimoire:
- Check sync logs for any errors during trip
- No action needed - sync continues automatically
On Netgrimoire:
- Review what content was most useful
- Curate more similar content for next trip
- Remove old/unwanted content from Pocket directory
Comparison: Single Dataset vs Two Instances
Why Not Just One Stash Instance?
Option A: Single Stash watching everything (NOT recommended):
One Stash instance
├── Watches all media (home + pocket)
├── Huge database (slow)
├── Long scan times
└── Everything syncs (or nothing does)
Problems:
- ❌ Can't sync just travel subset
- ❌ Full database is massive (slow on Pi)
- ❌ Scanning entire library takes hours
- ❌ No clear separation of content
Option B: Two instances (RECOMMENDED - this guide):
Stash-Main Stash-Pocket
├── All media ├── Pocket media only
├── Large database ├── Small database
├── Stays on Netgrimoire ├── Syncs to Pocket
└── Full features └── Read-only on travel
Benefits:
- ✅ Clear separation of home vs travel
- ✅ Smaller Pocket database (faster, lighter)
- ✅ Only travel data syncs
- ✅ Independent organization
- ✅ Preview travel setup before trips
Summary
What You Get with Two-Instance Stash
At Home (Netgrimoire):
- ✅ Stash-Main: Full library management (port 9999)
- ✅ Stash-Pocket: Travel subset preview (port 9998)
- ✅ Heavy operations (scanning, previews) on powerful hardware
- ✅ Independent databases and organizations
On Travel (Pocket Grimoire):
- ✅ Stash-Pocket: Full browsing of travel library (port 9999)
- ✅ All previews and metadata available offline
- ✅ Zero CPU load (read-only, no generation)
- ✅ Works with StashApp on Onn boxes
- ✅ Automatic sync every 6 hours when connected
Storage:
- Vault SSD: ~510GB-1.1TB (Stash + media + other data)
- Fits comfortably on 1-2TB Vault SSD
- Stash-Main data stays on Netgrimoire (doesn't sync)
Maintenance:
- Curate travel content on Netgrimoire
- Scan and generate previews there
- Automatic sync handles replication
- Read-only consumption on travel
- No manual database management needed
What This Guide Provides
✅ Two-instance architecture (Main at home, Pocket for travel)
✅ Single sync path (everything in /export/vault/Green/Pocket/)
✅ Automatic replication (existing ZFS sync handles it)
✅ Path consistency (same relative paths on both systems)
✅ Read-only travel mode (browse only, no writes)
✅ Complete Docker Compose files for all three instances
✅ No symlinks needed (media stored directly in Pocket directory)
✅ Professional setup (separation of concerns, clear organization)
This guide supplements the main Pocket Grimoire deployment guide. Ensure main guide is completed before adding Stash.
Architecture
┌─────────────────────────────────────────┐
│ NETGRIMOIRE (Home - Heavy Lifting) │
├─────────────────────────────────────────┤
│ Stash Container: │
│ - Full scanning │
│ - Preview generation │
│ - Scene detection │
│ - Database writes │
│ - All CPU/GPU intensive work │
│ │
│ ZFS Dataset: vault/stash │
│ - Stash database │
│ - Generated previews │
│ - Thumbnails & sprites │
│ - Scene markers │
└─────────────────────────────────────────┘
↓
ZFS Send/Receive
(via syncoid every 6 hours)
↓
┌─────────────────────────────────────────┐
│ POCKET GRIMOIRE (Travel - Read Only) │
├─────────────────────────────────────────┤
│ Stash Container: │
│ - Read-only mode │
│ - No scanning │
│ - No generation │
│ - Just browse existing data │
│ │
│ ZFS Dataset: vaultpg/stash │
│ - Mirrored from Netgrimoire │
│ - Complete database replica │
│ - All previews pre-generated │
└─────────────────────────────────────────┘
Storage Requirements
On Netgrimoire
Database: 500MB - 2GB (depends on library size)
Generated previews: 5GB - 50GB (depends on preview settings)
Blobs/markers: 1GB - 10GB
───────────────────────────────────────────────────────
Total: 6.5GB - 62GB
On Pocket Grimoire
Same as Netgrimoire (full replica via ZFS)
Stored on Vault SSD (vaultpg pool)
Sync Bandwidth
- Initial sync: 10-30GB (1-2 hours on gigabit LAN)
- Incremental sync: 50MB - 500MB per 6 hours (2-10 minutes)
- After adding 10 videos: ~210MB (database + previews)
Resource Impact
Updated Resource Profile (With Stash)
Idle:
Wiki.js + PostgreSQL: ~250MB RAM
Jellyfin (idle): ~150MB RAM
Stash (read-only): ~200MB RAM # Much lighter than active Stash
ZFS ARC: ~512MB RAM
System: ~200MB RAM
─────────────────────────────────────────
Total: ~1.3GB / 8GB RAM ✓
CPU: <10%
Temperature: Cool
Browsing Stash:
Stash (active): ~300MB RAM
Other services: ~1.1GB RAM
─────────────────────────────────────────
Total: ~1.4GB / 8GB RAM ✓
CPU: <15%
Temperature: Cool to Warm
Media Playback + Stash Browsing:
Jellyfin (serving): ~200MB RAM
Stash (active): ~300MB RAM
Wiki.js + PostgreSQL: ~250MB RAM
ZFS ARC: ~512MB RAM
System: ~200MB RAM
─────────────────────────────────────────
Total: ~1.5GB / 8GB RAM ✓
Still plenty of headroom
Installation: Netgrimoire (Home)
1. Create ZFS Datasets
# On Netgrimoire
sudo zfs create -o recordsize=16K vault/stash
sudo zfs create -o recordsize=16K vault/stash/config # Database
sudo zfs create -o recordsize=1M vault/stash/generated # Previews
sudo zfs create -o recordsize=128K vault/stash/blobs # Scene markers
sudo zfs create vault/stash/cache # Temporary (won't replicate)
# Set appropriate permissions
sudo chown -R 1000:1000 /vault/stash
Why different recordsizes:
- 16K for config (SQLite database performs best with small records)
- 1M for generated (large video preview files)
- 128K for blobs (medium-sized screenshots and markers)
2. Create Stash Docker Compose
mkdir -p /srv/netgrimoire/stacks/stash
nano /srv/netgrimoire/stacks/stash/docker-compose.yml
services:
stash:
image: stashapp/stash:latest
container_name: netgrimoire_stash
environment:
- STASH_STASH=/data/
- STASH_GENERATED=/generated/
- STASH_CACHE=/cache/
- STASH_BLOBS=/blobs/
- TZ=America/Chicago
volumes:
- /vault/stash/config:/root/.stash
- /vault/stash/generated:/generated
- /vault/stash/cache:/cache
- /vault/stash/blobs:/blobs
- /vault/media:/data:ro # Your media library (read-only)
ports:
- "9999:9999"
restart: unless-stopped
Start Stash:
cd /srv/netgrimoire/stacks/stash
docker compose up -d
3. Configure Stash
-
Access Stash:
- Open browser:
http://netgrimoire.local:9999 - Complete initial setup wizard
- Open browser:
-
Add Library:
- Settings → Library
- Add folder:
/data/library/movies(or your media path) - Save
-
Configure Previews:
- Settings → Tasks → Generate
- Preview Generation: Enable
- Preview Settings:
- Video encoding: VP9 or H.264
- Resolution: 720p (good quality, reasonable size)
- Segment duration: 10 seconds
- Generate image previews: Enable
- Generate sprites: Enable
-
Run Initial Scan:
- Tasks → Scan
- Wait for completion (can take hours depending on library size)
-
Generate Previews:
- Tasks → Generate → Generate Previews
- This is CPU intensive - let run at home
- Can take many hours depending on library size
-
Optional: Scene Detection:
- Tasks → Generate → Auto Tag
- Scene detection, performer matching, etc.
- Very CPU intensive, run at home only
4. Take ZFS Snapshots (Optional but Recommended)
# After initial scan and preview generation
sudo zfs snapshot vault/stash/config@initial
sudo zfs snapshot vault/stash/generated@initial
sudo zfs snapshot vault/stash/blobs@initial
Installation: Pocket Grimoire (Travel)
1. Create ZFS Datasets
# On Pocket Grimoire
sudo zfs create -o recordsize=16K vaultpg/stash
sudo zfs create -o recordsize=16K vaultpg/stash/config
sudo zfs create -o recordsize=1M vaultpg/stash/generated
sudo zfs create -o recordsize=128K vaultpg/stash/blobs
sudo zfs create vaultpg/stash/cache # Local cache only, not synced
# Set permissions
sudo chown -R 1000:1000 /srv/vaultpg/stash
2. Create Stash Docker Compose (Read-Only)
mkdir -p /srv/pocket-grimoire/stacks/stash
nano /srv/pocket-grimoire/stacks/stash/docker-compose.yml
services:
stash:
image: stashapp/stash:latest
container_name: pocketgrimoire_stash
environment:
- STASH_STASH=/data/
- STASH_GENERATED=/generated/
- STASH_CACHE=/cache/
- STASH_BLOBS=/blobs/
- TZ=America/Chicago
volumes:
- /srv/vaultpg/stash/config:/root/.stash:ro # READ-ONLY
- /srv/vaultpg/stash/generated:/generated:ro # READ-ONLY
- /srv/vaultpg/stash/blobs:/blobs:ro # READ-ONLY
- /srv/pocket-grimoire/data/stash/cache:/cache # Local cache (writable)
- /srv/mediapg:/data:ro # Media (already present, read-only)
ports:
- "9999:9999"
restart: unless-stopped
Note the :ro flags - Filesystem is mounted read-only, preventing any writes.
Start Stash:
cd /srv/pocket-grimoire/stacks/stash
docker compose up -d
3. Configure Stash for Read-Only Operation
After first start:
-
Access Stash:
- Open browser:
http://pocket-grimoire.local:9999 - Should show library from Netgrimoire (after first sync)
- Open browser:
-
Disable Background Tasks:
- Settings → Tasks
- Disable all automatic tasks:
- ❌ Auto-scan
- ❌ Auto-tag
- ❌ Auto-preview generation
- ❌ Auto-cleanup
-
Verify Read-Only:
- Try to edit a scene or performer
- Should fail with permission error
- This confirms read-only mode working
ZFS Replication Configuration
Update Sync Script
Edit your existing sync script to include Stash datasets:
sudo nano /usr/local/sbin/pocketgrimoire-zfs-pull.sh
Add these lines:
#!/usr/bin/env bash
set -euo pipefail
SRC_HOST="netgrimoire.local"
SSH_KEY="/srv/pocket-grimoire/keys/zfs_pull_ro"
# Existing vault data syncs...
syncoid --no-sync-snap --recursive \
--sshkey "${SSH_KEY}" \
"root@${SRC_HOST}:vault/docs" \
"vaultpg/mirror/docs"
syncoid --no-sync-snap --recursive \
--sshkey "${SSH_KEY}" \
"root@${SRC_HOST}:vault/photos" \
"vaultpg/mirror/photos"
# NEW: Stash database and generated content
syncoid --no-sync-snap \
--sshkey "${SSH_KEY}" \
"root@${SRC_HOST}:vault/stash/config" \
"vaultpg/stash/config"
syncoid --no-sync-snap \
--sshkey "${SSH_KEY}" \
"root@${SRC_HOST}:vault/stash/generated" \
"vaultpg/stash/generated"
syncoid --no-sync-snap \
--sshkey "${SSH_KEY}" \
"root@${SRC_HOST}:vault/stash/blobs" \
"vaultpg/stash/blobs"
# Note: We skip cache dataset (temporary data, not needed on Pocket)
Sync runs automatically every 6 hours via existing systemd timer.
Manual Sync (For Testing)
# Trigger sync immediately
sudo systemctl start pocketgrimoire-sync.service
# Watch progress
tail -f /var/log/pocketgrimoire-sync.log
# Verify Stash data synced
ls -lh /srv/vaultpg/stash/config
ls -lh /srv/vaultpg/stash/generated
Media Path Consistency
Critical: Media paths must be consistent between Netgrimoire and Pocket Grimoire.
Option 1: Matching Paths
If your media is in same location:
Netgrimoire: /vault/media/library/
Pocket: /srv/mediapg/library/
Stash stores absolute paths - ensure they match or use symlinks.
Option 2: Symlinks
# On Pocket Grimoire
sudo ln -s /srv/mediapg /vault/media
This makes /vault/media point to /srv/mediapg, matching Netgrimoire's paths.
Option 3: Stash Path Mapping (If Stash supports it)
Some versions of Stash support path mapping in config. Check Stash documentation.
Workflow
At Home (Before Trips)
On Netgrimoire:
- Add new media to library
- Stash auto-scans (or trigger manually)
- Previews generate automatically (or trigger manually)
- Tag/organize content as desired
- Everything happens in background
Pocket Grimoire (automatic):
- Every 6 hours: syncoid pulls changes from Netgrimoire
- Stash database updated
- New previews synced
- Scene markers updated
- Ready for next trip - no manual intervention
While Traveling
On Pocket Grimoire:
- Access Stash:
http://pocket-grimoire.local:9999 - Browse library, tags, performers, studios
- View previews and scene markers
- Click to play via Jellyfin or external player
- Cannot: Scan, edit tags, generate previews (read-only)
If you need to edit:
- VPN back to Netgrimoire (via WireGuard)
- Access Netgrimoire Stash:
http://netgrimoire.local:9999 - Make changes there
- Changes sync on next 6-hour cycle
After Returning Home
- Sync happens automatically
- Any changes made on Netgrimoire while away are pulled
- Pocket Grimoire stays up-to-date
- No manual intervention required
Accessing Stash
From Onn Streaming Boxes
Install StashApp for Android TV:
- See "Onn 4K Streaming Box Setup Guide" for detailed instructions
- Download APK from: https://github.com/damontecres/StashAppAndroidTV/releases
- Sideload onto Onn boxes
- Configure server:
http://pocket-grimoire.local:9999
From Laptop
Via Web Browser:
- Open:
http://pocket-grimoire.local:9999 - Full Stash web interface available
- Same as Netgrimoire, but read-only
From Phone/Tablet
Via Web Browser:
- Connect to portapotty WiFi
- Open:
http://pocket-grimoire.local:9999 - Mobile-responsive interface
Updated Service Access Summary
When connected to portapotty network:
Wiki.js: http://pocket-grimoire.local:3000
Jellyfin: http://pocket-grimoire.local:8096
Stash: http://pocket-grimoire.local:9999 ← NEW
File Browser: http://pocket-grimoire.local:8080
Dozzle: http://pocket-grimoire.local:8888
SSH: ssh user@pocket-grimoire.local
NFS Media: nfs://pocket-grimoire.local/srv/mediapg
Router Admin: http://192.168.8.1
Troubleshooting
Stash Won't Start
Check Docker container status:
docker ps | grep stash
docker logs pocketgrimoire_stash
Common issues:
- ZFS datasets not mounted:
zfs mount -a - Permission denied:
sudo chown -R 1000:1000 /srv/vaultpg/stash - Port conflict: Another service using port 9999
Stash Shows "Database is locked"
This means read-only mode is working correctly.
If you need to make changes:
- VPN to Netgrimoire
- Edit on Netgrimoire Stash
- Changes sync to Pocket on next cycle
Previews Not Showing
Verify previews synced:
ls /srv/vaultpg/stash/generated/
# Should show many .webp or .mp4 files
If empty:
- Previews not generated on Netgrimoire yet
- Sync hasn't completed (check sync logs)
- Check:
tail -n 200 /var/log/pocketgrimoire-sync.log
Media Files Not Found
Check paths match:
# On Netgrimoire, Stash sees files at:
# /vault/media/library/movies/
# On Pocket, files are at:
# /srv/mediapg/library/movies/
# Create symlink to match:
sudo ln -s /srv/mediapg /vault/media
Or verify Docker volume mount:
docker inspect pocketgrimoire_stash | grep -A 10 Mounts
# Should show /srv/mediapg mounted as /data
Sync Takes Too Long
Check what's being synced:
# Watch sync in progress
sudo zfs list -t snapshot | grep stash
# Check dataset sizes
sudo zfs list | grep stash
Optimization:
- Reduce preview quality on Netgrimoire (smaller files)
- Sync less frequently (change timer from 6h to 12h)
- Only sync when on fast network (manual trigger)
Stash API Key Issues
If StashApp asks for API key:
-
Find API key on Netgrimoire:
# On Netgrimoire cat /vault/stash/config/config.yml | grep api_key -
Or via Stash web UI:
- Settings → Security → API Key
- Generate key if not present
- Copy key
-
Configure StashApp:
- Settings → Server → API Key
- Paste key from Netgrimoire
Note: API key is in config, which syncs to Pocket, so should be the same.
Optimization Tips
Reduce Storage Usage
On Netgrimoire (affects Pocket via sync):
-
Lower preview quality:
- Settings → Tasks → Generate
- Video resolution: 480p instead of 720p
- Lower bitrate
- Smaller file sizes = faster sync
-
Disable sprite generation:
- Settings → Tasks → Generate
- Disable sprite generation (just use video previews)
- Saves significant space
-
Limit preview duration:
- Settings → Tasks → Generate
- Preview duration: 20 seconds instead of 60 seconds
- Smaller files
Speed Up Sync
Initial sync optimization:
# First sync: Compress during transfer
syncoid --compress=lz4 \
--sshkey "${SSH_KEY}" \
"root@${SRC_HOST}:vault/stash/generated" \
"vaultpg/stash/generated"
Bandwidth limiting (if needed):
# Limit to 10MB/s
syncoid --bwlimit=10M \
--sshkey "${SSH_KEY}" \
"root@${SRC_HOST}:vault/stash/config" \
"vaultpg/stash/config"
Reduce Preview Generation Load
On Netgrimoire:
- Generate previews during off-hours (nightly)
- Use Task Scheduler in Stash
- Limit concurrent preview generation
- Lower thread count for generation
Maintenance
Weekly
On Netgrimoire:
- Check Stash is running:
docker ps | grep stash - Verify previews generating (if auto-enabled)
- Check disk usage:
zfs list | grep stash
On Pocket Grimoire:
- Verify sync is working:
tail /var/log/pocketgrimoire-sync.log - Check Stash is accessible:
http://pocket-grimoire.local:9999
Monthly
On Netgrimoire:
- Run manual scan if auto-scan disabled
- Clean up orphaned files: Tasks → Clean
- Check database integrity: Tasks → Optimize Database
- ZFS scrub:
sudo zfs scrub vault/stash
On Pocket Grimoire:
- Verify dataset health:
sudo zpool status vaultpg - Check sync logs for errors
- Test Stash browsing and preview playback
Before Trips
- Run scan on Netgrimoire (capture new content)
- Generate previews for new content
- Verify sync completed successfully
- Test Stash on Pocket Grimoire
- Verify StashApp on Onn boxes connects
After Trips
- Check sync logs for any errors during trip
- No action needed - sync continues automatically
Alternative: Manual Database Export (Not Recommended)
If ZFS replication is not available:
You can manually export/import Stash database:
# On Netgrimoire - Export
sqlite3 /vault/stash/config/stash-go.sqlite ".backup /tmp/stash-backup.db"
scp /tmp/stash-backup.db pocket-grimoire:/tmp/
# On Pocket Grimoire - Import
docker compose down
cp /tmp/stash-backup.db /srv/vaultpg/stash/config/stash-go.sqlite
docker compose up -d
Why this is not recommended:
- Manual process (error-prone)
- Doesn't sync previews/blobs automatically
- Must copy those separately (tens of GB)
- ZFS replication is much cleaner
Summary
What you get with Stash on Pocket Grimoire:
- ✅ Full Stash browsing offline
- ✅ All previews and metadata available
- ✅ Zero CPU load on Pi (read-only)
- ✅ Automatic synchronization
- ✅ Professional media library management
- ✅ Scene markers and performer tagging
- ✅ Works with StashApp on Onn boxes
What you give up:
- ❌ Cannot edit/tag while traveling (must VPN to Netgrimoire)
- ❌ Cannot generate previews on travel (shouldn't anyway)
- ❌ 10-30GB additional storage on Vault SSD
- ❌ Slightly more complex setup (but worth it)
Recommended for:
- Large media libraries that need organization
- Users who want professional media management
- Those who already use or want to use Stash
- Anyone who values rich metadata and previews
Skip if:
- Just want simple media playback (Jellyfin is enough)
- Very limited storage on Vault SSD
- Don't want complexity of ZFS replication
- Don't need tagging/scene detection features
This guide supplements the main Pocket Grimoire deployment guide. Ensure main guide is completed before adding Stash.