BookStack Installation (ChatGPT)

For what you described — private “What I Learned Today,” searchable, web-based, VPN-only, mostly for not reinventing wheels — I’d use BookStack.

BookStack is a self-hosted wiki/documentation app with a simple WYSIWYG editor and structured organization around shelves/books/chapters/pages. That maps beautifully to your homelab notes: “Proxmox,” “Networking,” “PBS,” “Home Assistant,” “Linux fixes,” etc. (BookStack) It also has official install paths including Docker, Ubuntu scripts, and manual install options. (BookStack)

Your current lab layout already has a good place for this: a light service on pve3, or on pve1 if you want it with core services. Your fleet notes show pve1 = M93q, pve2 = M73 i7 + Coral, pve3 = M73 i5, with standalone PBS and travel/test nodes, so this is a tiny workload in your world.

My recommendation

Run:

BookStack in a small Debian/Ubuntu VM
access only by VPN
backed up by PBS
no public port forward

I’d avoid exposing it through Nginx Proxy Manager to the internet. VPN is enough and much cleaner.

Why BookStack over WordPress?

WordPress is good when you want a public site, themes, comments, plugins, SEO, publishing workflow — basically a little newspaper. That’s not your goal.

BookStack is better for:

"How did I fix that e1000e hang?"
"Where did I document PBS pruning?"
"What did I decide about file1 storage?"
"How did I mount that USB HDD?"
"What was the command for that Proxmox migration?"

That is a knowledge base, not really a blog.

Ghost is also more publishing-oriented; it’s modern and Docker-friendly, but still more “public publication/newsletter” than “private repair manual.” Ghost has official Docker install docs now, but I wouldn’t pick it for your use case. (Ghost Developer Docs)

DokuWiki is another good option: simple, mature, and it does not require a database, which is appealing for backups and portability. (DokuWiki) But BookStack is friendlier and prettier, and I think that matters because you’ll actually use it.

Suggested structure

Create shelves like this:

Homelab
Proxmox
PBS
Networking
Pi-hole / DNS / DHCP
VPN / WireGuard
Storage / Samba / NFS
Home Assistant
Frigate / Cameras
Linux Commands
House / RV / EV
RV
Genesis GV60
Electrical / UPS
Tools / Repairs
Personal Tech
Windows
Android
Hearing aids / audio
Audiobooks

For each page, use a repeatable template:

# Problem
# Symptoms
# Cause
# Fix
# Commands Used
# Verification
# Notes for Future Me

The killer section is “Notes for Future Me.” That’s where you put: “Do not try Ceph on USB drives again, genius.” Tiny little landmines defused.

Best deployment choice

I’d create a small VM, not an LXC, even though BookStack can run fine in either. Since this is something you want to keep for years, a VM is boring in a good way.

Something like:

VM name: wiltd
OS: Debian 12 or Ubuntu Server 24.04
CPU: 1 core
RAM: 2 GB
Disk: 20–40 GB
Backup: PBS weekly
Access: LAN/VPN only

Put it on internal SSD storage, not a USB HDD. The data is small, but you want it fast and reliable.

Simple Docker Compose setup

Inside the VM:

mkdir -p /opt/bookstack
cd /opt/bookstack
nano docker-compose.yml

Use this:

services:
bookstack:
image: lscr.io/linuxserver/bookstack:latest
container_name: bookstack
environment:
- PUID=1000
- PGID=1000
- TZ=America/Chicago
- APP_URL=http://bookstack.lan
- DB_HOST=bookstack-db
- DB_PORT=3306
- DB_USER=bookstack
- DB_PASS=change_this_password
- DB_DATABASE=bookstackapp
volumes:
- ./bookstack-config:/config
ports:
- 8080:80
restart: unless-stopped
depends_on:
- bookstack-db
bookstack-db:
image: lscr.io/linuxserver/mariadb:latest
container_name: bookstack-db
environment:
- PUID=1000
- PGID=1000
- TZ=America/Chicago
- MYSQL_ROOT_PASSWORD=change_this_root_password
- MYSQL_DATABASE=bookstackapp
- MYSQL_USER=bookstack
- MYSQL_PASSWORD=change_this_password
volumes:
- ./mariadb-config:/config
restart: unless-stopped

Then:

docker compose up -d

Access it at:

http://VM-IP:8080

Later, you can make Pi-hole resolve:

bookstack.lan -> VM-IP

Then use:

http://bookstack.lan:8080

Or, if you already have Nginx Proxy Manager internally, point:

http://wiki.lan

to:

VM-IP:8080

No public DNS. No public port forward. VPN only.

Remote access

Use your existing VPN path:

Laptop/phone away from home
-> WireGuard/PiVPN
-> http://bookstack.lan

That’s enough. Don’t expose it to the internet unless you later decide you want public sharing.

Backup plan

Because this is your “don’t reinvent the wheel” brain, back it up like it matters.

Do both:

1. PBS backup of the whole VM
2. Occasional app-level export/dump

For a simple app-level backup:

cd /opt
tar czf /root/bookstack-files-$(date +%F).tgz bookstack

The PBS VM backup is probably enough day-to-day, but having a plain tarball once in a while is comforting.

What about your old WordPress blog?

I’d handle that in one of two ways:

Option A — keep old WordPress as archive

Export the WordPress site and keep a local/static copy somewhere. Then start fresh in BookStack.

This avoids turning your new system into a migration swamp. Migration swamps are where projects go to wear little concrete shoes.

Option B — migrate only the useful posts

Go through the old posts and copy the still-useful ones into BookStack manually, cleaning them up as you go.

That sounds tedious, but it’s probably better than importing years of old cruft.

My practical “do this first” plan

I’d do this:

1. Create VM: wiltd
2. Install Docker + Docker Compose
3. Run BookStack + MariaDB
4. Make it reachable only on LAN/VPN
5. Add Pi-hole DNS entry: bookstack.lan
6. Add PBS backup job
7. Create shelves for Homelab, House/RV/EV, Personal Tech
8. Start documenting only new fixes
9. Backfill old WordPress posts only when they become useful again

The big habit change: every time you fix something annoying, write a short BookStack page before moving on. Not a novel. Just enough that Future Lynn doesn’t mutter bad words at Past Lynn.

Sprinter Maintenance

I have a Class C motorhome on a 2014 Sprinter chassis. I found one at a bargain, not realizing how expensive mainenance might be. There are two service procedures, A and B that alternate. A is primarily oil and filter change and various inspections. B adds fuel filter. Because I don’t drive many miles, my maintenance is annual. And because annual maintenance at the dealer is somewhat expensive, I’ve chosen to do it myself with some help. Grandpa Ron has a website that has really helped me get through the maintenance.

There are two gotchas that I struggled with. The first is that it is easy to replace the oil filter element not fully seated. You have to press really hard until you feel the final click. The other is that the the fuel return line has a clip that fits into a slot when you fully press the hose on to the filter connector. I couldn’t press the connector on far enough until I put Vaseline on it. Thanks, Claude!

Homelab Ideas

I found a website hosted by Robert Pooley with a lot of technical posts, many of which relate to homelabs. in 2024, Robert decided to move away from Austin. He has lived in several international cities since. He built a fit-in-your-suitcase homelab for the road that I really liked. He setup started with a GMKtec G3 and 7x4TB used SSD rives in an ICY DOCK enclosure running TrueNAS. More recently he was using a Beelink ME Mini that has room for six M.2 slots.

I stumbled on Robert’s website looking for a way to use a Blink camera to monitor my RV with a Franklin T9 hotspot running on house batteries. The T9 is notorious for shutting down for inactivity, requiring the press of a button to restart it. Robert has a fantastic post on hacking the T9. I’m hoping to last a month with this setup.

Checklist for New Ubuntu Instance

This is a comprehensive list of steps for setup of Debian family of Linux. It primarily applies to Proxmox Ubuntu VM’s and LXC’s.

  1. Create the VM/LXC from the Proxmox gui on local storage using the correct .iso image file. Sect Qemu Agent, Discard (for SSH TRIM), add public key.
  2. Add IP to DHCP
  3. edit /etc/ssh/sshd.conf
    • PasswordAuthentication no
    • PubkeyAuthentication yes
    • check /etc/ssh/sshd_conf.d/50… for additional settings
  4. mkdir ~/.bin and add it to your path. Edit ~/.bashrc and add ‘export PATH=$PATH:$HOME/.bin’ to the bottom of the file.
  5. for LXC, create local user
    • useradd <name>
    • apt install sudo
    • sudo usermod -aG sudo <name>
    • new user settings need a lot of work

Placekeeper: distrobox enter abcde-env

sudo usermod -aG sudo

Unattended Upgrades/SSH Without Passwords

Unattended Upgrades can be full (apt upgrade) or security only and are scheduled by systemd timers between 06:00 and 07:00. Most servers should be security only. Proxmox, Home Assistant and Frigate updates should be run manually.

sudo apt install unattended-upgrades mailutils

run this and select <Yes> for stable updates:

sudo dpkg-reconfigure -plow unattended-upgrades

Then this for configuration changes:

sudo nano /etc/apt/apt.conf.d/50unattended-upgrades

These are the only two uncommented lines to get security updates only:

"origin=Debian,codename=${distro_codename},label=Debian-Security";
"origin=Debian,codename=${distro_codename}-security,label=Debian-Security";

These two lines to get mailx notifications:

Unattended-Upgrade::Mail “ldh118@gmail.com”;
Unattended-Upgrade::MailReport “only-on-error”;

This one gets logs at /var/log/unattended-upgrades/:

Unattended-Upgrade::SyslogEnable “true”;

The upgrades are scheduled by systemd timers. Otherwise, you can specify it:

Unattended-Upgrade::Schedule “3:00”;

Configure /etc/msmtprc getting app password from Google here:

defaults
auth on
tls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
logfile /var/log/msmtp.log

account default
host smtp.gmail.com
port 587
from nginx@gmail.com
user ldh118@gmail.com
password <from Google>

Test mail with this:

echo “test” | mail -s “test from proxmox” ldh118@gmail.com

To run immediately use this and add –debug for verbose:

unattended-upgrade

SSH with Key

Generate private key/public key pair and add public key to ~.ssh/authorized_keys.

In /etc/ssh/sshd_config (on both hosts and guests):

PasswordAuthentication no
PermitRootLogin prohibit-password # or 'no' if you use a sudo user
ChallengeResponseAuthentication no
UsePAM no # optional but tightens it further
In /etc/ssh/sshd_config.d/50-cloud-init.conf:
PasswordAuthentication no

Then restart: systemctl restart ssh