Skip to main content

Overview

Umami uses environment variables for configuration. Variables are read from the environment or from a .env file in the application root.
Environment variables are defined in /next.config.ts and loaded using dotenv.

Core Variables

DATABASE_URL (Required)

PostgreSQL database connection string.
DATABASE_URL=postgresql://username:password@hostname:port/database
DATABASE_URL=postgresql://umami:password@localhost:5432/umami
Never commit .env files containing DATABASE_URL to version control!

APP_SECRET

Secret key for securing sessions and cryptographic operations.
APP_SECRET=your-random-secret-key
Generate a secure secret:
openssl rand -base64 32
  • Use a long, random string (32+ characters)
  • Never use the default value in production
  • Changing this will invalidate all existing sessions

Server Configuration

PORT

Server listening port.
PORT=3000
Default: 3000
In Docker, the internal port is always 3000. Map to a different external port using ports in docker-compose.yml.

HOSTNAME

Server bind address.
HOSTNAME=0.0.0.0
Default: 0.0.0.0 (all interfaces) Options:
  • 0.0.0.0 - Listen on all network interfaces
  • 127.0.0.1 - Listen only on localhost
  • :: - Listen on all IPv6 interfaces

BASE_PATH

Serve Umami from a subdirectory.
BASE_PATH=/analytics
Default: None (root path)
# No BASE_PATH
# Access at: https://example.com/
When using BASE_PATH, you must rebuild the application. It cannot be changed at runtime.

Database Configuration

CLICKHOUSE_URL

ClickHouse database connection for high-volume analytics.
CLICKHOUSE_URL=http://localhost:8123/umami
Default: None (uses PostgreSQL only)
CLICKHOUSE_URL=http://localhost:8123/umami
When CLICKHOUSE_URL is set, Umami uses dual databases: PostgreSQL for user data, ClickHouse for analytics.

REDIS_URL

Redis connection for session storage and caching.
REDIS_URL=redis://localhost:6379
Default: None (in-memory sessions)
REDIS_URL=redis://localhost:6379
REDIS_URL is required when running multiple Umami instances for session sharing.

Security Configuration

FORCE_SSL

Enforce HTTPS by adding Strict-Transport-Security header.
FORCE_SSL=1
Default: Not set Values:
  • 1 - Enable HSTS header
  • Not set - No HSTS header
When enabled, adds header:
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Only enable this if Umami is served over HTTPS. Enabling on HTTP will break access.

ALLOWED_FRAME_URLS

Allow embedding Umami in iframes from specific domains.
ALLOWED_FRAME_URLS=https://example.com https://app.example.com
Default: 'self' (only same origin) Updates Content-Security-Policy frame-ancestors directive:
Content-Security-Policy: frame-ancestors 'self' https://example.com https://app.example.com;
Only add trusted domains. Allowing untrusted domains creates clickjacking risks.

CORS_MAX_AGE

Maximum age for CORS preflight cache (in seconds).
CORS_MAX_AGE=86400
Default: 86400 (24 hours) Sets the Access-Control-Max-Age header for API endpoints.

Tracker Configuration

TRACKER_SCRIPT_NAME

Custom filename(s) for the tracking script.
TRACKER_SCRIPT_NAME=analytics.js,stats.js
Default: script.js Allows accessing the tracker at custom URLs to bypass ad blockers:
<!-- Default -->
<script async src="https://analytics.example.com/script.js"></script>

<!-- Custom -->
<script async src="https://analytics.example.com/analytics.js"></script>
Use multiple names separated by commas. All will serve the same tracking script.

TRACKER_SCRIPT_URL

Proxy tracking script from external URL.
TRACKER_SCRIPT_URL=https://cdn.example.com/umami.js
Default: None (serves from local) Useful for serving the tracker from a CDN:
next.config.ts
if (trackerScriptURL) {
  rewrites.push({
    source: TRACKER_SCRIPT,
    destination: trackerScriptURL,
  });
}

COLLECT_API_ENDPOINT

Custom endpoint for data collection.
COLLECT_API_ENDPOINT=/api/collect
Default: /api/send Changes the data collection endpoint URL to bypass ad blockers.

Localization

DEFAULT_LOCALE

Default language for the interface.
DEFAULT_LOCALE=en-US
Default: en-US Supported locales:
  • en-US - English (United States)
  • es-ES - Spanish (Spain)
  • fr-FR - French (France)
  • de-DE - German (Germany)
  • ja-JP - Japanese (Japan)
  • zh-CN - Chinese (Simplified)
  • pt-BR - Portuguese (Brazil)
  • And many more…
Users can override the default locale in their profile settings.

Cloud Mode

CLOUD_MODE

Enable cloud-specific features.
CLOUD_MODE=1
Default: Not set
This is for Umami Cloud only. Do not enable for self-hosted instances.

CLOUD_URL

URL for cloud-mode features.
CLOUD_URL=https://cloud.umami.is
Default: None
Only used when CLOUD_MODE is enabled.

Development Variables

NODE_ENV

Node.js environment.
NODE_ENV=production
Values:
  • production - Production mode (optimized, no debug)
  • development - Development mode (hot reload, debug)
  • test - Test mode
Always use production for deployed instances. Development mode has performance overhead and security implications.

NEXT_TELEMETRY_DISABLED

Disable Next.js telemetry.
NEXT_TELEMETRY_DISABLED=1
Default: 1 (disabled in Dockerfile) Umami disables this by default for privacy.

Database Control

SKIP_DB_CHECK

Skip database connection check on startup.
SKIP_DB_CHECK=1
Default: Not set
Only use for troubleshooting. Application will fail if database is unavailable.

SKIP_DB_MIGRATION

Skip automatic database migration on startup.
SKIP_DB_MIGRATION=1
Default: Not set
Use this if you want to manually control when migrations run.

GeoIP Database

GEO_DATABASE_URL

URL to download MaxMind GeoLite2 database.
GEO_DATABASE_URL=https://example.com/GeoLite2-City.mmdb
Default: None (uses included database) The build process downloads this automatically. Override to use a custom source.

Complete .env Example

Here’s a complete production .env file:
.env
# Required
DATABASE_URL=postgresql://umami:secure-password@localhost:5432/umami
APP_SECRET=generated-with-openssl-rand-base64-32

# Server
PORT=3000
HOSTNAME=0.0.0.0

# Optional: ClickHouse for high volume
# CLICKHOUSE_URL=http://localhost:8123/umami

# Optional: Redis for multiple instances
# REDIS_URL=redis://localhost:6379

# Security
FORCE_SSL=1

# Localization
DEFAULT_LOCALE=en-US

# Tracker customization (bypass ad blockers)
TRACKER_SCRIPT_NAME=stats.js,analytics.js
COLLECT_API_ENDPOINT=/api/collect

# Production mode
NODE_ENV=production

Docker Compose Example

docker-compose.yml
services:
  umami:
    image: ghcr.io/umami-software/umami:latest
    ports:
      - "3000:3000"
    environment:
      # Required
      DATABASE_URL: postgresql://umami:${DB_PASSWORD}@db:5432/umami
      APP_SECRET: ${APP_SECRET}
      
      # Optional
      FORCE_SSL: 1
      DEFAULT_LOCALE: en-US
      TRACKER_SCRIPT_NAME: analytics.js
      COLLECT_API_ENDPOINT: /api/collect
    depends_on:
      db:
        condition: service_healthy
    restart: always
    init: true
With .env file:
.env
DB_PASSWORD=your-secure-database-password
APP_SECRET=your-generated-app-secret

Kubernetes ConfigMap

configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: umami-config
  namespace: umami
data:
  PORT: "3000"
  HOSTNAME: "0.0.0.0"
  FORCE_SSL: "1"
  DEFAULT_LOCALE: "en-US"
  CORS_MAX_AGE: "86400"
  TRACKER_SCRIPT_NAME: "analytics.js,stats.js"
  COLLECT_API_ENDPOINT: "/api/collect"
secrets.yaml
apiVersion: v1
kind: Secret
metadata:
  name: umami-secrets
  namespace: umami
type: Opaque
stringData:
  DATABASE_URL: postgresql://umami:password@postgres:5432/umami
  APP_SECRET: your-app-secret
  REDIS_URL: redis://redis:6379

Environment Variable Priority

Variables are loaded in this order (later overrides earlier):
  1. Default values in next.config.ts
  2. .env file in application root
  3. System environment variables
  4. Docker/Kubernetes environment variables

Validation

Umami validates required environment variables on startup:
scripts/check-env.js
function checkMissing(requiredVars) {
  const missing = requiredVars.filter(name => !process.env[name]);
  if (missing.length > 0) {
    throw new Error(`Missing required environment variables: ${missing.join(', ')}`);
  }
}

checkMissing(['DATABASE_URL']);

Troubleshooting

Check .env file location:
# Must be in application root
/path/to/umami/.env
Verify file format:
# Correct
DATABASE_URL=postgresql://...

# Wrong - no spaces
DATABASE_URL = postgresql://...

# Wrong - no quotes needed
DATABASE_URL="postgresql://..."
Ensure DATABASE_URL is set:
# Check current environment
echo $DATABASE_URL

# Or in Docker
docker compose exec umami env | grep DATABASE_URL
Set it if missing:
export DATABASE_URL=postgresql://...
BASE_PATH requires rebuilding:
# Set BASE_PATH
export BASE_PATH=/analytics

# Rebuild application
pnpm build

# Or rebuild Docker image
docker build --build-arg BASE_PATH=/analytics -t umami .
Cannot be changed at runtime.
Set APP_SECRET to prevent session invalidation:
# Generate secret
openssl rand -base64 32

# Set in .env
APP_SECRET=generated-secret
Or use Redis for session storage:
REDIS_URL=redis://localhost:6379

Security Best Practices

Strong Secrets

Use cryptographically secure random values for APP_SECRET.

Secure Storage

Never commit .env files to version control.

Principle of Least Privilege

Database users should have minimum required permissions.

Regular Rotation

Rotate secrets periodically, especially after team changes.

.gitignore Entry

Always exclude environment files:
.gitignore
# Environment variables
.env
.env.local
.env.production
.env.development

Next Steps

Docker Deployment

Deploy with Docker Compose

PostgreSQL

Configure your database

Upgrading

Update your installation

Troubleshooting

Solve configuration issues

Build docs developers (and LLMs) love