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_dumpnightly. 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.