Outline Wiki Deployment: Build a Modern Collaborative Docs Hub with Docker

Step-by-step tutorial to self-hosting Outline wiki on a VPS using Docker Compose. Connect authentication, databases, and secure document storage.

Postgres and Redis Configurations

Outline requires a PostgreSQL relational database (version 12 or higher) and a Redis cache (version 6 or higher).

PostgreSQL Optimization

Outline utilizes UUIDs and pg_trgm for full-text search indexes. If the container user lacks SUPERUSER privileges, run the following SQL command before starting the container:

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "pg_trgm";

Redis Performance Tuning

For background jobs (Bull queue) and session storage, configure Redis persistence. Set AOF (Append Only File) options in your configurations to ensure jobs are not lost during restarts.


HTTPS Reverse Proxy Settings

Outline mandates SSL execution for session security. Configure Nginx with the following parameters:

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 80;
    server_name wiki.example.com;
    return 301 https://$server_name$request_uri;
}

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;

    client_max_body_size 100M;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header Host $http_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;
        proxy_buffering off;
    }
}

OIDC and Slack Login Integration

Outline relies exclusively on external identity providers for authentication.

Slack App Setup

Create a Slack App at api.slack.com. Under OAuth & Permissions, set the redirect URI to: https://wiki.example.com/auth/slack.callback

Configure the environment variables: - SLACK_CLIENT_ID - SLACK_CLIENT_SECRET

Google OIDC Setup

Create credentials in the Google Cloud Console under APIs & Services > Credentials. Add this redirect URI: https://wiki.example.com/auth/google.callback

Configure these environment variables: - GOOGLE_CLIENT_ID - GOOGLE_CLIENT_SECRET

Generic OIDC Setup

For generic identity providers like Keycloak or Authentik: - OIDC_CLIENT_ID - OIDC_CLIENT_SECRET - OIDC_AUTH_URI - OIDC_TOKEN_URI - OIDC_USERINFO_URI - OIDC_DISPLAY_NAME


Unified docker-compose.yml

Here is the complete multi-container docker-compose.yml defining the PostgreSQL, Redis, MinIO S3-compatible storage, and Outline instances.

version: '3.8'

services:
  postgres:
    image: postgres:15-alpine
    container_name: outline-postgres
    environment:
      POSTGRES_USER: outline_db_user
      POSTGRES_PASSWORD: secure_db_password_change_me
      POSTGRES_DB: outline_db
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U outline_db_user -d outline_db"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: always
    networks:
      - outline-internal

  redis:
    image: redis:7-alpine
    container_name: outline-redis
    command: redis-server --appendonly yes
    volumes:
      - redisdata:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: always
    networks:
      - outline-internal

  minio:
    image: minio/minio:RELEASE.2023-09-07T01-34-21Z
    container_name: outline-minio
    command: server /data --console-address ":9001"
    environment:
      MINIO_ROOT_USER: minio_admin_user
      MINIO_ROOT_PASSWORD: secure_minio_password_change_me
    volumes:
      - miniodata:/data
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: always
    ports:
      - "127.0.0.1:9000:9000"
      - "127.0.0.1:9001:9001"
    networks:
      - outline-internal

  outline:
    image: outlinewiki/outline:0.78.2
    container_name: outline-app
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
      minio:
        condition: service_healthy
    ports:
      - "127.0.0.1:3000:3000"
    env_file:
      - .env
    restart: always
    networks:
      - outline-internal

volumes:
  pgdata:
  redisdata:
  miniodata:

networks:
  outline-internal:
    driver: bridge

Complete Environment Configuration (.env)

Construct a .env file in the same directory as docker-compose.yml with the following variables:

NODE_ENV=production
URL=https://wiki.example.com
PORT=3000

# Secret Keys (Generate with: openssl rand -hex 32)
SECRET_KEY=e83d8e578c728e5d65f56b060d46f53a479d2b271d5300d8b5bc7c5b61545ad1
UTILS_SECRET=8f5db99cde78a635df0cf1e27a92df486c478cf3d467be893d98c7604f329971

# PostgreSQL
DATABASE_URL=postgres://outline_db_user:secure_db_password_change_me@postgres:5432/outline_db

# Redis
REDIS_URL=redis://redis:6379

# Storage (MinIO)
AWS_REGION=us-east-1
AWS_ACCESS_KEY_ID=minio_admin_user
AWS_SECRET_ACCESS_KEY=secure_minio_password_change_me
AWS_S3_UPLOAD_BUCKET_NAME=outline
AWS_S3_FORCE_PATH_STYLE=true
AWS_S3_UPLOAD_BUCKET_URL=https://wiki.example.com/api/s3
AWS_S3_SERVER_URL=http://minio:9000
AWS_S3_UPLOAD_MAX_SIZE=26214400

# Authentication
GOOGLE_CLIENT_ID=your-google-client-id.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=your-google-client-secret
# SLACK_CLIENT_ID=your-slack-client-id
# SLACK_CLIENT_SECRET=your-slack-client-secret

# Mail/SMTP settings
SMTP_HOST=smtp.mailgun.org
SMTP_PORT=587
SMTP_USERNAME=postmaster@yourdomain.com
SMTP_PASSWORD=smtp_password_here
SMTP_FROM_EMAIL=outline@yourdomain.com

Deployment and Verification

Initialize the databases and startup your environment:

  1. Bring up Postgres, Redis, and MinIO: bash docker compose up -d postgres redis minio
  2. Access your MinIO dashboard at http://YOUR_VPS_IP:9001 and create a bucket named outline.
  3. Run database migrations: bash docker compose run --rm outline yarn db:migrate --env=production
  4. Start the application container: bash docker compose up -d outline
  5. View container logs to verify normal operations: bash docker compose logs -f outline