Configuration
Tally is configured entirely through environment variables. No config files, no UI settings — just environment variables, the way infrastructure should be.
Required
ADMIN_PASSWORD # Dashboard login password (min 16 chars in production)
SITES # JSON map of sites: {"domain.com":{"token":"secret"}}
Production safety:
If
NODE_ENV=production
, the server refuses to start with the default password or any password shorter than 16
characters.
Server
PORT # HTTP port (default: 3000)
DB_PATH # SQLite database path (default: ./data/analytics.db)
GEOLITE2_PATH # MaxMind GeoLite2-City.mmdb path (default: ./data/GeoLite2-City.mmdb)
TRUSTED_PROXIES # Comma-separated IPs/CIDRs whose forwarding headers are trusted (default: none)
API_KEY # API authentication key. No fallback: unset means API auth is disabled
API authentication:
API_KEY
is never derived from
ADMIN_PASSWORD
. When it is unset, bearer-token API access is disabled entirely — generate one with, e.g.,
openssl rand -hex 32
.
Reverse proxies
Client IP resolution (rate limiting, analytics) uses the socket peer address by default;
X-Forwarded-For
and
X-Real-IP
are ignored unless the direct peer is listed in
TRUSTED_PROXIES
(exact IPs or IPv4 CIDR ranges, e.g.
TRUSTED_PROXIES=127.0.0.1,10.0.0.0/8
). Behind a trusted proxy, the forwarded chain is parsed from the trusted end, so a client
cannot forge its identity by sending its own
X-Forwarded-For
header.
TRUST_PROXY_AUTH
is separate: it trusts
Remote-User/Proxy-Secret
headers for authentication in front-door SSO setups.
Sites configuration
The
SITES
variable is a JSON object mapping site IDs to their tokens. The site ID is passed via the
data-site
attribute on the tracker script. The token is passed via
data-token
and used for origin validation.
SITES='{
"blog.example.com": { "token": "sk-blog-abc123" },
"docs.example.com": { "token": "sk-docs-def456" }
}'
GeoIP (optional)
MAXMIND_ACCOUNT_ID # MaxMind account ID for GeoLite2 downloads
MAXMIND_LICENSE_KEY # MaxMind license key
If both are provided, the Docker entrypoint automatically downloads the GeoLite2 City database on first start. Without GeoIP, country/city/region data will be unavailable.
Origin validation
The
ALLOWED_ORIGINS
variable controls which origins can send events:
ALLOWED_ORIGINS="https://example.com,https://www.example.com"
If empty, the server accepts events from any origin (useful for development). In production, set this to your site's origins.
Defaults (no configuration needed)
These work out of the box:
- SQLite database with WAL mode (automatic journaling and crash recovery)
- Daily aggregation rollups (runs every 6 hours)
- Session duration: 30 days (set by the tracker cookie)
- Ping interval: 15 seconds (for realtime tracking)
- Scroll beacon interval: 5 seconds (throttled)