Skip to content

Latest commit

 

History

History
1953 lines (1472 loc) · 43.1 KB

File metadata and controls

1953 lines (1472 loc) · 43.1 KB

🔝 Retour au Sommaire

9.2.2 Configuration Apache/Nginx (Ubuntu)

Introduction

Sur les systèmes Linux, particulièrement Ubuntu, deux serveurs web dominent le marché : Apache et Nginx. Chacun a ses forces, et FreePascal fonctionne parfaitement avec les deux grâce au support CGI et FastCGI.

Apache vs Nginx : Quel choisir ?

Aspect Apache Nginx
Architecture Processus par connexion Événementiel asynchrone
Performance Bonne (< 1000 req/s) Excellente (> 10000 req/s)
Mémoire Plus gourmand Très léger
Configuration Fichiers .htaccess Fichiers centralisés
Modules Très nombreux Moins nombreux
Facilité Plus simple pour débuter Syntaxe plus complexe
CGI/FastCGI Support natif excellent Excellent via proxy
Fichiers statiques Bon Excellent
Usage type Applications complètes Reverse proxy, API

Recommandation :

  • Apache : Idéal pour débuter, configuration plus intuitive
  • Nginx : Meilleur pour production haute performance

Dans ce tutoriel, nous couvrirons les deux solutions en détail.

Prérequis Ubuntu

Mise à jour du système

Avant toute installation, mettez à jour votre système :

sudo apt update  
sudo apt upgrade -y

Installation de FreePascal et outils

Si ce n'est pas déjà fait :

# FreePascal
sudo apt install -y fpc

# Outils de développement
sudo apt install -y build-essential git

# Vérification
fpc -version

Structure de répertoires recommandée

# Créer la structure
sudo mkdir -p /var/www/apps  
sudo mkdir -p /var/www/apps/monapp/{bin,public,logs}

# Permissions (www-data est l'utilisateur par défaut d'Apache/Nginx)
sudo chown -R $USER:www-data /var/www/apps  
sudo chmod -R 755 /var/www/apps

Structure obtenue :

/var/www/
├── html/                    (site par défaut)
└── apps/
    └── monapp/
        ├── bin/            (exécutables FreePascal)
        ├── public/         (fichiers statiques CSS, JS, images)
        └── logs/           (logs de l'application)

Configuration Apache sur Ubuntu

Installation d'Apache

# Installation du serveur Apache
sudo apt install -y apache2

# Installation du module FastCGI
sudo apt install -y libapache2-mod-fcgid

# Vérifier que Apache est actif
sudo systemctl status apache2

Test : Ouvrir un navigateur et aller à http://localhost ou http://[IP-du-serveur] Vous devriez voir la page par défaut d'Apache.

Comprendre la structure d'Apache sur Ubuntu

/etc/apache2/
├── apache2.conf           (configuration principale)
├── sites-available/       (sites disponibles)
│   ├── 000-default.conf  (site par défaut)
│   └── monapp.conf       (votre site)
├── sites-enabled/         (liens symboliques vers sites actifs)
├── mods-available/        (modules disponibles)
├── mods-enabled/          (modules actifs)
└── conf-available/        (configurations additionnelles)

Commandes essentielles :

# Activer/désactiver un site
sudo a2ensite monapp       # Activer  
sudo a2dissite monapp      # Désactiver

# Activer/désactiver un module
sudo a2enmod fcgid         # Activer FastCGI  
sudo a2dismod fcgid        # Désactiver

# Recharger la configuration
sudo systemctl reload apache2

# Redémarrer Apache
sudo systemctl restart apache2

# Voir les logs
sudo tail -f /var/log/apache2/error.log  
sudo tail -f /var/log/apache2/access.log

Application FreePascal CGI simple

Créer l'application : webapp.lpr

program WebAppCGI;

{$mode objfpc}{$H+}

uses
  SysUtils, Classes;

function GetCGIVar(const VarName: String): String;  
begin
  Result := GetEnvironmentVariable(VarName);
end;

var
  Name: String;
  QueryString: String;

begin
  // En-têtes HTTP
  WriteLn('Content-Type: text/html; charset=utf-8');
  WriteLn;

  // Récupérer les paramètres
  QueryString := GetCGIVar('QUERY_STRING');

  if Pos('name=', QueryString) > 0 then
    Name := Copy(QueryString, Pos('name=', QueryString) + 5, 100)
  else
    Name := 'Visiteur';

  // Page HTML
  WriteLn('<!DOCTYPE html>');
  WriteLn('<html lang="fr">');
  WriteLn('<head>');
  WriteLn('  <meta charset="utf-8">');
  WriteLn('  <title>Application FreePascal sur Apache</title>');
  WriteLn('  <style>');
  WriteLn('    body { font-family: Arial, sans-serif; max-width: 800px; margin: 50px auto; }');
  WriteLn('    h1 { color: #2c3e50; }');
  WriteLn('    .info { background: #ecf0f1; padding: 15px; border-radius: 5px; }');
  WriteLn('  </style>');
  WriteLn('</head>');
  WriteLn('<body>');
  WriteLn('  <h1>Bonjour ', Name, ' !</h1>');
  WriteLn('  <p>Cette application FreePascal fonctionne sur Apache/Ubuntu.</p>');
  WriteLn('  <div class="info">');
  WriteLn('    <strong>Informations de la requête :</strong><br>');
  WriteLn('    URI : ', GetCGIVar('REQUEST_URI'), '<br>');
  WriteLn('    Méthode : ', GetCGIVar('REQUEST_METHOD'), '<br>');
  WriteLn('    Serveur : ', GetCGIVar('SERVER_SOFTWARE'), '<br>');
  WriteLn('    IP client : ', GetCGIVar('REMOTE_ADDR'));
  WriteLn('  </div>');
  WriteLn('</body>');
  WriteLn('</html>');
end.

Compiler :

fpc -MObjFPC -Scghi webapp.lpr

Déployer :

# Copier l'exécutable
sudo cp webapp /var/www/apps/monapp/bin/

# Rendre exécutable
sudo chmod +x /var/www/apps/monapp/bin/webapp

# Vérifier les permissions
ls -la /var/www/apps/monapp/bin/webapp

Configuration d'un site CGI sous Apache

Créer le fichier de configuration : /etc/apache2/sites-available/monapp.conf

sudo nano /etc/apache2/sites-available/monapp.conf

Contenu :

<VirtualHost *:80>
    ServerName monapp.local
    ServerAdmin webmaster@localhost

    DocumentRoot /var/www/apps/monapp/public

    # Répertoire pour les fichiers statiques
    <Directory /var/www/apps/monapp/public>
        Options Indexes FollowSymLinks
        AllowOverride None
        Require all granted
    </Directory>

    # Configuration CGI
    ScriptAlias /cgi-bin/ /var/www/apps/monapp/bin/
    <Directory /var/www/apps/monapp/bin>
        Options +ExecCGI
        AddHandler cgi-script .cgi
        SetHandler cgi-script
        Require all granted
    </Directory>

    # Logs
    ErrorLog ${APACHE_LOG_DIR}/monapp-error.log
    CustomLog ${APACHE_LOG_DIR}/monapp-access.log combined
</VirtualHost>

Activer le site :

# Activer le module CGI
sudo a2enmod cgi

# Activer le site
sudo a2ensite monapp

# Recharger Apache
sudo systemctl reload apache2

Tester :

# Accès direct (si vous êtes sur le serveur)
curl http://localhost/cgi-bin/webapp

# Avec paramètre
curl "http://localhost/cgi-bin/webapp?name=Alice"

Configuration FastCGI avec Apache

FastCGI offre de bien meilleures performances que CGI.

Application FastCGI : webappfcgi.lpr

program WebAppFastCGI;

{$mode objfpc}{$H+}

uses
  fphttpapp, httpdefs, httproute, fpjson, SysUtils;

var
  RequestCount: Integer = 0;

procedure HandleHome(ARequest: TRequest; AResponse: TResponse);  
begin
  Inc(RequestCount);

  AResponse.Content := Format(
    '<!DOCTYPE html>' +
    '<html><head><title>FastCGI</title>' +
    '<style>body{font-family:Arial;max-width:800px;margin:50px auto;}</style>' +
    '</head><body>' +
    '<h1>Application FastCGI FreePascal</h1>' +
    '<p>Processus persistant - Performances maximales !</p>' +
    '<p><strong>Requêtes traitées :</strong> %d</p>' +
    '<p><strong>Heure serveur :</strong> %s</p>' +
    '</body></html>',
    [RequestCount, FormatDateTime('yyyy-mm-dd hh:nn:ss', Now)]
  );
end;

procedure HandleAPI(ARequest: TRequest; AResponse: TResponse);  
var
  JSONObj: TJSONObject;
begin
  JSONObj := TJSONObject.Create;
  try
    JSONObj.Add('status', 'ok');
    JSONObj.Add('message', 'FastCGI opérationnel');
    JSONObj.Add('requests', RequestCount);
    JSONObj.Add('timestamp', FormatDateTime('yyyy-mm-dd"T"hh:nn:ss', Now));

    AResponse.ContentType := 'application/json';
    AResponse.Content := JSONObj.AsJSON;
  finally
    JSONObj.Free;
  end;
end;

begin
  HTTPRouter.RegisterRoute('/', @HandleHome);
  HTTPRouter.RegisterRoute('/api', @HandleAPI);

  Application.Title := 'WebApp FastCGI';
  Application.Initialize;
  Application.Run;
end.

Compiler :

fpc -MObjFPC -Scghi webappfcgi.lpr  
sudo cp webappfcgi /var/www/apps/monapp/bin/  
sudo chmod +x /var/www/apps/monapp/bin/webappfcgi

Configuration Apache pour FastCGI : /etc/apache2/sites-available/monapp-fcgi.conf

<VirtualHost *:80>
    ServerName monapp.local
    ServerAdmin webmaster@localhost

    DocumentRoot /var/www/apps/monapp/public

    # Fichiers statiques
    <Directory /var/www/apps/monapp/public>
        Options Indexes FollowSymLinks
        AllowOverride None
        Require all granted
    </Directory>

    # Configuration FastCGI
    <IfModule mod_fcgid.c>
        # Socket Unix pour communication
        FcgidIPCDir /var/lib/apache2/fcgid/sock

        # Limites et timeouts
        FcgidMaxRequestsPerProcess 10000
        FcgidMaxProcesses 10
        FcgidMinProcessesPerClass 2
        FcgidIdleTimeout 600
        FcgidProcessLifeTime 3600
        FcgidIOTimeout 120

        # Wrapper FastCGI
        ScriptAlias /fcgi-bin/ /var/www/apps/monapp/bin/
        <Directory /var/www/apps/monapp/bin>
            Options +ExecCGI
            SetHandler fcgid-script
            Require all granted
        </Directory>

        # Rediriger tout vers l'application FastCGI
        RewriteEngine On
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule ^(.*)$ /fcgi-bin/webappfcgi/$1 [QSA,L]
    </IfModule>

    ErrorLog ${APACHE_LOG_DIR}/monapp-fcgi-error.log
    CustomLog ${APACHE_LOG_DIR}/monapp-fcgi-access.log combined
</VirtualHost>

Activer :

# Modules nécessaires
sudo a2enmod fcgid  
sudo a2enmod rewrite

# Activer le site
sudo a2ensite monapp-fcgi

# Désactiver l'ancien si nécessaire
sudo a2dissite monapp

# Recharger
sudo systemctl reload apache2

Tester :

curl http://localhost/  
curl http://localhost/api

Le compteur de requêtes devrait augmenter (preuve que le processus est persistant) !

Configuration avec socket Unix (recommandé)

Pour de meilleures performances, utilisez un socket Unix plutôt que TCP.

Script de démarrage : /var/www/apps/monapp/bin/start-fcgi.sh

#!/bin/bash

SOCKET_PATH="/var/run/monapp.sock"  
APP_PATH="/var/www/apps/monapp/bin/webappfcgi"

# Supprimer l'ancien socket
rm -f $SOCKET_PATH

# Démarrer l'application en mode FastCGI sur socket Unix
$APP_PATH &

# Attendre que le socket soit créé
sleep 2

# Permissions
chmod 666 $SOCKET_PATH

echo "FastCGI démarré sur $SOCKET_PATH"

Rendre exécutable :

sudo chmod +x /var/www/apps/monapp/bin/start-fcgi.sh

Configuration Nginx sur Ubuntu

Installation de Nginx

# Installation
sudo apt install -y nginx

# Vérifier le statut
sudo systemctl status nginx

Test : http://localhost devrait afficher la page par défaut de Nginx.

Structure de Nginx sur Ubuntu

/etc/nginx/
├── nginx.conf              (configuration principale)
├── sites-available/        (sites disponibles)
│   └── default
├── sites-enabled/          (liens symboliques)
│   └── default -> ../sites-available/default
├── conf.d/                 (configurations additionnelles)
└── snippets/               (fragments réutilisables)

Commandes essentielles :

# Tester la configuration
sudo nginx -t

# Recharger
sudo systemctl reload nginx

# Redémarrer
sudo systemctl restart nginx

# Voir les logs
sudo tail -f /var/log/nginx/error.log  
sudo tail -f /var/log/nginx/access.log

Configuration FastCGI avec Nginx

Nginx ne supporte pas CGI classique, uniquement FastCGI. C'est une bonne chose : FastCGI est bien plus performant !

Configuration Nginx : /etc/nginx/sites-available/monapp

server {
    listen 80;
    server_name monapp.local;

    root /var/www/apps/monapp/public;
    index index.html;

    # Logs
    access_log /var/log/nginx/monapp-access.log;
    error_log /var/log/nginx/monapp-error.log;

    # Fichiers statiques
    location /static/ {
        alias /var/www/apps/monapp/public/;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    # Application FastCGI
    location / {
        # Inclure les paramètres FastCGI standard
        include fastcgi_params;

        # Socket Unix (plus rapide)
        fastcgi_pass unix:/var/run/monapp.sock;

        # Ou TCP/IP
        # fastcgi_pass 127.0.0.1:9000;

        # Paramètres FastCGI
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;

        # Timeouts
        fastcgi_read_timeout 60s;
        fastcgi_send_timeout 60s;

        # Buffers
        fastcgi_buffer_size 128k;
        fastcgi_buffers 256 4k;
        fastcgi_busy_buffers_size 256k;
    }
}

Activer le site :

# Créer le lien symbolique
sudo ln -s /etc/nginx/sites-available/monapp /etc/nginx/sites-enabled/

# Tester la configuration
sudo nginx -t

# Recharger
sudo systemctl reload nginx

Démarrage automatique avec systemd

Pour que l'application FastCGI démarre automatiquement au boot.

Créer un service systemd : /etc/systemd/system/monapp-fcgi.service

sudo nano /etc/systemd/system/monapp-fcgi.service

Contenu :

[Unit]
Description=Application FastCGI FreePascal - MonApp  
After=network.target

[Service]
Type=simple  
User=www-data  
Group=www-data  
WorkingDirectory=/var/www/apps/monapp/bin

# Supprimer l'ancien socket
ExecStartPre=/bin/rm -f /var/run/monapp.sock

# Démarrer l'application
ExecStart=/var/www/apps/monapp/bin/webappfcgi

# Redémarrage automatique
Restart=always  
RestartSec=5

# Limites de ressources
LimitNOFILE=65536  
MemoryLimit=512M

# Variables d'environnement
Environment="APP_ENV=production"  
Environment="APP_LOG_LEVEL=info"

# Logging
StandardOutput=journal  
StandardError=journal  
SyslogIdentifier=monapp-fcgi

[Install]
WantedBy=multi-user.target

Activer et démarrer :

# Recharger systemd
sudo systemctl daemon-reload

# Activer au démarrage
sudo systemctl enable monapp-fcgi

# Démarrer
sudo systemctl start monapp-fcgi

# Vérifier le statut
sudo systemctl status monapp-fcgi

# Voir les logs
sudo journalctl -u monapp-fcgi -f

Commandes utiles :

# Démarrer
sudo systemctl start monapp-fcgi

# Arrêter
sudo systemctl stop monapp-fcgi

# Redémarrer
sudo systemctl restart monapp-fcgi

# Voir l'état
sudo systemctl status monapp-fcgi

# Logs en temps réel
sudo journalctl -u monapp-fcgi -f

# Logs des dernières 100 lignes
sudo journalctl -u monapp-fcgi -n 100

Configuration FastCGI avec socket TCP

Si vous préférez utiliser TCP (plus flexible pour répartition de charge) :

Modifier l'application FreePascal :

begin
  Application.Address := '127.0.0.1';
  Application.Port := 9000;
  Application.Initialize;
  Application.Run;
end.

Configuration Nginx :

location / {
    include fastcgi_params;
    fastcgi_pass 127.0.0.1:9000;  # TCP au lieu de socket Unix
    # ... reste identique
}

URLs propres avec Nginx

Configuration pour des URLs comme /users/123 :

server {
    listen 80;
    server_name monapp.local;

    root /var/www/apps/monapp/public;

    # Logs
    access_log /var/log/nginx/monapp-access.log;
    error_log /var/log/nginx/monapp-error.log;

    # Fichiers statiques
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    # API et routes dynamiques
    location / {
        # Essayer fichier statique d'abord, sinon FastCGI
        try_files $uri @fcgi;
    }

    location @fcgi {
        include fastcgi_params;
        fastcgi_pass unix:/var/run/monapp.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $uri;
        fastcgi_read_timeout 60s;
    }
}

Gestion des domaines et DNS

Fichier /etc/hosts pour tests locaux

sudo nano /etc/hosts

Ajouter :

127.0.0.1   monapp.local
127.0.0.1   api.monapp.local

Maintenant vous pouvez accéder à http://monapp.local dans votre navigateur.

Plusieurs applications sur le même serveur

Apache :

# /etc/apache2/sites-available/app1.conf
<VirtualHost *:80>
    ServerName app1.local
    DocumentRoot /var/www/apps/app1/public
    # ... configuration FastCGI ...
</VirtualHost>

# /etc/apache2/sites-available/app2.conf
<VirtualHost *:80>
    ServerName app2.local
    DocumentRoot /var/www/apps/app2/public
    # ... configuration FastCGI ...
</VirtualHost>

Nginx :

# /etc/nginx/sites-available/app1
server {
    listen 80;
    server_name app1.local;
    # ... configuration ...
}

# /etc/nginx/sites-available/app2
server {
    listen 80;
    server_name app2.local;
    # ... configuration ...
}

Configuration SSL/HTTPS avec Let's Encrypt

Installation de Certbot

# Installation
sudo apt install -y certbot

# Pour Apache
sudo apt install -y python3-certbot-apache

# Pour Nginx
sudo apt install -y python3-certbot-nginx

Obtenir un certificat SSL

Pour Apache :

sudo certbot --apache -d monapp.example.com

Pour Nginx :

sudo certbot --nginx -d monapp.example.com

Renouvellement automatique :

Certbot installe automatiquement un cron/timer pour renouveler les certificats.

Vérifier :

sudo systemctl status certbot.timer

# Test de renouvellement
sudo certbot renew --dry-run

Configuration manuelle HTTPS

Apache : /etc/apache2/sites-available/monapp-ssl.conf

<VirtualHost *:443>
    ServerName monapp.example.com

    DocumentRoot /var/www/apps/monapp/public

    # SSL
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/monapp.example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/monapp.example.com/privkey.pem

    # Configuration FastCGI
    # ... (identique à HTTP)

</VirtualHost>

# Redirection HTTP → HTTPS
<VirtualHost *:80>
    ServerName monapp.example.com
    Redirect permanent / https://monapp.example.com/
</VirtualHost>

Activer :

sudo a2enmod ssl  
sudo a2ensite monapp-ssl  
sudo systemctl reload apache2

Nginx :

# Redirection HTTP → HTTPS
server {
    listen 80;
    server_name monapp.example.com;
    return 301 https://$server_name$request_uri;
}

# HTTPS
server {
    listen 443 ssl http2;
    server_name monapp.example.com;

    # Certificats SSL
    ssl_certificate /etc/letsencrypt/live/monapp.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/monapp.example.com/privkey.pem;

    # Configuration SSL moderne
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    # Headers de sécurité
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;

    root /var/www/apps/monapp/public;

    # Configuration FastCGI
    location / {
        include fastcgi_params;
        fastcgi_pass unix:/var/run/monapp.sock;
        # ... reste de la config
    }
}

Optimisations pour production

Apache - Configuration optimisée

/etc/apache2/apache2.conf - Ajustements :

# Nombre de workers
<IfModule mpm_prefork_module>
    StartServers             5
    MinSpareServers          5
    MaxSpareServers         10
    MaxRequestWorkers      150
    MaxConnectionsPerChild   3000
</IfModule>

# Ou mieux, utiliser mpm_event (plus performant)
<IfModule mpm_event_module>
    StartServers             2
    MinSpareThreads         25
    MaxSpareThreads         75
    ThreadLimit             64
    ThreadsPerChild         25
    MaxRequestWorkers      150
    MaxConnectionsPerChild   3000
</IfModule>

# Compression
<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript application/json
</IfModule>

# Cache
<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType image/jpg "access plus 1 year"
    ExpiresByType image/jpeg "access plus 1 year"
    ExpiresByType image/png "access plus 1 year"
    ExpiresByType text/css "access plus 1 month"
    ExpiresByType application/javascript "access plus 1 month"
</IfModule>

Activer les modules :

sudo a2enmod deflate  
sudo a2enmod expires  
sudo a2enmod headers  
sudo a2enmod mpm_event  
sudo systemctl restart apache2

Nginx - Configuration optimisée

/etc/nginx/nginx.conf :

user www-data;  
worker_processes auto;  # Un par cœur CPU  
worker_rlimit_nofile 65535;

events {
    worker_connections 4096;
    use epoll;
    multi_accept on;
}

http {
    # Performance
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;

    # Timeouts
    keepalive_timeout 65;
    client_body_timeout 12;
    client_header_timeout 12;
    send_timeout 10;

    # Buffers
    client_body_buffer_size 10K;
    client_header_buffer_size 1k;
    client_max_body_size 10m;
    large_client_header_buffers 2 1k;

    # Compression Gzip
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css text/xml text/javascript
               application/json application/javascript application/xml+rss;

    # Cache fichiers ouverts
    open_file_cache max=200000 inactive=20s;
    open_file_cache_valid 30s;
    open_file_cache_min_uses 2;
    open_file_cache_errors on;

    # Logging
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log warn;

    # Inclure les configurations des sites
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

Redémarrer :

sudo nginx -t  
sudo systemctl restart nginx

Monitoring et logs

Analyser les logs Apache

# Dernières erreurs
sudo tail -f /var/log/apache2/error.log

# Requêtes en temps réel
sudo tail -f /var/log/apache2/access.log

# Statistiques du jour
sudo cat /var/log/apache2/access.log | awk '{print $1}' | sort | uniq -c | sort -nr | head -10

# Codes de statut
sudo awk '{print $9}' /var/log/apache2/access.log | sort | uniq -c | sort -nr

Analyser les logs Nginx

# Dernières erreurs
sudo tail -f /var/log/nginx/error.log

# Requêtes en temps réel
sudo tail -f /var/log/nginx/access.log

# Top 10 IPs
sudo awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -10

# URLs les plus demandées
sudo awk '{print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -10

Monitoring avec htop et netstat

Installation :

sudo apt install -y htop net-tools

Surveiller les ressources :

# Processus en temps réel
htop

# Connexions réseau actives
sudo netstat -tulpn | grep nginx  
sudo netstat -tulpn | grep apache2

# Nombre de connexions par état
sudo netstat -an | grep :80 | awk '{print $6}' | sort | uniq -c | sort -nr

Script de monitoring système

Créer : /usr/local/bin/monapp-monitor.sh

#!/bin/bash

# Couleurs
RED='\033[0;31m'  
GREEN='\033[0;32m'  
YELLOW='\033[1;33m'  
NC='\033[0m' # No Color

APP_NAME="monapp-fcgi"  
SOCKET_PATH="/var/run/monapp.sock"

echo "=== Monitoring MonApp ==="  
echo "Date: $(date '+%Y-%m-%d %H:%M:%S')"  
echo ""

# 1. Vérifier le service systemd
echo -n "Service $APP_NAME: "  
if systemctl is-active --quiet $APP_NAME; then
    echo -e "${GREEN}✓ Actif${NC}"
else
    echo -e "${RED}✗ Inactif${NC}"
fi

# 2. Vérifier le socket
echo -n "Socket $SOCKET_PATH: "  
if [ -S "$SOCKET_PATH" ]; then
    echo -e "${GREEN}✓ Présent${NC}"
else
    echo -e "${RED}✗ Absent${NC}"
fi

# 3. Processus
echo ""  
echo "Processus:"  
ps aux | grep webappfcgi | grep -v grep | awk '{printf "  PID: %s | CPU: %s%% | MEM: %s%% | RSS: %s KB\n", $2, $3, $4, $6}'

# 4. Mémoire et CPU
echo ""  
echo "Ressources système:"  
free -h | grep Mem | awk '{printf "  Mémoire: %s utilisé / %s total (%s disponible)\n", $3, $2, $7}'  
uptime | awk '{printf "  Load average: %s\n", substr($0, index($0,"average:")+9)}'

# 5. Espace disque
echo ""  
echo "Espace disque /var:"  
df -h /var | tail -1 | awk '{printf "  %s utilisé / %s total (%s disponible) - %s\n", $3, $2, $4, $5}'

# 6. Connexions réseau
echo ""  
echo "Connexions réseau:"  
NGINX_CONN=$(netstat -an | grep :80 | grep ESTABLISHED | wc -l)  
echo "  Connexions établies: $NGINX_CONN"

# 7. Logs récents
echo ""  
echo "Dernières erreurs (5 dernières lignes):"  
if [ -f "/var/log/nginx/error.log" ]; then
    sudo tail -5 /var/log/nginx/error.log | sed 's/^/  /'
elif [ -f "/var/log/apache2/error.log" ]; then
    sudo tail -5 /var/log/apache2/error.log | sed 's/^/  /'
else
    echo "  Aucun log trouvé"
fi

# 8. Health check HTTP
echo ""  
echo -n "Health check HTTP: "  
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost/health 2>/dev/null)  
if [ "$HTTP_CODE" = "200" ]; then
    echo -e "${GREEN}✓ OK (200)${NC}"
elif [ -z "$HTTP_CODE" ]; then
    echo -e "${RED}✗ Pas de réponse${NC}"
else
    echo -e "${YELLOW}⚠ Code $HTTP_CODE${NC}"
fi

echo ""  
echo "=== Fin du rapport ==="

Rendre exécutable :

sudo chmod +x /usr/local/bin/monapp-monitor.sh

Utilisation :

sudo /usr/local/bin/monapp-monitor.sh

Automatiser avec cron (toutes les 5 minutes dans un log) :

sudo crontab -e

Ajouter :

*/5 * * * * /usr/local/bin/monapp-monitor.sh >> /var/log/monapp-monitoring.log 2>&1

Endpoint de santé dans l'application

Ajouter dans votre application FreePascal :

uses
  fphttpapp, httpdefs, httproute, fpjson, SysUtils, Unix;

var
  AppStartTime: TDateTime;
  TotalRequests: Int64 = 0;

procedure HandleHealth(ARequest: TRequest; AResponse: TResponse);  
var
  JSONObj: TJSONObject;
  UptimeSeconds: Int64;
  LoadAvg: array[0..2] of Double;
begin
  JSONObj := TJSONObject.Create;
  try
    // Statut général
    JSONObj.Add('status', 'ok');
    JSONObj.Add('timestamp', FormatDateTime('yyyy-mm-dd"T"hh:nn:ss', Now));

    // Uptime
    UptimeSeconds := Round((Now - AppStartTime) * 86400);
    JSONObj.Add('uptime_seconds', UptimeSeconds);
    JSONObj.Add('uptime_human', Format('%d jours %d heures',
                [UptimeSeconds div 86400, (UptimeSeconds mod 86400) div 3600]));

    // Statistiques requêtes
    JSONObj.Add('total_requests', TotalRequests);
    if UptimeSeconds > 0 then
      JSONObj.Add('requests_per_second',
                  FormatFloat('0.00', TotalRequests / UptimeSeconds));

    // Load average (Linux uniquement)
    {$IFDEF LINUX}
    if getloadavg(@LoadAvg[0], 3) = 3 then
    begin
      JSONObj.Add('load_average_1min', FormatFloat('0.00', LoadAvg[0]));
      JSONObj.Add('load_average_5min', FormatFloat('0.00', LoadAvg[1]));
      JSONObj.Add('load_average_15min', FormatFloat('0.00', LoadAvg[2]));
    end;
    {$ENDIF}

    // Mémoire
    JSONObj.Add('memory_allocated_mb',
                Round(GetHeapStatus.TotalAllocated / (1024 * 1024)));

    // Version
    JSONObj.Add('version', '1.0.0');

    AResponse.ContentType := 'application/json';
    AResponse.Content := JSONObj.AsJSON;
    AResponse.Code := 200;
  finally
    JSONObj.Free;
  end;
end;

procedure RequestMiddleware(ARequest: TRequest; AResponse: TResponse);  
begin
  Inc(TotalRequests);
end;

begin
  AppStartTime := Now;

  // Enregistrer le endpoint de santé
  HTTPRouter.RegisterRoute('/health', @HandleHealth);

  // Middleware pour compter les requêtes
  Application.OnRequest := @RequestMiddleware;

  Application.Initialize;
  Application.Run;
end.

Outils de monitoring avancés

1. GoAccess - Analyse de logs en temps réel

Installation :

sudo apt install -y goaccess

Utilisation :

# Analyse interactive des logs Nginx
sudo goaccess /var/log/nginx/access.log --log-format=COMBINED

# Générer un rapport HTML
sudo goaccess /var/log/nginx/access.log \
  --log-format=COMBINED \
  -o /var/www/apps/monapp/public/stats.html

# Temps réel
sudo goaccess /var/log/nginx/access.log \
  --log-format=COMBINED \
  --real-time-html \
  -o /var/www/apps/monapp/public/stats.html

Accéder aux statistiques : http://monapp.local/stats.html

2. Netdata - Monitoring système complet

Installation :

# Script d'installation automatique
bash <(curl -Ss https://my-netdata.io/kickstart.sh)

Accès : http://localhost:19999

Netdata fournit :

  • CPU, mémoire, disque en temps réel
  • Processus et applications
  • Nginx/Apache monitoring
  • Alertes configurables

3. Prometheus + Grafana (avancé)

Pour un monitoring professionnel avec métriques et dashboards.

Installation Prometheus :

sudo apt install -y prometheus

Exporter des métriques depuis FreePascal :

procedure HandleMetrics(ARequest: TRequest; AResponse: TResponse);  
var
  Metrics: TStringList;
begin
  Metrics := TStringList.Create;
  try
    // Format Prometheus
    Metrics.Add('# HELP monapp_requests_total Total requests');
    Metrics.Add('# TYPE monapp_requests_total counter');
    Metrics.Add(Format('monapp_requests_total %d', [TotalRequests]));

    Metrics.Add('# HELP monapp_uptime_seconds Uptime in seconds');
    Metrics.Add('# TYPE monapp_uptime_seconds gauge');
    Metrics.Add(Format('monapp_uptime_seconds %d',
                [Round((Now - AppStartTime) * 86400)]));

    Metrics.Add('# HELP monapp_memory_bytes Memory usage in bytes');
    Metrics.Add('# TYPE monapp_memory_bytes gauge');
    Metrics.Add(Format('monapp_memory_bytes %d',
                [GetHeapStatus.TotalAllocated]));

    AResponse.ContentType := 'text/plain; version=0.0.4';
    AResponse.Content := Metrics.Text;
  finally
    Metrics.Free;
  end;
end;

// Enregistrer
HTTPRouter.RegisterRoute('/metrics', @HandleMetrics);

Sécurité et hardening

Firewall UFW

Installation et configuration :

# Installation
sudo apt install -y ufw

# Règles de base
sudo ufw default deny incoming  
sudo ufw default allow outgoing

# Autoriser SSH (important !)
sudo ufw allow ssh  
sudo ufw allow 22/tcp

# Autoriser HTTP et HTTPS
sudo ufw allow 80/tcp  
sudo ufw allow 443/tcp

# Activer le firewall
sudo ufw enable

# Vérifier le statut
sudo ufw status verbose

Limiter les connexions SSH (protection brute-force) :

sudo ufw limit ssh

Fail2Ban - Protection contre les attaques

Installation :

sudo apt install -y fail2ban

Configuration : /etc/fail2ban/jail.local

sudo nano /etc/fail2ban/jail.local

Contenu :

[DEFAULT]
# Bannir pour 1 heure
bantime = 3600
# Fenêtre de 10 minutes
findtime = 600
# 5 tentatives max
maxretry = 5
# Email d'alerte (optionnel)
destemail = admin@example.com  
sendername = Fail2Ban

[sshd]
enabled = true  
port = ssh  
logpath = /var/log/auth.log

[nginx-http-auth]
enabled = true  
port = http,https  
logpath = /var/log/nginx/error.log

[nginx-limit-req]
enabled = true  
port = http,https  
logpath = /var/log/nginx/error.log

[apache-auth]
enabled = true  
port = http,https  
logpath = /var/log/apache*/*error.log

[apache-noscript]
enabled = true  
port = http,https  
logpath = /var/log/apache*/*error.log

Démarrer et activer :

sudo systemctl enable fail2ban  
sudo systemctl start fail2ban

# Vérifier le statut
sudo fail2ban-client status

# Statut d'une jail spécifique
sudo fail2ban-client status sshd

Permissions et utilisateurs

Créer un utilisateur dédié pour l'application :

# Créer l'utilisateur sans login shell
sudo useradd -r -s /bin/false monapp

# Changer le propriétaire
sudo chown -R monapp:www-data /var/www/apps/monapp

# Permissions
sudo chmod 750 /var/www/apps/monapp/bin  
sudo chmod 770 /var/www/apps/monapp/logs

Modifier le service systemd :

[Service]
User=monapp  
Group=www-data

Limiter les requêtes (Rate Limiting)

Nginx :

# Dans http {}
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;  
limit_req_zone $binary_remote_addr zone=general_limit:10m rate=50r/s;

server {
    # API limitée
    location /api/ {
        limit_req zone=api_limit burst=20 nodelay;
        # ... FastCGI config
    }

    # Limite générale
    location / {
        limit_req zone=general_limit burst=100 nodelay;
        # ... FastCGI config
    }
}

Apache (avec mod_evasive) :

sudo apt install -y libapache2-mod-evasive  
sudo a2enmod evasive

Configuration : /etc/apache2/mods-enabled/evasive.conf

<IfModule mod_evasive20.c>
    DOSHashTableSize 3097
    DOSPageCount 5
    DOSSiteCount 100
    DOSPageInterval 1
    DOSSiteInterval 1
    DOSBlockingPeriod 60
    DOSEmailNotify admin@example.com
</IfModule>

Headers de sécurité

Nginx :

# Headers de sécurité communs
add_header X-Frame-Options "SAMEORIGIN" always;  
add_header X-Content-Type-Options "nosniff" always;  
add_header X-XSS-Protection "1; mode=block" always;  
add_header Referrer-Policy "no-referrer-when-downgrade" always;  
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;  
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

# Masquer la version Nginx
server_tokens off;

Apache :

# Dans la configuration du site ou .htaccess
Header always set X-Frame-Options "SAMEORIGIN"  
Header always set X-Content-Type-Options "nosniff"  
Header always set X-XSS-Protection "1; mode=block"  
Header always set Referrer-Policy "no-referrer-when-downgrade"  
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"

# Masquer la version Apache
ServerTokens Prod  
ServerSignature Off

Déploiement et CI/CD

Script de déploiement automatisé

Créer : /usr/local/bin/deploy-monapp.sh

#!/bin/bash

set -e  # Arrêter en cas d'erreur

APP_NAME="monapp"  
APP_USER="monapp"  
APP_PATH="/var/www/apps/$APP_NAME"  
BINARY_NAME="webappfcgi"  
SERVICE_NAME="monapp-fcgi"  
BACKUP_PATH="/var/backups/monapp"

# Couleurs
GREEN='\033[0;32m'  
YELLOW='\033[1;33m'  
RED='\033[0;31m'  
NC='\033[0m'

echo -e "${GREEN}=== Déploiement de $APP_NAME ===${NC}"  
echo "Date: $(date '+%Y-%m-%d %H:%M:%S')"

# 1. Vérifications préalables
echo -e "\n${YELLOW}[1/8] Vérifications...${NC}"

if [ ! -f "$BINARY_NAME" ]; then
    echo -e "${RED}Erreur: Binaire $BINARY_NAME non trouvé${NC}"
    exit 1
fi

if ! systemctl is-active --quiet $SERVICE_NAME; then
    echo -e "${YELLOW}Avertissement: Service non actif${NC}"
fi

# 2. Backup
echo -e "\n${YELLOW}[2/8] Création du backup...${NC}"  
BACKUP_DATE=$(date '+%Y%m%d_%H%M%S')  
mkdir -p $BACKUP_PATH

if [ -f "$APP_PATH/bin/$BINARY_NAME" ]; then
    cp "$APP_PATH/bin/$BINARY_NAME" "$BACKUP_PATH/${BINARY_NAME}_$BACKUP_DATE"
    echo "Backup créé: ${BINARY_NAME}_$BACKUP_DATE"
fi

# 3. Arrêt du service
echo -e "\n${YELLOW}[3/8] Arrêt du service...${NC}"  
sudo systemctl stop $SERVICE_NAME  
sleep 2

# 4. Copie du nouveau binaire
echo -e "\n${YELLOW}[4/8] Copie du binaire...${NC}"  
sudo cp $BINARY_NAME $APP_PATH/bin/  
sudo chown $APP_USER:www-data $APP_PATH/bin/$BINARY_NAME  
sudo chmod 750 $APP_PATH/bin/$BINARY_NAME

# 5. Vérification des permissions
echo -e "\n${YELLOW}[5/8] Vérification des permissions...${NC}"  
sudo chown -R $APP_USER:www-data $APP_PATH  
sudo chmod 750 $APP_PATH/bin  
sudo chmod 770 $APP_PATH/logs

# 6. Nettoyage
echo -e "\n${YELLOW}[6/8] Nettoyage...${NC}"
# Supprimer l'ancien socket
sudo rm -f /var/run/monapp.sock
# Nettoyer les vieux logs (> 30 jours)
find $APP_PATH/logs -name "*.log" -mtime +30 -delete

# 7. Redémarrage du service
echo -e "\n${YELLOW}[7/8] Redémarrage du service...${NC}"  
sudo systemctl start $SERVICE_NAME  
sleep 3

# 8. Vérification
echo -e "\n${YELLOW}[8/8] Vérification...${NC}"

if systemctl is-active --quiet $SERVICE_NAME; then
    echo -e "${GREEN}✓ Service actif${NC}"
else
    echo -e "${RED}✗ Service inactif${NC}"
    echo "Logs récents:"
    sudo journalctl -u $SERVICE_NAME -n 20 --no-pager
    exit 1
fi

# Health check
sleep 2  
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost/health 2>/dev/null)  
if [ "$HTTP_CODE" = "200" ]; then
    echo -e "${GREEN}✓ Health check OK${NC}"
else
    echo -e "${RED}✗ Health check échoué (code: $HTTP_CODE)${NC}"
    exit 1
fi

# Nettoyer les anciens backups (garder 10 derniers)
ls -t $BACKUP_PATH/${BINARY_NAME}_* | tail -n +11 | xargs -r rm

echo -e "\n${GREEN}=== Déploiement réussi ===${NC}"  
echo "Version déployée: $(stat -c %y $APP_PATH/bin/$BINARY_NAME)"

Rendre exécutable :

sudo chmod +x /usr/local/bin/deploy-monapp.sh

Utilisation :

# Compiler votre application
fpc -O3 -MObjFPC -Scghi webappfcgi.lpr

# Déployer
sudo /usr/local/bin/deploy-monapp.sh

Intégration GitHub Actions

.github/workflows/deploy.yml :

name: Deploy to Ubuntu Server

on:
  push:
    branches: [ main ]

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout code
      uses: actions/checkout@v3

    - name: Install FreePascal
      run: |
        sudo apt update
        sudo apt install -y fpc

    - name: Compile application
      run: |
        fpc -O3 -MObjFPC -Scghi webappfcgi.lpr

    - name: Deploy to server
      env:
        SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
        SERVER_HOST: ${{ secrets.SERVER_HOST }}
        SERVER_USER: ${{ secrets.SERVER_USER }}
      run: |
        # Configuration SSH
        mkdir -p ~/.ssh
        echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
        chmod 600 ~/.ssh/id_rsa
        ssh-keyscan -H $SERVER_HOST >> ~/.ssh/known_hosts

        # Copie du binaire
        scp webappfcgi $SERVER_USER@$SERVER_HOST:/tmp/

        # Déploiement
        ssh $SERVER_USER@$SERVER_HOST 'sudo /usr/local/bin/deploy-monapp.sh'

Déploiement avec Ansible (avancé)

Playbook Ansible : deploy.yml

---
- name: Deploy FreePascal Application
  hosts: webservers
  become: yes

  vars:
    app_name: monapp
    app_path: /var/www/apps/monapp
    service_name: monapp-fcgi

  tasks:
    - name: Create backup
      copy:
        src: "{{ app_path }}/bin/webappfcgi"
        dest: "/var/backups/monapp/webappfcgi_{{ ansible_date_time.iso8601_basic_short }}"
        remote_src: yes
      ignore_errors: yes

    - name: Stop service
      systemd:
        name: "{{ service_name }}"
        state: stopped

    - name: Copy new binary
      copy:
        src: ./webappfcgi
        dest: "{{ app_path }}/bin/webappfcgi"
        owner: monapp
        group: www-data
        mode: '0750'

    - name: Start service
      systemd:
        name: "{{ service_name }}"
        state: started
        daemon_reload: yes

    - name: Wait for service
      wait_for:
        path: /var/run/monapp.sock
        timeout: 30

    - name: Health check
      uri:
        url: http://localhost/health
        status_code: 200
      register: health_check
      retries: 5
      delay: 2

Exécution :

ansible-playbook -i inventory deploy.yml

Maintenance et troubleshooting

Problèmes courants

1. "502 Bad Gateway" sur Nginx

Causes possibles :

  • Service FastCGI non démarré
  • Socket inexistant ou mauvaises permissions
  • Application plantée

Diagnostic :

# Vérifier le service
sudo systemctl status monapp-fcgi

# Vérifier le socket
ls -la /var/run/monapp.sock

# Logs
sudo journalctl -u monapp-fcgi -n 50  
sudo tail -50 /var/log/nginx/error.log

Solutions :

# Redémarrer le service
sudo systemctl restart monapp-fcgi

# Vérifier les permissions du socket
sudo chmod 666 /var/run/monapp.sock

# Test manuel de l'application
sudo -u monapp /var/www/apps/monapp/bin/webappfcgi

2. "Permission denied" sur socket

# Corriger les permissions
sudo chown www-data:www-data /var/run/monapp.sock  
sudo chmod 666 /var/run/monapp.sock

# Ou ajouter nginx/apache au groupe monapp
sudo usermod -a -G monapp www-data

3. Application qui se termine immédiatement

Vérifier les dépendances :

# Lister les bibliothèques requises
ldd /var/www/apps/monapp/bin/webappfcgi

# Installer les dépendances manquantes
sudo apt install -y libssl1.1 libmysqlclient21

4. Timeout sur requêtes longues

Nginx :

location / {
    fastcgi_read_timeout 300s;  # 5 minutes
    fastcgi_send_timeout 300s;
    # ...
}

Apache :

FcgidIOTimeout 300  
FcgidBusyTimeout 300

Rotation des logs

Configuration logrotate : /etc/logrotate.d/monapp

sudo nano /etc/logrotate.d/monapp

Contenu :

/var/www/apps/monapp/logs/*.log {
    daily
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    create 0640 monapp www-data
    sharedscripts
    postrotate
        systemctl reload monapp-fcgi > /dev/null 2>&1 || true
    endscript
}

Test :

sudo logrotate -f /etc/logrotate.d/monapp

Mise à jour du système

Script de mise à jour sûre :

#!/bin/bash

echo "=== Mise à jour du système ==="

# 1. Backup de la configuration
sudo cp -r /etc/nginx /etc/nginx.backup.$(date +%Y%m%d)  
sudo cp -r /etc/apache2 /etc/apache2.backup.$(date +%Y%m%d)

# 2. Mise à jour des paquets
sudo apt update  
sudo apt upgrade -y

# 3. Nettoyage
sudo apt autoremove -y  
sudo apt autoclean

# 4. Vérifier les services
sudo systemctl status nginx  
sudo systemctl status apache2  
sudo systemctl status monapp-fcgi

echo "Mise à jour terminée"

Conclusion

La configuration d'Apache ou Nginx sur Ubuntu pour des applications FreePascal nécessite :

Installation correcte du serveur web et modules FastCGI
Configuration optimisée pour la production
Service systemd pour gestion automatique
SSL/HTTPS avec Let's Encrypt
Monitoring actif et logs configurés
Sécurité renforcée (firewall, fail2ban, rate limiting)
Scripts de déploiement automatisés
Backup et plans de restauration

Avec cette configuration complète, vos applications FreePascal fonctionneront de manière stable, performante et sécurisée sur Ubuntu avec Apache ou Nginx.

Comparaison finale : Apache vs Nginx

Critère Apache Nginx Recommandation
Débutant ⭐⭐⭐⭐⭐ ⭐⭐⭐ Apache
Performance ⭐⭐⭐ ⭐⭐⭐⭐⭐ Nginx
Mémoire ⭐⭐⭐ ⭐⭐⭐⭐⭐ Nginx
Configuration ⭐⭐⭐⭐ ⭐⭐⭐ Apache
Modules ⭐⭐⭐⭐⭐ ⭐⭐⭐ Apache
FastCGI ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ Nginx
Reverse Proxy ⭐⭐⭐ ⭐⭐⭐⭐⭐ Nginx

Verdict :

  • Apprentissage et petits projets → Apache
  • Production haute performance → Nginx
  • Les deux sont excellents pour FreePascal !

Dans la section suivante, nous explorerons le Brook Framework pour développer des API REST modernes avec FreePascal.

⏭️ Brook Framework pour applications REST