Triển khai BookStack trên Docker: Xây dựng Wiki tự host cho Homelab

HomeLab tutorial - IT technology blog
HomeLab tutorial - IT technology blog

Bắt đầu nhanh (5 phút)

Tài liệu homelab thường rất dễ rơi vào tình trạng lộn xộn. Các dải IP tĩnh, file Docker Compose, quy tắc firewall trên Proxmox hay các lệnh alias Bash ngẫu nhiên nhanh chóng bị rải rác khắp các ứng dụng ghi chú và file văn bản rời rạc. BookStack giải quyết triệt để vấn đề này bằng cách mô phỏng cấu trúc phân cấp của một thư viện thực tế: Kệ sách (Shelves), Sách (Books), Chương (Chapters) và Trang (Pages).

Với Docker Compose, bạn có thể dựng một hệ thống hoàn chỉnh chỉ trong vòng chưa đầy năm phút bằng cách sử dụng image gọn nhẹ của LinuxServer cùng một container MariaDB. Cấu hình cơ bản này chỉ tiêu tốn dưới 250MB RAM ở trạng thái nhàn rỗi.

Đầu tiên, hãy tạo một thư mục riêng cho dự án và chuyển vào thư mục đó:

mkdir -p ~/homelab/bookstack && cd ~/homelab/bookstack

Tạo file Compose của bạn:

nano docker-compose.yml

Dán nội dung cấu hình sau vào file:

version: "3.8"

services:
  bookstack:
    image: lscr.io/linuxserver/bookstack:latest
    container_name: bookstack
    environment:
      - PUID=1000
      - PGID=1000
      - APP_URL=http://192.168.1.50:6875
      - DB_HOST=bookstack_db
      - DB_PORT=3306
      - DB_USER=bookstack
      - DB_PASS=SecretBookStackPassword123
      - DB_DATABASE=bookstackapp
    volumes:
      - ./appdata:/config
    ports:
      - 6875: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
      - MYSQL_ROOT_PASSWORD=RootSecretPassword456
      - MYSQL_DATABASE=bookstackapp
      - MYSQL_USER=bookstack
      - MYSQL_PASSWORD=SecretBookStackPassword123
    volumes:
      - ./dbdata:/config
    restart: unless-stopped

Thay đổi http://192.168.1.50:6875 thành địa chỉ IP mạng LAN thực tế hoặc hostname DNS nội bộ của server bạn. Lưu ý không bỏ qua số cổng (port).

Khởi chạy các container dưới nền:

docker compose up -d

Theo dõi log quá trình migration cho đến khi web server sẵn sàng tiếp nhận yêu cầu:

docker compose logs -f bookstack

Khi thấy các dòng xác nhận từ Nginx xuất hiện, hãy mở trình duyệt và truy cập vào http://<your-server-ip>:6875. Đăng nhập bằng tài khoản quản trị mặc định:

Hãy đổi mật khẩu mặc định này ngay lập tức. Truy cập vào mục Edit Profile ở góc trên bên phải trước khi bắt đầu tạo kệ sách đầu tiên.

Đi sâu vào chi tiết

Dựng các dịch vụ self-hosted luôn là phần dễ dàng. Ghi nhớ cách bạn đã cấu hình chúng ra sao sau tám tháng – khi cần chuyển đổi phần cứng – mới là lúc rắc rối nảy sinh. Một trang wiki chuyên biệt sẽ giúp bạn tránh khỏi những cơn đau đầu đó.

Cách BookStack tổ chức cấu trúc tri thức

Cây thư mục Markdown dạng phẳng hoặc các wiki không cấu trúc thường nhanh chóng trở nên hỗn loạn. BookStack áp dụng một hệ thống phân cấp 4 tầng chặt chẽ để giữ cho tài liệu luôn ngăn nắp:

  1. Kệ sách (Shelves): Các danh mục vận hành tổng quát như Networking, Storage Pools, hoặc Kubernetes. Một kệ sách sẽ nhóm nhiều cuốn sách liên quan lại với nhau.
  2. Sách (Books): Đại diện cho từng hệ thống hoặc dịch vụ cụ thể, ví dụ: OPNsense Firewall, TrueNAS Core, hoặc Media Automation.
  3. Chương (Chapters): Các phân mục tùy chọn bên trong một cuốn sách. Ví dụ: VLAN Trunking hoặc WireGuard Road-Warrior Tunnel.
  4. Trang (Pages): Nơi chứa nội dung kỹ thuật thực tế như các đoạn code, sơ đồ mạng, so sánh thay đổi cấu hình (diffs) và file đính kèm.

Cấu trúc này tạo ra các ranh giới rõ ràng. Nó loại bỏ tình trạng các trang tài liệu bị mồ côi (orphaned pages) và giúp tài liệu luôn dễ tra cứu ngay cả khi homelab của bạn mở rộng lên đến hàng chục dịch vụ.

Giải thích các biến môi trường quan trọng

Ba biến sau trong file Compose cần được lưu ý trước khi đưa hệ thống vào sử dụng thực tế:

  • APP_URL: BookStack sử dụng chính xác chuỗi này để tạo các liên kết nội bộ, đường dẫn tài nguyên (assets) và tiêu đề chuyển hướng (redirect headers). Nếu giao thức, IP hoặc port không trùng khớp với thanh địa chỉ trình duyệt, tài nguyên CSS/JS sẽ không thể tải được và việc gửi form sẽ báo lỗi CSRF.
  • PUID và PGID: Các biến này ánh xạ tiến trình bên trong container với User ID trên máy chủ host (thường là 1000:1000 cho user chính trên Ubuntu hoặc Debian). Điều này ngăn container tạo ra các file thuộc sở hữu của quyền root trên các volume lưu trữ dữ liệu.
  • DB_HOST: Phải trùng với tên service được định nghĩa trong block database của bạn (bookstack_db). Hệ thống DNS tích hợp sẵn của Docker sẽ tự động điều hướng kết nối giữa các container qua mạng bridge mặc định.

Sử dụng nâng cao

Thiết lập HTTPS qua Reverse Proxy

Kết nối HTTP thuần túy có thể hoạt động tốt trong mạng con nội bộ an toàn, nhưng các trình duyệt hiện đại sẽ vô hiệu hóa nhiều tính năng bảo mật (như sao chép vào clipboard) trên các địa chỉ không dùng HTTPS. Nếu sử dụng reverse proxy như Caddy hoặc Nginx, hãy điều chỉnh file Compose trước.

Cập nhật APP_URL thành FQDN an toàn của bạn:

    environment:
      - APP_URL=https://wiki.lab.example.com

Dưới đây là một cấu hình mẫu cho Caddy giúp tự động tạo chứng chỉ SSL và chuyển tiếp các proxy header chuẩn xác:

wiki.lab.example.com {
    reverse_proxy 127.0.0.1:6875 {
        header_up X-Forwarded-Proto https
    }
}

Đối với reverse proxy Nginx tiêu chuẩn, hãy đảm bảo bạn đã forward đầy đủ thông tin giao thức và IP của client:

location / {
    proxy_pass http://127.0.0.1:6875;
    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 https;
}

Tự động hóa sao lưu cơ sở dữ liệu

Một chiếc USB hỏng hay một ổ SSD gặp sự cố không nên kéo theo toàn bộ tài liệu vận hành của bạn biến mất. Một script Bash đơn giản chạy qua cron sẽ giúp bạn tự động xuất bản sao lưu hàng ngày chỉ trong vài giây.

Tạo script sao lưu tại đường dẫn ~/homelab/bookstack/backup.sh:

#!/usr/bin/env bash
set -euo pipefail

BACKUP_DIR="${HOME}/homelab/bookstack/backups"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
mkdir -p "${BACKUP_DIR}"

# Xuất cơ sở dữ liệu MariaDB từ container đang chạy
docker exec bookstack_db /usr/bin/mariadb-dump \
  -u bookstack \
  -pSecretBookStackPassword123 \
  bookstackapp | gzip > "${BACKUP_DIR}/bookstack_db_${TIMESTAMP}.sql.gz"

# Nén các tệp tài nguyên đã tải lên, sơ đồ và tệp đính kèm
tar -czf "${BACKUP_DIR}/bookstack_files_${TIMESTAMP}.tar.gz" \
  -C "${HOME}/homelab/bookstack/appdata" www/storages

# Chỉ giữ lại các bản sao lưu trong vòng 14 ngày qua
find "${BACKUP_DIR}" -type f -name "bookstack_*" -mtime +14 -delete

echo "Sao lưu hoàn tất: ${TIMESTAMP}"

Cấp quyền thực thi cho script:

chmod +x ~/homelab/bookstack/backup.sh

Mở crontab để lên lịch công việc:

crontab -e

Thêm một tác vụ chạy định kỳ vào 03:00 sáng mỗi ngày:

0 3 * * * /bin/bash /home/ubuntu/homelab/bookstack/backup.sh >> /home/ubuntu/homelab/bookstack/backup.log 2>&1

Mẹo thực tế

Đặt Markdown làm trình soạn thảo mặc định

BookStack mặc định sử dụng trình soạn thảo WYSIWYG. Mặc dù phù hợp với văn bản thông thường, nó xử lý khá bất tiện với output từ CLI, các phiên dòng lệnh và các đoạn code cấu hình thô. Chuyển sang Markdown sẽ mang lại cho bạn giao diện chia đôi màn hình cùng khả năng hiển thị code gọn gàng, chuẩn xác.

  1. Đăng nhập với tài khoản quản trị viên.
  2. Truy cập Settings > Customization.
  3. Cuộn xuống phần Page Editor và chọn Markdown.
  4. Lưu các thay đổi. Các trang hiện có vẫn giữ nguyên định dạng cũ, trong khi tất cả các trang mới sẽ được mở bằng trình soạn thảo Markdown hai ngăn.

Khắc phục lỗi CSRF token khi đăng nhập

Lỗi “Page Expired” hoặc “Token Mismatch” khi gửi form đăng nhập thường xuất phát từ sự không đồng nhất trong cấu hình môi trường. Hãy kiểm tra hai thiết lập sau:

  1. Đảm bảo APP_URL trong file Compose khớp chính xác với URL trên thanh địa chỉ trình duyệt. Nếu bạn truy cập qua http://192.168.1.50:6875, nhưng lại đặt APP_URL=http://localhost:6875 thì token sẽ bị từ chối ngay lập tức.
  2. Khi chạy sau các reverse proxy có HTTPS, hãy chắc chắn proxy đã chuyển tiếp header X-Forwarded-Proto https. Nếu thiếu header này, BookStack sẽ coi kết nối là không mã hóa và loại bỏ cookie phiên làm việc.

Xây dựng cấu trúc kệ sách homelab đầu tiên

Sự nhất quán ngay từ ngày đầu là vô cùng quan trọng. Dưới đây là cấu trúc thực tế đã qua kiểm chứng, rất phù hợp cho hệ thống homelab:

  • Kệ sách: Infrastructure & Baremetal
    • Sách: Proxmox VE Cluster
      • Chương: Storage Pools → Trang: ZFS Scrub Schedules & Retention Policies
      • Chương: Network Bridges → Trang: VLAN Trunking on vmbr0 (10G SFP+)
    • Sách: Docker Hosts
      • Trang: Daemon JSON & Default Log Rotation
      • Trang: Shared Compose Templates & Subnets

Thiết lập chuẩn chỉnh ngay từ bây giờ sẽ đảm bảo rằng mỗi khi một bản cập nhật làm gián đoạn dịch vụ nội bộ, giải pháp khắc phục chính xác luôn chỉ cách bạn hai cú nhấp chuột.

Share: