← All articles
SERVICES Self-Hosted Wikis: BookStack, Wiki.js, and Outline f... 2026-02-09 · 13 min read · wiki · bookstack · wikijs

Self-Hosted Wikis: BookStack, Wiki.js, and Outline for Homelab Documentation

Services 2026-02-09 · 13 min read wiki bookstack wikijs outline 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.

BookStack logo

Why Document Your Homelab?

Before we get into the tools, let me convince you this is worth the effort:

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

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

  1. Open http://your-server:8080 (or https://wiki.example.com if you have a reverse proxy)
  2. Default credentials: [email protected] / password
  3. Change the password immediately
  4. 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

  1. Open http://your-server:8080
  2. The setup wizard will appear on first run
  3. Create your admin account
  4. 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:

  1. Go to Administration > Storage
  2. Enable Git as a storage target
  3. 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:

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:

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:

Cons:

WYSIWYG with Markdown Backend (BookStack, Outline)

Pros:

Cons:

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:

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.