Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
node_modules
dprint
.wrangler

.playwright-mcp/
data/matomo/
# Logs
*.log
*.log.*
Expand Down Expand Up @@ -46,6 +47,7 @@ data/caddy/
data/meilisearch
data/crawler
data/stalwart
data/mysql-analytics/

# SnappyMail data directory (contains emails, configs, user data)
sites/apps/snappymail.zoo/data/
Expand Down
10 changes: 10 additions & 0 deletions core/SITES.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ sites:
port: "4445"
service: hydra
hasOAuth: false
- domain: analytics.zoo
type: proxy
port: "80"
service: analytics-zoo
description: Open-source web analytics platform
icon: 📊
hasOAuth: false
onDemand: true
- domain: auth.zoo
type: proxy
port: 3000
Expand Down Expand Up @@ -152,6 +160,8 @@ sites:
hasOAuth: false
onDemand: true
services:
analytics-zoo:
hasHealthCheck: true
caddy:
hasHealthCheck: true
coredns:
Expand Down
44 changes: 38 additions & 6 deletions core/caddy/Caddyfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
}

# Load the replace-response module
order replace after encode
# Replace must happen BEFORE encode so we can modify uncompressed content
order replace before encode
# Load the fail_injector module
order fail_injector before reverse_proxy
order fail_injector before file_server
Expand Down Expand Up @@ -50,7 +51,7 @@
not header Content-Type font/*
not header Content-Type model/*
not header Content-Type multipart/*

# Exclude specific text formats that aren't HTML
not header Content-Type text/css*
not header Content-Type text/javascript*
Expand All @@ -59,17 +60,21 @@
not header Content-Type text/xml*
not header Content-Type text/plain*
}

encode gzip


handle @notBinary {
# Only inject before </body> - the replace directive won't modify content
# that doesn't contain this tag, providing natural HTML detection
replace "</body>" "<script src='https://performance.zoo/shared.js' async defer></script></body>"
replace "</BODY>" "<script src='https://performance.zoo/shared.js' async defer></script></BODY>"


# Strip CSP headers to allow injected scripts in development environment
# This is acceptable for Zoo since it's a development-only environment
header -Content-Security-Policy
header X-Performance-Zoo "injected"
}

# Apply compression after replacement (order directive ensures replace runs first)
encode gzip
}

# Snippet for fail injection (uses environment CHAOS_MODE)
Expand All @@ -90,6 +95,33 @@
# Trust only the proxy for client IP
trusted_proxies {$ZOO_PROXY_IP}
# Caddy will automatically handle X-Forwarded-* headers when trusted_proxies is set

# Request uncompressed content from upstream so replace directive can modify it
# This is critical for the replace directive to work on upstream responses
header_up Accept-Encoding identity
}
}

analytics.zoo {
import logging
import performance_zoo

route {
import proxy_handler analytics-zoo 80
}
}

http://analytics.zoo {
import logging

# Check if all sites should redirect to HTTPS
@all_https_only expression "{$ZOO_ALL_HTTPS_ONLY:false}" == "true"
redir @all_https_only https://{host}{uri} permanent

import performance_zoo

route {
import proxy_handler analytics-zoo 80
}
}

Expand Down
1 change: 1 addition & 0 deletions core/coredns/Corefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ zoo:53 {
# Use hosts plugin with environment variable support
hosts {
{$ZOO_CADDY_IP} admin.auth.zoo
{$ZOO_CADDY_IP} analytics.zoo
{$ZOO_CADDY_IP} auth.zoo
{$ZOO_CADDY_IP} classifieds.zoo
{$ZOO_CADDY_IP} example.zoo
Expand Down
3 changes: 3 additions & 0 deletions core/mysql/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ RUN curl -L https://raw.githubusercontent.com/bgrins/vwa_classifieds_optimized/f
COPY seed/northwind-schema.sql /tmp/sql/northwind-schema.sql
COPY seed/northwind-data.sql /tmp/sql/northwind-data.sql

# Copy analytics seed
COPY sql/analytics_seed.sql /tmp/sql/analytics_seed.sql

# Copy initialization script
COPY init-databases.sh /usr/local/bin/

Expand Down
5 changes: 5 additions & 0 deletions core/mysql/init-databases.sh
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ load_sql "northwind" "/tmp/sql/northwind-schema.sql"
load_sql "northwind" "/tmp/sql/northwind-data.sql"
create_snapshot "northwind"

# Matomo analytics (analytics.zoo)
create_db_for_site "analytics"
load_sql "analytics" "/tmp/sql/analytics_seed.sql"
create_snapshot "analytics"

# Example: Add more databases here
# create_db_for_site "myapp"
# load_sql "myapp" "/tmp/sql/myapp_seed.sql"
Expand Down
1,398 changes: 1,398 additions & 0 deletions core/mysql/snapshots/analytics_db.sql

Large diffs are not rendered by default.

1,279 changes: 1,279 additions & 0 deletions core/mysql/sql/analytics_seed.sql

Large diffs are not rendered by default.

35 changes: 35 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,41 @@ services:
profiles:
- on-demand

analytics-zoo:
<<: *zoo-common
build:
context: ./sites/apps/analytics.zoo
environment:
- MATOMO_DATABASE_HOST=mysql
- MATOMO_DATABASE_ADAPTER=mysql
- MATOMO_DATABASE_USERNAME=analytics_user
- MATOMO_DATABASE_PASSWORD=analytics_pw
- MATOMO_DATABASE_DBNAME=analytics_db
- MATOMO_DATABASE_TABLES_PREFIX=matomo_
- PHP_MEMORY_LIMIT=256M
volumes:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've typically not mounted volumes like these since we don't want data persisted across restarts. Have you found this to be necessary?

- ./data/matomo:/var/www/html
depends_on:
mysql:
condition: service_healthy
labels:
- "zoo.domains=analytics.zoo:80"
- "zoo.description=Open-source web analytics platform"
- "zoo.icon=📊"
healthcheck:
<<: *zoo-healthcheck
test: [
"CMD",
"curl",
"-f",
"-s",
"-o",
"/dev/null",
"http://localhost:80",
]
profiles:
- on-demand

volumes:
search_zoo_modules:
zoo_crawler_modules:
Expand Down
Loading