DockerSelf-HostingAI Coding Agents

Outline with Docker: self-host a team wiki with your own login (Linux, Windows, Mac)

Before you start

  • 21 min read

Boxes marked Run in terminal are what you type; plain text explains why. Check what you need first

What you get in one minute#

Outline is a beautiful, realtime, markdown-based team wiki you can run entirely on your own machine - but it ships with no login screen of its own: it needs an external OIDC identity provider (such as Authentik or Pocket ID), plus PostgreSQL and Redis, before anyone can sign in.

Outline official logo

Logo: Outline official logo, from the Outline repository The project is alive and busy: version v1.12.0 landed on 2026-10-23, the repository shows 41.2k stars and 10,961 commits (read 2026-11-05), and Docker is the docs' recommended and supported way to self-host. The same docs are honest about the effort: Outline "is engineered as a horizontally scalable cloud platform and requires dev-ops experience to successfully install and run in a production environment." This guide keeps that experience to one Docker Compose file, one env file, and one OIDC app.

ItemValue
Current versionv1.12.0 (released 2026-10-23, GitHub releases)
LicenceBusiness Source License 1.1 (see What the BSL licence means)
Time needed30-60 minutes plus your IdP setup (our estimate; we did not run it)
RAMMinimum 512MB, 1GB+ recommended (official requirements)
Image size~261 MB amd64 (outlinewiki/outline:1.12.0, Docker Hub, read 2026-11-05)
Ports3000 inside Docker (not published); 80/443 on your reverse proxy
Official docsdocs.getoutline.com/s/hosting

At a glance:

  • Markdown editor with realtime collaborative editing (the repo calls itself "beautiful, realtime collaborative, feature packed, and markdown compatible").
  • Collections with nested documents, search, and public sharing.
  • File attachments stored on your own disk (FILE_STORAGE=local) or S3-compatible storage.
  • Personal documents: a private section per user, new in v1.12.0.
  • Import from Notion and Slab; Mermaid diagrams; a built-in MCP server; passkey login in the desktop app (v1.12.0 release notes).

How it fits together#

One sentence: your browser talks HTTPS to a reverse proxy, the proxy forwards to the Outline container on port 3000, and Outline stores documents in PostgreSQL, runs jobs through Redis, saves uploads to a local folder, and checks every sign-in with your OIDC provider.

Diagram showing how Outline fits together: your browser reaches a reverse proxy over HTTPS, the proxy forwards to the Outline app on port 3000, and Outline talks to PostgreSQL for documents, Redis for jobs, a local folder for uploads, and an external OIDC provider for sign-in

The parts and who talks to whom. Notice the orange cloud: the login provider is the one piece Outline refuses to be - it is your Authentik or Pocket ID, not Outline. Everything purple stays on your machine. Source: the official Docker, configuration and OIDC docs, Nov 2026.

Before you start#

You need, per platform:

  • Linux: any distribution that runs Docker; the docs say operators deploy on Ubuntu, Debian "and similar" (the image itself is Alpine Linux).
  • Windows: Outline itself "is developed Unix-compatible operating systems only. It does not run on Microsoft Windows server" (official requirements). On Windows you run it through Docker Desktop's Linux containers - that is the only supported route on this list.
  • Mac: same as Linux - Docker Desktop running the Linux container.

Required software on every platform, with check commands:

Run in terminalbash
docker --version
docker compose version
Run in terminalpowershell
docker --version
docker compose version

You also need:

  • An OIDC provider. Our Authentik and Pocket ID guides cover two good self-hosted options; Outline's own docs list Authentik as an example provider and link its walkthrough.
  • A dedicated domain or subdomain (the official requirements list one, e.g. wiki.example.com), because Outline's URL must be a fully qualified address and sign-in redirects depend on it.
  • PostgreSQL v14+ and Redis v4+ - the Compose file below starts both for you.

Checklist before the first command:

  • [ ] Docker and Docker Compose installed and running
  • [ ] Your OIDC provider is up and you can log into it
  • [ ] The subdomain you plan to use is free (no other service on it)
  • [ ] Ports 80 and 443 are free if you follow the HTTPS section
  • [ ] A place for backups (the guide creates backups/ for you)

Not tested on DIY Lab Hub hardware: this guide was written without running the stack. Every command and config key below is copied from, or checked against, the official docs and repository (read 2026-11-05), and the places where we adapt or add something are labelled.

Step 1: Make the folder and generate two secrets#

Outline needs two random keys: SECRET_KEY (hex-encoded 32 bytes - the docs' own instruction is openssl rand -hex 32) and UTILS_SECRET (any unique random value; the same command works).

Linux#

Run in terminalbash
mkdir -p ~/docker_volumes/outline/{data,db,backups}
cd ~/docker_volumes/outline
openssl rand -hex 32
openssl rand -hex 32

Run the last command twice and keep both outputs - one for SECRET_KEY, one for UTILS_SECRET.

Windows (PowerShell)#

Codepowershell
New-Item -ItemType Directory -Force -Path "$HOME\docker_volumes\outline\data", "$HOME\docker_volumes\outline\db", "$HOME\docker_volumes\outline\backups" | Out-Null
Set-Location "$HOME\docker_volumes\outline"

The official docs only give the OpenSSL command. If OpenSSL is available in your PowerShell (many Git for Windows setups add it), run openssl rand -hex 32 twice. If not, here is a PowerShell-only equivalent that produces the same thing - 64 hex characters from 32 cryptographically random bytes (this snippet is ours, not from the docs):

Codepowershell
$rng = New-Object System.Security.Cryptography.RNGCryptoServiceProvider
$bytes = New-Object byte[] 32
$rng.GetBytes($bytes)
-join ($bytes | ForEach-Object { $_.ToString('x2') })

Mac (Terminal)#

Same commands as Linux:

Run in terminalbash
mkdir -p ~/docker_volumes/outline/{data,db,backups}
cd ~/docker_volumes/outline
openssl rand -hex 32
openssl rand -hex 32

Check it worked: you have an outline folder with data, db and backups inside, and two different 64-character hex strings. If SECRET_KEY is the wrong format or length, Outline fails at runtime with RangeError: Invalid key length (see Troubleshooting).

Step 2: Create the docker.env file#

The docs' minimum working set of environment variables is URL, DATABASE_URL, REDIS_URL and SECRET_KEY; "any missing variables depending on your setup will be displayed at startup." We build on the official .env.sample from the repository.

Linux#

Create docker.env in ~/docker_volumes/outline (for example nano docker.env):

Run in terminalbash
nano ~/docker_volumes/outline/docker.env
File contenttext
NODE_ENV=production

# The fully qualified URL users will visit. If using a proxy, this is the proxy's URL.
URL=https://wiki.example.com
PORT=3000

# Paste the two hex keys from Step 1
SECRET_KEY=<FIRST_64_HEX_CHARACTERS>
UTILS_SECRET=<SECOND_64_HEX_CHARACTERS>

# Database and queue - service names match docker-compose.yml
DATABASE_URL=postgres://user:<DB_PASSWORD>@postgres:5432/outline
REDIS_URL=redis://redis:6379

# Keep uploads on this machine
FILE_STORAGE=local
FILE_STORAGE_LOCAL_ROOT_DIR=/var/lib/outline/data
FILE_STORAGE_UPLOAD_MAX_SIZE=262144000

FORCE_HTTPS=true
ENABLE_UPDATES=true

Pick a strong <DB_PASSWORD>; it must match POSTGRES_PASSWORD in Step 3.

Windows (PowerShell)#

Create and edit the same file:

Run in terminalpowershell
notepad "$HOME\docker_volumes\outline\docker.env"

Paste the same content as Linux.

Mac (Terminal)#

Same commands as Linux: nano ~/docker_volumes/outline/docker.env, same content.

Check it worked: docker.env exists with no placeholder brackets left, and URL is the exact address people will use in the browser - Outline's sign-in redirects break if it differs. Lock the file down (see Security and testing).

Tip: URL is not cosmetic. The OIDC redirect URI in Step 4 is built from it, and a mismatch shows up as a redirect loop after login. Set it once, correctly, before the first start.

Step 3: Create docker-compose.yml#

This is the docs' Compose example, adapted to the house layout: pinned image tags (the docs recommend pinning "rather than relying on the latest tag"), bind mounts under ~/docker_volumes/outline/ instead of named volumes (bind mounts are a documented option for file storage), restart: unless-stopped, and no version: line. We also leave out the docs' https-portal service because the HTTPS section uses Traefik or Caddy instead, and we drop the docs' command: ["redis-server", "/redis.conf"] line because that config file is not provided anywhere in the docs page.

Linux#

Run in terminalbash
nano ~/docker_volumes/outline/docker-compose.yml
File contentyaml
services:
  outline:
    image: outlinewiki/outline:1.12.0
    env_file: ./docker.env
    restart: unless-stopped
    expose:
      - "3000"
    volumes:
      - ./data:/var/lib/outline/data
    depends_on:
      - postgres
      - redis

  redis:
    image: redis:8
    restart: unless-stopped
    expose:
      - "6379"
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 30s
      retries: 3

  postgres:
    image: postgres:18
    restart: unless-stopped
    expose:
      - "5432"
    volumes:
      - ./db:/var/lib/postgresql
    healthcheck:
      test: ["CMD", "pg_isready", "-d", "outline", "-U", "user"]
      interval: 30s
      timeout: 20s
      retries: 3
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: <DB_PASSWORD>
      POSTGRES_DB: outline

Windows (PowerShell)#

Run in terminalpowershell
notepad "$HOME\docker_volumes\outline\docker-compose.yml"

Same content as Linux.

Mac (Terminal)#

Same commands as Linux, same content.

Check it worked: from the outline folder, validate the file without starting anything (standard Docker Compose command):

Run in terminalbash
docker compose config
Run in terminalpowershell
docker compose config

Look for your three services in the output and no YAML errors. Note that expose keeps ports 3000, 5432 and 6379 inside Docker - nothing is reachable from your network until a proxy publishes 80/443.

Tip: If you later see permission errors when uploading attachments, the docs' fix for bind mounts is to give Outline's user ID ownership: chown 1001 ./data (Linux/Mac). On Windows, Docker Desktop manages bind-mount permissions for you.

Step 4: Point Outline at your OIDC provider#

This is the step that makes or breaks the install. Outline "does not support email + password authentication natively" (official docs), and the .env.sample is blunt: "at least ONE of these is required for a working installation or you'll have no sign-in options." Generic OIDC is the right choice with Authentik or Pocket ID - Outline "supports all OIDC-compatible authentication providers and automatic discovery out of the box."

First, in your IdP, create an OIDC application/provider for Outline with:

  • Redirect URI: https://wiki.example.com/auth/oidc.callback (this exact pattern comes from Outline's own source: ${URL}/auth/${config.id}.callback with plugin id oidc)
  • Scopes: openid profile email (Outline's default)
  • A provider that returns an email claim, a name (it reads preferred_username by default), and a user id - Outline's source rejects profiles without them

Authentik's own docs have a step-by-step walkthrough for Outline (linked from Outline's OIDC docs). Our Authentik and Pocket ID guides cover setting the providers up in the first place.

Then add the OIDC block to docker.env:

Linux#

Run in terminalbash
nano ~/docker_volumes/outline/docker.env

Append (auto-discovery route - Outline reads /.well-known/openid-configuration from your issuer):

Run in terminaltext
OIDC_CLIENT_ID=<FROM_YOUR_IDP>
OIDC_CLIENT_SECRET=<FROM_YOUR_IDP>
OIDC_ISSUER_URL=https://id.example.com
OIDC_DISPLAY_NAME=OpenID Connect
OIDC_SCOPES=openid profile email
OIDC_USERNAME_CLAIM=preferred_username
OIDC_LOGOUT_URI=https://id.example.com/logout

If your provider has no discovery endpoint, the docs' manual route replaces OIDC_ISSUER_URL with OIDC_AUTH_URI, OIDC_TOKEN_URI and OIDC_USERINFO_URI.

Two self-hoster traps, both from the official troubleshooting docs and real issues:

  • IdP on a private IP: Outline blocks requests to local networks as an anti-SSRF measure, so a LAN address for your IdP fails with "DNS lookup is not allowed". Fix: ALLOWED_PRIVATE_IP_ADDRESSES=10.0.10.0/24 (comma-separated IPs or CIDR ranges).
  • IdP with an internal certificate authority: add NODE_EXTRA_CA_CERTS=/etc/ssl/myca.crt to docker.env and bind-mount your root CA into the container (add - ./myca.crt:/etc/ssl/myca.crt:ro to the outline service's volumes in Step 3).

Windows (PowerShell)#

Run in terminalpowershell
notepad "$HOME\docker_volumes\outline\docker.env"

Same additions as Linux.

Mac (Terminal)#

Same commands as Linux, same additions.

Check it worked: from the server, confirm the discovery document is reachable - this is exactly what Outline fetches at startup:

Run in terminalbash
curl https://id.example.com/.well-known/openid-configuration
Run in terminalpowershell
curl.exe https://id.example.com/.well-known/openid-configuration

Expected: JSON containing authorization_endpoint, token_endpoint and userinfo_endpoint. If this fails from your server, Outline cannot sign anyone in either.

Tip: Set OIDC_LOGOUT_URI (or OIDC_DISABLE_REDIRECT) even though it is optional. The docs warn that without one "it will be very difficult for users to logout correctly."

Step 5: Start the stack and log in#

Linux#

Run in terminalbash
cd ~/docker_volumes/outline
docker compose up -d

Windows (PowerShell)#

Codepowershell
Set-Location "$HOME\docker_volumes\outline"
docker compose up -d

Mac (Terminal)#

Same commands as Linux.

Database migrations run automatically when the container starts (pass --no-migrate only if you want to run them by hand). The docs' advice on the output: "Check the output carefully for errors such as connecting to your database or redis instance."

Check it worked:

Run in terminalbash
docker compose ps
docker compose logs outline --tail 100
Run in terminalpowershell
docker compose ps
docker compose logs outline --tail 100

What to look for: outline, postgres and redis all Up (postgres and redis show (healthy) once their healthchecks pass), and no database or Redis connection errors in the logs. Then open https://wiki.example.com - or http://localhost:3000 only if you temporarily skipped the proxy and published the port - click the button labelled with your OIDC_DISPLAY_NAME, sign in through your IdP, and create your first collection. We did not run this ourselves, so treat the first login as your test.

Put it behind HTTPS with Traefik#

Outline's SSL doc is firm: "Outline should always be exposed over HTTPS whether over the wider internet or your internal network," and "you must ensure that websockets are forwarded through the proxy" - websocket support is a hard requirement (a proxy that blocks them leaves documents uneditable). This section is for a server with a domain; local-only users can skip to the Caddy route with tls internal.

With Traefik#

Add the outline service to your external proxy network with labels (create the network first if it does not exist: docker network create proxy). Add to the outline service in docker-compose.yml:

File contentyaml
    networks:
      - default
      - proxy
    labels:
      - traefik.enable=true
      - traefik.http.routers.outline.rule=Host(`wiki.example.com`)
      - traefik.http.routers.outline.entrypoints=https
      - traefik.http.routers.outline.tls=true
      - traefik.http.services.outline.loadbalancer.server.port=3000

And at the bottom of the file:

File contentyaml
networks:
  proxy:
    external: true

Traefik obtains the Let's Encrypt certificate and forwards to port 3000 inside the container; no port needs publishing.

Without Traefik: Caddy#

Caddy's reverse_proxy "supports WebSocket connections" out of the box, so it satisfies Outline's websocket requirement without extra config. The cleanest route is Caddy's own recommended Docker setup: a caddy service in the same Compose file, mounting the conf folder (not a single Caddyfile).

Create ~/docker_volumes/outline/caddy/Caddyfile (Linux/Mac: mkdir -p caddy && nano caddy/Caddyfile; Windows: create the folder in File Explorer and edit with notepad caddy\Caddyfile):

File contenttext
wiki.example.com {
    reverse_proxy outline:3000
}

Note it says outline:3000, not localhost:3000 - Caddy's docs warn that in Docker networking "localhost means 'this container', not 'this machine'", and containers on the same network reach each other without published ports.

Add to docker-compose.yml:

File contentyaml
  caddy:
    image: caddy:2.11.8
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - ./caddy:/etc/caddy
      - caddy_data:/data
      - caddy_config:/config
    depends_on:
      - outline

And add to the volumes: block at the bottom:

File contentyaml
  caddy_data:
  caddy_config:

Then docker compose up -d again. Caddy gets a Let's Encrypt certificate automatically as long as your DNS A/AAAA record points at the server and ports 80/443 are open (Caddy's automatic-HTTPS docs). If you prefer Caddy installed on the host instead (Debian/Ubuntu apt repo, Fedora dnf copr enable @caddy/caddy, Arch pacman -Syu caddy, Mac brew install caddy, Windows choco install caddy - all from Caddy's install docs), publish Outline's port to localhost only (ports: ["127.0.0.1:3000:3000"] on the outline service) and use reverse_proxy localhost:3000.

Home-only, no public domain: replace the site address line with tls internal config - Caddy signs certificates with its own local CA:

File contenttext
wiki.homelab.local {
    tls internal
    reverse_proxy outline:3000
}

Every client needs to trust Caddy's root CA (Caddy's docs: clients without it "will show security errors"). The root certificate lives in the caddy container at /data/caddy/pki/authorities/local/root.crt. Caddy's own per-OS trust commands:

Run in terminalbash
docker compose cp caddy:/data/caddy/pki/authorities/local/root.crt /usr/local/share/ca-certificates/root.crt
sudo update-ca-certificates
Run in terminalpowershell
docker compose cp caddy:/data/caddy/pki/authorities/local/root.crt $env:TEMP\root.crt
certutil -addstore -f "ROOT" $env:TEMP\root.crt
Run in terminalbash
docker compose cp caddy:/data/caddy/pki/authorities/local/root.crt /tmp/root.crt
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain /tmp/root.crt

(The first block is Linux, the second Windows PowerShell, the third Mac.) Firefox and Chrome keep their own trust stores, so import the same root.crt there too if you use them.

Check it worked:

Run in terminalbash
curl -I https://wiki.example.com
Run in terminalpowershell
curl.exe -I https://wiki.example.com

Expected: an HTTP response (a redirect or Outline's login page), not a connection error. We never teach Cloudflare Tunnel here - local certificates are enough.

Security and testing#

  • Secrets: docker.env holds SECRET_KEY, UTILS_SECRET, your database password and the OIDC client secret. Restrict it: chmod 600 docker.env (Linux/Mac); on Windows, keep it out of any synced or shared folder. Back it up after every change - the backups doc warns that losing SECRET_KEY makes "all encrypted data in the database becoming inaccessible."
  • Ports: the Compose file uses expose, so 3000/5432/6379 never leave Docker. Only the proxy publishes 80/443. Do not add ports: mappings for Outline itself unless you bind them to 127.0.0.1.
  • HTTPS: verify with curl -I https://wiki.example.com after the proxy section; Outline's FORCE_HTTPS=true (the default) redirects HTTP visitors to HTTPS.
  • Status and function tests: docker compose ps for health, docker compose logs outline --tail 100 for errors, then a real login and a document edit (editing proves websockets work).
  • More logs when debugging: set LOG_LEVEL=debug in docker.env - the troubleshooting doc says this level is "often requested" on the support forums. Put it back to info afterwards.
  • Rate limiting: on by default in the .env.sample (RATE_LIMITER_ENABLED=true, 1000 requests per 60 seconds globally).

What the BSL licence means for you#

Honest version, from the licence file itself: Outline is licensed under the Business Source License 1.1. The grant says you may use it, but not as a "Document Service" - "a commercial offering that allows third parties (other than your employees and contractors) to access the functionality of the Licensed Work." In practice:

  • Fine: running Outline for your own team, your household, your company's employees and contractors.
  • Not fine: selling, reselling, or hosting Outline as a service for third parties. The license-restrictions doc says doing so "automatically terminates your rights under the license."
  • Not an OSI open-source license: the BSL says so itself, but each version eventually becomes one. For v1.12.0 the Change Date is 2030-10-23, after which the code becomes Apache License 2.0.
  • Paid editions: Business and Enterprise licences add features and support (Outline's pricing page).

What leaves your machine#

The privacy angle, so you know what talks to what:

  • Update pings: ENABLE_UPDATES=true (the sample default) has the installation "check for updates by sending anonymized statistics to the maintainers." Set ENABLE_UPDATES=false in docker.env if you want zero outbound telemetry.
  • Sign-in traffic: Outline talks to your OIDC provider on every login. With a self-hosted Authentik or Pocket ID, that traffic stays on your network.
  • Only-if-configured services: SMTP (notification emails), Sentry error reporting, and integrations like Slack, Google, Iframely or Notion import - each is off unless you fill in its env vars.
  • Your content: documents live in the PostgreSQL volume and attachments in ./data - both on your disk with FILE_STORAGE=local.

Common mistakes#

We read 14 real reports on Outline's issue tracker (Nov 2026): 13 complaints and 1 neutral feature request. Issue trackers attract complaints, so that is not a satisfaction rate - but it is a good map of where self-hosters stumble. What they hit:

ThemeReports
OIDC and login6
Exports2
File storage / S31
SECRET_KEY format1
Sessions / CSRF1
Local-network calls blocked1
No local login (feature request)1
Config system (feature request)1

The mistakes behind them, and the fixes:

MistakeWhy it happensDo this instead
Launching with no auth provider configuredOutline looks like any web app, so people expect a signup formConfigure OIDC (Step 4) before the first start - the .env.sample says at least one provider is required or "you'll have no sign-in options"
IdP on a LAN IP, then "DNS lookup is not allowed"Outline blocks local-network requests to prevent SSRF by defaultSet ALLOWED_PRIVATE_IP_ADDRESSES=10.0.10.0/24 (IPs or CIDR ranges) - the fix added in PR #10093 for issue #10057
Wrong SECRET_KEY formatAny random string looks good enoughIt must be hex-encoded 32 bytes: openssl rand -hex 32. Wrong length gives RangeError: Invalid key length (#10890)
Old S3 keys or "you must run Minio" adviceTutorials and memories from before FILE_STORAGE existedCurrent keys are FILE_STORAGE=local (or s3 + AWS_S3_UPLOAD_BUCKET_URL etc.). One user's AWS_S3_ENDPOINT - not an Outline variable - caused an infinite restart loop (#12323)
HTTP to HTTPS redirect loop during setupFORCE_HTTPS=true is the default while people test over plain HTTPSet FORCE_HTTPS=false while testing, and clear the browser's cached HTTPS attempt (official troubleshooting doc)
Moving the IdP to a new domainOutline kept the old provider hostname in its databaseFixed in PRs #13574 and #14389; on v1.12.0 update to the next release if you hit SequelizeUniqueConstraintError at sign-in (#13572, #14383)
AI assistants giving stale Outline configAssistants trained on old tutorials and old .env.sample filesCheck every key against the current .env.sample: AWS_S3_UPLOAD_MAX_SIZE and MAXIMUM_IMPORT_SIZE no longer exist (now FILE_STORAGE_UPLOAD_MAX_SIZE, FILE_STORAGE_IMPORT_MAX_SIZE), Minio is no longer required for local storage, OIDC_ISSUER_URL discovery replaces manual URIs, and "install from source on Windows" is wrong - the docs say Outline does not run on Windows Server (we verified this by comparing the v0.67.0 sample with today's). The repo's README even pleads: "Please do not submit AI-generated pull requests."

Tip: Pin your image tag (outlinewiki/outline:1.12.0, not latest). The docs recommend pinning "so that you can remain in control of upgrades" - and Outline's release migrations are "not always backwards compatible."

Tip: Take a database backup before every upgrade. The backups doc recommends daily backups retained for a month, and always one before upgrading between releases.

Tip: When something fails, set LOG_LEVEL=debug and read docker compose logs outline --tail 100 before searching forums - the troubleshooting doc says debug logs are the first thing maintainers ask for.

Troubleshooting#

ProblemSolution
Redirect loop between HTTP and HTTPSFORCE_HTTPS=false while testing; clear the browser's cached HTTPS attempt
Documents load but cannot be editedYour proxy is not forwarding websockets - a hard Outline requirement
EADDRINUSE at startupAnother service (or another Outline copy) holds the port; change PORT or stop the other service
Cannot reach Postgres/Redis on the hostRun Docker with --net="host" and use localhost in docker.env (docs' advice), or keep them in Compose as here
Export fails or images missing from PDF exportKnown open bug for image-heavy PDF exports (#12441, open Nov 2026); export Markdown instead
"Config could not be parsed" in the browserA third party (often Cloudflare Rocket Loader) rewrites Outline's HTML; disable it for this hostname

"DNS lookup ... is not allowed. Because, It is private IP address."#

Outline refuses to fetch URLs that resolve to private IPs (anti-SSRF). With a LAN IdP or self-hosted integrations, allowlist them:

File contenttext
ALLOWED_PRIVATE_IP_ADDRESSES=10.0.10.0/24

RangeError: Invalid key length#

SECRET_KEY is not a hex-encoded 32-byte value. Regenerate with openssl rand -hex 32 and restart. If you lost a previously working SECRET_KEY, encrypted data (sessions, tokens, integrations) is unrecoverable; the docs' recovery script inside the container is node ./build/server/scripts/reset-encrypted-data.js.

Error connecting to IdP with self-signed certificate#

Mount your root CA into the container and set NODE_EXTRA_CA_CERTS=/etc/ssl/myca.crt (official self-signed certificates doc). Disabling verification with NODE_TLS_REJECT_UNAUTHORIZED="0" exists but the docs advise against it.

Known bugs#

  • Images missing in PDF export - open since May 2026 (#12441); no workaround beyond exporting in another format.
  • OIDC sign-in SequelizeUniqueConstraintError with multiple provider records - fixed on main on 2026-10-29 (#14389), which is after v1.12.0 shipped on 2026-10-23; the fix reaches the next tagged release.
  • Historical, already fixed: v1.6.0-1.6.1 showed an empty page after OIDC login until refresh (#11811, fixed March 2026); v1.8.1 blocked new-user logins for OIDC providers that omit the optional email_verified claim (#12630, #13242, fixed August 2026). We found no breakage reports for v1.12.0 itself in our reading.

Diagnostic commands:

Run in terminalbash
docker compose ps
docker compose logs outline --tail 100
docker inspect --format '{{.State.Health.Status}}' $(docker compose ps -q postgres)
Run in terminalpowershell
docker compose ps
docker compose logs outline --tail 100
docker inspect --format '{{.State.Health.Status}}' (docker compose ps -q postgres)

Updates and backups#

To update: back up first (migrations are "not always backwards compatible"), then pull and recreate:

Run in terminalbash
cd ~/docker_volumes/outline
docker compose exec -T postgres pg_dump -U user outline > backups/outline-db-$(date +%F).sql
# edit docker-compose.yml: bump outlinewiki/outline to the new tag
docker compose pull && docker compose up -d
Codepowershell
Set-Location "$HOME\docker_volumes\outline"
docker compose exec -T postgres pg_dump -U user outline | Out-File "backups\outline-db-$(Get-Date -Format yyyy-MM-dd).sql" -Encoding ascii
# edit docker-compose.yml: bump outlinewiki/outline to the new tag
docker compose pull; docker compose up -d

(The pg_dump line is the standard PostgreSQL dump run inside the container - Outline's backups doc defers to PostgreSQL's own backup documentation.)

Backup script, backup.sh (Linux/Mac) - tar the data, config and a database dump into backups/ with the date:

File contentbash
#!/bin/bash
set -e
cd "$HOME/docker_volumes/outline"
docker compose exec -T postgres pg_dump -U user outline > "backups/outline-db-$(date +%F).sql"
tar -czf "backups/outline-files-$(date +%F).tar.gz" data docker.env docker-compose.yml

Windows equivalent, backup.ps1:

Codepowershell
Set-Location "$HOME\docker_volumes\outline"
docker compose exec -T postgres pg_dump -U user outline | Out-File "backups\outline-db-$(Get-Date -Format yyyy-MM-dd).sql" -Encoding ascii
tar -czf "backups\outline-files-$(Get-Date -Format yyyy-MM-dd).tar.gz" data docker.env docker-compose.yml

Schedule it at 03:00. Linux and Mac (cron: crontab -e):

File contenttext
0 3 * * * $HOME/docker_volumes/outline/backup.sh

Windows (Task Scheduler, one-time setup):

Run in terminalpowershell
schtasks /Create /SC DAILY /ST 03:00 /TN "Outline backup" /TR "powershell -File $HOME\docker_volumes\outline\backup.ps1"

Restore test (do one before you trust the backups): stop the stack, swap in the db folder and data folder from a backup tarball, restore the dump with docker compose exec -T postgres psql -U user outline < backups/outline-db-<DATE>.sql on a fresh database, start, and log in. Outline can also export all content as HTML, Markdown or JSON from Settings -> Export - handy as a second, human-readable backup.

Performance and resources#

We did not measure this stack, so here are the official numbers and knobs:

  • Memory: minimum 512MB, 1GB+ recommended depending on users (requirements doc). The .env.sample's rule of thumb for processes: "divide your servers available memory by 512" for WEB_CONCURRENCY (default 1).
  • CPU: "relatively low powered hardware" is fine; load scales with active users editing simultaneously.
  • Image sizes at the pinned tags: Outline ~261 MB, postgres:18 ~163 MB, redis:8 ~56 MB, caddy:2.11.8 ~25 MB (Docker Hub, read 2026-11-05).
  • Watch live usage:
Run in terminalbash
docker stats
Run in terminalpowershell
docker stats
  • Upload cap: FILE_STORAGE_UPLOAD_MAX_SIZE=262144000 (250 MB per attachment) in the sample config.

FAQ#

Can people log in with email and password? No. The official docs: "Outline does not support email + password authentication natively." You need at least one external provider - OIDC (Authentik, Pocket ID, Keycloak, Authelia...), Slack, Google, Microsoft Entra or Discord. A long-open feature request for local authentication (#1881, 341 reactions) exists, but it is still open.

Sources#

Checked against the official docs on 2026-11-05.