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
| Key | Action |
|---|---|
F1 / h | Show help |
1–9, 0 | Jump to that section |
s | Change sort order of current panel |
t / T | Toggle top/bottom items |
o | Open/close detail panel |
q | Quit |
↑ / ↓ | 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:
| Keyword | Description |
|---|---|
COMBINED | Apache/Nginx combined format (most common) |
NCSA_COMBINED | NCSA combined format |
COMMON | CLF (Common Log Format) |
W3C | IIS W3C Extended log format |
SQUID | Squid native format |
CLOUDFRONT | Amazon CloudFront |
CLOUDSTORAGE | Google Cloud Storage |
AWSELB | Amazon 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
| Item | Description |
|---|---|
| Unique Visitors | Unique IP count per day |
| Requests | Total requests (static + dynamic) |
| Static Requests | Requests for JS, CSS, images, and other static files |
| Requests w/ a 404 | Count of Not Found responses |
| Bandwidth | Total bytes transferred |
| Log Size | Size of the analyzed log file |
Panel-by-Panel Highlights
| Panel | Key Metrics |
|---|---|
| 1. Unique Visitors | Visitors, requests, bandwidth, hit rate per day |
| 2. Requested Files | Request count, bandwidth, response time per URL |
| 4. Not Found | 404 URL list and request frequency |
| 5. Visitor IPs | Requests and bandwidth per IP |
| 8. Time Distribution | Request distribution by hour (heatmap) |
| 12. HTTP Status Codes | Request percentage per status code |
| 13. Geolocation | Visitor 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