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
- Open
http://your-server-ip:8000/in your browser - OWA will redirect to the installation wizard automatically on first run
- The database connection details are pre-filled from environment variables
- Create your admin account during the wizard
- After completing setup, delete or restrict access to the installer for security
To add your first website:
- Log in to the OWA dashboard
- Go to Settings → Sites → Add Site
- Enter your website URL and domain
- Copy the JavaScript tracking code and add it to your site’s
<head>section
Configuration
Key Features
| Feature | Status | Description |
|---|---|---|
| Page views & sessions | Built-in | Standard visit tracking |
| Heatmaps | Built-in | Visual click and mouse tracking |
| Click tracking | Built-in | DOM element click recording |
| Referrer tracking | Built-in | Traffic source analysis |
| Search terms | Built-in | On-site search tracking |
| WordPress plugin | Available | One-click WordPress integration |
| Custom events | Built-in | JavaScript API for custom tracking |
| REST API | Built-in | Programmatic 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
| Variable | Required | Description |
|---|---|---|
OWA_DB_TYPE | Yes | Database type (mysql) |
OWA_DB_HOST | Yes | Database host:port (db:3306) |
OWA_DB_NAME | Yes | Database name |
OWA_DB_USER | Yes | Database username |
OWA_DB_PASSWORD | Yes | Database password |
OWA_PUBLIC_URL | Yes | Public-facing URL with trailing slash |
OWA_NONCE_KEY | Yes | Random string for CSRF protection |
OWA_AUTH_KEY | Yes | Random string for auth tokens |
OWA_CACHE_OBJECTS | No | Enable object caching (true/false) |
OWA_ERROR_HANDLER | No | Error mode (production/development) |
Reverse Proxy
Place OWA behind a reverse proxy for SSL. With Nginx Proxy Manager:
- Scheme:
http - Forward Hostname:
open-web-analyticsor 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.
Related
Get self-hosting tips in your inbox
Get the Docker Compose configs, hardware picks, and setup shortcuts we don't put in articles. Weekly. No spam.
Comments