Before I had access to fancy analytics dashboards, AWStats was the tool I relied on to turn raw Apache log files into readable, visual reports — visitor counts, top pages, referrers, search engine keywords, and more. It’s still one of the fastest ways to get meaningful insight straight from your server’s own logs, without sending any data to a third party. Here’s how I set it up.
What Is AWStats?
AWStats (Advanced Web Statistics) is a free, open-source log analyzer that generates advanced web, streaming, FTP, or mail server statistics graphically. For Apache specifically, it parses access.log and produces detailed HTML reports covering traffic patterns, visitor behavior, and more.
Why I Use AWStats
- Self-hosted analytics — no third-party JavaScript trackers, no data leaving my server.
- Historical reporting — monthly breakdowns that accumulate over time.
- Detailed insight — visitor counts, unique visitors, pages viewed, bandwidth, referrers, search engine keywords, browsers, operating systems, and HTTP error codes, all in one report.
- Works from existing logs — no need to add any tracking code to your website.
Prerequisites
- A Linux server running Apache with standard logging enabled
- Perl installed (AWStats is a Perl-based tool)
- Root or sudo access
Step 1: Install AWStats
On Debian/Ubuntu:
sudo apt update
sudo apt install awstats -y
On CentOS/RHEL:
sudo yum install epel-release -y
sudo yum install awstats -y
Step 2: Locate the Configuration Directory
AWStats configuration files typically live in:
/etc/awstats/
The main config template is awstats.conf, which you copy and customize per domain.
Step 3: Create a Configuration File for Your Site
sudo cp /etc/awstats/awstats.conf /etc/awstats/awstats.mydomain.com.conf
Edit the new file:
sudo nano /etc/awstats/awstats.mydomain.com.conf
Update these key directives:
LogFile="/var/log/apache2/access.log"
LogType=W
LogFormat=1
SiteDomain="mydomain.com"
HostAliases="www.mydomain.com localhost 127.0.0.1"
DNSLookup=0
DirData="/var/lib/awstats"
Let me explain the important ones:
LogFile— path to Apache’s access log for this domain.LogFormat=1— tells AWStats to use the standard “combined” Apache log format.SiteDomain— the primary domain being analyzed.HostAliases— alternate hostnames that should be treated as the same site.DNSLookup=0— disables reverse DNS lookups during processing, which speeds things up significantly (I almost always keep this at 0 unless I specifically need hostname resolution).
Step 4: Ensure Your Apache Log Format Matches
AWStats expects the “combined” log format by default. Check your virtual host or main config for:
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
CustomLog ${APACHE_LOG_DIR}/access.log combined
If your logs use a custom format, you’ll need to adjust LogFormat in the AWStats config to match (AWStats supports custom format strings, but combined is by far the easiest to work with).
Step 5: Create the Data Directory
sudo mkdir -p /var/lib/awstats
Step 6: Run AWStats for the First Time
sudo /usr/lib/cgi-bin/awstats.pl -config=mydomain.com -update
You should see output like:
Create/Update database for config "/etc/awstats/awstats.mydomain.com.conf" by AWStats version 7.8 (build...)
From data in log file "/var/log/apache2/access.log"...
Phase 1 : First bypass old records, searching new record...
Direct access after last parsed record (after line 45021)
Jumped lines in file: 45021
Found 45021 already parsed records.
Phase 2 : Now process new records (log format: 1)...
Jumped lines in file: 0
Parsed lines in file: 12043
Found 12043 new qualified records.
This confirms it successfully parsed your log file and built its statistics database.
Step 7: Set Up the Web Interface
AWStats includes a CGI script to view reports interactively. Enable CGI on Apache:
sudo a2enmod cgi
Add a configuration block, typically at /etc/apache2/conf-available/awstats.conf:
Alias /awstatsclasses "/usr/share/awstats/lib/"
Alias /awstats-icon/ "/usr/share/awstats/icon/"
Alias /awstatscss "/usr/share/doc/awstats/examples/css/"
ScriptAlias /awstats/ /usr/lib/cgi-bin/
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
AddHandler cgi-script .pl
Require ip 192.168.1.0/24
Enable the config and restart Apache:
sudo a2enconf awstats
sudo systemctl restart apache2
Step 8: View the Report
Visit:
http://your-server-ip/awstats/awstats.pl?config=mydomain.com
You’ll get a full dashboard including:
- Monthly and daily visit summaries
- Unique visitors and total pages viewed
- Top viewed pages
- Top referring sites
- Search engines and keywords used to find your site
- Visitor browsers and operating systems
- HTTP error codes (404s, 500s, etc.)
- Robots/crawlers detected
Step 9: Automate Updates with Cron
I never want to run the update command manually every day, so I schedule it:
sudo crontab -e
Add:
0 * * * * /usr/lib/cgi-bin/awstats.pl -config=mydomain.com -update > /dev/null 2>&1
This runs hourly, keeping the statistics database fresh without needing to reprocess the entire log file each time (AWStats is smart enough to only process new lines since the last update).
Excluding Internal or Bot Traffic from Reports
One thing I always configure is excluding my own internal IPs and known monitoring bots so they don’t skew the visitor statistics. This is done with the SkipHosts and SkipUserAgents directives in the config file:
SkipHosts="127.0.0.1 192.168.1.0/24"
SkipUserAgents="Nagios-check UptimeRobot GoogleHC"
Without this, internal health checks and office traffic can make it look like your site has far more organic visitors than it actually does, which throws off any real analysis of user behavior.
Generating Static HTML Reports Instead of Using CGI
If you’d rather not enable CGI execution on your production Apache server (a reasonable security preference), AWStats can generate fully static HTML reports instead:
sudo /usr/share/awstats/tools/awstats_buildstaticpages.pl \
-config=mydomain.com \
-update \
-dir=/var/www/html/stats \
-awstatsprog=/usr/lib/cgi-bin/awstats.pl
This produces plain HTML files you can serve like any other static content, avoiding the need to expose an executable Perl script on your web server at all — my preferred approach for production sites where I want statistics but want to minimize the attack surface.
Comparing Month-Over-Month Trends
Because AWStats builds a persistent database per domain, I can revisit any past month’s report just by changing the URL parameters:
http://your-server-ip/awstats/awstats.pl?config=mydomain.com&month=06&year=2026
This makes month-over-month comparisons simple — I regularly check whether traffic, bandwidth, or error rates are trending up or down without needing a separate historical tool.
Real-World Use Case
I once used AWStats to diagnose a sudden traffic spike that looked great on the surface — until I checked the “robots/crawlers” report and realized nearly 80% of the “traffic” was actually an aggressive scraper bot repeatedly hitting product pages. That insight, which a basic visitor counter wouldn’t have surfaced, let me add rate-limiting rules targeting that specific user agent.
Common Mistakes I’ve Made
- Mismatched LogFormat — if your Apache
LogFormatdirective doesn’t match what AWStats expects, you’ll get garbled or missing data. Always verify both match. - Enabling DNSLookup — this dramatically slows down processing on high-traffic logs since it performs a reverse DNS lookup for every unique IP.
- Forgetting to schedule updates, leading to stale reports that don’t reflect recent traffic.
- Exposing the AWStats CGI script publicly — always restrict access, since it reveals detailed visitor information.
Security Best Practices
- Restrict access to the AWStats web interface with
Require ipor HTTP authentication. - Avoid enabling DNS lookups unless you have a specific need, both for performance and privacy reasons.
- Regularly review the “HTTP errors” report for spikes in 403/404s that might indicate scanning activity.
Performance Optimization Tips
- Keep
DNSLookup=0unless absolutely necessary. - Run updates via cron frequently (hourly or every few hours) rather than reprocessing huge log files in one go monthly.
- Pair AWStats with logrotate so it’s always working with reasonably sized, well-organized log files.
Troubleshooting Common Issues
“Error: SiteDomain parameter not defined” — make sure SiteDomain is set in your config file.
Reports show zero visits despite traffic — double-check that LogFile points to the correct, currently-in-use access log, and that LogFormat matches your Apache config.
CGI script returns 500 error — verify mod_cgi is enabled and the script has execute permissions:
sudo chmod +x /usr/lib/cgi-bin/awstats.pl
FAQs
Does AWStats work with log files that have already been rotated and compressed? Yes, AWStats can process .gz compressed log files directly, which is useful when combined with logrotate.
Can I analyze multiple domains with one AWStats installation? Yes — just create a separate config file per domain (e.g., awstats.domain2.com.conf) and run updates for each.
Is AWStats as accurate as JavaScript-based analytics tools like Google Analytics? It measures things differently — AWStats counts server-side requests, so it includes bot traffic more prominently and doesn’t rely on client-side JavaScript execution, which some ad blockers disable. Neither approach is strictly “more accurate”; they answer slightly different questions.
How resource-intensive is AWStats? It’s quite lightweight for typical traffic volumes, though very large log files can take longer to process on the first run. Incremental updates after that are fast.
Summary and Key Takeaways
AWStats turns your existing Apache access logs into detailed, self-hosted analytics reports without any third-party tracking. Setting it up involves creating a per-domain config, making sure your Apache log format matches, and scheduling regular updates via cron. I’ve found it invaluable for spotting traffic anomalies, understanding visitor behavior, and keeping tabs on error rates — all straight from data my server was already collecting.