Introduction
AWStats est une alternative libre à Google Analytics qui permet d’analyser le trafic de votre site Internet, de votre serveur de mail ou serveur FTP via une interface Web. Il prend en charge la plupart des serveurs. Le projet est assez ancien, mais complet et très simple à installer ; avec presque aucun pré-requis : Apache et Perl.
L’installation est assez simple. Je vais utiliser ‘ansible’ pour déployer le service dans un container Incus (la procédure sera la même pour un serveur standard).
Nous utiliserons ‘rsyslog’ sur le serveur pour réceptionner les logs des serveurs à analyser.
Hypothèse de travail
J’ai créé au préalable un container Incus basé sur une distribution Debian 12.
Je pars du principe que le serveur SSH est configuré coté serveur pour pouvoir exécuter les scripts ‘ansible’.
Ansible est installé sur votre poste client qui effectuera le déploiement du service ‘AWStats’. Mon répertoire de travail ‘.ansible’ se trouve à la racine du répertoire utilisateur.
Mes fichiers de déploiements ansible seront dans le répertoire : /home/user/.ansible/roles
L’architecture de mes fichiers de configuration ‘ansible’
J’utilise les ‘roles’ pour une structure modulaire et une simplication décritures de mes ‘Playbooks’.
Voici un apercu des fichiers et répertoires nécessaires :
La configuration des sources
Configuration des variables globales
Nous allons utilisez un fichier de configuration contenant des variables globale qui seront utilisées dans nos tâches.
Ce fichier est situé dans : config/commun/defaults/main.yml
awstats_src: "https://prdownloads.sourceforge.net/awstats/awstats-7.9.tar.gz"
awstats_dst: "awstats.tar.gz"
awstats_tar: "awstats.tar"
awstats_www: "/var/www/awstats/"
awstats_stats: "{{awstats_www}}/stats/"
awstats_www_config: "{{awstats_www}}/cgi-bin/awstats.conf"
awstats_local_apache_config: "/home/yannick/.ansible/roles/config/awstats/awstats_apache.conf"
awstats_server_apache_config: "/etc/apache2/sites-available/awstats.conf"
awstats_local_app_config: "/home/yannick/.ansible/roles/config/awstats/awstats_app.conf"
awstats_local_rsyslog_config: "/home/yannick/.ansible/roles/config/awstats/rsyslog.conf"
awstats_local_log_rotate_config: "/home/yannick/.ansible/roles/config/awstats/log_rotate_hugo"
awstats_log_rotate_conf: "/etc/logrotate.d/hugo"
La dernière version en cours, est la ‘7.9’ du 17/01/2023.
Remarque : J’ai pris comme exemple l’analyse des logs mon Blog basé sur le moteur ‘Hugo’.
Configuration de la tache
Nous allons utilisés un seul fichier de type ‘tasks’ pour décrire les installations à effectuer. Ce fichier est situé dans config/awstats/tasks/main.yml. Le fichier est assez facile à comprendre ; la logique est toujours la même.
Voici son contenu :
---
- name: "Installation des pre-requis : curl,apache2,libapache2-mod-perl2"
apt:
name: "curl,apache2,libapache2-mod-perl2,rsyslog"
state: "present"
- name: "Verifie si les sources ont deja ete recuperees"
stat:
path: "{{ awstats_dst }}"
register: rep_source
- name: "Recuperation des sources"
command:
curl -L "{{ awstats_src }}" -o "{{ awstats_dst }}"
when: not rep_source.stat.exists
- name: "Verifie si la source a deja ete deccompressee"
stat:
path: "{{ awstats_tar }}"
register: rep_source_tar
- name: Decompression des sources
shell: |
gunzip ./"{{ awstats_dst }}"
tar -xvf {{ awstats_tar }}
when: not rep_source_tar.stat.exists
- name: Verifie si les sources sont dans le répertoire www
stat:
path: "{{ awstats_www }}"
register: rep_wwww
- name: Copie des sources
shell: |
sudo mkdir "{{ awstats_www }}"
sudo cp -r ./awstats*/wwwroot/* "{{ awstats_www }}"
sudo chown -R www-data:www-data "{{ awstats_www }}"
when: not rep_wwww.stat.exists
- name: Verifie si le fichier de config apache existe
stat:
path: "{{ awstats_www_config }}"
register: config_apache_created
- name: Copie le fichier de configuration apache
ansible.builtin.copy:
src: "{{ awstats_local_apache_config }}"
dest: "{{ awstats_server_apache_config }}"
owner: root
group: root
mode: '0644'
when: not config_apache_created.stat.exists
- name: Verifie si le fichier de config de l'application existe
stat:
path: "{{ awstats_www_config }}"
register: config_www_created
- name: Copie le fichier de configuration de l'application
ansible.builtin.copy:
src: "{{ awstats_local_app_config }}"
dest: "{{ awstats_www_config }}"
owner: www-data
group: www-data
mode: '0644'
when: not config_www_created.stat.exists
- name: Verifie si le repertoire des stats existe
stat:
path: "{{ awstats_stats }}"
register: stat_created
- name: Creation du repertoire des stats
command:
mkdir "{{ awstats_stats }}"
when: not stat_created.stat.exists
- name: Activation et lancement apache
shell: |
sudo systemctl start apache2
sudo a2ensite awstats.conf
sudo a2enmod cgid
sudo systemctl enable apache2
sudo systemctl restart apache2
- name: Copie le fichier de configuration de rsyslog
ansible.builtin.copy:
src: "{{ awstats_local_rsyslog_config }}"
dest: "/etc/rsyslog.conf"
owner: root
group: root
mode: '0644'
- name: Lancement rsyslog
shell: |
sudo systemctl start rsyslog
sudo systemctl enable rsyslog
- name: Verifie si le fichier configuration pour logrotate existe
stat:
path: "{{ awstats_log_rotate_conf }}"
register: log_rotate
- name: Copie le fichier de configuration de logrotate
ansible.builtin.copy:
src: "{{ awstats_local_log_rotate_config }}"
dest: "{{ awstats_log_rotate_conf }}"
owner: root
group: root
mode: '0644'
when: not log_rotate.stat.exists
- name: Relance logrotate
command:
sudo systemctl restart logrotate.service
when: not log_rotate.stat.exists
Le fichier est assez volimineux ; il aurait pu être découpé en plusieurs tâches : pré-requis, installation des sources, configuration de rsyslog, configuration de logrotate...
Le fonctionnement du fichier est tout le temps le même : On vérifie l’existance d’un fichier ou répertoire et on exécute une commande si celui-ci n’existe pas.
Cela permet de relancer plusieurs fois le ‘Playbook’ et de continuer à l’endroit où il s’était arrêté (suite à une erreur ou à un abandon).
Configuration du Playbook
L’utilisation des rôles simplifie grandement les fichiers ‘Playbooks’. Je ne fais qu’ici, indiqué le nom du rôle répertoire contenant la tâche à lancer ‘awstats’. J’utilise ici ‘become’ et ‘become_method’ pour exécuter mes tâches avec les privilèges ‘sudo’. Ce fichier peut-être situer où vous voulez.
---
- name: Install AWStats
hosts: awstats
become: yes
become_method: sudo
roles:
- role: "config/awstats"
Remarque : J’utilise le fichier de configuration ‘hosts’ qui se trouve à la racine du répertoire ‘.ansible’. Pour la syntaxe de ce fichier, je vous renvoi à la documentation de Ansible.
Configuration des métadonnées pour le role ‘awstats’
Le fichier de configuration des ‘meta’ permet de faire le lien avec le fichier contenant les variables globales. Il se trouve dans config/awstats/meta/main.yml
Voici son contenu :
dependencies:
- role: "config/commun"
Fichiers de configurations du serveur
Le fichier de configuration apache
Le ‘Playbook’ vas copier ce fichier local sur le serveur dans le répertoire /etc/apache2/sites-available/awstats.conf
Son contenu est le suivant :
Listen 8080
<VirtualHost *:8080>
ServerName IP_SERVEUR:8080
DocumentRoot /var/www/awstats/
<Directory /var/www/awstats/>
Options +FollowSymlinks
AllowOverride All
Require all granted
</Directory>
<IfModule mod_cgid.c>
Define ENABLE_USR_LIB_CGI_BIN
</IfModule>
ScriptAlias /cgi-bin/ "/var/www/awstats/cgi-bin/"
<Directory "/var/www/awstats/cgi-bin">
AllowOverride None
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
#SetHandler perl-script
#PerlResponseHandler ModPerl::PerlRun
AddHandler cgi-script .pl
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
Remarque : Il faudra remplacer ‘IP_SERVEUR’ par l’adresse IP de votre serveur ‘awstats’.
Le fichier de configuration de awstats
Le ‘Playbook’ vas copier ce fichier local sur le serveur dans le répertoire /var/wwww/awstats/cgi-bin/awstats.conf
Son contenu est le suivant :
LogFile="/var/log/hugo/access.log"
LogType=W
LogFormat=1
LogSeparator=" "
SiteDomain="192.168.2.64:8080"
DNSLookup=2
DynamicDNSLookup=0
DirData="/var/www/awstats/stats/"
DirCgi="/cgi-bin"
DirIcons="/icon"
AllowToUpdateStatsFromBrowser=1
AllowFullYearView=2
EnableLockForUpdate=0
DNSStaticCacheFile="dnscache.txt"
DNSLastUpdateCacheFile="dnscachelastupdate.txt"
SkipDNSLookupFor=""
AllowAccessFromWebToAuthenticatedUsersOnly=0
AllowAccessFromWebToFollowingAuthenticatedUsers=""
AllowAccessFromWebToFollowingIPAddresses="192.168.2.5"
CreateDirDataIfNotExists=0
BuildHistoryFormat=text
BuildReportFormat=html
SaveDatabaseFilesWithPermissionsForEveryone=0
PurgeLogFile=0
ArchiveLogRecords=0
KeepBackupOfHistoricFiles=0
DefaultFile="index.php index.html"
SkipHosts=""
SkipUserAgents=""
SkipFiles=""
SkipReferrersBlackList=""
OnlyHosts=""
OnlyUserAgents=""
OnlyUsers=""
OnlyFiles=""
NotPageList="css js class gif jpg jpeg png bmp ico rss xml swf eot woff woff2"
ValidHTTPCodes="200 304"
ValidSMTPCodes="1 250"
TrapInfosForHTTPErrorCodes = "400 403 404"
AuthenticatedUsersNotCaseSensitive=0
URLNotCaseSensitive=0
URLWithAnchor=0
URLQuerySeparators="?;"
URLWithQuery=0
URLWithQueryWithOnlyFollowingParameters=""
URLWithQueryWithoutFollowingParameters=""
URLReferrerWithQuery=0
WarningMessages=1
ErrorMessages=""
DebugMessages=0
NbOfLinesForCorruptedLog=50
WrapperScript=""
DecodeUA=0
MiscTrackerUrl="/js/awstats_misc_tracker.js"
LevelForBrowsersDetection=2 # 0 disables Browsers detection.
# 2 reduces AWStats speed by 2%
# allphones reduces AWStats speed by 5%
LevelForOSDetection=2 # 0 disables OS detection.
# 2 reduces AWStats speed by 3%
LevelForRefererAnalyze=2 # 0 disables Origin detection.
# 2 reduces AWStats speed by 14%
LevelForRobotsDetection=2 # 0 disables Robots detection.
# 2 reduces AWStats speed by 2.5%
LevelForSearchEnginesDetection=2 # 0 disables Search engines detection.
# 2 reduces AWStats speed by 9%
LevelForKeywordsDetection=2 # 0 disables Keyphrases/Keywords detection.
# 2 reduces AWStats speed by 1%
LevelForFileTypesDetection=2 # 0 disables File types detection.
# 2 reduces AWStats speed by 1%
LevelForWormsDetection=0 # 0 disables Worms detection.
# 2 reduces AWStats speed by 15%
UseFramesWhenCGI=1
DetailedReportsOnNewWindows=1
Expires=0
MaxRowsInHTMLOutput=10000
Lang="auto" # fr
DirLang="./lang"
ShowMenu=1
ShowSummary=UVPHB
ShowMonthStats=UVPHB
ShowDaysOfMonthStats=VPHB
ShowDaysOfWeekStats=PHB
ShowHoursStats=PHB
ShowDomainsStats=PHB
ShowHostsStats=PHBL
ShowAuthenticatedUsers=0
ShowRobotsStats=HBL
ShowWormsStats=0
ShowEMailSenders=0
ShowEMailReceivers=0
ShowSessionsStats=1
ShowPagesStats=PBEX
ShowFileTypesStats=HB
ShowFileSizesStats=0
ShowDownloadsStats=HB
ShowOSStats=1
ShowBrowsersStats=1
ShowScreenSizeStats=0
ShowOriginStats=PH
ShowKeyphrasesStats=1
ShowKeywordsStats=1
ShowMiscStats=a
ShowHTTPErrorsStats=1
ShowHTTPErrorsPageDetail=R
ShowSMTPErrorsStats=0
ShowClusterStats=0
AddDataArrayMonthStats=1
AddDataArrayShowDaysOfMonthStats=1
AddDataArrayShowDaysOfWeekStats=1
AddDataArrayShowHoursStats=1
IncludeInternalLinksInOriginSection=0
MaxNbOfDomain = 10
MinHitDomain = 1
MaxNbOfHostsShown = 10
MinHitHost = 1
MaxNbOfLoginShown = 10
MinHitLogin = 1
MaxNbOfRobotShown = 10
MinHitRobot = 1
MaxNbOfDownloadsShown = 10
MinHitDownloads = 1
MaxNbOfPageShown = 10
MinHitFile = 1
MaxNbOfOsShown = 10
MinHitOs = 1
MaxNbOfBrowsersShown = 10
MinHitBrowser = 1
MaxNbOfScreenSizesShown = 5
MinHitScreenSize = 1
MinHitWindowSize = 1
MaxNbOfRefererShown = 10
MinHitRefer = 1
MaxNbOfKeyphrasesShown = 10
MinHitKeyphrase = 1
MaxNbOfKeywordsShown = 10
MinHitKeyword = 1
MaxNbOfEMailsShown = 20
MinHitEMail = 1
FirstDayOfWeek=1
ShowFlagLinks=""
ShowLinksOnUrl=1
UseHTTPSLinkForUrl=""
MaxLengthOfShownURL=64
HTMLHeadSection=""
HTMLEndSection=""
MetaRobot=0
Logo="awstats_logo6.png"
LogoLink="http://www.awstats.org"
BarWidth = 260
BarHeight = 90
StyleSheet=""
color_Background="FFFFFF" # Background color for main page (Default = "FFFFFF")
color_TableBGTitle="CCCCDD" # Background color for table title (Default = "CCCCDD")
color_TableTitle="000000" # Table title font color (Default = "000000")
color_TableBG="CCCCDD" # Background color for table (Default = "CCCCDD")
color_TableRowTitle="FFFFFF" # Table row title font color (Default = "FFFFFF")
color_TableBGRowTitle="ECECEC" # Background color for row title (Default = "ECECEC")
color_TableBorder="ECECEC" # Table border color (Default = "ECECEC")
color_text="000000" # Color of text (Default = "000000")
color_textpercent="606060" # Color of text for percent values (Default = "606060")
color_titletext="000000" # Color of text title within colored Title Rows (Default = "000000")
color_weekend="EAEAEA" # Color for week-end days (Default = "EAEAEA")
color_link="0011BB" # Color of HTML links (Default = "0011BB")
color_hover="605040" # Color of HTML on-mouseover links (Default = "605040")
color_u="FFAA66" # Background color for number of unique visitors (Default = "FFAA66")
color_v="F4F090" # Background color for number of visites (Default = "F4F090")
color_p="4477DD" # Background color for number of pages (Default = "4477DD")
color_h="66DDEE" # Background color for number of hits (Default = "66DDEE")
color_k="2EA495" # Background color for number of bytes (Default = "2EA495")
color_s="8888DD" # Background color for number of search (Default = "8888DD")
color_e="CEC2E8" # Background color for number of entry pages (Default = "CEC2E8")
color_x="C1B2E2" # Background color for number of exit pages (Default = "C1B2E2")
ExtraTrackedRowsLimit=500
Remarque : Il faudra adapter la variable ‘LogFile’ à votre fichier que vous souhaitez analyser.
Le fichier de configuration de rsyslog
Le ‘Playbook’ vas copier ce fichier local sur le serveur dans le répertoire /etc/rsyslog.conf
Son contenu est le suivant :
module(load="imuxsock") # provides support for local system logging
# provides UDP syslog reception
module(load="imudp")
input(type="imudp" port="514")
# provides TCP syslog reception
module(load="imtcp")
input(type="imtcp" port="514")
#
# Set the default permissions for all log files.
#
$FileOwner root
$FileGroup adm
$FileCreateMode 0640
$DirCreateMode 0755
$Umask 0022
#
# Where to place spool and state files
#
$WorkDirectory /var/spool/rsyslog
#
# Log anything besides private authentication messages to a single log file
#
*.*;auth,authpriv.none -/var/log/syslog
:msg, contains, "pam_unix" stop
:msg, contains, "pam_limits" stop
$IncludeConfig /etc/rsyslog.d/*.conf
#
# Log commonly used facilities to their own log file
#
auth,authpriv.* /var/log/auth.log
cron.* -/var/log/cron.log
kern.* -/var/log/kern.log
mail.* -/var/log/mail.log
user.* -/var/log/user.log
local7.* -/var/log/hugo.log
#
# Emergencies are sent to everybody logged in.
#
*.emerg :omusrmsg:*
Remarque : Il faudra adapter la variable ‘local7.*’ à votre fichier que vous souhaitez analyser.
Le fichier de configuration de logrotate
Le ‘Playbook’ vas copier ce fichier local sur le serveur dans le répertoire /etc/logrotate.d/hugo
Son contenu est le suivant :
/var/log/hugo/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 640 root www-data
sharedscripts
postrotate
/usr/lib/rsyslog/rsyslog-rotate
endscript
}
Remarque : Il faudra adapter la variable la premiere ligne à votre fichier que vous souhaitez analyser.
Lancement du ‘playbooks’
La commande à exécuter pour lancer le ‘Playbook’ est celle ci :
Vous devez indiquer le chemin où se trouve votre fichier ‘Playbook’en remplacant ‘repertoire_playbook’. Ce fichier peut-être n’importe où, mais vous pouvez le mettre à la racine de votre dossier ‘.ansible’.
Remarque : J’utilise le fichier de configuration ‘hosts’ qui se trouve à la racine du répertoire ‘.ansible’. L’option ‘–ask-become-pass’ indique qu’il faut demander le mot de passe ‘sudo’ nécessaire à l’éxecution des tâches sur le serveur.
Si tout se passe bien, vous devriez avoir comme résultat :
Consultation du service depuis votre LAN
AWStats est consultable via l’adresse : ip_du_serveur:8080
Si vous avez une erreur lors de la connexion au service ; c’est surement : un problème de droit sur des répertoires, un mauvais chemin dans la configuration… Le message affiché sera assez explicite.
Si le déploiement s’est bien exécuter, vous arriverez sur le tableau de bord principal :