<!-- OSSAlt AI-readable guide source -->
<!-- Canonical: https://ossalt.com/guides/self-hosting-guide-outline-2026 -->
<!-- Raw Markdown: https://ossalt.com/guides/self-hosting-guide-outline-2026/raw.md -->
<!-- Source path: content/guides/self-hosting-guide-outline-2026.mdx -->

---
og_image: "/images/guides/self-hosting-guide-outline-2026.webp"
title: "Self-Hosting Outline: Your Team Wiki 2026"
description: "Complete guide to self-hosting Outline wiki — Docker setup, OIDC authentication, S3 storage configuration, and production tips for team knowledge base in 2026."
date: "2026-03-08"
author: "OSSAlt Team"
tags: ["outline", "wiki", "self-hosting", "docker", "guide"]
tier: 1
---

Outline is the best-looking open source wiki and knowledge base. It's a Notion and Confluence alternative with real-time collaboration, Markdown support, and a clean interface your team will actually enjoy using.

## Requirements

- VPS with 2 GB RAM minimum
- Docker and Docker Compose
- Domain name (e.g., `wiki.yourdomain.com`)
- S3-compatible storage (MinIO self-hosted or AWS S3)
- OIDC authentication provider (required — Outline has no built-in auth)
- SMTP service

## Important: Authentication Requirement

Outline requires an external authentication provider. No username/password login. Options:

| Provider | Difficulty | Notes |
|----------|-----------|-------|
| **Google Workspace** | Easy | If your team uses Google |
| **GitHub** | Easy | Good for dev teams |
| **Keycloak** (self-hosted) | Medium | Full control, any team |
| **Authentik** (self-hosted) | Medium | Modern alternative to Keycloak |
| **Azure AD** | Easy | If your team uses Microsoft |

## Step 1: Set Up MinIO (S3 Storage)

Outline requires S3-compatible storage for file uploads:

```yaml
# Add to docker-compose.yml
services:
  minio:
    image: minio/minio:latest
    container_name: outline-minio
    restart: unless-stopped
    ports:
      - "9000:9000"
      - "9001:9001"
    volumes:
      - minio_data:/data
    environment:
      - MINIO_ROOT_USER=outline
      - MINIO_ROOT_PASSWORD=your-minio-password
    command: server /data --console-address ":9001"
```

After starting MinIO:
1. Open `http://your-server:9001`
2. Create a bucket named `outline`
3. Set bucket policy to allow the Outline service account

## Step 2: Create Docker Compose

```yaml
# docker-compose.yml
services:
  outline:
    image: outlinewiki/outline:latest
    container_name: outline
    restart: unless-stopped
    ports:
      - "3000:3000"
    env_file: .env
    depends_on:
      - postgres
      - redis
      - minio

  postgres:
    image: postgres:16-alpine
    container_name: outline-db
    restart: unless-stopped
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=outline
      - POSTGRES_USER=outline
      - POSTGRES_PASSWORD=your-strong-password

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

  minio:
    image: minio/minio:latest
    container_name: outline-minio
    restart: unless-stopped
    volumes:
      - minio_data:/data
    environment:
      - MINIO_ROOT_USER=outline
      - MINIO_ROOT_PASSWORD=your-minio-password
    command: server /data --console-address ":9001"

volumes:
  postgres_data:
  redis_data:
  minio_data:
```

## Step 3: Configure Environment

Create `.env`:
```env
# General
NODE_ENV=production
SECRET_KEY=your-random-secret-key-min-32-chars
UTILS_SECRET=your-random-utils-secret-min-32-chars
URL=https://wiki.yourdomain.com
PORT=3000

# Database
DATABASE_URL=postgres://outline:your-strong-password@postgres:5432/outline
DATABASE_CONNECTION_POOL_MIN=0
DATABASE_CONNECTION_POOL_MAX=10
PGSSLMODE=disable

# Redis
REDIS_URL=redis://redis:6379

# Storage (MinIO)
FILE_STORAGE=s3
FILE_STORAGE_UPLOAD_MAX_SIZE=26214400
AWS_ACCESS_KEY_ID=outline
AWS_SECRET_ACCESS_KEY=your-minio-password
AWS_REGION=us-east-1
AWS_S3_UPLOAD_BUCKET_URL=http://minio:9000
AWS_S3_UPLOAD_BUCKET_NAME=outline
AWS_S3_FORCE_PATH_STYLE=true
AWS_S3_ACL=private

# SMTP
SMTP_HOST=smtp.resend.com
SMTP_PORT=587
SMTP_USERNAME=resend
SMTP_PASSWORD=re_your_api_key
SMTP_FROM_EMAIL=wiki@yourdomain.com
SMTP_REPLY_EMAIL=wiki@yourdomain.com
SMTP_SECURE=true

# Authentication (Google example)
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret

# Or OIDC (Keycloak/Authentik)
# OIDC_CLIENT_ID=outline
# OIDC_CLIENT_SECRET=your-oidc-secret
# OIDC_AUTH_URI=https://auth.yourdomain.com/realms/master/protocol/openid-connect/auth
# OIDC_TOKEN_URI=https://auth.yourdomain.com/realms/master/protocol/openid-connect/token
# OIDC_USERINFO_URI=https://auth.yourdomain.com/realms/master/protocol/openid-connect/userinfo
# OIDC_LOGOUT_URI=https://auth.yourdomain.com/realms/master/protocol/openid-connect/logout
# OIDC_DISPLAY_NAME=SSO Login
```

Generate secrets:
```bash
openssl rand -hex 32  # SECRET_KEY
openssl rand -hex 32  # UTILS_SECRET
```

## Step 4: Start Outline

```bash
docker compose up -d

# Run database migrations
docker exec outline node build/server/scripts/seed.js
```

## Step 5: Reverse Proxy (Caddy)

```
# /etc/caddy/Caddyfile
wiki.yourdomain.com {
    reverse_proxy localhost:3000
}
```

```bash
sudo systemctl restart caddy
```

## Step 6: Organize Your Wiki

**Recommended collection structure:**

| Collection | Purpose |
|-----------|---------|
| 📋 Company | Mission, values, org chart, policies |
| 🚀 Engineering | Architecture, runbooks, onboarding |
| 📊 Product | Specs, roadmap, user research |
| 💼 Sales | Playbooks, pricing, case studies |
| 👋 Onboarding | New hire guides, setup instructions |
| 📝 Meeting Notes | Standups, retros, all-hands |

**Tips:**
- Use **templates** for recurring documents (meeting notes, RFCs, postmortems)
- Star important documents for quick access
- Use `/` commands in the editor for blocks, embeds, tables
- Drag and drop to reorder documents and collections

## Step 7: Integrations

| Integration | Setup |
|------------|-------|
| **Slack** | Settings → Integrations → Slack (notifications + search) |
| **Zapier/n8n** | Use Outline's API with webhooks |
| **Import from Notion** | Settings → Import → Notion (native importer) |
| **Import from Confluence** | Settings → Import → Confluence |

## Production Hardening

**Backups:**
```bash
# Database backup (daily cron)
docker exec outline-db pg_dump -U outline outline > /backups/outline-$(date +%Y%m%d).sql

# MinIO data backup
docker run --rm -v minio_data:/data -v /backups:/backup alpine \
  tar czf /backup/outline-files-$(date +%Y%m%d).tar.gz /data
```

**Updates:**
```bash
docker compose pull
docker compose up -d
```

**Performance:**
- Increase `DATABASE_CONNECTION_POOL_MAX` for larger teams
- Add PostgreSQL connection pooling (PgBouncer) for 100+ users
- Consider CDN for MinIO assets

## Resource Usage

| Users | RAM | CPU | Disk |
|-------|-----|-----|------|
| 1-20 | 2 GB | 2 cores | 10 GB |
| 20-50 | 4 GB | 2 cores | 20 GB |
| 50-200 | 8 GB | 4 cores | 50 GB |

## VPS Recommendations

| Provider | Spec (30 users) | Price |
|----------|-----------------|-------|
| Hetzner | 4 vCPU, 8 GB RAM | €8/month |
| DigitalOcean | 2 vCPU, 4 GB RAM | $24/month |
| Linode | 2 vCPU, 4 GB RAM | $24/month |

## Why Self-Host Outline

Outline Cloud's pricing scales with seats: the Team plan is $10/user/month, which means a 15-person company pays $150/month or $1,800/year. Notion charges $15/user/month for the Business plan. At 15 users, that's $2,700/year. Confluence Cloud is similarly priced at $8.15/user/month, and the costs compound as teams grow. Self-hosted Outline, by contrast, costs only your server bill — typically $8–20/month on a Hetzner or DigitalOcean instance regardless of how many users you add.

The math is stark for growing teams. A 30-person company self-hosting Outline pays approximately $100/year in infrastructure versus $3,600/year on Outline Cloud. Within the first year, the investment in setting up self-hosting pays back many times over.

**Data ownership and compliance:** Confluence and Notion route your company's internal knowledge — architecture docs, HR policies, customer data — through third-party infrastructure. For companies in regulated industries or jurisdictions with strict data residency requirements, this creates compliance risk. Self-hosting Outline means your wiki data never touches Atlassian's or Notion's servers. Legal, healthcare, and financial services teams often require this.

**Customization:** Self-hosted Outline lets you configure storage backends, authentication providers, and retention policies in ways the cloud product doesn't allow. You can pair it with self-hosted Keycloak for SSO, MinIO for on-premises file storage, and your own SMTP server for complete infrastructure independence.

**When NOT to self-host Outline:** If your team has fewer than 5 people, the free tiers on competing products may serve you well enough. Outline's setup is more involved than most self-hosted tools — it requires MinIO (or AWS S3) for file storage and an external OIDC provider for authentication; there is no simple username/password login. If you don't have someone comfortable managing Docker services, consider whether the operational overhead is worth it. For very small teams with no DevOps capacity, Notion's free tier or GitHub Wikis may be the pragmatic choice.

## Prerequisites (Expanded)

Before deploying Outline in a production environment, it helps to understand why each requirement matters rather than treating the list as a checklist to rush through.

**VPS with 2 GB RAM minimum:** Outline is a Node.js application that loads a sizable JavaScript bundle on startup. With only 1 GB RAM, the process risks OOM-killing under moderate load, especially during database migrations or after a fresh deployment. For teams larger than 10 people, start with 4 GB. Ubuntu 22.04 LTS is the recommended OS — it has long-term support through 2027, wide community knowledge, and predictable package versions. Avoid running on cutting-edge distros in production; stability matters more than novelty.

**Docker and Docker Compose:** Outline's setup expects Docker Compose v2+ (the `docker compose` subcommand, not the legacy `docker-compose`). Verify with `docker compose version` before starting. The Compose file orchestrates four containers — Outline, PostgreSQL, Redis, and MinIO — as a single unit.

**S3-compatible storage:** Outline stores all file attachments (images, PDFs, documents) in an S3-compatible bucket. This is not optional. The most common self-hosted choice is MinIO, which we've included in the Compose file above. Alternatively, you can use a real AWS S3 bucket, Cloudflare R2, or Backblaze B2 — all are S3-compatible.

**OIDC provider:** This is the most common stumbling block. Outline has no built-in password login; it delegates authentication entirely to an external provider. If your team uses Google Workspace, GitHub, or Microsoft 365, this is straightforward. If you want a fully self-hosted solution, pair Outline with self-hosted Keycloak or Authentik.

When choosing a VPS, providers like Hetzner (Europe) and Vultr offer good value for small teams. See our [VPS comparison for self-hosters](/guides/self-hosting-vps-comparison-2026) for a full breakdown of providers, pricing, and network performance that will help you make the right infrastructure choice.

## Production Security Hardening

Running Outline in production means you're protecting your company's internal knowledge base. Weak security here has real consequences — a compromised wiki exposes architecture docs, credentials that got accidentally pasted, and sensitive business information.

**Firewall with UFW:** Lock down your server to only the ports that need to be publicly accessible.

```bash
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp    # SSH
sudo ufw allow 80/tcp    # HTTP (for Caddy's ACME challenge)
sudo ufw allow 443/tcp   # HTTPS
sudo ufw enable
```

Never expose PostgreSQL (5432), Redis (6379), or MinIO (9000/9001) to the public internet. These ports should only be reachable within Docker's internal network.

**Fail2ban for SSH protection:** Brute-force attacks on SSH are constant background noise on any public server.

```bash
sudo apt install fail2ban
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
```

Edit `/etc/fail2ban/jail.local` to set `maxretry = 3` and `bantime = 3600` under `[sshd]`. Restart with `sudo systemctl restart fail2ban`.

**Keep secrets out of docker-compose.yml:** Never hardcode passwords or secret keys directly in the Compose file. The `.env` file approach used in this guide is correct — but make sure `.env` is never committed to version control. Add it to `.gitignore`. For additional security, consider using Docker secrets or a secrets manager for production deployments.

**Disable SSH password authentication:** Once you have SSH key-based access working, disable password auth entirely:

```bash
sudo sed -i 's/PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo systemctl restart sshd
```

**Automatic security updates:** Enable unattended upgrades to patch the OS automatically:

```bash
sudo apt install unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades
```

This handles kernel patches, OpenSSL updates, and other security fixes without manual intervention. Limit it to security updates only to avoid accidental application breakage.

**Disable Outline signups after setup:** Once your team accounts are created, set `WIKI_RESTRICTED_DOMAIN` in your `.env` file so only email addresses from your domain can register — or use OIDC authentication scoped to your identity provider, which handles this automatically.

For a complete server hardening checklist beyond what's covered here, see our [self-hosting security checklist](/guides/self-hosting-security-checklist-2026), which covers certificate pinning, log monitoring, and intrusion detection for self-hosted services.

## Troubleshooting Common Issues

**Outline container exits immediately on startup**

This almost always means a missing or incorrectly formatted `.env` variable. Outline is strict about its required configuration.

```bash
docker compose logs outline
```

Look for lines like `Error: Missing required environment variable: SECRET_KEY`. The most common culprits are a `SECRET_KEY` that's too short (must be 32+ chars), an invalid `DATABASE_URL` format, or a `URL` that doesn't include the protocol (`https://`).

**Files and images won't upload**

Outline will log `Error: connect ECONNREFUSED minio:9000` if MinIO isn't running or reachable. Check:

```bash
docker compose ps
docker compose logs minio
```

If MinIO is running, verify the bucket exists and the bucket policy allows the Outline service account to write. Log into the MinIO console at `http://your-server:9001` and confirm the `outline` bucket is present and the access policy is set to allow the credentials in your `.env`.

**OIDC authentication fails after clicking "Sign in with Google"**

If you're redirected back to the login page with no error, check that your OAuth callback URL exactly matches what you registered in your identity provider. For Google, the authorized redirect URI must be `https://wiki.yourdomain.com/auth/oidc.callback` — the trailing path matters. Also verify that `GOOGLE_CLIENT_ID` and `GOOGLE_CLIENT_SECRET` in `.env` match your Google Cloud Console credentials.

**Real-time collaboration isn't working (changes don't sync)**

Outline uses WebSockets for real-time collaboration. If edits don't appear live across multiple browser tabs, your reverse proxy may be stripping WebSocket upgrade headers. With Caddy, this is handled automatically. If you're using Nginx, add the following to your proxy configuration:

```nginx
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
```

**Database migration fails on first run**

If `docker exec outline node build/server/scripts/seed.js` exits with a PostgreSQL connection error, the database container may still be initializing. Wait 10 seconds and try again. You can watch the DB startup with `docker compose logs postgres`. The database is ready when you see `database system is ready to accept connections`.

**MinIO console is accessible from the internet**

By default, MinIO's admin console runs on port 9001. If you've opened this port in your firewall, it's publicly accessible with only the MinIO root credentials standing between attackers and your files. Close port 9001 in UFW immediately. Access the MinIO console only by SSH tunneling: `ssh -L 9001:localhost:9001 user@your-server`.

For Outline deployed at team scale, monitoring the application health proactively is important. The application exposes a `/api/health` endpoint — add it to your Uptime Kuma instance to get alerted if the Outline service becomes unavailable. Additionally, monitor your PostgreSQL instance for slow queries as the wiki grows: Outline's full-text search relies on PostgreSQL's built-in text search capabilities, and large wikis (over 5,000 documents) can develop slow query issues if the database isn't properly vacuumed and indexed. Schedule a weekly `VACUUM ANALYZE` job to keep PostgreSQL's statistics current and queries fast. These maintenance steps take under an hour to set up and prevent the most common performance degradation issues that large Outline deployments encounter.



*See the [VPS comparison for self-hosters](/guides/self-hosting-vps-comparison-2026) to choose the right server for your Outline deployment.*

*Set up [automated server backups with restic](/guides/automated-server-backups-restic-rclone-2026) to protect your Outline database and MinIO file storage.*

*Review the [self-hosting security checklist](/guides/self-hosting-security-checklist-2026) before going to production.*

*Compare wiki and knowledge base tools on [OSSAlt](https://www.ossalt.com) — features, import support, and pricing side by side.*

*See open source alternatives to Outline on [OSSAlt](https://www.ossalt.com/alternatives/outline).*
