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.

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.
| Item | Value |
|---|---|
| Current version | v1.12.0 (released 2026-10-23, GitHub releases) |
| Licence | Business Source License 1.1 (see What the BSL licence means) |
| Time needed | 30-60 minutes plus your IdP setup (our estimate; we did not run it) |
| RAM | Minimum 512MB, 1GB+ recommended (official requirements) |
| Image size | ~261 MB amd64 (outlinewiki/outline:1.12.0, Docker Hub, read 2026-11-05) |
| Ports | 3000 inside Docker (not published); 80/443 on your reverse proxy |
| Official docs | docs.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.
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:
docker --version docker compose version
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'sURLmust 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#
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)#
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):
$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:
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):
nano ~/docker_volumes/outline/docker.env
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:
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:
URLis 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#
nano ~/docker_volumes/outline/docker-compose.yml
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)#
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):
docker compose config
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}.callbackwith plugin idoidc) - Scopes:
openid profile email(Outline's default) - A provider that returns an email claim, a name (it reads
preferred_usernameby 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#
nano ~/docker_volumes/outline/docker.env
Append (auto-discovery route - Outline reads /.well-known/openid-configuration from your issuer):
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.crttodocker.envand bind-mount your root CA into the container (add- ./myca.crt:/etc/ssl/myca.crt:roto the outline service's volumes in Step 3).
Windows (PowerShell)#
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:
curl https://id.example.com/.well-known/openid-configuration
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(orOIDC_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#
cd ~/docker_volumes/outline docker compose up -d
Windows (PowerShell)#
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:
docker compose ps docker compose logs outline --tail 100
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:
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:
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):
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:
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:
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:
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:
docker compose cp caddy:/data/caddy/pki/authorities/local/root.crt /usr/local/share/ca-certificates/root.crt sudo update-ca-certificates
docker compose cp caddy:/data/caddy/pki/authorities/local/root.crt $env:TEMP\root.crt certutil -addstore -f "ROOT" $env:TEMP\root.crt
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:
curl -I https://wiki.example.com
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.envholdsSECRET_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 losingSECRET_KEYmakes "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 addports:mappings for Outline itself unless you bind them to127.0.0.1. - HTTPS: verify with
curl -I https://wiki.example.comafter the proxy section; Outline'sFORCE_HTTPS=true(the default) redirects HTTP visitors to HTTPS. - Status and function tests:
docker compose psfor health,docker compose logs outline --tail 100for errors, then a real login and a document edit (editing proves websockets work). - More logs when debugging: set
LOG_LEVEL=debugindocker.env- the troubleshooting doc says this level is "often requested" on the support forums. Put it back toinfoafterwards. - 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." SetENABLE_UPDATES=falseindocker.envif 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 withFILE_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:
| Theme | Reports |
|---|---|
| OIDC and login | 6 |
| Exports | 2 |
| File storage / S3 | 1 |
| SECRET_KEY format | 1 |
| Sessions / CSRF | 1 |
| Local-network calls blocked | 1 |
| No local login (feature request) | 1 |
| Config system (feature request) | 1 |
The mistakes behind them, and the fixes:
| Mistake | Why it happens | Do this instead |
|---|---|---|
| Launching with no auth provider configured | Outline looks like any web app, so people expect a signup form | Configure 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 default | Set 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 format | Any random string looks good enough | It 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" advice | Tutorials and memories from before FILE_STORAGE existed | Current 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 setup | FORCE_HTTPS=true is the default while people test over plain HTTP | Set FORCE_HTTPS=false while testing, and clear the browser's cached HTTPS attempt (official troubleshooting doc) |
| Moving the IdP to a new domain | Outline kept the old provider hostname in its database | Fixed 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 config | Assistants trained on old tutorials and old .env.sample files | Check 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, notlatest). 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=debugand readdocker compose logs outline --tail 100before searching forums - the troubleshooting doc says debug logs are the first thing maintainers ask for.
Troubleshooting#
| Problem | Solution |
|---|---|
| Redirect loop between HTTP and HTTPS | FORCE_HTTPS=false while testing; clear the browser's cached HTTPS attempt |
| Documents load but cannot be edited | Your proxy is not forwarding websockets - a hard Outline requirement |
EADDRINUSE at startup | Another service (or another Outline copy) holds the port; change PORT or stop the other service |
| Cannot reach Postgres/Redis on the host | Run 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 export | Known open bug for image-heavy PDF exports (#12441, open Nov 2026); export Markdown instead |
| "Config could not be parsed" in the browser | A 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:
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
SequelizeUniqueConstraintErrorwith 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_verifiedclaim (#12630, #13242, fixed August 2026). We found no breakage reports for v1.12.0 itself in our reading.
Diagnostic commands:
docker compose ps
docker compose logs outline --tail 100
docker inspect --format '{{.State.Health.Status}}' $(docker compose ps -q postgres)
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:
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
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:
#!/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:
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):
0 3 * * * $HOME/docker_volumes/outline/backup.sh
Windows (Task Scheduler, one-time setup):
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" forWEB_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:
docker stats
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#
- Outline repository and README (read Nov 2026)
- Outline hosting docs (read Nov 2026)
- Requirements, Installation methods, Docker (read Nov 2026)
- Authentication, OIDC, File storage, SMTP (read Nov 2026)
- SSL, Self-signed certificates, Backups, Troubleshooting, Licence restrictions (read Nov 2026)
- Outline LICENSE (BSL 1.1) and .env.sample (read Nov 2026)
- Release v1.12.0 (Oct 2026)
- User reports: issues #13572, #14383, #12630, #13242, #12323, #11811, #12884, #10983, #10890, #10057, #5709, #1881, #12441, #8530 (read Nov 2026)
- Caddy install, running, automatic HTTPS, reverse_proxy (read Nov 2026)
- Authentik's Outline integration guide (linked from Outline's OIDC docs; page would not render for us)
Checked against the official docs on 2026-11-05.