AWStats on Ubuntu 24.04 on Azure User Guide
Overview
AWStats is the long established open source log file analyser. It reads the log files a web, FTP or mail server already writes and renders them as a detailed graphical statistics report: unique visitors and visits, pages and hits, bandwidth consumed and visit duration, entry and exit pages, browsers and operating systems, search engines and keywords, referring sites, downloaded files, HTTP status codes, and how much of the traffic is robots rather than people. Because it analyses server logs rather than a tracking script, it needs no client side JavaScript, sets no cookies and sends nothing to a third party, so it counts every request including those from clients that block conventional analytics, and the data never leaves the instance.
The cloudimg image is a complete log analysis appliance: AWStats 8.0 is deployed behind the Apache web server with mod_cgid, the icon and data directories are wired up so every graph draws, log processing is scheduled to run automatically every ten minutes, and the whole reporting site is protected by password authentication from the first boot. The instance analyses its own Apache access log out of the box, and it also ships a fully populated demonstration report, regenerated against each instance's own clock, so every chart and screen can be explored the moment you sign in. All on a hardened, fully patched Ubuntu 24.04 LTS base, backed by 24/7 cloudimg support.
What is included:
- AWStats 8.0 (GPL-3.0) deployed from the pinned upstream
AWSTATS_8_0release, served by Apache withmod_cgid - Two ready made report configurations:
serverfor this instance's own Apache access log, anddemofor an included demonstration dataset - A demonstration dataset regenerated on every first boot against the current date, so the report you land on is always populated rather than an empty month
awstats-update.timer, a systemd timer that rebuilds the statistics from your logs every ten minutes- HTTP Basic authentication in front of the entire reporting site, with a password generated uniquely on each instance's first boot and recorded in a root only file
- No shipped default login: no known or blank credential authenticates; the password is rotated to a discarded random at build time and regenerated uniquely on first boot
- Browser triggered log parsing disabled, so no visitor can ever make the instance parse a log file
- Statistics data readable by the web tier but writable only by the scheduled updater, so reports cannot be forged through the web
apache2.serviceandawstats-update.timeras enabled systemd units- An unauthenticated
/healthzendpoint for Azure Load Balancer health probes - 24/7 cloudimg support
Prerequisites
An active Azure subscription, an SSH key pair, and a VNet plus subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a sensible starting point; step up to Standard_D2s_v3 if you are analysing very large log files or many sites. NSG inbound: allow 22/tcp from your management network and 80/tcp for the reports interface (add 443/tcp if you terminate TLS on the VM, see "Adding your own domain and TLS" below).
Step 1 - Deploy from the Azure Marketplace
- In the Azure Portal, choose Create a resource and search for AWStats on Ubuntu 24.04 LTS by cloudimg.
- Select Create, then choose your subscription, resource group and region.
- Set the VM size to Standard_B2s or larger.
- Under Administrator account, choose SSH public key, set the username to
azureuserand paste your public key. - Under Inbound port rules, allow SSH (22) and HTTP (80).
- Select Review + create, then Create.
Step 2 - Deploy from the Azure CLI
az vm create \
--resource-group my-resource-group \
--name my-awstats-vm \
--image cloudimg:awstats-ubuntu-24-04:default:latest \
--size Standard_B2s \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard
Then open the ports the reports interface needs:
az vm open-port --resource-group my-resource-group --name my-awstats-vm --port 80 --priority 1001
Retrieve the public address of the VM:
az vm show --resource-group my-resource-group --name my-awstats-vm --show-details --query publicIps --output tsv
Step 3 - Confirm the services are running
Connect over SSH, replacing <vm-ip> with the address from the previous step:
ssh azureuser@<vm-ip>
Check that the web server and the log update timer are both running:
systemctl is-active apache2.service awstats-update.timer
Expected output:
active
active

Confirm the analyser version and the configuration it is using:
sudo /usr/bin/perl /opt/awstats/wwwroot/cgi-bin/awstats.pl -version
Expected output:
awstats 8.0 (build 20240604)

Step 4 - Retrieve the per VM reports password
The reporting site is protected by HTTP Basic authentication. The password is generated uniquely on the first boot of every instance and written to a root only file:
sudo cat /root/awstats-credentials.txt
The file records the address of the reports site, the user name, and the password generated for this instance:
AWSTATS_URL=http://<vm-ip>/
awstats.web.user=awstats
awstats.web.pass=<AWSTATS_WEB_PASSWORD>
You can confirm the file and the password database exist with the correct ownership and permissions without printing any secret:
sudo stat -c '%n mode=%a owner=%U:%G' /root/awstats-credentials.txt /etc/apache2/awstats.htpasswd
Expected output:
/root/awstats-credentials.txt mode=600 owner=root:root
/etc/apache2/awstats.htpasswd mode=640 owner=root:www-data

Step 5 - Sign in to the reports site
Browse to http://<vm-ip>/. The browser prompts for the HTTP Basic credentials: enter awstats as the user name and the value of awstats.web.pass from the credentials file. The landing page lists the two reports available on the instance.

Step 6 - Read the statistics report
Choose Demonstration report to open a fully populated report. The summary at the top gives the reported period and the headline figures: unique visitors, number of visits, pages, hits and bandwidth, with the average visits per visitor and pages per visit alongside them. Robot and worm traffic is counted separately as "Not viewed traffic" so it never inflates your visitor numbers.

The navigation strip below the header jumps to each section of the report. Pages-URL shows which pages were viewed most, with the average page size and the number of times each page was the entry or exit point of a visit:

Browsers breaks the traffic down by browser and version, and Operating Systems does the same for platforms:

Use the Reported period selector at the top of the report to move between months, or choose Year to see the full year view.
Step 7 - Report on this server's own traffic
The server configuration analyses this instance's own Apache access log at /var/log/apache2/access.log. It starts nearly empty on a new VM and fills in as the instance receives traffic. awstats-update.timer rebuilds it every ten minutes; you can also rebuild it immediately:
sudo /usr/local/bin/awstats-update server
Then open This server from the landing page, or go straight to http://<vm-ip>/cgi-bin/awstats.pl?config=server.
To confirm the statistics data on disk, list the history files and read the visit totals out of the current month:
sudo ls /var/lib/awstats/demo/
Each file holds one month of history. Read the totals for the current month:
sudo awk '/^TotalVisits|^TotalUnique/{printf "%-14s %s\n", $1, $2}' /var/lib/awstats/demo/awstats$(date -u '+%m%Y').demo.txt

Step 8 - Analyse another site or another server
Each site or log source is one configuration file in /etc/awstats. To add another, copy the shipped server configuration and point it at the log you want to analyse:
sudo cp /etc/awstats/awstats.server.conf /etc/awstats/awstats.mysite.conf
Edit the new file and set at least these three directives:
sudo sed -i 's|^LogFile=.*|LogFile="/var/log/apache2/mysite-access.log"|' /etc/awstats/awstats.mysite.conf
sudo sed -i 's|^SiteDomain=.*|SiteDomain="mysite.example.com"|' /etc/awstats/awstats.mysite.conf
sudo sed -i 's|^DirData=.*|DirData="/var/lib/awstats/mysite"|' /etc/awstats/awstats.mysite.conf
Create its data directory and build the first report:
sudo mkdir -p /var/lib/awstats/mysite
sudo /usr/local/bin/awstats-update mysite
The new configuration is then available at http://<vm-ip>/cgi-bin/awstats.pl?config=mysite. To have it rebuilt automatically alongside the shipped one, add it to the updater invocation in /etc/systemd/system/awstats-update.service.
If the log you are analysing is not in the Apache combined format, set LogFormat in the configuration file. AWStats ships predefined values (1 for combined, 2 for the older common format, 3 for IIS) and accepts a custom format string for anything else.
Step 9 - No known or default credentials
The image ships with no usable credential. The reports password is set to a random value during the build, re randomised to a fresh discarded random during image cleanup, and generated uniquely on the first boot of every instance. You can prove that the site is genuinely protected.
An unauthenticated request to the report is rejected:
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/cgi-bin/awstats.pl?config=demo
Expected output:
401
A request with the wrong password is also rejected:
curl -s -o /dev/null -w '%{http_code}\n' -u awstats:not-the-password http://127.0.0.1/cgi-bin/awstats.pl?config=demo
Expected output:
401
The health endpoint is deliberately open, so an Azure Load Balancer can probe the instance without a credential:
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/healthz
Expected output:
200
Browser triggered log parsing is disabled in every shipped configuration, so no visitor can make the instance parse a log file:
grep -h '^AllowToUpdateStatsFromBrowser=' /etc/awstats/awstats.demo.conf /etc/awstats/awstats.server.conf
Expected output:
AllowToUpdateStatsFromBrowser=0
AllowToUpdateStatsFromBrowser=0
To change the reports password yourself:
sudo htpasswd -B /etc/apache2/awstats.htpasswd awstats
Server components
| Component | Version | Purpose |
|---|---|---|
| AWStats | 8.0 (build 20240604) | Log file analyser and HTML report generator |
| Apache HTTP Server | 2.4.58 (Ubuntu) | Serves the reports and executes the analyser as a CGI |
| Perl | 5.38.2 | Runtime for the analyser |
| Ubuntu | 24.04 LTS | Operating system |
Filesystem layout
| Path | Size | Purpose |
|---|---|---|
/ |
29 GB | Root filesystem |
/boot |
881 MB | Operating system kernel files |
/mnt |
7.8 GB | Azure temporary resource disk |
Key directories:
| Path | Purpose |
|---|---|
/opt/awstats |
The AWStats application, root owned and never writable by the web server |
/opt/awstats/wwwroot/cgi-bin/awstats.pl |
The analyser and report generator |
/opt/awstats/wwwroot/icon |
Report graph and marker images, served at /awstatsicons |
/opt/awstats/docs/LICENSE.TXT |
The GNU General Public License version 3 |
/etc/awstats |
One configuration file per site or log source |
/var/lib/awstats/demo |
History data for the demonstration report |
/var/lib/awstats/server |
History data for this instance's own report |
/var/log/apache2/access.log |
The log the server configuration analyses |
/root/awstats-credentials.txt |
Per VM reports password, root only |
Managing the services
sudo systemctl status apache2.service
sudo systemctl restart apache2.service
The log update timer:
systemctl list-timers awstats-update.timer
sudo systemctl start awstats-update.service
To change how often statistics are rebuilt, edit OnUnitActiveSec in /etc/systemd/system/awstats-update.timer and reload:
sudo systemctl daemon-reload
sudo systemctl restart awstats-update.timer
Adding your own domain and TLS
The image serves plain HTTP on port 80. To put your own hostname and a certificate in front of it, point a DNS A record at the public address of the VM, then:
sudo apt-get update
sudo apt-get install -y certbot python3-certbot-apache
sudo certbot --apache -d stats.example.com
Certbot rewrites the shipped virtual host to serve HTTPS and installs a renewal timer. Afterwards, restrict port 80 in the NSG to the ranges you need, or leave it open so Certbot can complete future HTTP challenges.
Backing up
The statistics history and the configuration are the two things worth keeping:
sudo tar czf awstats-backup.tar.gz /etc/awstats /var/lib/awstats
Restore by extracting the archive back over /etc/awstats and /var/lib/awstats and running sudo /usr/local/bin/awstats-update server.
Troubleshooting
The browser keeps asking for a password. The user name is awstats, not your Azure user. Read the current password with sudo cat /root/awstats-credentials.txt, or set a new one with sudo htpasswd -B /etc/apache2/awstats.htpasswd awstats.
The report says "Never updated". No statistics have been built for the period you are viewing. Build them and reload:
sudo /usr/local/bin/awstats-update server
This server's report is nearly empty. That is expected on a new instance: the server configuration analyses this VM's own access log, which only fills as the instance receives traffic. The demonstration report is populated immediately and is the right place to explore the interface.
The report loads but the graphs are missing. The graph bars are images served from /awstatsicons. Confirm they are reachable:
curl -s -o /dev/null -w '%{http_code} %{content_type}\n' http://127.0.0.1/awstatsicons/other/hh.png
Expected output:
200 image/png
Checking the web server logs. Errors from the analyser appear in the Apache error log:
sudo tail -n 30 /var/log/apache2/awstats-error.log
Confirming the first boot service ran. It generates the password and the demonstration dataset:
systemctl is-active awstats-firstboot.service
sudo journalctl -u awstats-firstboot.service --no-pager -n 20
Security notes
- The entire reporting site requires authentication. Only
/healthzis open, and it returns a fixed string with no instance detail. - The reports password is unique to every instance, generated on first boot and stored in a root only file. No known or blank credential ships in the image.
- Browser triggered log parsing is disabled in every shipped configuration, so a visitor can never cause the instance to parse a file. Statistics are rebuilt only by the root owned scheduled updater.
- The statistics data directory is readable by the web server but writable only by the updater, so reports cannot be altered through the web tier.
- The analyser reads configuration only from
/etc/awstats. The upstream protection that refuses a caller supplied configuration directory is left in place. - Restrict port 80 in the NSG to the networks that need the reports, and put TLS in front of the site before exposing it to the internet, since HTTP Basic credentials are sent with every request.
- The base image receives unattended security updates.
Support
cloudimg provides 24/7 technical support for this product by email at support@cloudimg.co.uk and via live chat. We help with AWStats deployment and configuration, log format definition for web, FTP and mail server logs, adding and configuring additional sites and log sources, scheduling and troubleshooting log processing, report interpretation, access control questions, and version upgrades. Critical issues receive a one hour average response time.
AWStats is licensed under the GNU General Public License version 3. All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.