Skip to content

📊 Service: GoAccess (Logging Analytics)

Location: /mnt/pool01/homelab/services/ops-stack/goaccess

GoAccess is a real-time web log analyzer that provides a visual dashboard for the Caddy reverse proxy. This specific configuration operates strictly in LAN-Only mode.

Docker Compose

networks:
  dockerapps-net:
    external: true
# ------------------------------------------------
# GOACCESS (Logs)
# ------------------------------------------------
services:
  goaccess:
    image: allinurl/goaccess:latest
    container_name: goaccess
    networks:
      dockerapps-net:
        ipv4_address: 172.20.0.29
        ipv6_address: fd00:dead:beef:2::29
    ports:
      # Changed to 7891 to free up 7890
      - "7891:7891" 
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
    volumes:
      # READ LOGS (Point to Caddy's folder)
      - /mnt/pool01/homelab/services/gateway-stack/caddy/logs:/var/log/caddy:ro
      - ./data:/srv/data
      - ./html:/srv/report
      # MAXMIND (Read from Caddy's folder)
      - /mnt/pool01/homelab/services/gateway-stack/caddy/maxmind:/srv/maxmind:ro
    tmpfs:
      - /var/www/goaccess
    command: >
      /var/log/caddy/access.log
      --log-format=CADDY
      --real-time-html
      --addr=0.0.0.0
      --port=7891
      --output=/srv/report/index.html
      --db-path=/srv/data
      --persist
      --restore
      --geoip-database=/srv/maxmind/GeoLite2-Country.mmdb
      --ws-url=ws://192.168.0.100:7891
      --origin=http://192.168.0.100:7890
      --exclude-ip=172.20.0.0/24
      --exclude-ip=192.168.0.0/16
      --exclude-ip=127.0.0.1
      --exclude-ip=fd00:dead:beef:1::/64
      --exclude-ip=::1
      --ignore-crawlers
    restart: unless-stopped

# 2. The Web Server (Frontend)
  report-server:
    image: caddy:alpine
    container_name: goaccess-webui
    networks:
      - dockerapps-net
    # Simple one-liner to just serve the folder
    command: caddy file-server --listen :80 --root /srv/report
    volumes:
      # Read the file GoAccess writes
      - ./html:/srv/report:ro
    ports:
      # Visit this port
      - "7890:80"
    restart: unless-stopped

Decoupled Setup

Unlike standard setups where GoAccess runs inside the web server, this stack is completely decoupled from the main Caddy gateway. It runs in its own directory with a dedicated frontend and backend, reading the gateway's logs via shared volume mounts.


Container Architecture

This stack consists of two separate containers working in tandem to overcome the challenge of serving static HTML while simultaneously streaming live data.

Service Container Name Port (Host) Role Description
GoAccess goaccess 7891 Backend Analyzes the raw logs and streams live data via WebSocket.
Report Server goaccess-webui 7890 Frontend A lightweight Caddy instance that strictly serves the static HTML dashboard.

Traffic Flow (Real-Time Sync)

To support real-time updates without exposing the backend to the public internet, we use a split-port data flow:

  1. The "Visit" (Frontend): * We visit http://192.168.0.100:7890 in our local browser.

    • The goaccess-webui container serves the index.html file (which is just a static visual "skeleton").
  2. The "Stream" (Backend): * The JavaScript inside index.html executes and opens a background data pipe.

    • It connects directly to ws://192.168.0.100:7891 (The goaccess container).
    • Live log data is pushed to the browser via WebSocket.

Configuration & Mounts

Execution Flags

The goaccess command in the compose.yml uses specific flags to make this LAN-only setup work. I aim to not change these unless our host machine's IP address changes.

Flag Value Purpose
--real-time-html Enabled Tells GoAccess to generate an HTML file that constantly listens for WebSocket updates.
--ws-url ws://192.168.0.100:7891 Critical: Defines the WebSocket endpoint. Must use ws:// (Unencrypted) and target the backend port 7891.
--origin http://192.168.0.100:7890 Security: Strict CORS Allow-list. Only allows WebSocket connections initiated from the Frontend Dashboard URL.

Cross-Stack Volume Mounts

Because this service is decoupled, it relies on files generated by the gateway-stack located in a sibling directory.

  • Logs (access.log): ../gateway-stack/caddy/logs:/var/log/caddy:ro (Read-only access to parse the Caddy traffic).
  • GeoIP Database: ../gateway-stack/caddy/maxmind:/srv/maxmind:ro (Shared MaxMind database to map IP addresses to countries).

Troubleshooting

WebSocket Connection Failed

  • Symptoms: The dashboard loads but shows a red disconnected icon in the corner.
  • Cause: The browser cannot reach Port 7891.
  • Fix: Ensure --ws-url uses ws:// (not wss://) and that port 7891 is successfully exposed in your compose.yml.

HTTP Error 400 (Bad Request)

  • Symptoms: The browser console shows Unexpected response code: 400 and data won't load.
  • Cause: Origin Mismatch (CORS block). The browser is visiting from an IP/URL that doesn't match the --origin flag.
  • Fix: Update --origin in the compose.yml to match our exact host machine IP or LAN DNS name (e.g., http://192.168.0.100:7890).

Dashboard Not Updating (Stale File)

  • Symptoms: We changed a configuration (like updating a port), but the browser still tries to connect to the old port.
  • Cause: GoAccess failed to overwrite the old index.html file in the persistent volume.
  • Fix:
    1. Delete the stale file: rm ./html/index.html
    2. Force recreate the container: docker compose up -d --force-recreate
    3. Perform a Hard Refresh in browser (Ctrl + F5).