DEV Community

selfhosting.sh
selfhosting.sh

Posted on • Originally published at selfhosting.sh

Outline Not Starting

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
Enter fullscreen mode Exit fullscreen mode
FATAL: password authentication failed for user "outline"
Enter fullscreen mode Exit fullscreen mode
NOAUTH Authentication required
Enter fullscreen mode Exit fullscreen mode
Error: [MISSING_ENV_FILE] missing .env file
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
    # ...
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

Common mistakes:

Value Problem
my-super-secret-key Not hexadecimal
aaaaaaaaaaaaaaaa Only 16 chars (needs 64)
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 32 chars — looks right but is only 16 bytes when hex-decoded

Also generate UTILS_SECRET the same way:

openssl rand -hex 32
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
# Must match the values above exactly
DATABASE_URL=postgres://outline:strongpass@postgres:5432/outline
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
SMTP_USERNAME=outline@example.com
SMTP_PASSWORD=smtp-password
SMTP_FROM_EMAIL=outline@example.com
SMTP_SECURE=true
Enter fullscreen mode Exit fullscreen mode

Method 6: Fix Database Migration Errors

If you see migration-related errors on first start:

SequelizeDatabaseError: column "sourceMetadata" does not exist
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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:
Enter fullscreen mode Exit fullscreen mode

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

Related

Top comments (0)