docs: update Netgrimoire/Pocket/Deployment_Guide

This commit is contained in:
Administrator 2026-02-21 04:26:10 +00:00 committed by John Smith
parent 513b1e729b
commit 9327335fb8

View file

@ -2,7 +2,7 @@
title: Pocket Grimoire
description:
published: true
date: 2026-02-20T04:54:31.450Z
date: 2026-02-21T04:25:58.904Z
tags:
editor: markdown
dateCreated: 2026-02-20T04:41:35.122Z
@ -502,35 +502,33 @@ sudo apt install -y zfsutils-linux
sudo zpool list
```
### 4. Configure ZFS Pools
### 4. Initial Drive Setup on Netgrimoire (Before Moving to Pocket)
**Important:** Replace `/dev/sdX` with your actual device identifiers. Use `lsblk` to identify drives.
**IMPORTANT: Build drives on Netgrimoire first, then move to Pocket Grimoire.**
**Create Vault Pool (Always Connected):**
This approach allows you to:
- Create encrypted pools with proper passphrases
- Perform initial ZFS sync while drives are fast-connected (SATA/USB 3.0)
- Verify data integrity before moving drives
- Test encryption/unlock on powerful hardware first
#### On Netgrimoire: Create and Populate Drives
**Connect drives to Netgrimoire:**
- VAULT SSD (1-2TB) via USB 3.0 or SATA
- MEDIA-PERSONAL SSD (2TB+) via USB 3.0 or SATA
- MEDIA-FAMILY SSD (2TB+) via USB 3.0 or SATA (optional, can be created later)
**Identify drives:**
```bash
# Identify Vault SSD
# On Netgrimoire
lsblk
# Create encrypted ZFS pool
sudo zpool create -o ashift=12 \
-O encryption=on \
-O keylocation=prompt \
-O keyformat=passphrase \
-O compression=lz4 \
-O atime=off \
-O recordsize=1M \
-m /srv/vaultpg \
vaultpg /dev/sdX
# Create datasets
sudo zfs create -o recordsize=16K vaultpg/wiki-pg # PostgreSQL
sudo zfs create vaultpg/repos # Git repos
sudo zfs create vaultpg/pocket-grimoire # App data
# Note device names: /dev/sdX, /dev/sdY, /dev/sdZ
```
**Create Media Pool (Rotated):**
**Create VAULT pool (encrypted):**
```bash
# For Personal Media SSD
# On Netgrimoire
sudo zpool create -o ashift=12 \
-O encryption=on \
-O keylocation=prompt \
@ -538,23 +536,184 @@ sudo zpool create -o ashift=12 \
-O compression=lz4 \
-O atime=off \
-O recordsize=1M \
-m /srv/mediapg \
mediapg /dev/sdY
-m /mnt/pocket-vault \
pocket-vault /dev/sdX
sudo zfs create mediapg/library
sudo zfs create mediapg/library/movies
sudo zfs create mediapg/library/tv
# Enter STRONG passphrase when prompted
# Write down this passphrase - you'll need it on Pocket Grimoire
# For Family Media SSD (unencrypted)
# When swapping drives:
sudo zpool export mediapg
# Connect family SSD
# Create datasets matching Pocket structure
sudo zfs create -o recordsize=16K pocket-vault/wiki-pg
sudo zfs create pocket-vault/repos
sudo zfs create pocket-vault/pocket-grimoire
sudo zfs create pocket-vault/Green
sudo zfs create pocket-vault/Green/Pocket
sudo zfs create pocket-vault/Green/Pocket/stash
sudo zfs create pocket-vault/Green/Pocket/media
sudo zfs create pocket-vault/veracrypt-containers
# Set ownership
sudo chown -R 1000:1000 /mnt/pocket-vault
```
**Create MEDIA-PERSONAL pool (encrypted):**
```bash
# On Netgrimoire
sudo zpool create -o ashift=12 \
-O encryption=on \
-O keylocation=prompt \
-O keyformat=passphrase \
-O compression=lz4 \
-O atime=off \
-O recordsize=1M \
-m /mnt/pocket-media-personal \
pocket-media-personal /dev/sdY
# Enter STRONG passphrase (can be different from VAULT)
# Write down this passphrase
# Create datasets
sudo zfs create pocket-media-personal/library
sudo zfs create pocket-media-personal/library/movies
sudo zfs create pocket-media-personal/library/tv
# Set ownership
sudo chown -R 1000:1000 /mnt/pocket-media-personal
```
**Create MEDIA-FAMILY pool (unencrypted, optional now or later):**
```bash
# On Netgrimoire
sudo zpool create -o ashift=12 \
-O compression=lz4 \
-O atime=off \
-O recordsize=1M \
-m /srv/mediapg \
mediapg /dev/sdY
-m /mnt/pocket-media-family \
pocket-media-family /dev/sdZ
# No encryption - family can use this drive on any system
# Create datasets
sudo zfs create pocket-media-family/library
sudo zfs create pocket-media-family/library/movies
sudo zfs create pocket-media-family/library/tv
# Set ownership
sudo chown -R 1000:1000 /mnt/pocket-media-family
```
**Perform initial sync to VAULT:**
```bash
# On Netgrimoire
# Sync data from Netgrimoire to Pocket VAULT drive
# Sync Pocket directory structure
sudo rsync -avP --exclude='cache' \
/export/vault/Green/Pocket/ \
/mnt/pocket-vault/Green/Pocket/
# Or use ZFS send/receive for atomic snapshot
sudo zfs snapshot vault/Green/Pocket@initial
sudo zfs send vault/Green/Pocket@initial | \
sudo zfs receive pocket-vault/Green/Pocket
# Verify data
ls -lh /mnt/pocket-vault/Green/Pocket/
du -sh /mnt/pocket-vault/Green/Pocket/
```
**Populate MEDIA-PERSONAL (optional - curate content):**
```bash
# On Netgrimoire
# Copy curated personal media to Pocket media drive
# Example: Copy favorite movies
sudo cp /export/vault/media/library/movies/favorites/*.mp4 \
/mnt/pocket-media-personal/library/movies/
# Or use rsync for large transfers
sudo rsync -avP \
/export/vault/media/library/tv/FavoriteShow/ \
/mnt/pocket-media-personal/library/tv/FavoriteShow/
# Verify
du -sh /mnt/pocket-media-personal/library/
```
**Export pools before disconnecting:**
```bash
# On Netgrimoire
# CRITICAL: Export pools before physically disconnecting drives
sudo zpool export pocket-vault
sudo zpool export pocket-media-personal
sudo zpool export pocket-media-family # if created
# Verify exported
zpool list
# Should NOT show pocket-* pools
```
**Physically disconnect drives from Netgrimoire.**
### 5. Configure ZFS Pools on Pocket Grimoire
**Now connect drives to Pocket Grimoire:**
- VAULT → Anker USB-A port #2
- MEDIA-PERSONAL or MEDIA-FAMILY → Raspberry Pi USB 3.0 port
**Import and rename pools:**
```bash
# On Pocket Grimoire (SSH into Pi)
ssh user@pocket-grimoire.local
# Import VAULT pool with new name
sudo zpool import pocket-vault vaultpg
# Import MEDIA pool with new name
sudo zpool import pocket-media-personal mediapg
# Or:
# sudo zpool import pocket-media-family mediapg
# Verify pools imported
zpool list
# Should show: vaultpg, mediapg
```
**Set mount points for Pocket Grimoire:**
```bash
# Set proper mount points
sudo zfs set mountpoint=/srv/vaultpg vaultpg
sudo zfs set mountpoint=/srv/mediapg mediapg
# Create mount points
sudo mkdir -p /srv/vaultpg
sudo mkdir -p /srv/mediapg
# Unmount and remount with new paths
sudo zfs unmount -a
sudo zfs mount -a
# Verify mounted
df -h | grep srv
# Should show:
# vaultpg mounted on /srv/vaultpg
# mediapg mounted on /srv/mediapg
# Verify data
ls /srv/vaultpg/Green/Pocket/
ls /srv/mediapg/library/
```
**Configure for headless unlock:**
```bash
# Set pools to NOT auto-mount on boot
# This prevents boot hanging waiting for passphrase
sudo zfs set canmount=noauto vaultpg
sudo zfs set canmount=noauto mediapg
# Pools will need manual unlock via SSH after boot
```
**Cap ZFS ARC Memory:**
@ -565,10 +724,248 @@ sudo nano /etc/modprobe.d/zfs.conf
# Add this line (for 8GB Pi, cap at 1GB):
options zfs zfs_arc_max=1073741824
# Reboot to apply
# Save and apply
sudo update-initramfs -u
sudo reboot
```
### 6. Create Headless Unlock Script
**After reboot, SSH back in and create unlock script:**
```bash
sudo nano /usr/local/sbin/unlock-pocket-grimoire.sh
```
```bash
#!/bin/bash
# Unlock Pocket Grimoire encrypted ZFS pools (headless operation)
set -e
echo "=========================================="
echo " Pocket Grimoire ZFS Unlock (Headless)"
echo "=========================================="
echo
# Check if pools are already unlocked
if zfs list vaultpg &>/dev/null && mount | grep -q /srv/vaultpg; then
echo "✓ vaultpg already unlocked and mounted"
else
# Import pool if needed
if ! zpool list vaultpg &>/dev/null; then
echo "Importing vaultpg pool..."
sudo zpool import vaultpg
fi
# Unlock Vault pool
echo "Unlocking vaultpg (VAULT SSD)..."
sudo zfs load-key vaultpg
# Mount all vaultpg datasets
sudo zfs mount vaultpg
sudo zfs mount -a
if mount | grep -q /srv/vaultpg; then
echo "✓ vaultpg unlocked and mounted at /srv/vaultpg"
else
echo "✗ Failed to mount vaultpg"
exit 1
fi
fi
echo
# Check if media pool is present and unlock
if zpool list mediapg &>/dev/null; then
if zfs list mediapg &>/dev/null && mount | grep -q /srv/mediapg; then
echo "✓ mediapg already unlocked and mounted"
else
echo "Unlocking mediapg (MEDIA-PERSONAL or MEDIA-FAMILY)..."
# Check if encrypted (MEDIA-PERSONAL) or not (MEDIA-FAMILY)
if zfs get encryption mediapg | grep -q "encryption.*on"; then
sudo zfs load-key mediapg
fi
sudo zfs mount mediapg
sudo zfs mount -a
if mount | grep -q /srv/mediapg; then
echo "✓ mediapg unlocked and mounted at /srv/mediapg"
else
echo "✗ Failed to mount mediapg"
exit 1
fi
fi
else
echo " mediapg pool not found (media drive may not be connected)"
fi
echo
# Optional: Mount VeraCrypt containers
if [ -f /usr/local/sbin/mount-veracrypt-vault.sh ]; then
echo "VeraCrypt container found. Mount now? (y/n)"
read -r response
if [[ "$response" == "y" ]]; then
/usr/local/sbin/mount-veracrypt-vault.sh
fi
fi
echo
echo "=========================================="
echo " Starting Docker Services"
echo "=========================================="
echo
# Start Docker service
if ! systemctl is-active --quiet docker; then
echo "Starting Docker..."
sudo systemctl start docker
sleep 3
fi
# Start containers
echo "Starting Wiki.js stack..."
cd /srv/pocket-grimoire/stacks/wikijs && docker compose up -d
echo "Starting Jellyfin stack..."
cd /srv/pocket-grimoire/stacks/jellyfin && docker compose up -d
echo "Starting Stash stack..."
if [ -d /srv/pocket-grimoire/stacks/stash ]; then
cd /srv/pocket-grimoire/stacks/stash && docker compose up -d
fi
# Optional containers
if [ -d /srv/pocket-grimoire/stacks/filebrowser ]; then
echo "Starting File Browser..."
cd /srv/pocket-grimoire/stacks/filebrowser && docker compose up -d
fi
echo
echo "=========================================="
echo " Pocket Grimoire Ready!"
echo "=========================================="
echo
echo "Services available at:"
echo " Wiki.js: http://pocket-grimoire.local:3000"
echo " Jellyfin: http://pocket-grimoire.local:8096"
echo " Stash: http://pocket-grimoire.local:9999"
echo " File Browser: http://pocket-grimoire.local:8080"
echo
echo "Total unlock time: $(($SECONDS / 60)) minutes $(($SECONDS % 60)) seconds"
echo
```
```bash
sudo chmod +x /usr/local/sbin/unlock-pocket-grimoire.sh
```
### 7. Disable Docker Auto-Start (Headless Configuration)
**Prevent Docker from starting before ZFS pools are unlocked:**
```bash
# Disable Docker auto-start on boot
sudo systemctl disable docker
# Docker will be started manually by unlock script
```
**Or, configure Docker to wait for ZFS (if you prefer):**
```bash
sudo mkdir -p /etc/systemd/system/docker.service.d
sudo nano /etc/systemd/system/docker.service.d/wait-for-zfs.conf
```
```ini
[Unit]
# Don't start Docker until after manual ZFS unlock
After=zfs-mount.service
Wants=zfs-mount.service
[Service]
# Restart Docker if it fails (ZFS not ready)
Restart=on-failure
RestartSec=10
```
```bash
sudo systemctl daemon-reload
```
**Recommended: Just disable auto-start and use unlock script.**
### 8. Test Headless Unlock Procedure
**Test at home before traveling:**
```bash
# 1. Reboot Pi
sudo reboot
# 2. Wait 2-3 minutes for boot (don't connect monitor/keyboard)
# 3. SSH from laptop
ssh user@pocket-grimoire.local
# 4. Run unlock script
/usr/local/sbin/unlock-pocket-grimoire.sh
# Enter passphrases when prompted:
# - VAULT passphrase
# - MEDIA-PERSONAL passphrase (if encrypted)
# - VeraCrypt password (if using)
# 5. Wait for Docker containers to start
# 6. Verify services running
docker ps
# 7. Access from browser
# http://pocket-grimoire.local:3000
# http://pocket-grimoire.local:8096
# http://pocket-grimoire.local:9999
# 8. Verify data accessible
ls /srv/vaultpg/Green/Pocket/
ls /srv/mediapg/library/
```
**If everything works, you're ready for travel!**
### 9. Quick Manual Unlock (If Script Fails)
```bash
# SSH into Pocket Grimoire
ssh user@pocket-grimoire.local
# Import pools if needed
sudo zpool import vaultpg
sudo zpool import mediapg
# Load encryption keys
sudo zfs load-key vaultpg
sudo zfs load-key mediapg # Only if MEDIA-PERSONAL (encrypted)
# Mount all datasets
sudo zfs mount -a
# Verify mounted
df -h | grep srv
# Start Docker
sudo systemctl start docker
# Start containers manually
cd /srv/pocket-grimoire/stacks/wikijs && docker compose up -d
cd /srv/pocket-grimoire/stacks/jellyfin && docker compose up -d
cd /srv/pocket-grimoire/stacks/stash && docker compose up -d
```
**Configure ZFS to Wait for Passphrase on Boot:**
```bash
# Edit /etc/systemd/system/zfs-load-key.service
@ -1319,24 +1716,70 @@ sudo umount /mnt/pocket-media
### 8. Document Passphrases
- [ ] ZFS encryption passphrases (written down, secured)
- VAULT (vaultpg): [write passphrase on paper]
- MEDIA-PERSONAL (mediapg): [write passphrase on paper]
- MEDIA-FAMILY: N/A (unencrypted)
- [ ] VeraCrypt container passwords (if using, written down, secured)
- [ ] WiFi credentials for travel router (portapotty network)
- [ ] Jellyfin admin password
- [ ] Wiki.js admin password
- [ ] Stash admin password
- [ ] Keep all passphrases in secure location separate from device
### 9. Test VeraCrypt Containers (If Using)
### 9. Test Headless Unlock Procedure (CRITICAL)
```bash
# Verify container can mount
sudo veracrypt --text --mount \
/srv/vaultpg/veracrypt-containers/vault.vc \
/mnt/veracrypt/vault1
# At home, test the exact hotel deployment workflow
# Access files
ls /mnt/veracrypt/vault1
# 1. Reboot Pi without monitor/keyboard attached
sudo reboot
# Unmount
sudo veracrypt --text --dismount /mnt/veracrypt/vault1
# 2. Wait 2-3 minutes for boot
# 3. SSH from laptop
ssh user@pocket-grimoire.local
# 4. Run unlock script
/usr/local/sbin/unlock-pocket-grimoire.sh
# 5. Enter passphrases when prompted
# - VAULT passphrase
# - MEDIA-PERSONAL passphrase (if encrypted)
# - VeraCrypt password (if applicable)
# 6. Wait for Docker containers to start (~30 seconds)
# 7. Verify all services running
docker ps
# 8. Test access from browser
# http://pocket-grimoire.local:3000 (Wiki.js)
# http://pocket-grimoire.local:8096 (Jellyfin)
# http://pocket-grimoire.local:9999 (Stash)
# 9. Test media playback in Jellyfin
# 10. Test Stash preview playback
# 11. Test NFS mount from laptop (optional)
```
**If anything fails during this test, debug at home before traveling!**
### 10. Verify Data Synced from Netgrimoire
```bash
# Check Vault data present
ls /srv/vaultpg/Green/Pocket/stash/
ls /srv/vaultpg/Green/Pocket/media/
du -sh /srv/vaultpg/Green/Pocket/
# Check media drive populated (if applicable)
ls /srv/mediapg/library/
du -sh /srv/mediapg/
# Verify Stash database and previews
ls -lh /srv/vaultpg/Green/Pocket/stash/config/
# Should show: stash-go.sqlite
ls /srv/vaultpg/Green/Pocket/stash/generated/ | wc -l
# Should show: hundreds of preview files
```
---
@ -1347,52 +1790,109 @@ sudo veracrypt --text --dismount /mnt/veracrypt/vault1
### Physical Setup (5 minutes)
1. Unpack Pocket Grimoire enclosure
2. Connect Beryl AX to hotel WiFi (configure via phone app)
3. Connect Pi to Beryl AX via Ethernet
2. Connect Beryl AX to hotel WiFi (configure via phone app or admin panel)
3. Connect Pi to Beryl AX via Ethernet (CAT5 cable)
4. Plug Anker Prime into wall outlet
5. Connect all USB devices to Anker Prime
5. Connect all USB devices to Anker Prime:
- VAULT SSD → Anker USB-A port #2
- Media SSD (PERSONAL or FAMILY) → Pi USB 3.0 port
- Beryl AX → Anker USB-C retractable port
- Pi → Anker USB-A port #1
6. Power on (wait 2-3 minutes for boot)
### ZFS Unlock (2 minutes)
### SSH Connection (1 minute)
```bash
# From laptop (connected to portapotty WiFi)
ssh user@pocket-grimoire.local
# If .local doesn't work, find Pi's IP:
# - Check Beryl AX admin: http://192.168.8.1
# - Look for "pocket-grimoire" in client list
# - SSH via IP: ssh user@192.168.8.50
```
### ZFS Unlock (2-3 minutes)
```bash
# Run unlock script
/usr/local/sbin/unlock-pocket-grimoire.sh
# Script will prompt for passphrases:
# Enter passphrase for 'vaultpg': [type VAULT passphrase]
# Enter passphrase for 'mediapg': [type MEDIA-PERSONAL passphrase]
# (MEDIA-FAMILY is unencrypted, no passphrase needed)
# Script automatically:
# - Unlocks ZFS pools
# - Mounts all datasets
# - Starts Docker service
# - Starts all containers (Wiki.js, Jellyfin, Stash)
# - Displays service URLs
# Total unlock time: ~2-3 minutes
```
### Verify Services (1 minute)
### Verify Services (1 minute)
```bash
# Check Docker containers running
docker ps
# Should show:
# pocketgrimoire_wikijs
# pocketgrimoire_db
# pocketgrimoire_jellyfin
# pocketgrimoire_stash
# Check ZFS pools mounted
df -h | grep srv
# Should show:
# vaultpg mounted on /srv/vaultpg
# mediapg mounted on /srv/mediapg
```
### Access Services (1 minute)
**From laptop browser (connected to portapotty WiFi):**
- Wiki.js: `http://pocket-grimoire.local:3000`
- Jellyfin: `http://pocket-grimoire.local:8096`
- Stash: `http://pocket-grimoire.local:9999`
- File Browser: `http://pocket-grimoire.local:8080` (if enabled)
**From Onn Streaming Boxes:**
- Configure Jellyfin app: Server `http://pocket-grimoire.local:8096`
- Configure StashApp: Server `http://pocket-grimoire.local:9999`
**Total setup time: ~10-12 minutes**
### If Unlock Script Fails
**Manual unlock procedure:**
```bash
# SSH into Pi
ssh user@pocket-grimoire.local
# If ZFS pools didn't auto-unlock, unlock manually
# Import pools
sudo zpool import vaultpg
sudo zpool import mediapg
# Load encryption keys
sudo zfs load-key vaultpg
sudo zfs load-key mediapg # Only if MEDIA-PERSONAL (encrypted)
# Mount datasets
sudo zfs mount -a
sudo zfs load-key mediapg
sudo zfs mount -a
# Verify
df -h | grep srv
# Verify pools mounted
zfs list
# Start Docker
sudo systemctl start docker
# Start containers
cd /srv/pocket-grimoire/stacks/wikijs && docker compose up -d
cd /srv/pocket-grimoire/stacks/jellyfin && docker compose up -d
cd /srv/pocket-grimoire/stacks/stash && docker compose up -d
```
### VeraCrypt Mount (Optional, 1 minute)
```bash
# If using VeraCrypt containers
# SSH into Pi (if not already)
ssh user@pocket-grimoire.local
# Mount VeraCrypt container(s)
sudo /usr/local/sbin/mount-veracrypt-vault.sh
# Enter password when prompted
# Verify mounted
df -h /mnt/veracrypt/vault1
ls /mnt/veracrypt/vault1
# Or mount manually:
sudo veracrypt --text --mount \
/srv/vaultpg/veracrypt-containers/vault.vc \
/mnt/veracrypt/vault1
# List all mounted VeraCrypt volumes
veracrypt --text --list
```
### Verify Services (2 minutes)
```bash
# Check Docker containers
docker ps
@ -1646,11 +2146,11 @@ htop
## Shutdown Procedure
**Proper shutdown to protect encrypted ZFS pools:**
**Proper shutdown to protect encrypted ZFS pools (headless operation):**
### From SSH
### From SSH (Recommended)
```bash
# SSH into Pi
# SSH into Pi from laptop
ssh user@pocket-grimoire.local
# Stop Docker containers
@ -1660,6 +2160,9 @@ docker compose down
cd /srv/pocket-grimoire/stacks/jellyfin
docker compose down
cd /srv/pocket-grimoire/stacks/stash
docker compose down
# Optional: Stop other containers
cd /srv/pocket-grimoire/stacks/filebrowser
docker compose down
@ -1678,22 +2181,57 @@ sudo zfs unmount -a
sudo zpool export vaultpg
sudo zpool export mediapg
# Verify pools exported
zpool list
# Should NOT show vaultpg or mediapg
# Shutdown Pi
sudo shutdown -h now
# Wait 30 seconds for complete shutdown
# Red LED will turn off when safe to unplug
# Pi's green ACT LED will stop blinking
# Red power LED will turn off
# Safe to unplug power
```
**Total shutdown time: ~2-3 minutes**
### Emergency Shutdown
**If SSH is unavailable:**
**If SSH is unavailable or Pi is unresponsive:**
1. Unplug Ethernet cable from Pi (stops network activity)
2. Wait 10 seconds
3. Unplug power from Anker Prime
4. ZFS pools and VeraCrypt containers may need recovery on next boot (usually auto-repairs)
1. Stop all network activity:
- Unplug Ethernet cable from Pi
- Wait 10 seconds
**Note:** ZFS is resilient, but proper shutdown is always better. VeraCrypt containers are generally safe with sudden unmount.
2. Power off:
- Unplug power from Anker Prime (pulls power from everything)
- Wait 10 seconds
3. Consequences:
- ZFS pools may need recovery on next boot (usually auto-repairs)
- VeraCrypt containers are generally safe with sudden unmount
- Docker containers will need restart
- No data loss expected (ZFS is resilient)
**Note:** ZFS and VeraCrypt are resilient to sudden power loss, but proper shutdown is always better for data integrity.
### Shutdown Checklist
Before leaving hotel:
- [ ] SSH into Pocket Grimoire
- [ ] Stop all Docker containers
- [ ] Unmount VeraCrypt (if using)
- [ ] Export ZFS pools (vaultpg, mediapg)
- [ ] Shutdown Pi (`sudo shutdown -h now`)
- [ ] Wait for Pi LEDs to turn off (30 seconds)
- [ ] Unplug power from Anker Prime
- [ ] Disconnect and pack all equipment
**Never skip the ZFS export step!** Exporting pools ensures:
- All data is flushed to disk
- Filesystem is marked clean
- Prevents corruption
- Allows pools to be imported cleanly on next boot
---