Forum général.général "Reverse proxy" avec nginx

1
19
oct.
2016

Bonjour,
Je poursuis mes essais pour tenter d'auto-héberger des services libres sur mon nas synology, le tout derrière une Freebox. L'idée est que chaque service soit un conteneur Docker et que l'aiguillage se fasse avec un "reverse proxy". Adepte de la stratégie des petits pas, j'essaie dans un premier temps de faire fonctionner le tout en HTTP, le "S" viendra ensuite.

Il se trouve que les nas Synology exécute nginx, et qu'on a donc accès à la configuration "reverse" assez facilement. Cela dit, j'ai l'impression que les choses ne fonctionnent pas comme elles le devraient, d'où ma question ici.

Premier essai avec ce code :

    server {
        listen 80;
        listen [::]:80;
        server_name romu.fr;

        location / {
            proxy_set_header        Host                $host;
            proxy_set_header        X-Real-IP           $remote_addr;
            proxy_set_header        X-Forwarded-For     $proxy_add_x_forwarded_for;
            proxy_set_header        X-Forwarded-Proto   $scheme;
            proxy_intercept_errors  on;
            proxy_http_version      1.1;

            proxy_pass http://localhost:4000;

        }
    }

Sachant que j'ai redirigé le port 80 sur ma Freebox pour l'envoyer vers le nas, si je tape http://romu.fr, j'arrive à la page de login de Wallabag, mon premier conteneur, hébergé sur le port 4000.

Mais comme je n'ai pas un certficat "wildcard", je ne souhaite pas "piloter" mes services en faisant wallabag.romu.fr, mais plutôt romu.fr/wallabag. Donc je tente cette configuration :

    server {
        listen 80;
        listen [::]:80;
        server_name romu.fr;

        location /wallabag {
            proxy_set_header        Host                $host;
            proxy_set_header        X-Real-IP           $remote_addr;
            proxy_set_header        X-Forwarded-For     $proxy_add_x_forwarded_for;
            proxy_set_header        X-Forwarded-Proto   $scheme;
            proxy_intercept_errors  on;
            proxy_http_version      1.1;

            proxy_pass http://localhost:4000;

        }
    }

Et là, ça ne fonctionne pas, j'ai une erreur 404. Une idée ? Il y a un truc que je fais mal ?

Merci.

  • # Normal

    Posté par . Évalué à 4.

    http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass

    If the proxy_pass directive is specified with a URI, then when a request is passed to the server, the part of a normalized request URI matching the location is replaced by a URI specified in the directive:
    
        location /name/ {
            proxy_pass http://127.0.0.1/remote/;
        }
    
    If proxy_pass is specified without a URI, the request URI is passed to the server in the same form as sent by a client when the original request is processed, or the full normalized request URI is passed when processing the changed URI:
    
        location /some/path/ {
            proxy_pass http://127.0.0.1;
        }
    

    Dans le premier cas, romu.fr/toto est passé à ton wallabag: localhost:4000/toto, ce qui fonctionne (si /toto est reconnu par wallabag, évidemment)

    Dans le second cas, romu.fr/wallabag/toto est passé ainsi: localhost:4000/wallabag/toto.

    Deux solutions :

    • soit wallabag a une option pour reconnaître qu’il est à l’intérieur d’un namespace (/wallabag), et tu dois le configurer
    • soit tu dis à nginx de transformer romu.fr/wallabag/toto en localhost:4000/toto. Ajouter juste un / à la fin de l’adresse du reverse proxy dans proxy_pass devrait suffire. Problème : si wallabag utilise des URL absolues (type <a href="/tata">), alors tous les liens vont péter, puisqu’au premier lien tu seras redirigé vers romu.fr/tata, qui ne sera pas reconnu comme faisant partie du namespace wallabag. Pour cette raison, faire du reverse proxying dans un namespace est considéré comme une mauvaise idée.

    À ta place je m’emmerderai pas et je prendrai un certificat letsencrypt pour wallabag.romu.fr.

    • [^] # Re: Normal

      Posté par . Évalué à 2.

      Ok, merci beaucoup, c'est très clair. Effectivement si je rajoute un "/" à l'URI, ça fonctionne…pour la page d'accueil et tout pête après. Donc j'en prends note, et vais m'organiser pour faire des sous-domaines.

      Merci encore.

  • # Certificat Let's Encrypt

    Posté par . Évalué à 3. Dernière modification le 19/10/16 à 12:09.

    Comme dit au dessus, personnellement j'utilise un certificat Let's Encrypt et NGINX sous la forme truc.bidule.fr et je n'ai aucun soucis. En plus ça fait plus propre et plus classe, après c'est un avis perso :D

  • # Let's Encrypt

    Posté par . Évalué à 4. Dernière modification le 19/10/16 à 21:28.

    Concernant les certificats, tu pourras aussi essayer let's Encrypt.
    Tu verras que c'est bien plus simple que les autres formes de certificats.

    Concernant tes erreurs 404, il faut regarder les logs de Nginx, tu verras ce qu'il essaye de faire.

    La partie :

        proxy_set_header        Host                $host;
        proxy_set_header        X-Real-IP           $remote_addr;
        proxy_set_header        X-Forwarded-For     $proxy_add_x_forwarded_for;
        proxy_set_header        X-Forwarded-Proto   $scheme;
        proxy_intercept_errors  on;
        proxy_http_version      1.1;

    peut être placée plus haut dans la config, parce qu'il est inutile de la répéter à chaque fois.
    Regarde la doc de nginx, il y a plein d'exemple.

    Bon courage

  • # Si j'ai bien compris toutes vos interventions...

    Posté par . Évalué à 2.

    …alors la bonne façon de faire est d'utiliser des sous domaines (wallabag.romu.fr pour wallabgag, wekan.romu.fr pour WeKan, etc), et des certificats Let's Encrypt. Le problème que je vois à cette solution (arrêtez moi si je me trompe), c'est sa relative complexité.

    Mon idée première était d'avoir le reverse proxy qui écouterait en HTTPS avec le certificat qui va bien, pour distribuer les échanges vers les bons conteneurs (wallabag, mais aussi les autres) directement en HTTP (ce serait local au nas, pas de pb de sécurité).

    Or, à ma connaissance, Let's Encrypt ne founit pas de certificat "wildcard". Chaque conteneur (=service) doit donc avoir son propre certificat. Dans un tel cas, comment doit être configurée la sécurité du "reverse proxy" ?

    merci.

    • [^] # Re: Si j'ai bien compris toutes vos interventions...

      Posté par . Évalué à 3.

      Mon idée première était d'avoir le reverse proxy qui écouterait en HTTPS avec le certificat qui va bien, pour distribuer les échanges vers les bons conteneurs (wallabag, mais aussi les autres) directement en HTTP (ce serait local au nas, pas de pb de sécurité).

      Oui

      Chaque conteneur (=service) doit donc avoir son propre certificat

      Ben non, puisque le conteneur n’a aucune idée qu’il est en HTTPS. C’est le frontal nginx qui aura un certificat différent pour chaque conteneur, mais en pratique ça veut dire deux lignes (ssl_certificate/ssl_certificate_key) différentes par vhost.

      Tu mets la config globale (ssl_protocols/ssl_ciphers/... [1], proxy_set_header/proxy_http_version) dans la section http (donc commune à tous les vhosts). Ensuite dans chaque vhost tu auras (par exemple) :

      server {
              server_name wallabag.romu.fr;
      
              listen 443 ssl;
              ssl_certificate /var/lib/acme/live/wallabag.romu.fr/fullchain;
              ssl_certificate_key /var/lib/acme/live/wallabag.romu.fr/privkey;
              ssl_trusted_certificate /var/lib/acme/live/wallabag.romu.fr/chain;
      
              location / {
                      proxy_pass http://localhost:4000;
              }
      }
      

      (ces chemins pour le certificat/clé sont ceux de l’outil acmetool. Un autre outil pourrait en avoir d’autres)

      Pour l’obtention des certificats, ça dépend de l’outil. Avec acmetool, il suffit d’ajouter à tous tes vhosts :

              location /.well-known/acme-challenge {
                      allow all;
                      default_type text/plain;
                      root /var/www;
              }
      

      (/var/www dépend de la configuration d’acmetool)

      puis de faire un acmetool want wallabag.romu.fr.

      [1] Aide toi de ça pour configurer correctement SSL.

      • [^] # Re: Si j'ai bien compris toutes vos interventions...

        Posté par . Évalué à 2.

        Ok merci. Donc je garde mon principe : nginx pour aiguiller et chiffrer le trafic et un conteneur en http simple pour chaque service. Et tous les certificats et la config de sécurité sont spécifiées dans la config de nginx. Ca me semble plutôt pas mal.

        Merci beaucoup…je ne suis pas sur de ne pas revenir avec d'autres questions.

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.