Outline: Docker Not Starting — Fix

The Problem

Outline fails to start in Docker, entering a restart loop or crashing immediately. The logs show one of these errors:

Updated March 2026: Verified with latest Docker images and configurations.

Error: connect ECONNREFUSED 127.0.0.1:5432
FATAL: password authentication failed for user "outline"
NOAUTH Authentication required
Error: [MISSING_ENV_FILE] missing .env file

Or Outline starts but crashes on the first login attempt with Invalid key length.

The Cause

Outline has several strict requirements that differ from most self-hosted apps:

  1. DATABASE_URL uses localhost — doesn’t work inside Docker’s network
  2. Redis URL format changed in v0.67.0+ — usernames in the URL are rejected
  3. SECRET_KEY must be exactly 64 hex characters — other formats crash at runtime
  4. PostgreSQL credentials mismatch — the Compose service and DATABASE_URL disagree
  5. Missing required environment variables — Outline doesn’t start without a complete config

The Fix

Method 1: Fix DATABASE_URL (Most Common)

Inside Docker, services reach each other by service name — not localhost. Change:

# WRONG — localhost refers to the Outline container itself
DATABASE_URL=postgres://outline:password@localhost:5432/outline

# CORRECT — use the Compose service name
DATABASE_URL=postgres://outline:password@postgres:5432/outline

The hostname in DATABASE_URL must match the service name in your docker-compose.yml:

services:
  outline:
    image: outlinewiki/outline:1.5.0
    # ...
  postgres:  # ← This name must match the DATABASE_URL hostname
    image: postgres:16-alpine
    # ...

Method 2: Fix Redis URL Format (v0.67.0+)

Starting with Outline v0.67.0, the Redis URL parser rejects usernames. Change:

# WRONG — has a username before the colon
REDIS_URL=redis://user:password@redis:6379

# CORRECT — colon only, no username
REDIS_URL=redis://:password@redis:6379

# CORRECT — no auth (if Redis has no password)
REDIS_URL=redis://redis:6379

Like DATABASE_URL, the hostname must match the Redis service name in your Compose file.

Method 3: Fix SECRET_KEY Format

Outline’s SECRET_KEY must be exactly 64 hexadecimal characters (representing 32 bytes). Generate it correctly:

openssl rand -hex 32

This outputs a 64-character hex string like a1b2c3d4e5f6....

Common mistakes:

ValueProblem
my-super-secret-keyNot hexadecimal
aaaaaaaaaaaaaaaaOnly 16 chars (needs 64)
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa32 chars — looks right but is only 16 bytes when hex-decoded

Also generate UTILS_SECRET the same way:

openssl rand -hex 32

Method 4: Fix PostgreSQL Credential Mismatch

Ensure the credentials in your Compose file match DATABASE_URL exactly:

services:
  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: outline         # Must match DATABASE_URL user
      POSTGRES_PASSWORD: strongpass   # Must match DATABASE_URL password
      POSTGRES_DB: outline           # Must match DATABASE_URL database
    volumes:
      - postgres-data:/var/lib/postgresql/data
    restart: unless-stopped
# Must match the values above exactly
DATABASE_URL=postgres://outline:strongpass@postgres:5432/outline

If credentials worked before but now fail: PostgreSQL stores credentials in the data volume. If you change POSTGRES_PASSWORD in the Compose file but the volume already exists, the old password persists. Either:

# Option A: Update the password inside PostgreSQL
docker exec -it postgres psql -U outline -c "ALTER USER outline PASSWORD 'newpassword';"

# Option B: Delete the volume and recreate (DESTROYS ALL DATA)
docker compose down -v
docker compose up -d

Method 5: Fix Missing Environment Variables

Outline requires these variables at minimum:

# Authentication
SECRET_KEY=<64 hex chars from openssl rand -hex 32>
UTILS_SECRET=<64 hex chars from openssl rand -hex 32>

# Database
DATABASE_URL=postgres://outline:password@postgres:5432/outline

# Redis
REDIS_URL=redis://redis:6379

# Application
URL=https://wiki.example.com
PORT=3000

# File storage
FILE_STORAGE=local
FILE_STORAGE_LOCAL_ROOT_DIR=/var/lib/outline/data

You also need at least one authentication provider configured (Slack, Google, OIDC, SAML, or email). Without one, Outline starts but you can’t log in.

For email-based login:

SMTP_HOST=smtp.example.com
SMTP_PORT=587
[email protected]
SMTP_PASSWORD=smtp-password
[email protected]
SMTP_SECURE=true

Method 6: Fix Database Migration Errors

If you see migration-related errors on first start:

SequelizeDatabaseError: column "sourceMetadata" does not exist

This is a known bug in v0.73.0 with fresh databases. Upgrade to v0.74.0+ or run migrations manually:

docker exec outline yarn db:migrate
docker compose restart outline

For general migration issues after upgrading:

# Check current migration status
docker exec outline yarn db:migrate:status

# Run pending migrations
docker exec outline yarn db:migrate

Complete Working Docker Compose

services:
  outline:
    image: outlinewiki/outline:1.5.0
    container_name: outline
    env_file: .env
    ports:
      - "3000:3000"
    volumes:
      - outline-data:/var/lib/outline/data
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_started
    restart: unless-stopped

  postgres:
    image: postgres:16-alpine
    container_name: outline-postgres
    environment:
      POSTGRES_USER: outline
      POSTGRES_PASSWORD: strongpass
      POSTGRES_DB: outline
    volumes:
      - postgres-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U outline"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped

  redis:
    image: redis:7.4-alpine
    container_name: outline-redis
    restart: unless-stopped

volumes:
  outline-data:
  postgres-data:

Prevention

  • Generate SECRET_KEY and UTILS_SECRET with openssl rand -hex 32 — never use arbitrary strings
  • Always use Docker service names (not localhost) in DATABASE_URL and REDIS_URL
  • Test the database connection before starting Outline: docker exec postgres pg_isready -U outline
  • Pin the Outline image version — don’t use :latest to avoid surprise breaking changes
  • Add a healthcheck on PostgreSQL so Outline waits for the database to be ready

Comments