Skip to content

Configuration

Peek Stash Browser is configured through environment variables and the setup wizard. This page documents all available configuration options.

Stash Connection (Setup Wizard)

As of v2.0, Stash connection details are configured via the Setup Wizard and stored in the database:

  • Stash URL: Your Stash GraphQL endpoint (e.g., http://192.168.1.100:9999/graphql)
  • Stash API Key: API key from Stash Settings → Security

The wizard runs automatically on first access. No environment variables needed for Stash connection!

Upgrading from v1.x? Your existing STASH_URL and STASH_API_KEY environment variables will auto-migrate to the database on first start. You can remove them from your container configuration after successful migration.

Multi-Instance Support

Peek can connect to multiple Stash servers simultaneously. This is useful when you have separate Stash instances for different media types, locations, or libraries.

Adding Instances

Location: Settings → Server Configuration → Stash Instances

  1. Click Add Instance
  2. Fill in the instance details:
  3. Name (required) — Display name (e.g., "Main Library", "Archive Server")
  4. Description — Help users understand what content this instance contains
  5. URL (required) — Stash GraphQL endpoint (must end with /graphql)
  6. API Key (required) — From the Stash instance's Settings → Security
  7. Priority — Lower number = higher priority for deduplication
  8. Click Test Connection to validate
  9. Save the instance

Peek automatically triggers a full sync for new instances in the background.

Managing Instances

Each instance can be:

  • Edited — Update URL, API key, name, or priority
  • Enabled/Disabled — Temporarily hide an instance without deleting it
  • Deleted — Permanently remove (cannot delete the last enabled instance)

Per-User Instance Selection

When multiple instances are configured, each user can choose which instances they see content from:

Location: Settings → Content → Content Sources

  • Check or uncheck instances to control which content appears in your library
  • At least one instance must remain selected
  • New users see all instances by default

First-Login Setup

When a new user logs in and multiple instances are available, they're prompted to select which instances they want to see.

How Multi-Instance Content Works

  • Content from all selected instances appears together in search results, carousels, and browsing pages
  • Each entity is tagged internally with its source instance
  • If the same content exists on multiple instances, the instance with the lowest priority number is used as the primary source
  • Ratings, watch history, and playlists track which instance each scene belongs to

Required Environment Variables

Variable Description Example
JWT_SECRET JWT signing key Generate with openssl rand -base64 32

Generating JWT Secret

Linux/macOS/unRAID:

openssl rand -base64 32

Windows PowerShell:

$rng = [System.Security.Cryptography.RandomNumberGenerator]::Create()
$bytes = New-Object byte[] 32
$rng.GetBytes($bytes)
[Convert]::ToBase64String($bytes)

Optional Environment Variables

These settings have sensible defaults but can be customized:

Variable Description Default Notes
DATABASE_URL SQLite database file file:/app/data/peek-stash-browser.db Path inside container
CONFIG_DIR App data directory /app/data Database location
NODE_ENV Environment mode production development or production
PROXY_AUTH_HEADER Proxy Auth Header Disabled by default

Video Streaming (v2.0+)

As of v2.0, Peek streams video directly through Stash - no local media access required!

  • Videos are proxied through the Stash API
  • No media volume mounts needed
  • No path mapping configuration required
  • Simpler container setup

This is a significant simplification from v1.x which required mounting media directories and configuring path mappings.

Security Settings

Variable Description Default When to Use
SECURE_COOKIES Enable secure cookie flag false Set to true when using HTTPS reverse proxy

Security Best Practices

  • Set a strong JWT_SECRET during installation (required)
  • Set SECURE_COOKIES=true when using HTTPS
  • Never expose Peek directly to the internet - always use a reverse proxy
  • Admin credentials are created during setup wizard (no default passwords)
  • Stash API key is stored securely in the database (not in environment variables)

Proxy Authentication

Peek supports delegating authentication to your reverse proxy (e.g., Nginx, Traefik, Caddy, Authelia, Authentik). This is useful when you already have an authentication system in place and want Peek to trust the authenticated user from the proxy.

How It Works

  1. Your reverse proxy handles authentication (SSO, OAuth, basic auth, etc.)
  2. The proxy adds a header with the authenticated username to all requests
  3. Peek reads this header and looks up the corresponding user in its database
  4. If no header is present, Peek falls back to standard JWT token authentication

Configuration

Set the PROXY_AUTH_HEADER environment variable to the name of the header your proxy uses:

PROXY_AUTH_HEADER=X-Peek-Username

Common header names: - X-Peek-Username (recommended) - X-Forwarded-User (common with Authelia/Traefik) - Remote-User (common with Nginx auth_request) - X-Auth-Request-User (oauth2-proxy)

Security Requirements

Critical Security Requirements

When using proxy authentication, you MUST ensure:

  1. Peek is NOT accessible directly - Only allow access through the reverse proxy
  2. The proxy sanitizes the authentication header - The proxy must strip any user-supplied headers with the same name to prevent header injection attacks
  3. Network isolation - Peek should only listen on localhost or a private network, not on public interfaces

Failure to follow these requirements will allow anyone to impersonate any user by setting the header in their request.

Example: Nginx with auth_request

location / {
    # Authentication endpoint
    auth_request /auth;

    # Pass authenticated username to Peek
    auth_request_set $user $upstream_http_x_auth_user;
    proxy_set_header Remote-User $user;

    # CRITICAL: Strip any user-provided Remote-User headers
    proxy_set_header Remote-User "";  # Clear first
    proxy_set_header Remote-User $user;  # Then set from auth

    # Proxy to Peek
    proxy_pass http://localhost:6969;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
}
# Peek configuration
PROXY_AUTH_HEADER=Remote-User

Example: Traefik with ForwardAuth (Authelia)

# docker-compose.yml
services:
  traefik:
    labels:
      - "traefik.http.middlewares.authelia.forwardauth.address=http://authelia:9091/api/verify?rd=https://auth.example.com"
      - "traefik.http.middlewares.authelia.forwardauth.authResponseHeaders=Remote-User"

  peek:
    environment:
      - PROXY_AUTH_HEADER=Remote-User
    labels:
      - "traefik.http.routers.peek.middlewares=authelia@docker"

User Management

Users must exist in Peek's database for proxy authentication to work:

  1. Create users through Peek's admin panel (Settings → User Management)
  2. The username in Peek must exactly match the username passed by the proxy
  3. User roles and permissions are still managed within Peek
  4. Passwords are not used when proxy auth is enabled (but must still be set in the database)

Fallback Behavior

When PROXY_AUTH_HEADER is set but the header is not present in a request, Peek falls back to standard JWT cookie authentication. This allows:

  • Mixed authentication (some users via proxy, others via direct login)
  • API access using JWT tokens
  • Testing and development without the proxy

Troubleshooting

401 Unauthorized - User not found - Verify the user exists in Peek's database - Check that usernames match exactly (case-sensitive) - Verify the proxy is passing the correct header name

Users being logged in as wrong user - CRITICAL: Your proxy is not sanitizing the header properly - Verify the proxy strips user-supplied headers before setting the authenticated value - Check that Peek is not accessible directly (bypass proxy)

Example Configurations

Minimal Production Configuration (v2.0+)

# Required
JWT_SECRET=your_very_long_random_secret_key_here

# Stash connection configured via Setup Wizard (stored in database)
# All other settings use defaults

Complete Production Configuration

# Authentication (Required)
JWT_SECRET=your_very_long_random_secret_key_here

# Database (Optional - defaults shown)
DATABASE_URL=file:/app/data/peek-stash-browser.db
CONFIG_DIR=/app/data

# Security (Optional)
SECURE_COOKIES=true

# Environment (Optional)
NODE_ENV=production

# Stash connection configured via Setup Wizard (stored in database)

Development Configuration

# Authentication
JWT_SECRET=dev-secret-change-in-production

# Database (local SQLite file)
DATABASE_URL=file:./data/peek-db.db

# Development
NODE_ENV=development

# Stash connection configured via Setup Wizard

Docker Compose Example

services:
  peek:
    image: carrotwaxr/peek-stash-browser:latest
    container_name: peek-stash-browser
    ports:
      - "6969:80"
    volumes:
      - peek-data:/app/data
    environment:
      - JWT_SECRET=${JWT_SECRET}
      # Optional
      - NODE_ENV=production
      - SECURE_COOKIES=false
    restart: unless-stopped

volumes:
  peek-data:

Stash Connection

Stash URL and API key are configured via the Setup Wizard on first access and stored in the database.

Port Conflict with Whisparr

Peek's default port (6969) is the same as Whisparr's default port. If you're running Whisparr, change the port mapping to "6970:80" or another available port.

Troubleshooting Configuration Issues

Cannot Connect to Stash

Check:

  • Stash URL is accessible from the Peek container
  • Stash API key is correct and not expired
  • Stash GraphQL API is enabled

Test connectivity:

docker exec peek-stash-browser curl http://your-stash-ip:9999/graphql

You can update Stash connection details in Settings → Stash Configuration.

Videos Won't Play

Check:

  • Stash connection is configured correctly (Settings → Stash Configuration)
  • Stash server is running and accessible
  • The scene exists in Stash and has a valid video file

Authentication Issues

Check:

  • JWT_SECRET is set
  • SECURE_COOKIES matches your HTTP/HTTPS setup
  • Database is writable

Next Steps