Observability Azure

AWStats on Ubuntu 24.04 on Azure User Guide

| Product: AWStats on Ubuntu 24.04 LTS on Azure

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_0 release, served by Apache with mod_cgid
  • Two ready made report configurations: server for this instance's own Apache access log, and demo for 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.service and awstats-update.timer as enabled systemd units
  • An unauthenticated /healthz endpoint 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

  1. In the Azure Portal, choose Create a resource and search for AWStats on Ubuntu 24.04 LTS by cloudimg.
  2. Select Create, then choose your subscription, resource group and region.
  3. Set the VM size to Standard_B2s or larger.
  4. Under Administrator account, choose SSH public key, set the username to azureuser and paste your public key.
  5. Under Inbound port rules, allow SSH (22) and HTTP (80).
  6. 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

Apache and the AWStats update timer both active on a freshly booted instance

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)

The AWStats version and the two shipped report configurations

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

The first boot service reports active and the per VM credentials file exists with root only permissions

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.

The AWStats reports landing page listing this server's report and the demonstration report

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 AWStats summary report showing unique visitors, visits, pages, hits and bandwidth with the monthly history chart

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:

The Pages URL report ranking the most viewed pages with entry and exit counts

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

The Browsers report breaking traffic down by browser and version

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

Running the log update and reading the visit totals straight out of the history data

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 /healthz is 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.