VirtualHost : proxy

Eléphant du PHP | 386 Messages

11 Jan 2017, 23:03

Bonjour,

j'aimerai savoir si le code ci-dessous est bien codé ?
Il fonctionne, et redirige mon serveur nodejs https://io.monsite.fr:3016 vers le fichier js de socket.io ;)
(C'est juste pour éviter de montrer le port de mon serveur au visiteur, et plus facile dans le code)

Code : Tout sélectionner

<VirtualHost *:80 *:443>
    ServerAdmin admin@monsite.fr
    ServerName  io.monsite.fr
    # io.monsite.fr est redirigé vers io.monsite.fr:3016 (le serveur nodejs en question)

    SSLEngine on
        SSLProxyEngine on
        SSLProxyVerify none
        SSLProxyCheckPeerCN off
        SSLProxyCheckPeerName off
        SSLProxyCheckPeerExpire off
        SSLCertificateFile      /etc/ssl/certs/cert.crt
        SSLCertificateKeyFile   /etc/ssl/private/key.key
        SSLCertificateChainFile /etc/ssl/certs/cert_int.crt

    RewriteEngine On
    RewriteCond %{REQUEST_URI} ^/socket.io [NC]
    RewriteCond %{QUERY_STRING} transport=websocket [NC]
    RewriteRule /(.*) wss://io.monsite.fr:3016/$1 [P,L]

        ProxyRequests off

        <Proxy *>
            Order deny,allow
            Allow from all
        </Proxy>
        ProxyPass /socket.io/1/websocket wss://io.monsite.fr:3016/socket.io/1/websocket
        ProxyPassReverse /socket.io/1/websocket wss://io.monsite.fr:3016/socket.io/1/websocket

        ProxyPass /socket.io/ https://io.monsite.fr:3016/socket.io/
        ProxyPassReverse /socket.io/ https://io.monsite.fr:3016/socket.io/

        ProxyPass / https://io.monsite.fr:3016/
        ProxyPassReverse / https://io.monsite.fr:3016/

</VirtualHost>

ViPHP
ViPHP | 5872 Messages

12 Jan 2017, 00:00

Bonjour,

L'idée est bonne mais souffre de quelques petits problèmes de mise en oeuvre.

C'est effectivement une bonne pratique de placer un serveur HTTP (apache, nginx, etc) devant un serveur applicatif. Le serveur HTTP est théoriquement mieux protégé, et tu peux lui faire faire pas mal d'opérations de traitement de la requête (gestion de la connexion TLS, mise en cache, etc).

Par contre, ton VirtualHost reçoit les connexions http (port 80) et https (port 443) mais, si je ne me trompe, va essayer de traiter la connexion comme https dans les deux cas étant donné que tu actives le SSLEngine. Ce n'est donc pas correct.
D'autre part, cela veut dire que tu souhaites proxyfier tout le trafic vers le serveur applicatif, ce qui n'est pas une bonne pratique. En général, on propose la connexion https, et on redirige toutes les requêtes http vers l'url https correspondante, cette pratique permet d'assurer que toutes les requêtes et réponses seront sécurisées (on force l'utilisateur à utiliser https).

Il est donc préférable d'utiliser une configuration telle que celle ci :

Code : Tout sélectionner

<VirtualHost *:80>
    ServerName www.example.net
    RedirectMatch "^/(.*)" "https://www.example.com/$1"
</VirtualHost>

<VirtualHost *:443>
    ServerName www.example.net

    (... - le reste de la configuration - ...)
</VirtualHost>


Un autre soucis est que tu places Apache en frontal, qui va assurer la connexion https, et donc en principe soulager le serveur NodeJS, mais tu utilises ensuite des connexions wss et https (donc sécurisées) de Apache vers le serveur NodeJS. Ce que cela veut dire, c'est que après avoir traité la requête sécurisée provenant du client, Apache devra ré-établir une nouvelle requête sécurisée vers le serveur NodeJS, impliquant le double de travail.

La bonne pratique est, lorsqu'on place un serveur en frontal, de réaliser la communication entre le frontal et le serveur applicatif en non sécurisé, afin de ne pas consommer des ressources et engendrer un délai inutilement.

Il est donc préférable de supprimer les lignes suivantes :

Code : Tout sélectionner

        SSLProxyEngine on
        SSLProxyVerify none
        SSLProxyCheckPeerCN off
        SSLProxyCheckPeerName off
        SSLProxyCheckPeerExpire off


Et remplacer les adresses wss:// et https:// dans les directives ProxyPass et ProxyPassReverse par leurs équivalents ws:// et http://.

Dernier point, si tu utilises un serveur pour proxyfier tes requêtes, alors il n'est plus utile de laisser le port 3016 du serveur NodeJS accessible. Je te suggère donc de t'assurer que ton parefeu est configuré en conséquence. Plus généralement, c'est une bonne idée de vérifier que ton parefeu est actif et d'interdire tout port qui ne correspond pas à un service utile.

Cordialement

Eléphant du PHP | 386 Messages

12 Jan 2017, 01:52

Merci beaucoup de votre réponse
J'ai un message d'erreur si j'enlève ce que vous m'avez dit :


Proxy Error

The proxy server received an invalid response from an upstream server.
The proxy server could not handle the request GET /socket.io/socket.io.js.

Reason: Error reading from remote server


Quand il fonctionne, dès qu'on va sur io.monsite.fr, le serveur tourne en boucle, il y a le message en bas : En attente de io.monsite.fr qui tourne sans cesse.
Pouvez-vous me dire comment faire pour que dès qu'un visiteur va sur io.monsite.fr, le serveur affiche une erreur 403 ?

Merci

ViPHP
ViPHP | 5872 Messages

12 Jan 2017, 11:19

Bonjour,
As tu bien désactivé le support TLS sur le serveur NodeJS ?
Plus généralement, pour savoir ce qu'il se passe, il faut aller lire les logs (aussi bien du serveur Apache que du serveur NodeJS), en augmentant le niveau de debug si besoin.
Cordialement

Eléphant du PHP | 386 Messages

12 Jan 2017, 15:13

Voici mon serveur node :

Si j'enlève la partie sécurisé, je met http au lieu d'https et j'enlève les options, j'ai toujours l'erreur 502 Proxy Error

Code : Tout sélectionner

var fs             = require('fs');
var path          = require('path');
var options    = {
   key: fs.readFileSync(path.join(__dirname,'/../../var/ssl/webastro.key')),
   cert: fs.readFileSync(path.join(__dirname,'/../../var/ssl/webastro.crt')),
   ca: fs.readFileSync(path.join(__dirname,'/../../var/ssl/webastro_int.crt'))
};
var https       = require('https');

var server      = https.createServer(options,function(req,res){
   res.writeHead(200,{"Content-Type":"text/plain"});
   console.log("one client connect");
   res.write("Hello World from node");
   res.end();
});

server.listen(1812);

var io = require('socket.io').listen(server);

io.sockets.on('connection', function(socket){

   socket.on('disconnect', function(){

   });

});


Et voici mon virtualHost actuel :

Code : Tout sélectionner

<VirtualHost *:80>
   ServerAdmin   admin@monsite.fr
   ServerName   io.monsite.fr

   RewriteEngine On
   RewriteCond %{REQUEST_URI} ^/socket.io [NC]
   RewriteCond %{QUERY_STRING} transport=websocket [NC]
   RewriteRule /(.*) ws://io.monsite.fr:1812/$1 [P,L]

   ProxyPass / http://io.monsite.fr:1812/
   ProxyPassReverse / http://io.monsite.fr:1812/
</VirtualHost>


Voila ce que j'ai dans mon log :

[Thu Jan 12 14:18:13.252052 2017] [proxy_http:error] [pid 6545] (20014)Internal error: [client 2.8.192.65:49811] AH01102: error reading status line from remote server io.monsite.fr:1812, referer: http://io.monsite.fr/

Je vais repartir à zéro sur ce code et ce virtualhost
Je t'explique ce que je veux :

J'aimerai que mon serveur nodejs avec lequel je travaillerai avec socket.io pointe sur io.monsite.fr
Et que io.monsite.fr soit redirigé en proxy sur le port 1812
Mais vu que mon site est en https, comment trouver le fichier socket.io.js en http sur mon site il va trouver l'erreur :

The page at 'https://www.monsite.fr/login' was loaded over HTTPS, but requested an insecure script 'http://io.monsite.fr/socket.io/socket.io.js'. This request has been blocked; the content must be served over HTTPS.

ViPHP
ViPHP | 5872 Messages

12 Jan 2017, 16:04

nico44530 a écrit :Voici mon serveur node :

Si j'enlève la partie sécurisé, je met http au lieu d'https et j'enlève les options, j'ai toujours l'erreur 502 Proxy Error
(...)


Si c'est un problème de NodeJS, on ne pourra probablement pas t'aider.

Le mieux est de réaliser tes tests de manière unitaire. Avant d'essayer de voir si tu peux proxyfier, tu dois valider le fait que ton application NodeJS se comporte il faut. C'est à dire, si on veut que le serveur NodeJS serve ses pages en http ou ws, alors tu dois vérifier qu'il sert bien ses pages en http ou ws directement sur le port 1812. Une fois que tu es sûr de ça, tu as éliminé une source d'erreur et tu peux passer à la suite (Apache).

nico44530 a écrit :Et voici mon virtualHost actuel :

Code : Tout sélectionner

<VirtualHost *:80>
   ServerAdmin   admin@monsite.fr
   ServerName   io.monsite.fr

   RewriteEngine On
   RewriteCond %{REQUEST_URI} ^/socket.io [NC]
   RewriteCond %{QUERY_STRING} transport=websocket [NC]
   RewriteRule /(.*) ws://io.monsite.fr:1812/$1 [P,L]

   ProxyPass / http://io.monsite.fr:1812/
   ProxyPassReverse / http://io.monsite.fr:1812/
</VirtualHost>


Sur le principe, c'est une bonne chose dans le cadre d'un test. C'est à dire que ça te permet de vérifier que Apache peut proxyfier en http des requêtes qui lui viennent en http. Donc un cas assez simple.
Ensuite, une fois validé, tu peux passer à proxyfier HTTPS vers HTTP.

nico44530 a écrit :Voila ce que j'ai dans mon log :

[Thu Jan 12 14:18:13.252052 2017] [proxy_http:error] [pid 6545] (20014)Internal error: [client 2.8.192.65:49811] AH01102: error reading status line from remote server io.monsite.fr:1812, referer: http://io.monsite.fr/

Je vais repartir à zéro sur ce code et ce virtualhost


Pas forcément besoin de repartir à zéro, il faut surtout que tu investigues pourquoi est-ce que Apache reçoit une information qui n'est pas formattée comme il s'y attend. Un bonne outil peut-être wireshark (ou tshark en ligne de commande). Cela peut te mettre de voir le contenu des paquets échangés entre les deux serveurs et d'identifier une anomalie.

nico44530 a écrit :Je t'explique ce que je veux :

J'aimerai que mon serveur nodejs avec lequel je travaillerai avec socket.io pointe sur io.monsite.fr
Et que io.monsite.fr soit redirigé en proxy sur le port 1812
Mais vu que mon site est en https, comment trouver le fichier socket.io.js en http sur mon site il va trouver l'erreur :

The page at 'https://www.monsite.fr/login' was loaded over HTTPS, but requested an insecure script 'http://io.monsite.fr/socket.io/socket.io.js'. This request has been blocked; the content must be served over HTTPS.

Oui, c'est en réalité assez logique. Effectivement les contenus d'une page HTTPS doivent être HTTPS également. Mais ça me parait être un problème mineur, que tu dois pouvoir régler assez facilement dans le code qui génère tes pages web. Je te suggère de regarder le code html et js de tes pages générées pour trouver l'origine de cette erreur.
Tu as peut-être des options dans tes modules NodeJS pour définir le format des urls générées.

Cordialement

Eléphant du PHP | 386 Messages

12 Jan 2017, 21:55

Je me suis penché vers node-http-proxy, je vais essayer de voir ça au lieu de passer par apache pour faire les proxy.
J'ai vu sur internet qu'on peut faire ça avec node ;)
Ça éviterai à apache de faire le travail.

Tu en pense quoi de ce module ?
Merci ;)

ViPHP
ViPHP | 5872 Messages

13 Jan 2017, 01:23

nico44530 a écrit :Je me suis penché vers node-http-proxy, je vais essayer de voir ça au lieu de passer par apache pour faire les proxy.
J'ai vu sur internet qu'on peut faire ça avec node ;)
Ça éviterai à apache de faire le travail.

Tu en pense quoi de ce module ?
Merci ;)


Je ne sais pas, je n'ai jamais touché à NodeJS.
Par contre si c'est pour proxyfier vers ton site (donc vers un serveur NodeJS), je ne vois pas l'utilité par rapport à simplement faire écouter ton site sur le port 443.

Cordialement