How to Self-Host Open Web Analytics with Docker

What Is Open Web Analytics?

Open Web Analytics (OWA) is a self-hosted web analytics platform that provides Google Analytics-style tracking with features like heatmaps, click tracking, and DOM click recording. It’s one of the oldest open-source analytics tools, licensed under GPL-2.0. OWA stores all data in your own MySQL database — no third-party data sharing. It includes a WordPress plugin for easy integration but works with any website via a JavaScript tracker.

Prerequisites

  • A Linux server (Ubuntu 22.04+ recommended)
  • Docker and Docker Compose installed (guide)
  • 512 MB of free RAM (minimum)
  • 3 GB of free disk space
  • A domain name (optional, for remote access)

Docker Compose Configuration

Create a directory for your OWA deployment:

mkdir -p ~/owa && cd ~/owa

Create a docker-compose.yml file:

services:
  owa:
    image: jhughes2112/openwebanalytics:latest  # No versioned Docker tags published — :latest is the only option
    container_name: open-web-analytics
    depends_on:
      db:
        condition: service_healthy
    environment:
      # Database connection
      OWA_DB_TYPE: mysql
      OWA_DB_HOST: "db:3306"
      OWA_DB_NAME: owa
      OWA_DB_USER: owa
      OWA_DB_PASSWORD: ${OWA_DB_PASSWORD}
      # Public URL — CHANGE to your domain
      OWA_PUBLIC_URL: ${OWA_PUBLIC_URL:-http://localhost:8000/}
      # Security keys — CHANGE all of these to random strings
      OWA_NONCE_KEY: ${OWA_NONCE_KEY}
      OWA_NONCE_SALT: ${OWA_NONCE_SALT}
      OWA_AUTH_KEY: ${OWA_AUTH_KEY}
      OWA_AUTH_SALT: ${OWA_AUTH_SALT}
      # Application settings
      OWA_ERROR_HANDLER: production
      OWA_LOG_PHP_ERRORS: "false"
      OWA_CACHE_OBJECTS: "true"
    ports:
      - "8000:8000"
    volumes:
      - owa_html:/var/www/html
    restart: unless-stopped
    networks:
      - owa-net

  db:
    image: mysql:5.7
    container_name: owa-db
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: owa
      MYSQL_USER: owa
      MYSQL_PASSWORD: ${OWA_DB_PASSWORD}
    volumes:
      - owa_db:/var/lib/mysql
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped
    networks:
      - owa-net

volumes:
  owa_html:
  owa_db:

networks:
  owa-net:
    driver: bridge

Create a .env file alongside it:

# Database passwords — CHANGE THESE
OWA_DB_PASSWORD=change-me-strong-password
MYSQL_ROOT_PASSWORD=change-me-root-password

# Public URL — CHANGE to your domain
OWA_PUBLIC_URL=http://analytics.example.com:8000/

# Security keys — generate random strings for each
# Use: openssl rand -hex 32
OWA_NONCE_KEY=change-me-random-string-1
OWA_NONCE_SALT=change-me-random-string-2
OWA_AUTH_KEY=change-me-random-string-3
OWA_AUTH_SALT=change-me-random-string-4

Start the stack:

docker compose up -d

Initial Setup

  1. Open http://your-server-ip:8000/ in your browser
  2. OWA will redirect to the installation wizard automatically on first run
  3. The database connection details are pre-filled from environment variables
  4. Create your admin account during the wizard
  5. After completing setup, delete or restrict access to the installer for security

To add your first website:

  1. Log in to the OWA dashboard
  2. Go to Settings → Sites → Add Site
  3. Enter your website URL and domain
  4. Copy the JavaScript tracking code and add it to your site’s <head> section

Configuration

Key Features

FeatureStatusDescription
Page views & sessionsBuilt-inStandard visit tracking
HeatmapsBuilt-inVisual click and mouse tracking
Click trackingBuilt-inDOM element click recording
Referrer trackingBuilt-inTraffic source analysis
Search termsBuilt-inOn-site search tracking
WordPress pluginAvailableOne-click WordPress integration
Custom eventsBuilt-inJavaScript API for custom tracking
REST APIBuilt-inProgrammatic data access

WordPress Integration

OWA includes a built-in WordPress plugin. Install it directly from the OWA web interface or download from the GitHub repository. The plugin auto-injects the tracking code — no manual snippet placement needed.

Environment Variable Reference

VariableRequiredDescription
OWA_DB_TYPEYesDatabase type (mysql)
OWA_DB_HOSTYesDatabase host:port (db:3306)
OWA_DB_NAMEYesDatabase name
OWA_DB_USERYesDatabase username
OWA_DB_PASSWORDYesDatabase password
OWA_PUBLIC_URLYesPublic-facing URL with trailing slash
OWA_NONCE_KEYYesRandom string for CSRF protection
OWA_AUTH_KEYYesRandom string for auth tokens
OWA_CACHE_OBJECTSNoEnable object caching (true/false)
OWA_ERROR_HANDLERNoError mode (production/development)

Reverse Proxy

Place OWA behind a reverse proxy for SSL. With Nginx Proxy Manager:

  • Scheme: http
  • Forward Hostname: open-web-analytics or your server IP
  • Forward Port: 8000
  • Enable SSL and force HTTPS

Update OWA_PUBLIC_URL to your HTTPS domain (e.g., https://analytics.example.com/). See our Reverse Proxy Setup guide.

Backup

Back up the MySQL database:

docker exec owa-db mysqldump -u owa -p"$OWA_DB_PASSWORD" owa > owa_backup_$(date +%Y%m%d).sql

Back up both the owa_db (database) and owa_html (application config) volumes. See our Backup Strategy guide.

Troubleshooting

Port 80 Not Working

Symptom: Container fails to bind to port 80. Fix: OWA runs as a non-root user inside the container and cannot bind to privileged ports. Use port 8000 and put a reverse proxy in front.

MySQL Connection Error on First Start

Symptom: OWA shows database connection errors. Fix: MySQL 5.7 can take 30-60 seconds to initialize on first run. Wait for the health check to pass (docker compose ps — look for “healthy” status), then reload OWA.

Heatmaps Not Recording

Symptom: Heatmap data is empty despite page views recording. Fix: Heatmaps require the JavaScript tracker (not just the pixel). Verify the OWA JS snippet is loading in your browser’s DevTools Network tab. Check for Content-Security-Policy headers blocking the script.

Tracking Code Not Counting Visits

Symptom: Zero page views in dashboard. Fix: Verify OWA_PUBLIC_URL matches the URL your tracking script uses. If they differ (e.g., HTTP vs HTTPS), requests will be blocked by the browser’s mixed-content policy.

Resource Requirements

  • RAM: ~128 MB idle, ~512 MB under load
  • CPU: Low
  • Disk: ~200 MB for application, plus MySQL data growth (scales with traffic volume)

Verdict

OWA targets a niche that most modern analytics tools have abandoned: full Google Analytics-style tracking (heatmaps, click recording, DOM analysis) in a self-hosted package. The heatmap feature alone sets it apart from Plausible, Umami, and Shynet. The downside is age — the codebase is PHP 7, there’s no official Docker image, and development pace is slow compared to newer tools. Use OWA if you specifically need heatmaps and click tracking without paying for Hotjar. For general web analytics, Plausible or Umami are better maintained.

Comments