Skip to main content

GoAccess — Real-Time Web Log Analyzer

GoAccess is an open-source real-time web log analyzer that works in both terminal and browser environments. It parses logs from Nginx, Apache, Amazon S3, and many other formats, and instantly visualizes visitor counts, request statistics, bandwidth, response time, and more. It runs as a single binary with no database or backend dependency, making it easy to install on production servers and start analyzing immediately.


Introduction and Installation

Key Features

  • Real-time updates: Both the terminal dashboard and HTML report refresh live via WebSocket
  • Wide format support: Nginx combined/main, Apache combined, Amazon S3, W3C, CSV, and more
  • Single binary: No dependencies, runs immediately after download
  • Rich statistics: Visitors, requests, status codes, bandwidth, response time, GeoIP location data

Install — Debian/Ubuntu (apt)

# Ubuntu 22.04 and later
sudo apt-get update
sudo apt-get install -y goaccess

# Verify installation
goaccess --version

To install the latest version, add the official GoAccess repository:

# Add the official GoAccess APT repository
echo "deb https://deb.goaccess.io/ $(lsb_release -cs) main" | \
sudo tee /etc/apt/sources.list.d/goaccess.list
wget -O- https://deb.goaccess.io/gnugpg.key | sudo apt-key add -
sudo apt-get update
sudo apt-get install -y goaccess

Install — macOS (Homebrew)

brew install goaccess

# Install with GeoIP support
brew install goaccess --with-geoip

Install — Docker

# Using the allinea/goaccess image
docker pull allinea/goaccess

# Quick test run
docker run --rm -v /var/log/nginx:/var/log/nginx allinea/goaccess \
/var/log/nginx/access.log \
--log-format=COMBINED \
--no-global-config \
-o /var/log/nginx/report.html

Terminal Real-Time Dashboard

Basic Usage

# Launch terminal dashboard with COMBINED format (Nginx/Apache default)
goaccess /var/log/nginx/access.log --log-format=COMBINED

# Pipe from tail -f for live streaming
tail -f /var/log/nginx/access.log | goaccess --log-format=COMBINED -

After launch, the terminal displays these sections:

Dashboard — Overall Analyzed Requests
Visitors Requests Static Requests
Unique Visitors Not Found Log Size
Dynamic Requests Failed Requests Bandwidth
...

1. Unique Visitors per Day
2. Requested Files (URLs)
3. Static Requests
4. Not Found URLs (404)
5. Visitor Hostnames and IPs
6. Operating Systems
7. Browsers
8. Time Distribution
9. Referrers URLs
10. Referring Sites
11. Key Phrases from Google's search engine
12. HTTP Status Codes
13. Geolocation

Keyboard Shortcuts

KeyAction
F1 / hShow help
19, 0Jump to that section
sChange sort order of current panel
t / TToggle top/bottom items
oOpen/close detail panel
qQuit
/ Scroll

Real-Time Streaming Mode

# Enable real-time HTML report alongside terminal dashboard
tail -f /var/log/nginx/access.log | goaccess \
--log-format=COMBINED \
--real-time-html \
-o /var/www/html/report.html -

Generating HTML Reports

Static HTML Report

# Generate a standalone HTML report
goaccess /var/log/nginx/access.log \
-o /var/www/html/report.html \
--log-format=COMBINED

# Open in browser
# http://your-server/report.html

The generated HTML file is a fully self-contained interactive dashboard. All JavaScript and CSS are inlined, so it works as a single file with no external dependencies.

Merging Multiple Log Files

# Merge rotated log files in order
zcat /var/log/nginx/access.log.*.gz | goaccess \
--log-format=COMBINED \
-o /var/www/html/monthly-report.html -

# Analyze current log and compressed archived logs together
zcat /var/log/nginx/access.log.2.gz /var/log/nginx/access.log.1.gz \
| cat - /var/log/nginx/access.log \
| goaccess --log-format=COMBINED -o report.html -

JSON and CSV Output

# Output in JSON format
goaccess /var/log/nginx/access.log \
--log-format=COMBINED \
-o report.json

# Output in CSV format
goaccess /var/log/nginx/access.log \
--log-format=COMBINED \
-o report.csv

Nginx/Apache Log Format Configuration

Predefined Format Keywords

GoAccess provides predefined keywords for common log formats:

KeywordDescription
COMBINEDApache/Nginx combined format (most common)
NCSA_COMBINEDNCSA combined format
COMMONCLF (Common Log Format)
W3CIIS W3C Extended log format
SQUIDSquid native format
CLOUDFRONTAmazon CloudFront
CLOUDSTORAGEGoogle Cloud Storage
AWSELBAmazon Elastic Load Balancing

Custom Format Specification

For a Nginx custom format that includes response time:

# Example Nginx timed format:
# '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent rt=$request_time'

goaccess /var/log/nginx/access.log \
--log-format='%h - %e [%d:%t %^] "%r" %s %b rt=%T' \
--date-format='%d/%b/%Y' \
--time-format='%H:%M:%S'

Using a Configuration File

Instead of passing options each time, use a configuration file:

# /etc/goaccess/goaccess.conf (or ~/.goaccessrc)

# Nginx combined format
log-format COMBINED

# Date/time format (auto-set for COMBINED, but can be explicit)
date-format %d/%b/%Y
time-format %H:%M:%S

# Log file path
log-file /var/log/nginx/access.log

# HTML report output path
output /var/www/html/report.html

# Optional: GeoIP database
# geoip-database /usr/share/GeoIP/GeoLite2-City.mmdb

# Enable real-time HTML
real-time-html true
ws-url wss://your-domain.com:7890
port 7890

Apply the configuration file:

goaccess --config-file=/etc/goaccess/goaccess.conf

Real-Time HTML Dashboard (WebSocket)

GoAccess can push live updates to HTML reports via WebSocket.

Starting the Real-Time Server

# Start live HTML generation with WebSocket server
tail -f /var/log/nginx/access.log | goaccess \
--log-format=COMBINED \
--real-time-html \
--ws-url=wss://monitor.example.com \
--port=7890 \
-o /var/www/html/live-report.html -

Nginx Reverse Proxy Configuration (External Access)

# /etc/nginx/sites-available/goaccess-monitor
server {
listen 443 ssl;
server_name monitor.example.com;

ssl_certificate /etc/letsencrypt/live/monitor.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/monitor.example.com/privkey.pem;

# Protect with basic authentication
auth_basic "GoAccess Monitor";
auth_basic_user_file /etc/nginx/.htpasswd;

# Serve the HTML report
location / {
root /var/www/html;
index live-report.html;
}

# WebSocket proxy
location /ws {
proxy_pass http://127.0.0.1:7890;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400;
}
}
# Create the htpasswd file for access control
htpasswd -c /etc/nginx/.htpasswd admin
nginx -t && systemctl reload nginx

Running GoAccess with Docker

Standalone Docker Run

# Mount log files and generate HTML report
docker run --rm \
-v /var/log/nginx:/var/log/nginx:ro \
-v /var/www/html:/output \
allinea/goaccess \
/var/log/nginx/access.log \
--log-format=COMBINED \
--no-global-config \
-o /output/report.html

# Verify the report was created
ls -lh /var/www/html/report.html

Real-Time Dashboard with Docker Compose

# docker-compose.yml
version: '3.8'

services:
goaccess:
image: allinea/goaccess
container_name: goaccess
restart: unless-stopped
volumes:
- /var/log/nginx:/var/log/nginx:ro
- ./reports:/var/www/html
command: >
/var/log/nginx/access.log
--log-format=COMBINED
--no-global-config
--real-time-html
--ws-url=wss://monitor.example.com
--port=7890
-o /var/www/html/live-report.html
ports:
- "7890:7890"

nginx:
image: nginx:alpine
container_name: goaccess-web
restart: unless-stopped
volumes:
- ./reports:/usr/share/nginx/html:ro
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
ports:
- "8080:80"
depends_on:
- goaccess

Key Statistics Explained

Summary Panel

ItemDescription
Unique VisitorsUnique IP count per day
RequestsTotal requests (static + dynamic)
Static RequestsRequests for JS, CSS, images, and other static files
Requests w/ a 404Count of Not Found responses
BandwidthTotal bytes transferred
Log SizeSize of the analyzed log file

Panel-by-Panel Highlights

PanelKey Metrics
1. Unique VisitorsVisitors, requests, bandwidth, hit rate per day
2. Requested FilesRequest count, bandwidth, response time per URL
4. Not Found404 URL list and request frequency
5. Visitor IPsRequests and bandwidth per IP
8. Time DistributionRequest distribution by hour (heatmap)
12. HTTP Status CodesRequest percentage per status code
13. GeolocationVisitor distribution by country/region

Enabling GeoIP Location Statistics

Install the GeoLite2 Database

# MaxMind GeoLite2 database (free, requires account)
# Sign up at: https://www.maxmind.com/en/geolite2/signup

# Install geoipupdate tool
sudo apt-get install -y geoipupdate

# Configure /etc/GeoIP.conf
sudo tee /etc/GeoIP.conf <<'EOF'
AccountID YOUR_ACCOUNT_ID
LicenseKey YOUR_LICENSE_KEY
EditionIDs GeoLite2-City GeoLite2-Country
EOF

# Download the database
sudo geoipupdate
ls /var/lib/GeoIP/
# GeoLite2-City.mmdb GeoLite2-Country.mmdb

Apply GeoIP to GoAccess

# Use GeoLite2-City for city-level location data
goaccess /var/log/nginx/access.log \
--log-format=COMBINED \
--geoip-database=/var/lib/GeoIP/GeoLite2-City.mmdb \
-o report.html

# Or add to the config file:
# geoip-database /var/lib/GeoIP/GeoLite2-City.mmdb

Automated Report Generation with Cron

# /etc/cron.d/goaccess-report
# Generate yesterday's report every day at 2:00 AM
0 2 * * * root zcat /var/log/nginx/access.log.*.gz 2>/dev/null | \
cat /var/log/nginx/access.log.1 - | \
goaccess --log-format=COMBINED --no-global-config \
-o /var/www/html/reports/$(date +\%Y\%m\%d).html - 2>/dev/null
# Clean up reports older than 30 days
find /var/www/html/reports/ -name "*.html" -mtime +30 -delete

Pro Tips

Auto-detection: GoAccess supports --log-format=AUTO to attempt automatic format detection, but in production it is more reliable to specify the format explicitly.

Large log files: GoAccess handles GB-sized log files efficiently, but memory usage can climb. Use --max-items=N to cap the number of entries per panel and keep memory usage in check.

Persistent database: The --db-path option combined with --persist and --restore allows GoAccess to save and continue previous analysis sessions, making it useful for maintaining cumulative statistics across rotated log files.

# Save analysis results to a database
goaccess /var/log/nginx/access.log \
--log-format=COMBINED \
--db-path=/tmp/goaccess-db \
--persist \
-o report.html

# Continue analysis the next day
goaccess /var/log/nginx/access.log \
--log-format=COMBINED \
--db-path=/tmp/goaccess-db \
--persist \
--restore \
-o report.html