What Is GoAccess?
GoAccess is a real-time web log analyzer that parses your web server access logs (Nginx, Apache, Caddy) and generates analytics dashboards — either in the terminal or as a self-updating HTML report. No JavaScript tracking snippet required. No cookies. No impact on page load speed. GoAccess reads what your web server already records and turns it into visitor stats, top pages, referrers, geolocation, HTTP status codes, and bandwidth usage.
Updated March 2026: Verified with latest Docker images and configurations.
Prerequisites
- A Linux server (Ubuntu 22.04+ recommended)
- Docker and Docker Compose installed (guide)
- 256 MB of free RAM
- Access to your web server's access log files (Nginx, Apache, Caddy, etc.)
- A domain name (optional, for the HTML dashboard)
Docker Compose Configuration
Create a docker-compose.yml file:
services:
goaccess:
image: allinurl/goaccess:1.10.1
container_name: goaccess
restart: unless-stopped
ports:
- "7890:7890" # HTML report WebSocket (real-time updates)
volumes:
- /var/log/nginx/access.log:/var/log/access.log:ro # CHANGE: path to your access log
- goaccess-data:/srv/data # Persistent database
- goaccess-html:/srv/report # HTML report output
command: >
--log-file=/var/log/access.log
--log-format=COMBINED
--real-time-html
--ws-url=wss://analytics.example.com:7890
--output=/srv/report/index.html
--persist
--restore
--db-path=/srv/data
--anonymize-ip
--geoip-database=/usr/local/share/GeoIP/GeoLite2-City.mmdb
networks:
- analytics
networks:
analytics:
driver: bridge
volumes:
goaccess-data:
goaccess-html:
Key Configuration Options
| Flag | Purpose |
|---|---|
--log-format=COMBINED |
Standard Nginx/Apache combined log format. Change to VCOMBINED for virtual host logs, or define a custom format |
--real-time-html |
Enables WebSocket-based live updates in the HTML dashboard |
--ws-url |
WebSocket URL clients connect to. Set to your domain + port for remote access |
--persist / --restore
|
Saves parsed data to disk so you don't lose history on restart |
--anonymize-ip |
Hashes the last octet of IP addresses for privacy |
--geoip-database |
Path to MaxMind GeoLite2 database for geographic data |
Start the stack:
docker compose up -d
Log Format Configuration
GoAccess supports several preset log formats. Match the format to your web server:
Nginx (default combined)
--log-format=COMBINED
This matches Nginx's default combined format:
$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"
Apache
--log-format=COMBINED
Apache's combined format is identical to Nginx's default.
Caddy
Caddy's default JSON log format requires a custom format string:
--log-format='{"request":{"remote_ip":"%h","method":"%m","uri":"%U","proto":"%H"},"status":"%s","size":"%b","resp_headers":{"Content-Type":["%^"]},"duration":"%T","ts":"%d"}'
Alternatively, configure Caddy to output common/combined format logs, which are easier for GoAccess to parse.
Custom Format
Define your own with GoAccess's format specifiers:
--log-format='%h %^[%d:%t %^] "%r" %s %b "%R" "%u"'
--date-format=%d/%b/%Y
--time-format=%H:%M:%S
Initial Setup
- Verify GoAccess can read your logs:
docker logs goaccess
Look for lines like Parsed X lines. If you see format errors, your --log-format doesn't match your actual log format.
- Access the HTML dashboard at
http://your-server-ip:7890 - The dashboard auto-refreshes via WebSocket — no page reload needed
Serving the HTML Report
For production use, serve the generated HTML report through your existing web server instead of exposing the GoAccess WebSocket port directly.
Nginx Configuration
server {
listen 443 ssl;
server_name analytics.example.com;
location / {
root /path/to/goaccess-html;
index index.html;
}
location /ws {
proxy_pass http://localhost:7890;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
Mount the goaccess-html volume to a path your Nginx can serve.
See Reverse Proxy Setup for full configuration.
GeoIP Setup
GoAccess can map visitor IPs to countries/cities using MaxMind's GeoLite2 database:
- Register for a free MaxMind account at maxmind.com
- Download the GeoLite2-City database (
.mmdbformat) - Mount it into the container:
volumes:
- /path/to/GeoLite2-City.mmdb:/usr/local/share/GeoIP/GeoLite2-City.mmdb:ro
- Add the flag:
--geoip-database=/usr/local/share/GeoIP/GeoLite2-City.mmdb
The database should be updated monthly. MaxMind provides a free geoipupdate tool for automated updates.
Terminal Mode
GoAccess also works as a terminal-based dashboard — no web server needed:
docker exec -it goaccess goaccess /var/log/access.log --log-format=COMBINED
This opens an interactive ncurses interface with real-time stats. Useful for quick checks via SSH.
Troubleshooting
"Unable to open log file"
Symptom: GoAccess exits with a permission error on the log file
Fix: Ensure the log file volume mount is correct and the file exists. Check permissions:
ls -la /var/log/nginx/access.log
The container runs as root by default, so file permissions are rarely the issue — more likely the mount path is wrong.
"No valid format found"
Symptom: GoAccess reports 0 parsed lines or format errors
Fix: Your --log-format doesn't match the actual log format. Check a sample line from your log:
head -1 /var/log/nginx/access.log
Then match it against GoAccess's format specifiers.
Dashboard Shows No Data After Restart
Symptom: Restarting the container loses all historical data
Fix: Ensure --persist and --restore flags are set, and the goaccess-data volume is properly mounted. Without persistence, GoAccess only shows data from logs loaded since the last start.
WebSocket Connection Fails
Symptom: HTML report loads but shows "Connecting..." without live updates
Fix: The --ws-url must match how clients access the WebSocket. If behind a reverse proxy, ensure WebSocket upgrade headers are passed through. Check that port 7890 is accessible.
Resource Requirements
- RAM: 100-200 MB (depends on log volume and GeoIP database)
- CPU: Minimal — log parsing is not CPU-intensive
- Disk: Negligible for the application. Log files themselves are the main storage cost.
Verdict
GoAccess is the most efficient analytics tool you can run. It adds zero overhead to your website — no tracking scripts, no cookies, no client-side impact. It reads logs your web server already generates and produces clean dashboards.
The trade-off: GoAccess only sees what's in your access logs. It can't track JavaScript events, user sessions across pages (without custom configuration), or anything that requires client-side instrumentation. For those needs, use Plausible or Umami.
For a personal site, blog, or any situation where you want analytics without adding a tracking script, GoAccess is ideal. It pairs well with a JavaScript-based tool — run GoAccess for server-side metrics and Plausible for user-facing analytics.
Frequently Asked Questions
Does GoAccess require any JavaScript on my website?
No. GoAccess reads your web server's access log files — it doesn't add anything to your website. Zero impact on page load speed, no cookies, no client-side code. This makes it ideal for privacy-focused analytics.
Can GoAccess analyze historical log files?
Yes. Point GoAccess at any log file (current or archived) and it parses the entire thing. With --persist and --restore, it builds a database across multiple log rotations. You can even pipe multiple log files together for a combined view.
Does GoAccess support multiple websites?
Yes. Run separate GoAccess instances, each reading a different access log file and outputting to a different HTML report. You can also use VCOMBINED log format with virtual host logs to show all sites in one dashboard, filtered by hostname.
How does GoAccess compare to Plausible or Umami?
GoAccess is server-side only — it reads log files and can't track JavaScript events, goals, or user sessions across pages. Plausible and Umami use client-side JavaScript and provide richer analytics (UTM tracking, custom events, real-time dashboards). GoAccess is lighter, more private, and adds zero overhead to your website. Many people run both.
Can I use GoAccess with Caddy or Traefik?
Yes, but you need to configure these web servers to output logs in a format GoAccess can parse. Caddy's default JSON format requires a custom format string. The simplest approach is configuring Caddy/Traefik to output combined-format logs, which GoAccess parses natively.
Is GeoIP data required?
No. GeoIP is optional. Without it, GoAccess shows all analytics except geographic location data. For geo data, download the free MaxMind GeoLite2 database and mount it into the container.
Top comments (0)