web-dev-qa-db-fra.com

HAProxy comme serveur web

HAProxy peut-il fonctionner en tant que serveur Web sans autre serveur Web (Apache, NGINX, par exemple)? On m'a dit pour une telle configuration, mais je ne suis pas sûr de l'exactitude des informations.

5
i486

Non, HAProxy n'est pas un serveur Web et ne peut pas agir comme tel. À partir du Guide de démarrage HAProxy, Qu'est-ce qu'HAProxy est et n'est pas :

HAProxy n'est pas un serveur web:

Au démarrage, il s’isole dans une prison chroot et supprime ses privilèges, de sorte qu’il n’effectuera aucun accès au système de fichiers une fois démarré. En tant que tel, il ne peut pas être transformé en serveur Web. Il existe d'excellents logiciels open-source pour cela, tels qu'Apache ou Nginx, et HAProxy peut être installé devant eux pour fournir un équilibrage de charge et une haute disponibilité.

6

La réponse acceptée de "non, ce n'est pas fait pour cela" est correcte.

Mais le logiciel étant ce qu’il est, si vous voulez quand même le faire, il existe une solution de contournement.

Vous avez besoin d'une liste de contrôle d'accès pointant la demande vers un serveur personnalisé. Pour cet exemple, disons que vous vouliez servir un fichier robots.txt

frontend port80
    acl is_robotstxt path /robots.txt
    use_backend robots if is_robotstxt
backend robots
    mode http
    errorfile 503 /etc/haproxy/errors/robots.http

Notez qu'il n'y a pas de serveurs définis pour ce moteur, donc quand /robots.txt est demandé et qu'haproxy l'utilise, il génère une erreur 503. Nous spécifions que 503 erreurs doivent servir /etc/haproxy/errors/robots.http, qui, heureusement, spécifie les en-têtes de sortie HTTP complets et tous.

Donc, dans ce dossier, nous mettons

HTTP/1.0 200 Found
Cache-Control: no-cache
Connection: close
Content-Type: text/plain

Content here

alors maintenant, ce qui devrait être une erreur 503 est en fait une réponse 200 Found, contenu et tout.

Notez que cela n'est pas vraiment recommandé et vient avec de nombreuses limitations. Le plus évident est que vous ne pouvez servir qu'un seul fichier de cette manière par serveur. Ce qui est moins évident, c'est que ce fichier doit tenir dans BUFSIZE de haproxy, qui est généralement de 8 ou 16 ko. Haproxy ne fait pas non plus de désinfection sur le fichier servi de cette façon, il vous incombe donc de servir les bons en-têtes de la bonne façon. Si vos clients ont besoin de\r\n au lieu de\n, c’est à vous de les gérer.

Vous feriez bien mieux de mettre en place une copie de votre serveur Web de choix et de simplement avoir un "backend d'actifs statique" que haproxy peut acheminer.

6
semi

tout d’abord - et c’est important - HA-Proxy n’est pas un serveur Web. Cela devrait être très clair maintenant. Cependant, il existe des moyens de servir des fichiers via LUA. Je suis venu avec la solution suivante:

Configuration HA-Proxy:

lua-load /etc/haproxy/lua/load-file.lua

...

backend lua-load-file
  http-request set-header X-LUA-LOADFILE-DOCROOT /etc/haproxy/docroot
  http-request use-service lua.load-file

Comme vous pouvez le voir, je charge un fichier Lua appelé load-file.lua. Le contenu de ce fichier est le suivant:

core.register_service("load-file", "http", function(applet)
  local docroot
  local location
  local file
  local retval
  local response
  local extension

  if(applet.path == nil or applet.headers["x-lua-loadfile-docroot"] == nil or applet.headers["x-lua-loadfile-docroot"][0] == "") then
    retval = 500
    response = "Internal Server Error"
  else
    docroot = applet.headers["x-lua-loadfile-docroot"][0]
    location = applet.path
    if(location == "" or location == "/") then
      location = "/index.html"
    end
    file = io.open(docroot .. location, "r")
    if(file == nil) then
      retval = 404
      response = "File Not Found"
    else
      retval = 200
      response = file:read("*all")
      file:close()
    end
  end

  extension = string.match(location, ".(%w+)$")
  if       extension == "css"  then applet:add_header("content-type", "text/css")
    elseif extension == "gif"  then applet:add_header("content-type", "image/gif")
    elseif extension == "htm"  then applet:add_header("content-type", "text/html")
    elseif extension == "html" then applet:add_header("content-type", "text/html")
    elseif extension == "ico"  then applet:add_header("content-type", "image/x-icon")
    elseif extension == "jpg"  then applet:add_header("content-type", "image/jpeg")
    elseif extension == "jpeg" then applet:add_header("content-type", "image/jpeg")
    elseif extension == "js"   then applet:add_header("content-type", "application/javascript; charset=UTF-8")
    elseif extension == "json" then applet:add_header("content-type", "application/json")
    elseif extension == "mpeg" then applet:add_header("content-type", "video/mpeg")
    elseif extension == "png"  then applet:add_header("content-type", "image/png")
    elseif extension == "txt"  then applet:add_header("content-type", "text/plain")
    elseif extension == "xml"  then applet:add_header("content-type", "application/xml")
    elseif extension == "Zip"  then applet:add_header("content-type", "application/Zip")
  end

  applet:set_status(retval)
  if(response ~= nil and response ~= "") then
    applet:add_header("content-length", string.len(response))
  end
  applet:start_response()
  applet:send(response)
end)

Fondamentalement, ce code lit les fichiers depuis un emplacement de racine de document spécifié dans le système de fichiers en fonction de la chaîne de requête et génère les réponses HTTP appropriées, comme le ferait un serveur Web normal. C'est pourquoi le script a besoin d'une racine de document qui doit être configurée via l'en-tête HTTP X-LUA-LOADFILE-DOCROOT. Cet en-tête est défini via la configuration haproxy, comme indiqué dans les exemples. En outre, le code gère également des types de base de types MIME très élémentaires - étendez la liste selon vos besoins. J'espère que quelqu'un trouvera cela utile.

à votre santé!

3
Christian