1 <?php 
declare(strict_types
=1); 
   4  * This file is part of the Rapsys BlogBundle package. 
   6  * (c) Raphaël Gertz <symfony@rapsys.eu> 
   8  * For the full copyright and license information, please view the LICENSE 
   9  * file that was distributed with this source code. 
  12 namespace Rapsys\BlogBundle\Fixture
; 
  14 use Doctrine\Bundle\FixturesBundle\Fixture
; 
  15 use Doctrine\Persistence\ObjectManager
; 
  17 use Rapsys\PackBundle\Util\SluggerUtil
; 
  19 use Rapsys\BlogBundle\Entity\Civility
; 
  20 use Rapsys\BlogBundle\Entity\Group
; 
  21 use Rapsys\BlogBundle\Entity\User
; 
  22 use Rapsys\BlogBundle\Entity\UserTranslation
; 
  23 use Rapsys\BlogBundle\Entity\Keyword
; 
  24 use Rapsys\BlogBundle\Entity\KeywordTranslation
; 
  25 use Rapsys\BlogBundle\Entity\Article
; 
  26 use Rapsys\BlogBundle\Entity\ArticleTranslation
; 
  31 class BlogFixture 
extends Fixture 
{ 
  33          * @var Rapsys\PackBundle\Util\SluggerUtil 
  35         private SluggerUtil 
$slugger; 
  40         public function __construct(SluggerUtil 
$slugger) { 
  42                 $this->slugger 
= $slugger; 
  48         public function load(ObjectManager 
$manager) { 
  58                 foreach($civilityTree as $civilityData) { 
  59                         $civility = new Civility($civilityData); 
  60                         $manager->persist($civility); 
  61                         $civilitys[$civilityData] = $civility; 
  66                 //XXX: ROLE_XXX is required by 
  74                 foreach($groupTree as $groupData) { 
  75                         $group = new Group($groupData); 
  76                         $manager->persist($group); 
  77                         $groups[$groupData] = $group; 
  81                 //Flush to get the ids 
  87                                 'civility' => 'Mister', 
  89                                 'mail' => 'blog@rapsys.eu', 
  91                                 'forename' => 'Raphaël', 
  95                                 'pseudonym' => 'Rapsys', 
  96                                 'slug' => $this->slugger
->slug('Raphaël Gertz (rapsys)'), 
  98                                         'en_gb' => 'Raphaël Gertz, born in 1984, is a web developper since 2007. Interested in free software, since 2004, when he begin contributing to a linux distribution, known now as Mageia, some path has been traveled since then.', 
  99                                         'fr_fr' => 'Raphaël Gertz, né en 1984, est développeur web depuis 2007. Passionné par le monde du logiciel libre, depuis 2004, où il commence à contribuer à une distribution linux, connue maintenant sous le nom Mageia, un certain chemin a été parcouru dès lors.' 
 106                 foreach($userTree as $userData) { 
 107                         $user = new User($userData['mail'], $userData['password'], $civilitys[$userData['civility']], $userData['forename'], $userData['surname'], $userData['active'], $userData['enable'], $userData['pseudonym'], $userData['slug']); 
 108                         $user->addGroup($groups[$userData['group']]); 
 109                         $manager->persist($user); 
 110                         //Flush to get the id 
 112                         $users[$userData['mail']] = $user; 
 113                         foreach($userData['translations'] as $locale => $description) { 
 114                                 $userTranslation = new UserTranslation($users[$userData['mail']], $locale, $description); 
 115                                 $manager->persist($userTranslation); 
 116                                 unset($userTranslation); 
 121                 //Flush to get the ids 
 129                                         'description' => 'Portable Network Graphics (PNG) is an raster graphics file open format that supports lossless data compression' 
 133                                         'description' => 'Le Portable Network Graphics (PNG) est un format ouvert d’images numériques, qui a été créé pour remplacer le format GIF, à l’époque propriétaire et dont la compression était soumise à un brevet' 
 138                                         'title' => 'Imagick', 
 139                                         'description' => 'ImageMagick is a free and open-source software suite for displaying, converting, and editing raster image and vector image files' 
 142                                         'title' => 'Imagick', 
 143                                         'description' => 'Image Magick est une collection de logiciels libres pour afficher, convertir et modifier des images numériques matricielles ou vectorielles dans de nombreux formats' 
 149                                         'description' => 'An image is an artifact that depicts visual perception, for example, a photo or a two-dimensional picture, that has a similar appearance to some subject' 
 153                                         'description' => 'Une image est une représentation visuelle, voire mentale, de quelque chose' 
 158                                         'title' => 'Varnish', 
 159                                         'description' => 'Varnish is an HTTP cache server deployed as a reverse proxy between applications servers and clients' 
 162                                         'title' => 'Varnish', 
 163                                         'description' => 'Varnish est un serveur de cache HTTP déployé en tant que proxy inverse entre les serveurs d\'application et les clients' 
 168                                         'title' => 'Web service', 
 169                                         'description' => 'A web service is a service offered by an electronic device to another electronic device, communicating with each other via the World Wide Web' 
 172                                         'title' => 'Service web', 
 173                                         'description' => 'Un service web, ou service de la toile, est un protocole d\'interface informatique de la famille des technologies web permettant la communication et l\'échange de données entre applications et systèmes hétérogènes' 
 179                                         'description' => 'Representational state transfer (REST) or RESTful web services are a way of providing interoperability between computer systems on the Internet' 
 183                                         'description' => 'Representational state transfer (REST) ou services web RESTful est une manière de fournir de l\'intéropérabilité entre systèmes d\'information sur Internet' 
 188                                         'title' => 'HATEOAS', 
 189                                         'description' => 'HATEOAS, abbreviation of Hypermedia As The Engine Of Application State, is a constraint of the REST application architecture that distinguishes it from other network application architectures' 
 192                                         'title' => 'HATEOAS', 
 193                                         'description' => 'HATEOAS, abréviation de Hypermedia As Engine of Application State, Hypermédia en tant que moteur de l\'état d\'application, constitue une contrainte de l\'architecture d\'application REST qui la distingue de la plupart des autres architectures d\'applications réseau' 
 199                                         'description' => 'In information technology, a Uniform Resource Identifier (URI) is a string of characters used to identify a resource' 
 203                                         'description' => 'En technologie de l\'information, une URI, abréviation d\'Uniform Resource Identifier, Identifiant uniforme de ressource, est une chaine de caractères utilisée pour identifier une ressource' 
 209                                         'description' => 'Classless Inter-Domain Routing, CIDR, is a method for aggregating IP addresses and route them' 
 213                                         'description' => 'Routage inter-domaine sans classe, de l\'anglais Classless Inter-Domain Routing, CIDR, est une méthode pour agréger des adresses IP et les router' 
 219                                         'description' => 'Amazon Elastic Compute Cloud or EC2 is an Amazon server renting service allowing third party to run their own web application' 
 223                                         'description' => 'Amazon Elastic Compute Cloud ou EC2 est un service proposé par Amazon permettant à des tiers de louer des serveurs sur lesquels exécuter leurs propres applications web' 
 229                                         'description' => 'PHP: Hypertext Preprocessor, better known as PHP, is an open programming language, used mostly to produce dynamic web pages through an HTTP server' 
 233                                         'description' => 'PHP : Hypertext Preprocessor, plus connu sous son sigle PHP, est un langage de programmation libre, principalement utilisé pour produire des pages Web dynamiques via un serveur HTTP' 
 239                                         'description' => 'MySQL is a free and open-source relational database management system' 
 243                                         'description' => 'MySQL est un logiciel libre de gestion de bases de données relationnelles' 
 249                                         'description' => 'Microsoft Azure, formerly Windows Azure, is a cloud computing service created by Microsoft for building, testing, deploying, and managing applications and services through a global network of Microsoft-managed data centers' 
 253                                         'description' => 'Microsoft Azure, anciennement Windows Azure, est une plateforme applicative en nuage crée par Microsoft pour construire, tester, déployer et gérer des applications et services sur un réseau global de centres de données opéré par Microsoft' 
 258                                         'title' => 'Microsoft', 
 259                                         'description' => 'Microsoft Corporation is an american multinational technology company, founded in 1975 by Bill Gates and Paul Allen' 
 262                                         'title' => 'Microsoft', 
 263                                         'description' => 'Microsoft Corporation est une multinationale informatique et micro-informatique américaine, fondée en 1975 par Bill Gates et Paul Allen' 
 269                                         'description' => 'Apache is a free and open-source HTTP server for modern operating systems' 
 273                                         'description' => 'Apache est un logiciel libre serveur HTTP pour les systèmes d\'exploitation modernes' 
 278                                         'title' => 'HAProxy', 
 279                                         'description' => 'HAProxy is a reliable high performance TCP/HTTP free and open-source load balancer' 
 282                                         'title' => 'HAProxy', 
 283                                         'description' => 'HAProxy est un logiciel libre équilibreur de charge TCP/HTTP fiable et haute performance' 
 289                                         'description' => 'HTTP, abbreviation of HyperText Transfer Protocol, is a network client-server communications protocol developed for the World Wide Web' 
 293                                         'description' => 'HTTP, abréviation de HyperText Transfer Protocol, est un protocole de communication client-serveur réseau développé pour le World Wide Web' 
 299                                         'description' => 'Intermediate server application between two hosts to improve privacy, security and performance' 
 303                                         'description' => 'Application serveur intermédiaire entre deux hôtes pour améliorer la confidentialité, la sécurité et les performances' 
 309                                         'description' => 'QUIC, abbreviation of Quick UDP Internet Connections, is a fast network client-server communications protocol over UDP developed for Google' 
 313                                         'description' => 'QUIC, abréviation de Quick UDP Internet Connections, est un protocole de communication client-serveur réseau rapide sur UDP développé pour Google' 
 319                                         'description' => 'Mageia is a free operating system community project, based on GNU/Linux, supported by a French 1901 law association made up of elected contributors' 
 323                                         'description' => 'Mageia est un projet communautaire de système d\'exploitation libre, basé sur GNU/Linux, soutenu par une association loi 1901 française constituée de contributeurs élus' 
 329                                         'description' => 'Google organize the world\'s information and make it universally accessible and useful' 
 333                                         'description' => 'Google organise les informations à l\'échelle mondiale pour les rendre accessibles et utiles à tous' 
 340                 foreach($keywordTree as $name => $data) { 
 341                         $keyword = new Keyword(); 
 342                         $manager->persist($keyword); 
 343                         //Flush to get the id 
 345                         $keywords[$name] = $keyword; 
 346                         foreach($data as $locale => $translation) { 
 347                                 $keywordTranslation = new KeywordTranslation($keywords[$name], $locale, $translation['description'], $this->slugger
->slug($translation['title']), $translation['title']); 
 348                                 $manager->persist($keywordTranslation); 
 349                                 unset($keywordTranslation); 
 354                 //Flush to get the ids 
 360                                 'mail' => 'blog@rapsys.eu', 
 361                                 'keywords' => ['image', 'imagick', 'png'], 
 364                                                 'title' => 'How to reliably detect transparency in PNG image with PHP', 
 365                                                 'description' => 'Reliable PHP function to detect PNG images with transparency supporting all the variants to process.', 
 366                                                 'body' => 'The primary need is to find out if a PNG has transparency using PHP. 
 368 All the code I found didn\'t seemed to work correctly for the collection of PNG I had to convert. 
 370 I finished using the following function: 
 372 function png_has_transparency($im) { 
 373         //Retrieve content from imagick object 
 374         $content = $im->getImageBlob(); 
 376         //Detect 32-bit png (each pixel has tranparency level) 
 377         if (ord(substr($content, 25, 1)) & 4) { 
 379                 $p = $im->getPixelIterator(); 
 383                         //Loop on each row pixel 
 384                         foreach($r as $pix) { 
 385                                 //Check if pixel has partial transparency 
 386                                 if ($pix->getColorValue(Imagick::COLOR_ALPHA) != 1) { 
 391         //Check 8-bit png transparency 
 392         } elseif (stripos($content, \'PLTE\') !== false || stripos($content, \'tRNS\') !== false) { 
 396         //Didn\'t found clue of transparency 
 401 This function works with the only two transparency possibilities: 8 and 32-bit PNG. 
 403 The first case is a 32-bit PNG with transparency enabled, we have then to check every pixel to detect if it has transparent part or not. 
 405 The second case is a 8-bit PNG, then we only have to look the file content for transparency markers. 
 407 In this function configuration, we only read part of the file in 32-bit PNG until we detect one transparent pixel or parse content until transparency marker is detected in 8-bit PNG. 
 409 The worst case scenario will be 32-bit PNG with transparency flag without transparency or 8-bit PNG without transparency flag. 
 411 Depending on how likely you are to have transparency in each cases you might want to reverse the flow of this function. 
 413 Big thanks to these articles which expains how these parts work in a bit more detail: 
 414 - <https://www.jonefox.com/blog/2011/04/15/how-to-detect-transparency-in-png-images> 
 415 - <http://camendesign.com/code/uth1_is-png-32bit> 
 416 - <https://stackoverflow.com/questions/5495275/how-to-check-if-an-image-has-transparency-using-gd> 
 418 Hope this helps someone else out there.' 
 421                                                 'title' => 'Comment détecter la tranparence dans des images PNG en PHP de manière fiable', 
 422                                                 'description' => 'Fonction PHP fiable pour détecter les images PNG avec transparence prenant en charge toutes les variantes à traiter.', 
 423                                                 'body' => 'Le besoin principal est de savoir si un PNG a de la transparence en utilisant PHP. 
 425 Les codes trouvés ne semblaient pas fonctionner de manière satisfaisante pour les différents types de PNG à contrôler. 
 427 J\'ai fini par utiliser la fonction suivante: 
 429 function png_has_transparency($im) { 
 430         //Retrieve content from imagick object 
 431         $content = $im->getImageBlob(); 
 433         //Detect 32bit png (each pixel has tranparency level) 
 434         if (ord(substr($content, 25, 1)) & 4) { 
 436                 $p = $im->getPixelIterator(); 
 440                         //Loop on each row pixel 
 441                         foreach($r as $pix) { 
 442                                 //Check if pixel has partial transparency 
 443                                 if ($pix->getColorValue(Imagick::COLOR_ALPHA) != 1) { 
 448         //Check 8bit png transparency 
 449         } elseif (stripos($content, \'PLTE\') !== false || stripos($content, \'tRNS\') !== false) { 
 453         //Didn\'t found clue of transparency 
 458 Cette fonction fonctionne avec les deux seules possibilités : PNG 8 et 32 bits. 
 460 Le premier cas est un PNG 32 bits avec transparence activée, on doit alors vérifier l\'opacité de chaque pixel savoir si l\'image a de la transparence ou non. 
 462 Le second cas est un PNG 8 bits, on a simplement à détecter un marqueur de transparence dans le contenu du fichier. 
 464 Dans cette configuration de fonction, on lit seulement une partie du PNG 32 bits jusqu\'à détection d\'un pixel transparent où on analyse le contenu jusqu\'à trouver un marqueur de transparence dans un PNG 8 bits. 
 466 Les pires cas seront un PNG 32 bits avec marqueur de transparence sans pixel transparent ou PNG 8 bits sans marqueur de transparence. 
 468 Selon les probabilités de rencontrer les différents cas de transparence vous pouvez être intéressé pour renverser l\'ordre des tests de cette fonction. 
 470 Un grand merci à ces articles qui expliquent plus en détail comment fonctionnent les différentes parties de ce code: 
 471 - <https://www.jonefox.com/blog/2011/04/15/how-to-detect-transparency-in-png-images> 
 472 - <http://camendesign.com/code/uth1_is-png-32bit> 
 473 - <https://stackoverflow.com/questions/5495275/how-to-check-if-an-image-has-transparency-using-gd> 
 475 En espérant que cela puisse aider quelques personnes.' 
 480                                 'mail' => 'blog@rapsys.eu', 
 481                                 'keywords' => ['hateoas', 'http', 'rest', 'uri', 'varnish', 'webservice'], 
 484                                                 'title' => 'Caching webservice with Varnish', 
 485                                                 'description' => 'Cache a webservice responses by ignoring the Authorization header using Varnish.', 
 486                                                 'body' => 'The primary goal is to find a way to reduce the load of a webservice by caching its responses. 
 488 The webservice is a RESTfull API serving as a gateway between a private HATEOAS API and a client generating more than 500 000 requests a day. 
 490 The first surprise is that if your well educated client, sending you a header Authorization: Bearer, will not be cached by default by Varnish ! 
 492 Let\'s force back the standard behaviour with this header for our webservice uri prefix: 
 496         # Force cache response even with req.http.Authorization set 
 497         if (req.http.Authorization) { 
 498                 if (req.url ~ "^/webservice/uri/prefix/") { 
 505 This has security implication, because anyone allowed to request varnish will be able to retrieve a cached result without authentification. 
 507 It is important to validate the Authorization header value before serving the result from cache. 
 509 Now, our webservice has three possibles answers : 
 510 - 200: the data in JSON 
 511 - 404: data was not found 
 512 - 410: data is not available anymore 
 514 Let\'s cache our results depending on the reponse code: 
 518        if (req.url ~ "^/webservice/uri/prefix/") { 
 519                 if (beresp.status == 404) { 
 522                 if (beresp.status == 410) { 
 525                 if (beresp.status == 200) { 
 526                         set beresp.ttl = 24h; 
 532 With this configuration, we divided by 5 the quantity of request on our gateway from the client who was not able to cache our result himself.' 
 535                                                 'title' => 'Mise en cache de webservice avec Varnish', 
 536                                                 'description' => 'Mettre en cache les réponses d\'un service web en ignorant l’en-tête Authorization à l’aide de Varnish.', 
 537                                                 'body' => 'Le but premier est de trouver une solution pour réduire la charge d\'un service web en mettant en cache ses réponses. 
 539 L\'API RESTfull du webservice sert de passerelle entre un API privé HATEOAS et un client générant plus de 500 000 requêtes par jour. 
 541 La première surprise est qu\'un client bien élevé, envoyant un en-tête Authorization: Bearer, ne sera pas mis en cache par Varnish par défaut ! 
 543 Forçons le fonctionnement standard avec l\'en-tête pour le préfixe de l\'uri de notre webservice: 
 547         # Force la mise en cache de la réponse même avec req.http.Authorization présent 
 548         if (req.http.Authorization) { 
 549                 if (req.url ~ "^/webservice/uri/prefix/") { 
 556 Ce changement a des conséquences sur la sécurité, puisque n\'importe quelle personne autorisée à interroger Varnish sera en mesure de récupérer un résultat en cache sans s\'identifier. 
 558 Il est important de valider la valeur de l\'en-tête Authorization avant de fournir le résultat depuis le cache. 
 560 Notre webservice a trois réponses possibles : 
 561 - 200: les données en JSON 
 562 - 404: données non trouvées 
 563 - 410: données plus jamais disponibles 
 565 Mettons en cache les résultats selon le code de retour : 
 569        if (req.url ~ "^/webservice/uri/prefix/") { 
 570                 if (beresp.status == 404) { 
 573                 if (beresp.status == 410) { 
 576                 if (beresp.status == 200) { 
 577                         set beresp.ttl = 24h; 
 583 Avec cette configuration, on a divisé par 5 la quantité de demandes sur notre passerelle pour le client qui n\'était pas en mesure de mettre en cache lui-même nos résultats.' 
 588                                 'mail' => 'blog@rapsys.eu', 
 589                                 'keywords' => ['amazon', 'azure', 'cidr', 'http', 'microsoft', 'mysql', 'php', 'webservice', 'google'], 
 592                                                 'title' => 'Dealing with IP range in PHP/MySQL', 
 593                                                 'description' => 'Secure a webservice by granting access only to remote IP address included in a CIDR blocks set.', 
 594                                                 'body' => 'The goal is to process some CIDR blocks to tighten a webservice security. 
 596 First let\'s see how to compute the first and last address of an IP range with just the block base IP and mask: 
 599 $range = [\'127.0.0.1\', 8]; 
 600 function rangeBegin($range) { 
 603 function rangeEnd($range) { 
 604         return long2ip(ip2long($range[0]) | ((1 << (32 - $range[1])) - 1)); 
 608 How to detect if an IP is present in a CIDR block: 
 612 $range = [\'127.0.0.1\', 8]; 
 613 function ipInRange($ip, $range) { 
 614         if (ip2long($range[0]) <= ip2long($ip) && ip2long($ip) <= (ip2long($range[0]) | ((1 << (32 - $range[1])) - 1))) { 
 621 As a first bonus, how to retrieve amazon IP ranges: 
 624 function fetchAmazonRange() { 
 628         $ctx = stream_context_create( 
 631                                 \'method\' => \'GET\', 
 632                                 \'max_redirects\' => 0, 
 634                                 \'ignore_errors\' => false, 
 636                                         \'Connection: close\', 
 637                                         \'Accept: application/json\' 
 644         if (($json = file_get_contents(\'https://ip-ranges.amazonaws.com/ip-ranges.json\', false, $ctx)) === false) { 
 649         if (($json = json_decode($json)) === null || empty($json->prefixes)) { 
 654         foreach($json->prefixes as $range) { 
 655                 //Skip ipv6 and invalid ranges 
 656                 if (empty($range->ip_prefix)||!preg_match(\'/^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\/([0-9]+)$/\', $range->ip_prefix, $matche 
 661                 array_shift($matches); 
 663                 $amazonRanges[] = $matches; 
 667         return $amazonRanges; 
 671 Microsoft Azure IP ranges urls: 
 672 - <https://www.microsoft.com/en-us/download/details.aspx?id=41653> 
 673 - <https://msdn.microsoft.com/library/mt757330.aspx> 
 675 Google IP ranges urls: 
 676 - <https://support.google.com/a/answer/10026322?hl=en>' 
 679                                                 'title' => 'Gestion des plages d\'IP en PHP/MySQL', 
 680                                                 'description' => 'Sécuriser un service web en accordant l\'accès uniquement à l\'adresse IP distante incluse dans un jeu de blocs CIDR.', 
 681                                                 'body' => 'L\'objectif est de traiter des blocs CIDR pour renforcer la sécurité d’un service web. 
 683 Premièrement, voyons comment calculer la première et la dernière adresse IP d\'une plage (bloc CIDR) avec sa base et son masque : 
 686 $range = [\'127.0.0.1\', 8]; 
 687 function rangeBegin($range) { 
 690 function rangeEnd($range) { 
 691         return long2ip(ip2long($range[0]) | ((1 << (32 - $range[1])) - 1)); 
 695 Maintenant comment vérifier si une IP est présente dans une plage (bloc CIDR) : 
 699 $range = [\'127.0.0.1\', 8]; 
 700 function ipInRange($ip, $range) { 
 701         if (ip2long($range[0]) <= ip2long($ip) && ip2long($ip) <= (ip2long($range[0]) | ((1 << (32 - $range[1])) - 1))) { 
 708 En premier bonus, comment récupérer les plages d\'IP d\'amazon : 
 711 function fetchAmazonRange() { 
 715         $ctx = stream_context_create( 
 718                                 \'method\' => \'GET\', 
 719                                 \'max_redirects\' => 0, 
 721                                 \'ignore_errors\' => false, 
 723                                         \'Connection: close\', 
 724                                         \'Accept: application/json\' 
 731         if (($json = file_get_contents(\'https://ip-ranges.amazonaws.com/ip-ranges.json\', false, $ctx)) === false) { 
 736         if (($json = json_decode($json)) === null || empty($json->prefixes)) { 
 741         foreach($json->prefixes as $range) { 
 742                 //Skip ipv6 and invalid ranges 
 743                 if (empty($range->ip_prefix)||!preg_match(\'/^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\/([0-9]+)$/\', $range->ip_prefix, $matche 
 748                 array_shift($matches); 
 750                 $amazonRanges[] = $matches; 
 754         return $amazonRanges; 
 758 Urls pour les plages d\'IP de Microsoft Azure : 
 759 - <https://www.microsoft.com/en-us/download/details.aspx?id=41653> 
 760 - <https://msdn.microsoft.com/library/mt757330.aspx> 
 762 Urls pour les plages d\'IP de Google : 
 763 - <https://support.google.com/a/answer/10026322?hl=en>' 
 768                                 'mail' => 'blog@rapsys.eu', 
 769                                 'keywords' => ['apache', 'haproxy', 'http', 'mageia', 'proxy', 'quic'], 
 772                                                 'title' => 'A load balancer to standardize access to heterogeneous web services', 
 773                                                 'description' => 'Setup a single entry point for various web services including Apache and a few others available on exotic ports.', 
 774                                                 'body' => 'The primary need is to set up a single entry point for different web services including Apache and a few others on exotic ports. 
 776 Like any new project, implementation, as usual, took longer than initially expected. 
 778 To this end, I packaged the HAProxy service in the Mageia Linux distribution with a transparent proxy configuration by default. 
 780 HAProxy does not support the certificate path layout used on Red Hat-derived distributions, where public and private keys are separated into two separate files in two different directories. 
 782 HAProxy suffers from a critical bug when using standard output for logging which resumes at the beginning of the file after a restart. 
 784 HAProxy is penalized by disabling the buffer on its standard output when used for logging. 
 786 Three fixes were made by me for this purpose to resolve these problems: 
 787 - support for certificate path layout for Red Hat distribution 
 788 - no longer starts at the beginning of the log file after a restart 
 789 - no longer deactivate the standard output buffer 
 791 New features are being developed for the next version of HAProxy that could make my choices and developments on logging obsolete. 
 793 To make support of the HTTP/3 protocol possible by HAProxy, it was necessary to integrate the quictls library, a branch of OpenSSL with support for the QUIC protocol. 
 795 To install the server: 
 797 # urpmi haproxy haproxy-quic 
 800 Activate the service: 
 802 # systemctl enable haproxy.service 
 807 # systemctl start haproxy.service 
 810 In order to avoid a waltz of ports when integrating into an existing architecture, port indirection in Shorewall is proposed: 
 812 # Redirect tcp traffic from net on port 80 to 8000 
 813 REDIRECT net 8000 tcp 80 
 814 # Redirect tcp traffic from net on port 443 to 8000 
 815 REDIRECT net 8000 tcp 443 
 816 # Redirect udp traffic from net on port 443 to 8443 
 817 REDIRECT net 8443 udp 443 
 820 This allows HAProxy to capture HTTP and HTTPS traffic on port 8000/TCP and QUIC on port 8443/UDP. 
 822 The default configuration captures HTTP and HTTPS traffic on the tcp_default front end, then switches it to the tcp_http and tcp_https back ends, the latter will send the flows to the http_default and https_default front ends, taking care to add a proxy header to transmit the original IP address and port. This configuration allows other TCP services (SSH, VPN, etc.) to be captured and redistributed as needed. 
 824 The traffic is then received by the http_default and https_default front-ends respectively, the original IP address and port is preserved via the proxy header received from the TCP back-ends. 
 826 They can advertise HTTP/3 support, clean up some headers, deny access to bots, forward original IP addresses and ports via a Forwarded header, and distribute to different backends based on hosts and requested paths. 
 828 Configuring Apache to receive the proxy header is problematic, it\'s simpler to pass the Forwarded header than to configure the freshly released mod_remoteip. 
 830 Support for the HTTP/3 protocol is announced by sending an alt-svc: h3="<host>:<port>"; ma=<timeout> where host can be empty, port=443 and timeout=3600 for example. The certificate served must match the initial host name and not the offload server for security reasons. 
 832 Configuring the different http backends will come down to declaring the offload servers, the additional headers to add, the compression according to the content types and the method to test their health. 
 834 Without further ado, the configuration to adapt to your needs: 
 836 # HAProxy configuration file 
 841         log stdout format short daemon 
 845         pidfile /run/haproxy/haproxy.pid 
 848         stats socket /run/haproxy/haproxy.sock mode 0660 level admin 
 854         # Certificate base dir 
 855         crt-base /etc/pki/tls/certs 
 856         # Private key base dir 
 857         key-base /etc/pki/tls/private 
 858         # Don\'t load extra files 
 859         ssl-load-extra-files none 
 860         # Disable SSL-v3 TLSv1.0 TLSv1.1 and TLS tickets 
 861         ssl-default-server-options ssl-min-ver TLSv1.2 no-tls-tickets 
 862         # Do not verify certificate 
 863         ssl-server-verify none 
 864         # Supported bind ciphers 
 865         #XXX: https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended-configurations 
 866         ssl-default-bind-ciphers TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 
 868         # SSL/TLS session cache size 
 869         tune.ssl.cachesize 20000 
 870         # SSL/TLS session life time in cache 
 871         tune.ssl.lifetime 300 
 872         # SSL/TLS layer maximum passed bytes at a time 
 874         # Diffie-Hellman ephemeral keys max size 
 875         tune.ssl.default-dh-param 2048 
 878         # Reserved buffer size 
 880         # Max number of headers 
 893         # Set http keep alive mode 
 894         #XXX: https://cbonte.github.io/haproxy-dconv/2.3/configuration.html#4 
 895         option http-keep-alive 
 896         # Dont log empty line 
 898         # Dissociate client from dead server 
 901         # Number of retries on connection failure 
 903         # Max concurrent connections 
 905         # Max pending connections 
 908         # Max time for a connection attempt 
 910         # Max inactivitiy time on client side 
 912         # Max inactivitiy time on server side 
 914         # Max inactivitiy time on client and server for tunnels 
 916         # Max time for new request 
 917         timeout http-keep-alive 1s 
 918         # Max time for a complete http request 
 919         timeout http-request 15s 
 920         # Max time for a free slot 
 922         # Duration for tarpitted connections 
 926         errorfile 400 /usr/share/doc/haproxy/error/400.http 
 927         errorfile 403 /usr/share/doc/haproxy/error/403.http 
 928         errorfile 408 /usr/share/doc/haproxy/error/408.http 
 929         errorfile 500 /usr/share/doc/haproxy/error/500.http 
 930         errorfile 502 /usr/share/doc/haproxy/error/502.http 
 931         errorfile 503 /usr/share/doc/haproxy/error/503.http 
 932         errorfile 504 /usr/share/doc/haproxy/error/504.http 
 935 # Default tcp frontend 
 946         tcp-request inspect-delay 5s 
 947         # Wait for extension detection 
 948         #tcp-request content accept if { req.proto_http } or { req.ssl_hello_type 1 } or { req.ssl_ec_ext 1 } 
 949         tcp-request content accept if { req.proto_http } or { req.ssl_hello_type 1 } 
 951         # Send to https tcp backend 
 952         use_backend tcp_https if { req.ssl_hello_type 1 } 
 954         # Send to ec tcp backend 
 955         #use_backend tcp_ec if { req.ssl_ec_ext 1 } 
 957         # Send to OpenVPN backend 
 958         #acl openvpn payload(0,2) -m bin 003c 
 959         #tcp-request content accept if openvpn 
 960         #use_backend tcp_openvpn if openvpn 
 962         # Send to OpenSSH backend 
 963         #XXX: https://jonnyzzz.com/blog/2017/05/24/ssh-haproxy/ 
 964         #XXX: https://issues.apache.org/jira/browse/SSHD-656 
 965         #acl ssh payload(0,7) -m str SSH-2.0 
 966         #tcp-request content accept if ssh 
 967         #use_backend tcp_ssh if ssh 
 969         # Send to http tcp backend (if { req.proto_http }) 
 970         default_backend tcp_http 
 977         # Send to localhost without ssl with v2 proxy header 
 978         server haproxy 127.0.0.1:8080 no-ssl verify none send-proxy-v2 
 985         # Send to localhost without ssl with v2 proxy header 
 986         server haproxy 127.0.0.1:8443 no-ssl verify none send-proxy-v2-ssl 
 989 # Default http frontend 
 990 frontend http_default 
 992         bind :::8080 accept-proxy 
 993         # Insert X-Forwarded-For header 
 995         # Set http log format 
1000         # Check if acme challenge 
1001         acl acme_challenge path_beg /.well-known/acme-challenge/ 
1003         # Add X-Backend header 
1004         #http-response add-header X-Backend %[haproxy.backend_name] 
1007         #http-response add-header alt-svc \'h3=":443"; ma=3600\' 
1008         #http-after-response add-header alt-svc \'h3=":443"; ma=3600\' 
1010         # Remove server and x-powered-by headers 
1011         #http-after-response del-header server 
1012         #http-after-response del-header x-powered-by 
1014         # Redirect to https scheme when unsecure and not acme challenge 
1015         http-request redirect scheme https code 302 unless { ssl_fc } || acme_challenge 
1017         # Check if denied path 
1018         #XXX: use ,url_dec like in https://serverfault.com/questions/754752/block-specific-url-in-haproxy-url-encoding 
1019         #acl denied_path path_reg ^/(\.env|login|admin/|wp-login\.php|\.git/config)$ 
1020         # Deny access on denied path 
1021         #http-request deny if denied_path 
1023         # Check if protected path 
1024         #acl protected_path path_reg ^/(contact|register)$ 
1025         # Deny access on protected path 
1026         #http-request deny deny_status 503 if protected_path { method \'POST\' } { req.ver \'1.0\' } 
1028         # Store origin variable as txn 
1029         http-request set-var(txn.origin) req.hdr(Origin) 
1030         # Store host variable as txn 
1031         http-request set-var(txn.host) req.hdr(Host),field(1,:),lower 
1032         # Store proto variable as txn 
1033         http-request set-var(txn.proto) ssl_fc,iif(https,http) 
1035         # Set forwarded proto 
1036         http-request set-header X-Forwarded-Proto %[var(txn.proto)] 
1037         # Set forwarded port 
1038         http-request set-header X-Forwarded-Port %[dst_port] 
1040         #http-request set-header X-Forwarded-For %[src] 
1042         http-request set-header X-Forwarded-By %[dst] 
1045         #http-request set-header Forwarded by=%[dst]:%[dst_port];for=%[src]:%[src_port];host=%[var(txn.host)];proto=%[var(txn.proto)] 
1046         http-request set-header Forwarded by=%[dst]:%[dst_port];for=%[src]:%[src_port];proto=%[var(txn.proto)] 
1048         # Check if host is cdn.example.com 
1049         acl cdn var(txn.host) -m str cdn.example.com 
1050         # Check if cdn css path 
1051         acl cdn_css path_beg /css 
1052         # Check if cdn js path 
1053         acl cdn_js path_beg /js 
1054         # Check if haproxy status path 
1055         acl haproxy_status path_beg /haproxy-status 
1056         # Check if debug path 
1057         acl debug path_beg /debug 
1059         # Send to css backend if path start with /css 
1060         use_backend http_css if cdn cdn_css 
1061         # Send to js backend if path start with /js 
1062         use_backend http_js if cdn cdn_js 
1063         # Send to status backend if path start with /haproxy-status 
1064         use_backend http_status if haproxy_status 
1065         # Send to debug backend if path start with /debug 
1066         use_backend http_debug if debug 
1068         # Send to https backend 
1069         use_backend https_default if { ssl_fc } 
1071         # Send to default backend 
1072         default_backend http_default 
1074 # Default https frontend 
1075 #XXX: copy of upper one, just done to skip logs here 
1076 frontend https_default 
1077         # Bind to 8443 tcp port as ssl 
1078         bind :::8443 ssl crt haproxy.pem alpn h2,http/1.1,http/1.0 accept-proxy 
1079         # Bind to 8443 udp port as ssl 
1080         #bind quic6@:::8443 ssl crt haproxy.pem alpn h3 
1081         # Insert X-Forwarded-For header 
1083         # Set http log format 
1088         # Check if acme challenge 
1089         acl acme_challenge path_beg /.well-known/acme-challenge/ 
1091         # Add X-Backend header 
1092         #http-response add-header X-Backend %[haproxy.backend_name] 
1095         #http-response add-header alt-svc \'h3=":443"; ma=3600\' 
1096         #http-after-response add-header alt-svc \'h3=":443"; ma=3600\' 
1098         # Remove server and x-powered-by headers 
1099         #http-after-response del-header server 
1100         #http-after-response del-header x-powered-by 
1102         # Redirect to https scheme when unsecure and not acme challenge 
1103         http-request redirect scheme https code 302 unless { ssl_fc } || acme_challenge 
1105         # Check if denied path 
1106         #XXX: use ,url_dec like in https://serverfault.com/questions/754752/block-specific-url-in-haproxy-url-encoding 
1107         #acl denied_path path_reg ^/(\.env|login|admin/|wp-login\.php|\.git/config)$ 
1108         # Deny access on denied path 
1109         #http-request deny if denied_path 
1111         # Check if protected path 
1112         #acl protected_path path_reg ^/(contact|register)$ 
1113         # Deny access on protected path 
1114         #http-request deny deny_status 503 if protected_path { method \'POST\' } { req.ver \'1.0\' } 
1116         # Store origin variable as txn 
1117         http-request set-var(txn.origin) req.hdr(Origin) 
1118         # Store host variable as txn 
1119         http-request set-var(txn.host) req.hdr(Host),field(1,:),lower 
1120         # Store proto variable as txn 
1121         http-request set-var(txn.proto) ssl_fc,iif(https,http) 
1123         # Set forwarded proto 
1124         http-request set-header X-Forwarded-Proto %[var(txn.proto)] 
1125         # Set forwarded port 
1126         http-request set-header X-Forwarded-Port %[dst_port] 
1128         #http-request set-header X-Forwarded-For %[src] 
1130         http-request set-header X-Forwarded-By %[dst] 
1133         #http-request set-header Forwarded by=%[dst]:%[dst_port];for=%[src]:%[src_port];host=%[var(txn.host)];proto=%[var(txn.proto)] 
1134         http-request set-header Forwarded by=%[dst]:%[dst_port];for=%[src]:%[src_port];proto=%[var(txn.proto)] 
1136         # Check if host is cdn.example.com 
1137         acl cdn var(txn.host) -m str cdn.example.com 
1138         # Check if cdn css path 
1139         acl cdn_css path_beg /css 
1140         # Check if cdn js path 
1141         acl cdn_js path_beg /js 
1142         # Check if haproxy status path 
1143         acl haproxy_status path_beg /haproxy-status 
1144         # Check if debug path 
1145         acl debug path_beg /debug 
1147         # Send to css backend if path start with /css 
1148         use_backend http_css if cdn cdn_css 
1149         # Send to js backend if path start with /js 
1150         use_backend http_js if cdn cdn_js 
1151         # Send to status backend if path start with /haproxy-status 
1152         use_backend http_status if haproxy_status 
1153         # Send to debug backend if path start with /debug 
1154         use_backend http_debug if debug 
1156         # Send to https backend 
1157         use_backend https_default if { ssl_fc } 
1159         # Send to default backend 
1160         default_backend http_default 
1163 # Debug http backend 
1166         acl trusted src 127.0.0.0/8 ::1 
1167         # Allow access from trusted only 
1168         http-request deny unless trusted 
1169         # Server without ssl or check 
1170         server debug 127.0.0.1:8090 no-ssl verify none 
1173 # Default http backend 
1174 backend http_default 
1177         # User server default 
1178         http-check connect default 
1179         # Send HEAD on / with protocol HTTP/1.1 for host example.com 
1180         http-check send meth HEAD uri / ver HTTP/1.1 hdr Host example.com 
1181         # Expect return code between 200 and 399 
1182         http-check expect status 200-399 
1184         # Insert header X-Server: apache 
1185         #http-response add-header X-Server apache 
1187         # Set compression algorithm 
1188         #compression algo gzip 
1189         # Enable compression for html, plain and css text types 
1190         #compression type text/html text/plain text/css 
1192         # Server with ssl and check without certificate verification 
1193         server apache 127.0.0.1:80 no-ssl verify none check #cookie apache 
1196 # Default https backend 
1197 backend https_default 
1200         # User server default 
1201         http-check connect default 
1202         # Send HEAD on / with protocol HTTP/1.1 for host example.com 
1203         http-check send meth HEAD uri / ver HTTP/1.1 hdr Host example.com 
1204         # Expect return code between 200 and 399 
1205         http-check expect status 200-399 
1207         # Insert header X-Server: apache 
1208         #http-response add-header X-Server apache 
1210         # Force HSTS for 5 minutes on domain and all subdomains 
1211         #http-response set-header Strict-Transport-Security max-age=300#;\ includeSubDomains#;\ preload 
1213         # Set compression algorithm 
1214         #compression algo gzip 
1215         # Enable compression for html, plain and css text types 
1216         #compression type text/html text/plain text/css 
1218         # Server with ssl and check without certificate verification 
1219         server apache 127.0.0.1:443 ssl verify none check #cookie apache 
1226         # User server default 
1227         http-check connect default 
1228         # Send GET on /css/empty.css with protocol HTTP/1.1 for host cdn.example.com 
1229         http-check send meth GET uri /css/empty.css ver HTTP/1.1 hdr Host cdn.example.com 
1230         # Expect return code between 200 and 399 
1231         http-check expect status 200-399 
1233         # Server with check without ssl and certificate verification 
1234         server css 127.0.0.1:80 no-ssl verify none check 
1241         # User server default 
1242         http-check connect default 
1243         # Send HEAD on /js/missing.js with protocol HTTP/1.1 for host cdn.example.com 
1244         http-check send meth HEAD uri /js/missing.js ver HTTP/1.1 hdr Host cdn.example.com 
1245         # Expect return code 404 
1246         http-check expect status 404 
1248         # Check if txn.origin start with https://cdn.example.com 
1249         acl cdn_origin var(txn.origin) -m beg https://cdn.example.com 
1250         # Send origin as ACAO 
1251         http-response set-header Access-Control-Allow-Origin %[var(txn.origin)] if cdn_origin 
1252         # Set ACMA for one day 
1253         http-response set-header Access-Control-Max-Age 86400 if cdn_origin 
1255         # Server with check without ssl and certificate verification 
1256         server js 127.0.0.1:80 no-ssl verify none check 
1262         user admin insecure-password ADMINPASSWORD 
1264         user operator insecure-password OPERATORPASSWORD 
1265         # Assign admin in admin group 
1266         group admin users admin 
1267         # Assign operator and admin in operator group 
1268         group operator users operator,admin 
1271 # Status http backend 
1274         acl is_operator http_auth(status) 
1276         acl is_admin http_auth_group(status) admin 
1278         acl trusted src 127.0.0.0/8 ::1 
1281         # Set stats hook on /haproxy-status 
1282         stats uri /haproxy-status 
1289         # Allow access from trusted or authentified operator only 
1290         #stats http-request auth unless trusted or is_operator 
1291         stats http-request auth unless trusted 
1292         # Activate admin interface from trusted or authentified admin only 
1293         #stats admin if is_admin 
1296 Hope this article was helpful to you.' 
1299                                                 'title' => 'Un équilibreur de charge pour standardiser l\'accès aux services web hétérogènes', 
1300                                                 'description' => 'Configurer un point d\'entrée unique pour différents services web dont Apache et quelques autres disponibles sur des ports exotiques.', 
1301                                                 'body' => 'Le besoin principal est de mettre en place un point d\'entrée unique pour différents services web dont Apache et quelques autres sur des ports exotiques. 
1303 Comme tout nouveau projet, la mise en œuvre, comme d\'habitude, a nécessité plus de temps que prévu initialement. 
1305 À cet effet, j\'ai réalisé la mise en paquet du service HAProxy dans la distribution linux Mageia avec une configuration de proxy transparent par défaut. 
1307 HAProxy ne prend pas en charge la disposition de chemin des certificats utilisée sur les distributions dérivées de Red Hat, où clef publique et privée sont séparées en deux fichiers distincts dans deux répertoires différents. 
1309 HAProxy souffre d\'un bug critique lors de l\'usage de la sortie standard pour la journalisation qui reprend en début de fichier après un redémarage. 
1311 HAProxy est pénalisé par la désactivation du tampon sur sa sortie standard lorsqu\'elle est utilisée pour la journalisation. 
1313 Trois correctifs ont été réalisé par mes soins à cet effet pour résoudre ces problèmes sur le chemin de mes besoins : 
1314 - prise en charge de la disposition de chemin des certificats pour distribution Red Hat 
1315 - ne recommence plus au début du fichier journal après un redémarage 
1316 - ne plus désactiver le tampon de la sortie standard 
1318 De nouvelles fonctionnalités sont en cours de développement pour la prochaine version d\'HAProxy qui pourraient rendre obsolètes mes choix et développements sur la journalisation. 
1320 Pour rendre possible la prise en charge du protocole HTTP/3 par HAProxy, il a été nécessaire d\'intégrer la librairie quictls, une branche d\'OpenSSL avec support du protocole QUIC. 
1322 Pour installer le serveur : 
1324 # urpmi haproxy haproxy-quic 
1327 Activer le service : 
1329 # systemctl enable haproxy.service 
1332 Démarrer le service : 
1334 # systemctl start haproxy.service 
1337 Afin d\'éviter une valse de ports lors de l\'intégration dans une architecture existante, l\'indirection de ports dans Shorewall est proposée : 
1339 # Redirect tcp traffic from net on port 80 to 8000 
1340 REDIRECT        net     8000    tcp     80 
1341 # Redirect tcp traffic from net on port 443 to 8000 
1342 REDIRECT        net     8000    tcp     443 
1343 # Redirect udp traffic from net on port 443 to 8443 
1344 REDIRECT        net     8443    udp     443 
1347 Cela permet à HAProxy de capturer le trafic HTTP et HTTPS sur le port 8000/TCP et QUIC sur le port 8443/UDP. 
1349 La configuration par défaut capture le trafic HTTP et HTTPS sur le frontal tcp_default, puis le bascule sur les dorsaux tcp_http et tcp_https, ces derniers enverront les flux sur les frontaux http_default et https_default, en prenant soin d\'ajouter un en-tête proxy pour transmettre l\'adresse IP et le port d\'origine. Cette configuration permet à d\'autre services TCP (SSH, VPN, etc) d\'être capturés et redistribués au besoin. 
1351 Le trafic est ensuite reçu respectivement par les frontaux http_default et https_default, l\'adresse IP et le port d\'origine est conservée via l\'en-tête proxy reçu des dorsaux TCP. 
1353 Ils peuvent annoncer la prise en charge de HTTP/3, nettoyer certains en-têtes, refuser l\'accès aux robots, transférer les adresses IP et ports d\'origine via un en-tête Forwarded et distribuer à différents dorsaux en fonction des hôtes et chemins demandés. 
1355 Configurer Apache pour recevoir l\'en-tête proxy est problématique, il est plus simple de transmettre l\'en-tête Forwarded que de configurer le fraîchement publié mod_remoteip. 
1357 La prise en charge du protocole HTTP/3 est annoncée par l\'envoi d\'un en-tête alt-svc: h3="<host>:<port>"; ma=<timeout> où host peut être vide, port=443 et timeout=3600 par exemple. Le certificat servi doit correspondre au nom d\'hôte initial et non à celui du serveur de déchargement pour des raisons de sécurité. 
1359 Configurer les différents backends http se résumera à déclarer les serveurs de déchargement, les en-têtes supplémentaires à ajouter, la compression selon les types de contenus et la méthode pour tester leur santé. 
1361 Sans plus attendre la configuration à adapter à vos besoins : 
1363 # HAProxy configuration file 
1368         log stdout format short daemon 
1372         pidfile /run/haproxy/haproxy.pid 
1375         stats socket /run/haproxy/haproxy.sock mode 0660 level admin 
1381         # Certificate base dir 
1382         crt-base /etc/pki/tls/certs 
1383         # Private key base dir 
1384         key-base /etc/pki/tls/private 
1385         # Don\'t load extra files 
1386         ssl-load-extra-files none 
1387         # Disable SSL-v3 TLSv1.0 TLSv1.1 and TLS tickets 
1388         ssl-default-server-options ssl-min-ver TLSv1.2 no-tls-tickets 
1389         # Do not verify certificate 
1390         ssl-server-verify none 
1391         # Supported bind ciphers 
1392         #XXX: https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended-configurations 
1393         ssl-default-bind-ciphers TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 
1395         # SSL/TLS session cache size 
1396         tune.ssl.cachesize 20000 
1397         # SSL/TLS session life time in cache 
1398         tune.ssl.lifetime 300 
1399         # SSL/TLS layer maximum passed bytes at a time 
1400         tune.ssl.maxrecord 0 
1401         # Diffie-Hellman ephemeral keys max size 
1402         tune.ssl.default-dh-param 2048 
1405         # Reserved buffer size 
1406         tune.maxrewrite 1024 
1407         # Max number of headers 
1408         tune.http.maxhdr 101 
1420         # Set http keep alive mode 
1421         #XXX: https://cbonte.github.io/haproxy-dconv/2.3/configuration.html#4 
1422         option http-keep-alive 
1423         # Dont log empty line 
1425         # Dissociate client from dead server 
1428         # Number of retries on connection failure 
1430         # Max concurrent connections 
1432         # Max pending connections 
1435         # Max time for a connection attempt 
1437         # Max inactivitiy time on client side 
1439         # Max inactivitiy time on server side 
1441         # Max inactivitiy time on client and server for tunnels 
1442         timeout tunnel 3600s 
1443         # Max time for new request 
1444         timeout http-keep-alive 1s 
1445         # Max time for a complete http request 
1446         timeout http-request 15s 
1447         # Max time for a free slot 
1449         # Duration for tarpitted connections 
1453         errorfile 400 /usr/share/doc/haproxy/error/400.http 
1454         errorfile 403 /usr/share/doc/haproxy/error/403.http 
1455         errorfile 408 /usr/share/doc/haproxy/error/408.http 
1456         errorfile 500 /usr/share/doc/haproxy/error/500.http 
1457         errorfile 502 /usr/share/doc/haproxy/error/502.http 
1458         errorfile 503 /usr/share/doc/haproxy/error/503.http 
1459         errorfile 504 /usr/share/doc/haproxy/error/504.http 
1462 # Default tcp frontend 
1463 frontend tcp_default 
1473         tcp-request inspect-delay 5s 
1474         # Wait for extension detection 
1475         #tcp-request content accept if { req.proto_http } or { req.ssl_hello_type 1 } or { req.ssl_ec_ext 1 } 
1476         tcp-request content accept if { req.proto_http } or { req.ssl_hello_type 1 } 
1478         # Send to https tcp backend 
1479         use_backend tcp_https if { req.ssl_hello_type 1 } 
1481         # Send to ec tcp backend 
1482         #use_backend tcp_ec if { req.ssl_ec_ext 1 } 
1484         # Send to OpenVPN backend 
1485         #acl openvpn payload(0,2) -m bin 003c 
1486         #tcp-request content accept if openvpn 
1487         #use_backend tcp_openvpn if openvpn 
1489         # Send to OpenSSH backend 
1490         #XXX: https://jonnyzzz.com/blog/2017/05/24/ssh-haproxy/ 
1491         #XXX: https://issues.apache.org/jira/browse/SSHD-656 
1492         #acl ssh payload(0,7) -m str SSH-2.0 
1493         #tcp-request content accept if ssh 
1494         #use_backend tcp_ssh if ssh 
1496         # Send to http tcp backend (if { req.proto_http }) 
1497         default_backend tcp_http 
1504         # Send to localhost without ssl with v2 proxy header 
1505         server haproxy 127.0.0.1:8080 no-ssl verify none send-proxy-v2 
1512         # Send to localhost without ssl with v2 proxy header 
1513         server haproxy 127.0.0.1:8443 no-ssl verify none send-proxy-v2-ssl 
1516 # Default http frontend 
1517 frontend http_default 
1519         bind :::8080 accept-proxy 
1520         # Insert X-Forwarded-For header 
1522         # Set http log format 
1527         # Check if acme challenge 
1528         acl acme_challenge path_beg /.well-known/acme-challenge/ 
1530         # Add X-Backend header 
1531         #http-response add-header X-Backend %[haproxy.backend_name] 
1534         #http-response add-header alt-svc \'h3=":443"; ma=3600\' 
1535         #http-after-response add-header alt-svc \'h3=":443"; ma=3600\' 
1537         # Remove server and x-powered-by headers 
1538         #http-after-response del-header server 
1539         #http-after-response del-header x-powered-by 
1541         # Redirect to https scheme when unsecure and not acme challenge 
1542         http-request redirect scheme https code 302 unless { ssl_fc } || acme_challenge 
1544         # Check if denied path 
1545         #XXX: use ,url_dec like in https://serverfault.com/questions/754752/block-specific-url-in-haproxy-url-encoding 
1546         #acl denied_path path_reg ^/(\.env|login|admin/|wp-login\.php|\.git/config)$ 
1547         # Deny access on denied path 
1548         #http-request deny if denied_path 
1550         # Check if protected path 
1551         #acl protected_path path_reg ^/(contact|register)$ 
1552         # Deny access on protected path 
1553         #http-request deny deny_status 503 if protected_path { method \'POST\' } { req.ver \'1.0\' } 
1555         # Store origin variable as txn 
1556         http-request set-var(txn.origin) req.hdr(Origin) 
1557         # Store host variable as txn 
1558         http-request set-var(txn.host) req.hdr(Host),field(1,:),lower 
1559         # Store proto variable as txn 
1560         http-request set-var(txn.proto) ssl_fc,iif(https,http) 
1562         # Set forwarded proto 
1563         http-request set-header X-Forwarded-Proto %[var(txn.proto)] 
1564         # Set forwarded port 
1565         http-request set-header X-Forwarded-Port %[dst_port] 
1567         #http-request set-header X-Forwarded-For %[src] 
1569         http-request set-header X-Forwarded-By %[dst] 
1572         #http-request set-header Forwarded by=%[dst]:%[dst_port];for=%[src]:%[src_port];host=%[var(txn.host)];proto=%[var(txn.proto)] 
1573         http-request set-header Forwarded by=%[dst]:%[dst_port];for=%[src]:%[src_port];proto=%[var(txn.proto)] 
1575         # Check if host is cdn.example.com 
1576         acl cdn var(txn.host) -m str cdn.example.com 
1577         # Check if cdn css path 
1578         acl cdn_css path_beg /css 
1579         # Check if cdn js path 
1580         acl cdn_js path_beg /js 
1581         # Check if haproxy status path 
1582         acl haproxy_status path_beg /haproxy-status 
1583         # Check if debug path 
1584         acl debug path_beg /debug 
1586         # Send to css backend if path start with /css 
1587         use_backend http_css if cdn cdn_css 
1588         # Send to js backend if path start with /js 
1589         use_backend http_js if cdn cdn_js 
1590         # Send to status backend if path start with /haproxy-status 
1591         use_backend http_status if haproxy_status 
1592         # Send to debug backend if path start with /debug 
1593         use_backend http_debug if debug 
1595         # Send to https backend 
1596         use_backend https_default if { ssl_fc } 
1598         # Send to default backend 
1599         default_backend http_default 
1601 # Default https frontend 
1602 #XXX: copy of upper one, just done to skip logs here 
1603 frontend https_default 
1604         # Bind to 8443 tcp port as ssl 
1605         bind :::8443 ssl crt haproxy.pem alpn h2,http/1.1,http/1.0 accept-proxy 
1606         # Bind to 8443 udp port as ssl 
1607         #bind quic6@:::8443 ssl crt haproxy.pem alpn h3 
1608         # Insert X-Forwarded-For header 
1610         # Set http log format 
1615         # Check if acme challenge 
1616         acl acme_challenge path_beg /.well-known/acme-challenge/ 
1618         # Add X-Backend header 
1619         #http-response add-header X-Backend %[haproxy.backend_name] 
1622         #http-response add-header alt-svc \'h3=":443"; ma=3600\' 
1623         #http-after-response add-header alt-svc \'h3=":443"; ma=3600\' 
1625         # Remove server and x-powered-by headers 
1626         #http-after-response del-header server 
1627         #http-after-response del-header x-powered-by 
1629         # Redirect to https scheme when unsecure and not acme challenge 
1630         http-request redirect scheme https code 302 unless { ssl_fc } || acme_challenge 
1632         # Check if denied path 
1633         #XXX: use ,url_dec like in https://serverfault.com/questions/754752/block-specific-url-in-haproxy-url-encoding 
1634         #acl denied_path path_reg ^/(\.env|login|admin/|wp-login\.php|\.git/config)$ 
1635         # Deny access on denied path 
1636         #http-request deny if denied_path 
1638         # Check if protected path 
1639         #acl protected_path path_reg ^/(contact|register)$ 
1640         # Deny access on protected path 
1641         #http-request deny deny_status 503 if protected_path { method \'POST\' } { req.ver \'1.0\' } 
1643         # Store origin variable as txn 
1644         http-request set-var(txn.origin) req.hdr(Origin) 
1645         # Store host variable as txn 
1646         http-request set-var(txn.host) req.hdr(Host),field(1,:),lower 
1647         # Store proto variable as txn 
1648         http-request set-var(txn.proto) ssl_fc,iif(https,http) 
1650         # Set forwarded proto 
1651         http-request set-header X-Forwarded-Proto %[var(txn.proto)] 
1652         # Set forwarded port 
1653         http-request set-header X-Forwarded-Port %[dst_port] 
1655         #http-request set-header X-Forwarded-For %[src] 
1657         http-request set-header X-Forwarded-By %[dst] 
1660         #http-request set-header Forwarded by=%[dst]:%[dst_port];for=%[src]:%[src_port];host=%[var(txn.host)];proto=%[var(txn.proto)] 
1661         http-request set-header Forwarded by=%[dst]:%[dst_port];for=%[src]:%[src_port];proto=%[var(txn.proto)] 
1663         # Check if host is cdn.example.com 
1664         acl cdn var(txn.host) -m str cdn.example.com 
1665         # Check if cdn css path 
1666         acl cdn_css path_beg /css 
1667         # Check if cdn js path 
1668         acl cdn_js path_beg /js 
1669         # Check if haproxy status path 
1670         acl haproxy_status path_beg /haproxy-status 
1671         # Check if debug path 
1672         acl debug path_beg /debug 
1674         # Send to css backend if path start with /css 
1675         use_backend http_css if cdn cdn_css 
1676         # Send to js backend if path start with /js 
1677         use_backend http_js if cdn cdn_js 
1678         # Send to status backend if path start with /haproxy-status 
1679         use_backend http_status if haproxy_status 
1680         # Send to debug backend if path start with /debug 
1681         use_backend http_debug if debug 
1683         # Send to https backend 
1684         use_backend https_default if { ssl_fc } 
1686         # Send to default backend 
1687         default_backend http_default 
1690 # Debug http backend 
1693         acl trusted src 127.0.0.0/8 ::1 
1694         # Allow access from trusted only 
1695         http-request deny unless trusted 
1696         # Server without ssl or check 
1697         server debug 127.0.0.1:8090 no-ssl verify none 
1700 # Default http backend 
1701 backend http_default 
1704         # User server default 
1705         http-check connect default 
1706         # Send HEAD on / with protocol HTTP/1.1 for host example.com 
1707         http-check send meth HEAD uri / ver HTTP/1.1 hdr Host example.com 
1708         # Expect return code between 200 and 399 
1709         http-check expect status 200-399 
1711         # Insert header X-Server: apache 
1712         #http-response add-header X-Server apache 
1714         # Set compression algorithm 
1715         #compression algo gzip 
1716         # Enable compression for html, plain and css text types 
1717         #compression type text/html text/plain text/css 
1719         # Server with ssl and check without certificate verification 
1720         server apache 127.0.0.1:80 no-ssl verify none check #cookie apache 
1723 # Default https backend 
1724 backend https_default 
1727         # User server default 
1728         http-check connect default 
1729         # Send HEAD on / with protocol HTTP/1.1 for host example.com 
1730         http-check send meth HEAD uri / ver HTTP/1.1 hdr Host example.com 
1731         # Expect return code between 200 and 399 
1732         http-check expect status 200-399 
1734         # Insert header X-Server: apache 
1735         #http-response add-header X-Server apache 
1737         # Force HSTS for 5 minutes on domain and all subdomains 
1738         #http-response set-header Strict-Transport-Security max-age=300#;\ includeSubDomains#;\ preload 
1740         # Set compression algorithm 
1741         #compression algo gzip 
1742         # Enable compression for html, plain and css text types 
1743         #compression type text/html text/plain text/css 
1745         # Server with ssl and check without certificate verification 
1746         server apache 127.0.0.1:443 ssl verify none check #cookie apache 
1753         # User server default 
1754         http-check connect default 
1755         # Send GET on /css/empty.css with protocol HTTP/1.1 for host cdn.example.com 
1756         http-check send meth GET uri /css/empty.css ver HTTP/1.1 hdr Host cdn.example.com 
1757         # Expect return code between 200 and 399 
1758         http-check expect status 200-399 
1760         # Server with check without ssl and certificate verification 
1761         server css 127.0.0.1:80 no-ssl verify none check 
1768         # User server default 
1769         http-check connect default 
1770         # Send HEAD on /js/missing.js with protocol HTTP/1.1 for host cdn.example.com 
1771         http-check send meth HEAD uri /js/missing.js ver HTTP/1.1 hdr Host cdn.example.com 
1772         # Expect return code 404 
1773         http-check expect status 404 
1775         # Check if txn.origin start with https://cdn.example.com 
1776         acl cdn_origin var(txn.origin) -m beg https://cdn.example.com 
1777         # Send origin as ACAO 
1778         http-response set-header Access-Control-Allow-Origin %[var(txn.origin)] if cdn_origin 
1779         # Set ACMA for one day 
1780         http-response set-header Access-Control-Max-Age 86400 if cdn_origin 
1782         # Server with check without ssl and certificate verification 
1783         server js 127.0.0.1:80 no-ssl verify none check 
1789         user admin insecure-password ADMINPASSWORD 
1791         user operator insecure-password OPERATORPASSWORD 
1792         # Assign admin in admin group 
1793         group admin users admin 
1794         # Assign operator and admin in operator group 
1795         group operator users operator,admin 
1798 # Status http backend 
1801         acl is_operator http_auth(status) 
1803         acl is_admin http_auth_group(status) admin 
1805         acl trusted src 127.0.0.0/8 ::1 
1808         # Set stats hook on /haproxy-status 
1809         stats uri /haproxy-status 
1816         # Allow access from trusted or authentified operator only 
1817         #stats http-request auth unless trusted or is_operator 
1818         stats http-request auth unless trusted 
1819         # Activate admin interface from trusted or authentified admin only 
1820         #stats admin if is_admin 
1823 Espérons que cet article vous a été utile.' 
1830                 foreach($articleTree as $i => $data) { 
1831                         $article = new Article($users[$data['mail']]); 
1832                         foreach($data['keywords'] as $keyword) { 
1833                                 $article->addKeyword($keywords[$keyword]); 
1835                         $manager->persist($article); 
1836                         //Flush to get the id 
1838                         $articles[$i] = $article; 
1839                         foreach($data['translations'] as $locale => $translation) { 
1840                                 $articleTranslation = new ArticleTranslation($articles[$i], $locale, $translation['body'], $translation['description'], $this->slugger
->slug($translation['title']), $translation['title']); 
1841                                 $manager->persist($articleTranslation); 
1846                 //Flush to get the ids