The stack

  • Outline app — Node.js + React; serves the SPA and the API.
  • PostgreSQL — documents, users, permissions, history.
  • Redis — pub/sub for realtime collaboration, session cache.
  • S3-compatible storage — attachments + uploaded images. Pair with MinIO (see that tutorial) for self-hosted.

docker compose

# docker-compose.yml
services:
  outline:
    image: outlinewiki/outline:latest
    restart: unless-stopped
    env_file: .env
    ports:
      - "127.0.0.1:3000:3000"
    depends_on: [ postgres, redis ]
    volumes:
      - storage-data:/var/lib/outline/data

  postgres:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_USER: outline
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: outline
    volumes:
      - db-data:/var/lib/postgresql/data

  redis:
    image: redis:7-alpine
    restart: unless-stopped
    volumes:
      - redis-data:/data

volumes:
  storage-data:
  db-data:
  redis-data:

.env:

# Generate with: openssl rand -hex 32
SECRET_KEY=<hex-string>
UTILS_SECRET=<hex-string>

DATABASE_URL=postgres://outline:${POSTGRES_PASSWORD}@postgres:5432/outline
DATABASE_URL_TEST=postgres://outline:${POSTGRES_PASSWORD}@postgres:5432/outline-test
REDIS_URL=redis://redis:6379

URL=https://wiki.example.com
PORT=3000
FORCE_HTTPS=true

# File storage — local disk
FILE_STORAGE=local
FILE_STORAGE_LOCAL_ROOT_DIR=/var/lib/outline/data

# Or S3-compatible (MinIO, AWS S3, etc.)
# FILE_STORAGE=s3
# AWS_ACCESS_KEY_ID=...
# AWS_SECRET_ACCESS_KEY=...
# AWS_REGION=us-east-1
# AWS_S3_ACCELERATE_URL=
# AWS_S3_UPLOAD_BUCKET_URL=https://s3.example.com
# AWS_S3_UPLOAD_BUCKET_NAME=outline
# AWS_S3_FORCE_PATH_STYLE=true
# AWS_S3_ACL=private

# Auth — at least one is required. OIDC is the easiest with Authentik / Auth0 / Keycloak.
OIDC_CLIENT_ID=<client-id>
OIDC_CLIENT_SECRET=<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_LOGOUT_URI=https://auth.example.com/if/session-end/outline/
OIDC_DISPLAY_NAME=Authentik
OIDC_SCOPES=openid profile email

# SMTP for invite + notification emails
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USERNAME=outline@example.com
SMTP_PASSWORD=...
SMTP_FROM_EMAIL=outline@example.com
SMTP_REPLY_EMAIL=outline@example.com
SMTP_SECURE=true
SMTP_TLS_CIPHERS=

POSTGRES_PASSWORD=<long-random>
docker compose up -d
docker compose logs -f outline

Reverse proxy

# Caddy
wiki.example.com {
    reverse_proxy 127.0.0.1:3000
    request_body { max_size 100MB }
}

WebSockets work without extra config; Outline uses them for live cursor positions and document sync.

First login & team setup

Browse to the URL; click "Continue with <OIDC provider>". The first user to log in becomes admin. Subsequent OIDC-provisioned users are auto-registered with permissions defined by the OIDC groups claim (configurable in admin settings).

For email-based auth instead of OIDC, set EMAIL_FROM_AUTH=true and remove the OIDC vars; users sign in with magic-link emails.

Collections, documents, and permissions

Outline's structure:

  • Collection — top-level grouping. "Engineering," "Operations," "HR." Each has its own permissions.
  • Document — a single page. Can have nested children (creating a tree).
  • Group — a named set of users for permission assignment.

Per collection, permissions are: View, Edit, Manage. Per document, you can override the inherited permissions (e.g. a "Salaries" doc inside the HR collection visible only to HR managers).

Editor capabilities

The editor is built on ProseMirror + Yjs. It supports:

  • Tables (resizable, formula support coming)
  • Code blocks with syntax highlighting (Prism-based, ~150 languages)
  • LaTeX math (KaTeX inline / display)
  • Mermaid diagrams via fenced code blocks
  • Embeds from 100+ services (YouTube, Figma, Loom, Linear, Notion (for migration), etc.)
  • @mentions of users and documents
  • Slash commands (/table, /embed, /code, etc.)

Real-time collaboration: multiple users editing the same document see each other's cursors and changes immediately; the underlying CRDT is conflict-free.

Slack / Discord / Teams integrations

Outline can post document updates to chat channels, and pasting a doc link expands to a preview. Configure under Settings → Integrations → pick the platform and authorize.

Migration from Notion / Confluence / GitBook

The Outline "Import" feature accepts:

  • Notion (ZIP export from Notion's Workspace settings)
  • Confluence (HTML export)
  • GitBook (Markdown export)
  • Plain Markdown files

Folder structure is preserved as collections + nested documents; images / attachments are uploaded to the configured storage.

Backups

  • PostgreSQL — pg_dump nightly. Has everything: documents, users, comments, history.
  • Local file storage (or S3) — the actual attachment binaries.
  • Outline's built-in "Export" function (Settings → Export) writes a JSON+attachments archive of the entire instance.

Combine all three into a restic job (see that tutorial) on a nightly timer.

When Outline isn't the right tool

  • For a public-facing documentation site (versioned, searchable, with deep linking), a static site generator like Astro (see that tutorial) or Docusaurus + git-backed content is more appropriate.
  • For project management with task tracking, Outline doesn't replace Linear / Jira / Asana — it complements them.
  • For end-user-facing knowledge bases with branded portals, Helpjuice / Document360 / Crisp have more polish on that specific use case.

For "internal team wiki that people actually keep up to date," Outline is the most polished open-source pick.

BookStack as a lighter alternative

BookStack is a PHP-based wiki with a simpler ops profile (LAMP stack, no Redis, no S3 required) and a less polished but functional editor. For homelabs or very small teams, it's a smaller install with most of the same outcomes.