AWStats on AWS User Guide
Overview
This image runs AWStats, the long established open source log file analyser, behind the Apache web server with mod_cgid on Ubuntu 24.04 LTS. AWStats reads the log files a web, FTP or mail server already writes and turns them into a rich, graphical HTML statistics report: visits and unique visitors, pages and hits, bandwidth, entry and exit pages, browsers and operating systems, search engines and keywords, referrers, HTTP status codes, file types and robot traffic. Because it processes server logs rather than a browser tracking script, it needs no cookies and no third party service, and it reports on every request rather than only on visitors who allow client side analytics.
The image delivers a complete, ready to use log analysis appliance. Apache is installed and configured to execute the analyser, the Perl modules AWStats needs are present, the icon and data directories are wired up so every graph draws correctly, and a systemd timer reprocesses this instance's own web server log every ten minutes. The whole reporting site, including the report CGI, is protected by HTTP Basic authentication from the moment the instance starts, and a fresh report password unique to that instance is generated on first boot and written to a root only file, so no shared or default password ships in the image.
Two reports are configured. The demonstration report analyses a synthetic access log that is regenerated against the current date on first boot, so it is fully populated and explorable the moment you sign in. The server report analyses this instance's own /var/log/apache2/access.log, so the appliance begins reporting on its own real traffic immediately and keeps growing as requests arrive.
Prerequisites
Before you deploy this image you need:
- An Amazon Web Services account where you can launch EC2 instances
- IAM permissions to launch instances, create security groups, and subscribe to AWS Marketplace products
- An EC2 key pair in the target Region for SSH access to the instance
- A VPC and subnet in the target Region, with a security group allowing inbound port 22 from your management network and inbound ports 80 and 443 from the networks you will reach the reports on
- The AWS CLI (version 2) installed locally if you plan to deploy from the command line
Step 1: Launch the Instance from the AWS Marketplace
Sign in to the AWS Management Console, open the EC2 service, and select Launch instance. Under Application and OS Images choose AWS Marketplace AMIs and search for AWStats. Select the cloudimg listing and choose Select, then Continue on the subscription summary.
Pick an instance type of m5.large or larger. Choose your EC2 key pair under Key pair (login). Under Network settings select your VPC and subnet, and either create or select a security group that allows inbound port 22 from your management network and inbound ports 80 and 443 from the networks you will view the reports from. Leave the root volume at the default size or larger.
Select Launch instance. First boot initialisation takes a few seconds after the instance state becomes Running and the status checks pass; during that time the per instance report password is generated and the demonstration dataset is rebuilt against the current date.
Step 2: Launch the Instance from the AWS CLI
The following block launches an instance from the cloudimg AWStats Marketplace AMI into an existing subnet and security group. Replace <ami-id> with the AMI ID shown on the Marketplace listing, <key-name> with your EC2 key pair name, <subnet-id> with your subnet ID, and <security-group-id> with a security group that opens ports 22 and 80 (and 443 if you will terminate TLS) as described above.
aws ec2 run-instances \
--image-id <ami-id> \
--instance-type m5.large \
--key-name <key-name> \
--subnet-id <subnet-id> \
--security-group-ids <security-group-id> \
--metadata-options "HttpTokens=required,HttpEndpoint=enabled" \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=awstats}]'
Connecting to Your Instance
Connect over SSH on port 22 using the private key for the EC2 key pair you selected at launch. The login user depends on the operating system variant you launched:
| OS variant | SSH login user |
|---|---|
| Ubuntu 24.04 LTS | ubuntu |
For example, on the Ubuntu variant:
ssh -i /path/to/your-key.pem ubuntu@<public-ip>
Step 3: Retrieve Your Report Password
The whole reporting site is behind HTTP Basic authentication with the user name awstats. The password is generated uniquely for your instance on first boot and written to /root/awstats-credentials.txt, readable only by root. Retrieve it over SSH:
sudo cat /root/awstats-credentials.txt
This file contains the reporting URL, the user name awstats, and the awstats.web.pass value for this instance. If you see a short placeholder note instead of credentials, first boot has not finished yet; wait for the instance status checks to pass and read the file again.
Step 4: Sign In and View Your Reports
Browse to http://<public-ip>/ and sign in with the user name awstats and the password from the credentials file. You land on a small chooser with two reports: This server (statistics for this instance's own Apache access log) and Demonstration report (a fully populated sample dataset).

Open the Demonstration report to explore a complete AWStats report straight away. The top of the report is the summary: the reported period, unique visitors, number of visits, pages, hits and bandwidth, followed by the monthly history graph.

Scrolling down, AWStats renders the full breakdown on a single page: days of the month, days of the week and hourly traffic, the busiest hosts, the most requested pages, visit duration, file types, referrers, search engines and keywords, browsers, operating systems, and HTTP status codes. Every bar in every graph is drawn from the analyser's own icon set, so the report is fully graphical.

The navigation strip at the top of the report links to the detail views. For example, Who > Hosts > Full list opens the complete list of visiting hosts with their pages, hits, bandwidth and last visit.

To read this instance's own traffic instead of the demonstration data, open the This server report, or browse directly to the CGI with the config=server parameter. Because the reports are behind Basic authentication, any request without a valid credential is refused:
# From your workstation, replace the password with awstats.web.pass from the credentials file.
curl -u "awstats:<AWSTATS_WEB_PASSWORD>" "http://<public-ip>/cgi-bin/awstats.pl?config=server"
Step 5: Verify the Services
The reporting stack is Apache serving the AWStats CGI, plus a systemd timer that reprocesses this instance's log every ten minutes. Check both are healthy and confirm the report is refused without a credential:
systemctl is-active apache2
systemctl is-active awstats-update.timer
curl -s http://127.0.0.1/healthz
curl -s -o /dev/null -w 'report without auth: HTTP %{http_code}\n' "http://127.0.0.1/cgi-bin/awstats.pl?config=server"
curl -s -o /dev/null -w 'health endpoint: HTTP %{http_code}\n' http://127.0.0.1/healthz
apache2 and awstats-update.timer report active, the health endpoint returns ok and HTTP 200 without a credential (for load balancer probes), and the report CGI returns HTTP 401 when no credential is supplied.
The Two Reports and Their Configuration
AWStats configurations live in /etc/awstats, and the processed history data lives under /var/lib/awstats:
ls -1 /etc/awstats/
sudo ls -1 /var/lib/awstats/
systemctl list-timers awstats-update.timer --no-pager
awstats.server.confanalyses/var/log/apache2/access.log, this instance's own web server log. Theawstats-update.timerreprocesses it every ten minutes, so the This server report fills in as real traffic arrives.awstats.demo.confanalyses a synthetic access log regenerated against the current date on first boot, so the Demonstration report is always populated for the current month.
The updater runs only from the root owned systemd timer. Triggering a log parse from the browser is disabled in both configurations, and the history data directory is not served over HTTP, so a request can never forge or corrupt statistics.
Analysing Additional Logs
To analyse a different log file or another server, copy one of the shipped configurations and point it at the new log. For example, to add a config named mysite:
sudo cp /etc/awstats/awstats.server.conf /etc/awstats/awstats.mysite.conf
sudo sed -i 's#^LogFile=.*#LogFile="/var/log/mysite/access.log"#' /etc/awstats/awstats.mysite.conf
sudo sed -i 's#^SiteDomain=.*#SiteDomain="<your-domain>"#' /etc/awstats/awstats.mysite.conf
sudo /usr/local/bin/awstats-update mysite
The report is then available at http://<public-ip>/cgi-bin/awstats.pl?config=mysite. Keep the LogType, LogFormat, DirIcons, UseFramesWhenCGI=0 and AllowToUpdateStatsFromBrowser=0 settings from the shipped configuration so the report renders correctly and stays secure. Adjust LogFormat if the new log is in a different format (AWStats supports the common web, FTP and mail log formats).
Enabling HTTPS
The image serves on port 80 so a load balancer or reverse proxy can terminate TLS in front of it. To terminate TLS on the instance itself, install a certificate with Let's Encrypt. Point a DNS name at the instance's public address first, then run:
sudo apt-get update
sudo apt-get install -y certbot python3-certbot-apache
sudo certbot --apache -d your-domain.example.com
Certbot obtains a certificate and configures Apache to serve the reports over HTTPS.
Where Things Live
| Path | Purpose |
|---|---|
/opt/awstats |
The AWStats application tree (root owned, read only to the web server) |
/etc/awstats |
The demo and server configurations |
/var/lib/awstats |
Processed history data, one directory per configuration |
/var/log/apache2/access.log |
This instance's own web server log (the server report source) |
/etc/apache2/awstats.htpasswd |
The Basic authentication password file |
/root/awstats-credentials.txt |
The per instance report password (root only) |
/usr/local/bin/awstats-update |
The log updater run by the systemd timer |
Confirm the root disk has room as history data grows:
df -hT /
The Security Model
- The whole reporting site, including the report CGI, sits behind HTTP Basic authentication. Only the
/healthzendpoint is open, so a load balancer can probe the instance without a credential. - The report password is generated uniquely on first boot and stored only in
/root/awstats-credentials.txt(mode 0600). No default or shared password ships in the image. - Log processing runs only from the root owned systemd timer. It can never be triggered from the browser, and the raw history data is not reachable over HTTP.
- The analyser is deployed with the extra CGI entry points and the legacy Java applet left out, and the
configdirCGI parameter is refused, so the historically abused injection paths are closed. - Change the report password at any time and update the credentials file to match:
sudo htpasswd -bB /etc/apache2/awstats.htpasswd awstats '<new-password>'
sudo systemctl reload apache2
Troubleshooting
- The report page loads but shows nothing. Confirm the timer has run at least once with
systemctl list-timers awstats-update.timer, and runsudo /usr/local/bin/awstats-update serverto reprocess the log immediately. A brand new instance has little of its own traffic yet, so start with the Demonstration report. - A 401 when you expected the report. You are being asked to authenticate. Read the password with
sudo cat /root/awstats-credentials.txtand sign in asawstats. - The graphs are broken images. This should not happen on the shipped image; if you have edited a configuration, make sure
DirIcons="/awstatsicons"is present so Apache serves the analyser's icon set. - Check the Apache error log for CGI problems:
sudo tail -n 30 /var/log/apache2/awstats-error.log
Support
This image is published by cloudimg with 24/7 technical support by email at support@cloudimg.co.uk and live chat. We help with AWStats deployment and configuration, defining log formats for web, FTP and mail server logs, adding additional sites and log sources, report interpretation, access control, and version upgrades. Critical issues receive a one hour average response time.