Self-Hosted Wikis: BookStack, Wiki.js, and Outline for Homelab Documentation
You know that feeling when you set something up in your homelab six months ago, it breaks, and you have absolutely no idea how you configured it? Maybe the config files have cryptic values you don't remember choosing. Maybe the service depends on three other services you've since changed. Maybe you forgot the whole thing existed until it started throwing errors.
This is why you need a wiki. Not a pile of text files in a folder called "notes." Not a README.md that's three months out of date. A proper, searchable, organized knowledge base that you actually maintain.
I've run all three of the major self-hosted wiki options — BookStack, Wiki.js, and Outline — and each has a sweet spot. This guide will help you pick the right one and get it running.

Why Document Your Homelab?
Before we get into the tools, let me convince you this is worth the effort:
- Future you is a different person. You won't remember why you chose those specific NFS mount options in six months.
- Disaster recovery depends on documentation. If your server dies, can you rebuild from scratch? Only if you wrote down how it was built.
- Debugging is faster with context. When something breaks, knowing how it was configured narrows down what went wrong.
- It makes the hobby more fun. Seriously. Having a clean wiki with your network diagram, service inventory, and configuration notes is satisfying.
What to Document
At minimum, your homelab wiki should cover:
| Category | What to Include |
|---|---|
| Network | IP assignments, VLAN layout, DNS records, firewall rules |
| Hardware | Server specs, disk layouts, purchase dates, warranty info |
| Services | What's running, on which host, how it's configured, how to restart it |
| Credentials | Where passwords are stored (not the passwords themselves!) |
| Procedures | How to add a new VM, how to restore from backup, how to update services |
| Decisions | Why you chose Proxmox over ESXi, why you use ZFS, etc. |
| Incidents | What broke, when, why, and how you fixed it |
Comparing BookStack, Wiki.js, and Outline
Here's the comprehensive comparison:
| Feature | BookStack | Wiki.js | Outline |
|---|---|---|---|
| Architecture | PHP + MySQL | Node.js + PostgreSQL | Node.js + PostgreSQL + Redis |
| Editor | WYSIWYG + Markdown | Markdown + Visual | Markdown (block-based) |
| Organization | Shelves > Books > Chapters > Pages | Folders > Pages | Collections > Documents |
| Search | Built-in (MySQL fulltext) | Built-in + Elasticsearch (optional) | Built-in (PostgreSQL) |
| API | REST API | GraphQL API | REST API |
| Auth | LDAP, SAML, OIDC, Social | LDAP, SAML, OIDC, Social, many more | OIDC, SAML, Slack, Google |
| Diagram support | draw.io integration | draw.io, PlantUML, Mermaid | Mermaid |
| File attachments | Yes (local or S3) | Yes (local, S3, Azure, Git) | Yes (local or S3) |
| Docker image size | ~300MB | ~500MB | ~400MB |
| RAM usage | ~200MB | ~300MB | ~500MB (with Redis) |
| Best for | Structured documentation | Technical wikis with code | Team knowledge bases |
| Vibes | Traditional wiki | Developer-focused | Modern Notion-like |
| License | MIT | AGPL v3 | BSL 1.1 |
| Maturity | Very mature, stable | Mature | Newer, actively developed |
Quick Recommendation
- BookStack if you want a traditional, well-organized wiki with a proven track record. Great for solo homelabbers.
- Wiki.js if you want maximum flexibility, excellent markdown support, and Git-based storage options. Great for developer-types.
- Outline if you want a modern, Notion-like experience with real-time collaboration. Great if others will use it too.
Deploying BookStack with Docker
BookStack is my default recommendation for homelab documentation. It's stable, performant, and the shelf/book/chapter/page hierarchy maps perfectly to how you'd organize homelab docs.
Docker Compose Setup
# docker-compose.yml
services:
bookstack:
image: lscr.io/linuxserver/bookstack:latest
container_name: bookstack
environment:
- PUID=1000
- PGID=1000
- TZ=America/New_York
- APP_URL=https://wiki.example.com
- DB_HOST=bookstack-db
- DB_PORT=3306
- DB_USER=bookstack
- DB_PASS=your-strong-db-password
- DB_DATABASE=bookstackapp
# Optional: OIDC authentication (e.g., with Authentik or Keycloak)
# - AUTH_METHOD=oidc
# - OIDC_NAME=Authentik
# - OIDC_DISPLAY_NAME_CLAIMS=name
# - OIDC_CLIENT_ID=bookstack
# - OIDC_CLIENT_SECRET=your-oidc-secret
# - OIDC_ISSUER=https://auth.example.com/application/o/bookstack/.well-known/openid-configuration
# - OIDC_ISSUER_DISCOVER=true
volumes:
- ./bookstack-data:/config
ports:
- "8080:80"
restart: unless-stopped
depends_on:
bookstack-db:
condition: service_healthy
bookstack-db:
image: mariadb:11
container_name: bookstack-db
environment:
- MYSQL_ROOT_PASSWORD=your-strong-root-password
- MYSQL_DATABASE=bookstackapp
- MYSQL_USER=bookstack
- MYSQL_PASSWORD=your-strong-db-password
volumes:
- ./bookstack-db:/var/lib/mysql
restart: unless-stopped
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 10s
timeout: 5s
retries: 5
volumes:
bookstack-data:
bookstack-db:
Starting BookStack
# Create the directory
mkdir -p /opt/bookstack && cd /opt/bookstack
# Save the docker-compose.yml above, then:
docker compose up -d
# Check logs
docker compose logs -f bookstack
# Wait for "Application key set successfully" in the logs
First Login and Setup
- Open
http://your-server:8080(orhttps://wiki.example.comif you have a reverse proxy) - Default credentials:
[email protected]/password - Change the password immediately
- Go to Settings > Users and update the admin email
Organizing Your Homelab Wiki in BookStack
BookStack's hierarchy is: Shelves > Books > Chapters > Pages
Here's a structure that works well:
📚 Shelf: Infrastructure
📖 Book: Network
📑 Chapter: Core Network
📄 Page: IP Address Assignments
📄 Page: VLAN Configuration
📄 Page: Firewall Rules
📄 Page: DNS Records
📑 Chapter: WiFi
📄 Page: Access Point Configuration
📄 Page: SSIDs and VLANs
📖 Book: Servers
📑 Chapter: Proxmox Cluster
📄 Page: Node Specifications
📄 Page: Storage Configuration
📄 Page: VM Inventory
📑 Chapter: NAS
📄 Page: TrueNAS Configuration
📄 Page: ZFS Pool Layout
📄 Page: Share Definitions
📚 Shelf: Services
📖 Book: Media Stack
📄 Page: Plex Configuration
📄 Page: Sonarr Setup
📄 Page: Radarr Setup
📖 Book: Monitoring
📄 Page: Prometheus Configuration
📄 Page: Grafana Dashboards
📄 Page: Alertmanager Rules
📚 Shelf: Procedures
📖 Book: Runbooks
📄 Page: Adding a New VM
📄 Page: Backup Restoration
📄 Page: Service Recovery
📖 Book: Incident Log
📄 Page: 2026-02-01 — NAS Drive Failure
📄 Page: 2026-01-15 — Network Outage
BookStack API Usage
BookStack has a comprehensive REST API that's great for automation:
# Create an API token in BookStack:
# Settings > Users > [your user] > API Tokens > Create Token
# List all books
curl -s "https://wiki.example.com/api/books" \
-H "Authorization: Token YOUR_TOKEN_ID:YOUR_TOKEN_SECRET" | jq '.data[].name'
# Create a new page
curl -s "https://wiki.example.com/api/pages" \
-H "Authorization: Token YOUR_TOKEN_ID:YOUR_TOKEN_SECRET" \
-H "Content-Type: application/json" \
-d '{
"book_id": 1,
"name": "New Service Documentation",
"markdown": "# Service Name\n\n## Overview\n\nDescription here..."
}'
# Search across all content
curl -s "https://wiki.example.com/api/search?query=proxmox+storage" \
-H "Authorization: Token YOUR_TOKEN_ID:YOUR_TOKEN_SECRET" | jq '.data[].name'
This means you can write scripts that automatically update your wiki when infrastructure changes. For example, updating the VM inventory page when VMs are created or destroyed.
Deploying Wiki.js with Docker
Wiki.js is the developer's choice. It has excellent markdown support, built-in diagram rendering, and can store content in a Git repository for version control outside the database.
Docker Compose Setup
# docker-compose.yml
services:
wikijs:
image: ghcr.io/requarks/wiki:2
container_name: wikijs
environment:
- DB_TYPE=postgres
- DB_HOST=wikijs-db
- DB_PORT=5432
- DB_USER=wikijs
- DB_PASS=your-strong-db-password
- DB_NAME=wikijs
volumes:
- ./wikijs-data:/wiki/data
ports:
- "8080:3000"
restart: unless-stopped
depends_on:
wikijs-db:
condition: service_healthy
wikijs-db:
image: postgres:16-alpine
container_name: wikijs-db
environment:
- POSTGRES_DB=wikijs
- POSTGRES_USER=wikijs
- POSTGRES_PASSWORD=your-strong-db-password
volumes:
- ./wikijs-db:/var/lib/postgresql/data
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U wikijs"]
interval: 10s
timeout: 5s
retries: 5
Starting Wiki.js
mkdir -p /opt/wikijs && cd /opt/wikijs
# Save the docker-compose.yml, then:
docker compose up -d
# Watch the logs for startup completion
docker compose logs -f wikijs
Initial Configuration
- Open
http://your-server:8080 - The setup wizard will appear on first run
- Create your admin account
- Configure your site URL and other settings
Wiki.js Git Storage
One of Wiki.js's killer features is Git-based storage. Your wiki content is synced to a Git repository, giving you version history and off-site backup for free.
To set this up:
- Go to Administration > Storage
- Enable Git as a storage target
- Configure the repository URL, branch, and authentication
Repository URI: [email protected]:yourusername/homelab-wiki.git
Branch: main
Authentication Type: SSH
Private Key: (paste your deploy key)
Sync Direction: Bi-directional
Sync Schedule: Every 5 minutes
This means:
- Every page edit is pushed to your Git repo
- You can edit pages by pushing to the repo directly
- Your wiki content survives even if the database is destroyed
- You get full Git history for every page
Wiki.js Markdown Features
Wiki.js has excellent support for diagrams directly in markdown:
# Network Overview
```mermaid
graph LR
Internet[Internet] --> Firewall[pfSense]
Firewall --> Switch[Core Switch]
Switch --> VLAN10[VLAN 10: Servers]
Switch --> VLAN20[VLAN 20: IoT]
Switch --> VLAN30[VLAN 30: Management]
VLAN10 --> Proxmox[Proxmox Cluster]
VLAN10 --> NAS[TrueNAS]
```
```plantuml
@startuml
!define RECTANGLE class
RECTANGLE "DNS Query" as dns
RECTANGLE "Pi-hole" as pihole
RECTANGLE "Upstream DNS" as upstream
RECTANGLE "Local DNS" as local
dns --> pihole : Port 53
pihole --> upstream : If not blocked
pihole --> local : If local domain
@enduml
```
Wiki.js Search with Elasticsearch
For larger wikis, add Elasticsearch for better search:
# Add to docker-compose.yml
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.12.0
container_name: wikijs-search
environment:
- discovery.type=single-node
- xpack.security.enabled=false
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
volumes:
- ./elasticsearch-data:/usr/share/elasticsearch/data
restart: unless-stopped
Then in Wiki.js Administration > Search > select Elasticsearch and configure the connection to http://elasticsearch:9200.
Deploying Outline with Docker
Outline is the most modern option, with a Notion-like editing experience. It's great if you want something that feels contemporary and supports real-time collaboration.
Prerequisites
Outline requires:
- PostgreSQL
- Redis
- S3-compatible storage (MinIO works great for self-hosting)
- An OIDC provider for authentication (Outline doesn't have local auth)
Docker Compose Setup
# docker-compose.yml
services:
outline:
image: docker.getoutline.com/outlinewiki/outline:latest
container_name: outline
env_file: ./outline.env
ports:
- "8080:3000"
restart: unless-stopped
depends_on:
outline-db:
condition: service_healthy
outline-redis:
condition: service_started
outline-minio:
condition: service_started
outline-db:
image: postgres:16-alpine
container_name: outline-db
environment:
- POSTGRES_DB=outline
- POSTGRES_USER=outline
- POSTGRES_PASSWORD=your-strong-db-password
volumes:
- ./outline-db:/var/lib/postgresql/data
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U outline"]
interval: 10s
timeout: 5s
retries: 5
outline-redis:
image: redis:7-alpine
container_name: outline-redis
restart: unless-stopped
outline-minio:
image: minio/minio:latest
container_name: outline-minio
command: server /data --console-address ":9001"
environment:
- MINIO_ROOT_USER=outline
- MINIO_ROOT_PASSWORD=your-strong-minio-password
volumes:
- ./minio-data:/data
ports:
- "9000:9000"
- "9001:9001"
restart: unless-stopped
Outline Environment Configuration
Outline needs quite a few environment variables. Create an outline.env file:
# outline.env
# Required: Generate these with `openssl rand -hex 32`
SECRET_KEY=your-64-char-hex-secret
UTILS_SECRET=your-64-char-hex-utils-secret
# Database
DATABASE_URL=postgres://outline:your-strong-db-password@outline-db:5432/outline
DATABASE_CONNECTION_POOL_MIN=1
DATABASE_CONNECTION_POOL_MAX=10
# Redis
REDIS_URL=redis://outline-redis:6379
# S3/MinIO storage
AWS_ACCESS_KEY_ID=outline
AWS_SECRET_ACCESS_KEY=your-strong-minio-password
AWS_REGION=us-east-1
AWS_S3_UPLOAD_BUCKET_URL=http://outline-minio:9000
AWS_S3_UPLOAD_BUCKET_NAME=outline-data
AWS_S3_FORCE_PATH_STYLE=true
AWS_S3_ACL=private
FILE_STORAGE=s3
# Application URL
URL=https://docs.example.com
PORT=3000
FORCE_HTTPS=false
# Authentication — OIDC example (using Authentik, Keycloak, etc.)
OIDC_CLIENT_ID=outline
OIDC_CLIENT_SECRET=your-oidc-client-secret
OIDC_AUTH_URI=https://auth.example.com/application/o/authorize/
OIDC_TOKEN_URI=https://auth.example.com/application/o/token/
OIDC_USERINFO_URI=https://auth.example.com/application/o/userinfo/
OIDC_DISPLAY_NAME=Authentik
OIDC_SCOPES=openid profile email
Setting Up MinIO Bucket
Before starting Outline, create the S3 bucket:
# Start just MinIO first
docker compose up -d outline-minio
# Create the bucket using the MinIO client
docker run --rm --network=host \
minio/mc:latest \
alias set local http://localhost:9000 outline your-strong-minio-password
docker run --rm --network=host \
minio/mc:latest \
mb local/outline-data
# Now start everything
docker compose up -d
Authentication Setup
Outline requires an external authentication provider. For a homelab, your best options are:
Option 1: Authentik (recommended for homelabs)
# In Authentik admin panel:
# 1. Create a new OAuth2/OpenID Provider for Outline
# 2. Set the redirect URI to: https://docs.example.com/auth/oidc.callback
# 3. Note the client ID and secret
# 4. Update outline.env with the OIDC values
Option 2: Google OAuth (simpler setup)
# In outline.env, replace the OIDC settings with:
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
Option 3: Slack OAuth (if you use Slack)
SLACK_CLIENT_ID=your-slack-client-id
SLACK_CLIENT_SECRET=your-slack-client-secret
Backup and Restore Strategies
Your wiki is only useful if it survives hardware failures. Here's how to back up each platform.
BookStack Backup
#!/bin/bash
# bookstack-backup.sh
set -euo pipefail
BACKUP_DIR="/backup/bookstack/$(date +%Y%m%d)"
mkdir -p "$BACKUP_DIR"
# Dump the database
docker exec bookstack-db mysqldump \
-u bookstack \
-p'your-strong-db-password' \
bookstackapp > "$BACKUP_DIR/database.sql"
# Copy uploaded files and configuration
cp -r /opt/bookstack/bookstack-data "$BACKUP_DIR/data"
# Create a compressed archive
tar czf "/backup/bookstack-$(date +%Y%m%d).tar.gz" -C "$BACKUP_DIR" .
# Clean up the uncompressed backup
rm -rf "$BACKUP_DIR"
# Keep only the last 7 daily backups
find /backup/ -name "bookstack-*.tar.gz" -mtime +7 -delete
echo "BookStack backup complete: /backup/bookstack-$(date +%Y%m%d).tar.gz"
BookStack Restore
#!/bin/bash
# bookstack-restore.sh
set -euo pipefail
BACKUP_FILE="${1:?Usage: bookstack-restore.sh /path/to/backup.tar.gz}"
RESTORE_DIR="/tmp/bookstack-restore"
mkdir -p "$RESTORE_DIR"
tar xzf "$BACKUP_FILE" -C "$RESTORE_DIR"
# Stop BookStack (keep the database running)
cd /opt/bookstack
docker compose stop bookstack
# Restore the database
docker exec -i bookstack-db mysql \
-u bookstack \
-p'your-strong-db-password' \
bookstackapp < "$RESTORE_DIR/database.sql"
# Restore uploaded files
rm -rf /opt/bookstack/bookstack-data
cp -r "$RESTORE_DIR/data" /opt/bookstack/bookstack-data
# Restart BookStack
docker compose up -d bookstack
# Clean up
rm -rf "$RESTORE_DIR"
echo "BookStack restored from $BACKUP_FILE"
Wiki.js Backup
#!/bin/bash
# wikijs-backup.sh
set -euo pipefail
BACKUP_DIR="/backup/wikijs"
mkdir -p "$BACKUP_DIR"
# Dump PostgreSQL database
docker exec wikijs-db pg_dump \
-U wikijs \
-d wikijs \
--format=custom \
> "$BACKUP_DIR/wikijs-$(date +%Y%m%d).pgdump"
# Copy data directory
tar czf "$BACKUP_DIR/wikijs-data-$(date +%Y%m%d).tar.gz" \
-C /opt/wikijs wikijs-data
# Clean up old backups
find "$BACKUP_DIR" -name "*.pgdump" -mtime +7 -delete
find "$BACKUP_DIR" -name "*.tar.gz" -mtime +7 -delete
echo "Wiki.js backup complete"
Wiki.js Restore
#!/bin/bash
# wikijs-restore.sh
set -euo pipefail
DB_BACKUP="${1:?Usage: wikijs-restore.sh /path/to/backup.pgdump}"
cd /opt/wikijs
docker compose stop wikijs
# Drop and recreate the database
docker exec wikijs-db psql -U wikijs -c "DROP DATABASE IF EXISTS wikijs;"
docker exec wikijs-db psql -U wikijs -c "CREATE DATABASE wikijs OWNER wikijs;"
# Restore the database
docker exec -i wikijs-db pg_restore \
-U wikijs \
-d wikijs \
--no-owner \
< "$DB_BACKUP"
docker compose up -d wikijs
echo "Wiki.js restored from $DB_BACKUP"
Outline Backup
#!/bin/bash
# outline-backup.sh
set -euo pipefail
BACKUP_DIR="/backup/outline"
mkdir -p "$BACKUP_DIR"
# Dump PostgreSQL database
docker exec outline-db pg_dump \
-U outline \
-d outline \
--format=custom \
> "$BACKUP_DIR/outline-$(date +%Y%m%d).pgdump"
# Backup MinIO data
tar czf "$BACKUP_DIR/outline-minio-$(date +%Y%m%d).tar.gz" \
-C /opt/outline minio-data
# Clean up old backups
find "$BACKUP_DIR" -name "*.pgdump" -mtime +7 -delete
find "$BACKUP_DIR" -name "*.tar.gz" -mtime +7 -delete
echo "Outline backup complete"
Automate Backups with Cron
# /etc/cron.d/wiki-backup
# Daily wiki backup at 2 AM
0 2 * * * root /usr/local/bin/bookstack-backup.sh >> /var/log/wiki-backup.log 2>&1
Or with a systemd timer for better logging:
# /etc/systemd/system/wiki-backup.timer
[Unit]
Description=Daily wiki backup
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
[Install]
WantedBy=timers.target
# /etc/systemd/system/wiki-backup.service
[Unit]
Description=Wiki backup
After=docker.service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/bookstack-backup.sh
StandardOutput=journal
StandardError=journal
sudo systemctl daemon-reload
sudo systemctl enable --now wiki-backup.timer
Markdown vs. WYSIWYG Editing
This is a surprisingly heated topic. Here's the practical breakdown:
Pure Markdown (Wiki.js)
Pros:
- Portable — your content is plain text
- Version control friendly — diffs are meaningful
- Can be edited with any text editor
- Git sync means you can use your favorite editor locally
Cons:
- Steeper learning curve for non-technical users
- Tables are painful to write in markdown
- Image embedding requires copy-pasting or uploading separately
WYSIWYG with Markdown Backend (BookStack, Outline)
Pros:
- Accessible to everyone, not just developers
- Rich formatting is point-and-click
- Tables, images, and embeds are easy
- Still stores markdown (in BookStack's case, the content is accessible via API)
Cons:
- WYSIWYG editors sometimes produce messy HTML
- Less control over exact formatting
- Copy-paste from other sources can bring unwanted formatting
My Take
For a personal homelab wiki where you're the primary (or only) author, markdown is fine and keeps things simple. If family members or non-technical housemates might contribute, a WYSIWYG editor removes a barrier.
BookStack offers both modes — you can switch between WYSIWYG and markdown per-page, which is the best of both worlds.
Authentication Integration
If you're running multiple services in your homelab, single sign-on (SSO) is a huge quality-of-life improvement.
LDAP Integration (BookStack Example)
# Add to BookStack's docker-compose.yml environment:
environment:
- AUTH_METHOD=ldap
- LDAP_SERVER=ldap://your-ldap-server:389
- LDAP_BASE_DN=dc=example,dc=com
- LDAP_DN=cn=admin,dc=example,dc=com
- LDAP_PASS=your-ldap-admin-password
- LDAP_USER_FILTER=(&(objectClass=inetOrgPerson)(uid=${user}))
- LDAP_VERSION=3
- LDAP_ID_ATTRIBUTE=uid
- LDAP_EMAIL_ATTRIBUTE=mail
- LDAP_DISPLAY_NAME_ATTRIBUTE=cn
OIDC Integration (All Three)
OIDC (OpenID Connect) works with Authentik, Keycloak, or any other OIDC provider:
# BookStack OIDC
environment:
- AUTH_METHOD=oidc
- OIDC_NAME=My SSO
- OIDC_DISPLAY_NAME_CLAIMS=name
- OIDC_CLIENT_ID=bookstack
- OIDC_CLIENT_SECRET=your-client-secret
- OIDC_ISSUER=https://auth.example.com/application/o/bookstack/
- OIDC_ISSUER_DISCOVER=true
# Wiki.js — configure in the admin panel:
# Administration > Authentication > Add Strategy > OpenID Connect
# Fill in: Client ID, Client Secret, Authorization URL, Token URL, User Info URL
Tips for Maintaining Your Wiki
Setting up the wiki is the easy part. Keeping it useful is the hard part. Here are the habits that work:
1. Document as you go, not after. When you're setting up a new service, have your wiki open in another tab. Write down what you're doing as you do it. It's 10x harder to document something after the fact.
2. Use templates. Create a standard template for service documentation:
# Service Name
## Overview
What this service does and why we run it.
## Access
- URL: https://service.example.com
- Port: 8080
- Network: VLAN 10
## Dependencies
- Depends on: PostgreSQL, Redis
- Depended on by: None
## Configuration
Location: /opt/service/docker-compose.yml
Key config files: [list them]
## Maintenance
- Backup: [how and when]
- Update: [how to update]
- Restart: `docker compose restart`
## Troubleshooting
Common issues and their solutions.
3. Link liberally. When your Prometheus page mentions Grafana, link to the Grafana page. When your VM page mentions the storage pool, link to the storage documentation. Cross-references make your wiki navigable.
4. Review quarterly. Set a reminder to review your wiki every three months. Delete outdated pages, update changed configurations, and fill in gaps you've noticed.
5. Don't aim for perfection. A rough page with the key commands and config file locations is infinitely more useful than no page at all. You can always improve it later.
6. Include "why," not just "how." Future you won't just want to know what the config is — you'll want to know why you chose that value.
Putting a Reverse Proxy in Front
All three wikis should be behind a reverse proxy with TLS. Here's a quick Caddy configuration (which handles Let's Encrypt automatically):
# Caddyfile
wiki.example.com {
reverse_proxy localhost:8080
}
Or with nginx:
server {
listen 443 ssl http2;
server_name wiki.example.com;
ssl_certificate /etc/letsencrypt/live/wiki.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/wiki.example.com/privkey.pem;
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# WebSocket support (needed for Outline real-time collaboration)
location /realtime {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
}
Wrapping Up
A self-hosted wiki is one of the highest-value, lowest-effort services you can run in your homelab. It pays dividends every time something breaks and you can look up how it was configured instead of guessing.
Here's the summary:
- BookStack for structured, traditional documentation — deploy with Docker + MySQL, organize with shelves and books
- Wiki.js for developer-focused documentation with Git sync — deploy with Docker + PostgreSQL, enjoy native diagram support
- Outline for a modern, collaborative knowledge base — deploy with Docker + PostgreSQL + Redis + MinIO, requires OIDC auth
Pick one, deploy it today, and start documenting. Your future self will thank you the next time something breaks at 11 PM and you can't remember how you set it up.
The best wiki is the one you actually use. Don't overthink the choice — just start writing.