Obiz Solutions

GoAccess Dashboard — automated multi-site traffic tracking

GoAccess Dashboard is an automated system that runs daily, aggregates traffic across multiple sites (starting with obiz-solution.com, growing to cover others like vuecs.com), and serves a single dashboard at goaccess.obiz-solution.com — password-protected, no need to open the AWS Console just to check numbers.

Architecture

GoAccess Dashboard architecture: CloudFront logs from multiple sites → GitHub Actions (daily cron) → GoAccess → S3 → CloudFront with Basic Auth → browser

  1. Each source site (obiz-solution.com, vuecs.com…) already has CloudFront access logs enabled, writing to its own S3 bucket.
  2. GitHub Actions in the goaccess-dashboard repo runs on a schedule (cron, once a day) — not triggered by a code push, since the goal is fetching fresh data, not deploying new code.
  3. For each site declared in systems.json, the workflow syncs the latest logs from that site’s bucket, runs goaccess to produce a per-site HTML report, then builds an index.html listing every site.
  4. The whole output is synced to a separate private S3 bucket (goaccess.obiz-solution.com), through the same kind of OIDC role as the main site — no stored access keys.
  5. CloudFront sits in front of that bucket, with a CloudFront Function running at the Viewer Request stage to check HTTP Basic Auth — wrong or missing credentials return 401 right at the edge, never even reaching S3.

Basic Auth without a server

Since the whole stack is still a static site (S3 + CloudFront), there’s no server around to check a password the traditional way. The fix: a CloudFront Function — a tiny bit of JS that runs directly at the edge location, comparing the request’s Authorization header against an expected value. That value (a Basic <base64> string) lives in a CloudFront KeyValueStore — set through the AWS Console, never committed to git — keeping the credential entirely out of the source code.

systems.json — an extensible config

[
  { "name": "obiz-solution.com", "logBucket": "obiz-solution.com-logs", "logPrefix": "cf-logs/" },
  { "name": "vuecs.com", "logBucket": "vuecs.com-logs", "logPrefix": "cf-logs/" }
]

Adding a new site is just one more line (as long as that site also has CloudFront logging enabled with the same agreed 33-field format) — nothing in the workflow or script needs to change.

Why once a day, not real-time

CloudFront delivers logs in batches, not instantly, and the goal here is spotting traffic trends, not real-time monitoring — running once a day is plenty fresh, keeps Athena/GoAccess costs near zero, and avoids paying for CloudFront real-time logs (which use Kinesis and cost continuously).