Skip to content

A privacy-focused, self-hosted web analytics platform

Notifications You must be signed in to change notification settings

atgreen/happening

Repository files navigation

Happening

A privacy-focused, self-hosted web analytics platform written in Common Lisp.

Features

  • Privacy-first - No cookies, no personal data collection
  • Self-hosted - Your data stays on your server
  • Automatic HTTPS - Built-in Let's Encrypt certificate management via pure-tls
  • Country detection - Built-in IP-to-country lookup (no external API calls)
  • Lightweight - Single binary, SQLite database, runs on free-tier cloud VMs (AWS, GCP, Azure, etc.)
  • Simple setup - Interactive wizard or command-line options

Quick Start

Building

make

Setup

Interactive setup wizard:

./happening setup

Or non-interactive:

./happening setup \
  -a admin \
  -P yourpassword \
  -u https://analytics.example.com \
  -e [email protected]

Running

# HTTP only (development)
./happening -p 8080

# HTTPS with automatic Let's Encrypt certificates
./happening -u https://analytics.example.com

Configuration

Command Line Options

Option Description
-p, --port PORT HTTP server port (default: 8080)
-u, --url URL Public base URL (enables HTTPS if https://)
-d, --database PATH SQLite database path
-s, --slynk-port PORT Start Slynk server for remote REPL

Environment Variables

Variable Description
ACME_EMAIL Contact email for Let's Encrypt account
ACME_STAGING Set to true for staging certificates (default: production)
ACME_CERT_PATH Custom certificate storage path
ACME_RENEWAL_DAYS Days before expiry to trigger renewal (default: 30)

Environment variables can also be set in a .env file.

HTTPS Configuration

When you specify an https:// URL with -u, Happening automatically:

  1. Obtains a Let's Encrypt certificate using TLS-ALPN-01 challenge
  2. Serves HTTPS on port 443
  3. Renews certificates automatically before expiry

Requirements:

  • Port 443 must be accessible from the internet
  • Domain must resolve to your server's IP address

Example deployment:

# First time setup
./happening setup -a admin -P secret123 \
  -u https://analytics.example.com \
  -e [email protected]

# Run with production certificates (default)
[email protected] \
./happening -u https://analytics.example.com

Tracking Script

After setup, add this script to your website:

<script defer src="https://analytics.example.com/js/script.js"
        data-api="https://analytics.example.com/api/event"></script>

Country Detection

Country data from ipverse/country-ip-blocks is embedded in the binary—no setup required. To use fresher data, clone the repo:

git clone https://github.com/ipverse/country-ip-blocks data/country-ip-blocks

External data takes priority over embedded data. See docs/GEOIP-SETUP.md for details.

Acknowledgments

Development

Prerequisites

  • SBCL (Steel Bank Common Lisp)
  • Make

Building from Source

make clean && make

Running with Slynk

./happening -p 8080 -s 4005

Then connect from Emacs with M-x sly-connect.

License

MIT License

Copyright (c) 2025 Anthony Green

About

A privacy-focused, self-hosted web analytics platform

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages