Question Le proxy inverse de Nginx WebSocket conserve un retour 200 au lieu de 101


J'essaie actuellement d'avoir un bidouillez sur mon serveur personnel de travail.

Longue histoire courte, il se compose de deux serveurs. Le premier est un simple serveur httpd servant javascript et CSS. Le second, le système de discussion, est un serveur node.js auquel le javascript se connecte à l'aide de websocket. Et voici les problèmes.

Je veux que tout utilise le port 80, avec un nom de domaine différent sur une seule adresse IP, en utilisant un bloc serveur distinct dans Nginx.

J'ai suivi le doc websocket de Nginx mais ça ne fonctionne pas. Lorsque le WebSocket essaie de se connecter, il obtient toujours un code de retour de 200 alors que, si j’ai bien compris, il devrait obtenir 101 (protocole de commutation).

Ma version de Nginx est la 1.8.0 et mon serveur tourne sous gentoo avec linux 4.0.5

Voici un dump des fichiers de configuration nginx pertinents:

nginx.conf:

user nginx nginx;
worker_processes 1;

error_log /var/log/nginx/error_log info;

events {
    worker_connections 1024;
    use epoll;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    log_format main
        '$remote_addr - $remote_user [$time_local] '
        '"$request" $status $bytes_sent '
        '"$http_referer" "$http_user_agent" '
        '"$gzip_ratio"';

    client_header_timeout 10m;
    client_body_timeout 10m;
    send_timeout 10m;

    connection_pool_size 256;
    client_header_buffer_size 1k;
    large_client_header_buffers 4 2k;
    request_pool_size 4k;

    gzip on;
    gzip_min_length 1100;
    gzip_buffers 4 8k;
    gzip_types text/plain;

    output_buffers 1 32k;
    postpone_output 1460;

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;

    keepalive_timeout 75 20;

    ignore_invalid_headers on;

    include /etc/nginx/sites-enabled/*;
}

Sites activés / chat:

map $http_upgrade $connection_upgrade{
    default upgrade;
    ''  close;
}

server{
    listen 0.0.0.0:80;
    server_name chat.axellink.fr;

    location / {
        proxy_pass http://127.0.0.1:6060;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
    }

    access_log /var/log/nginx/chat_access;
    error_log /var/log/nginx/chat_error debug;
}

Quand je regarde access_log, il affiche effectivement la réponse 200 et il n'y a pas d'erreur dans error_log. Malheureusement, le serveur node.js ne me fournit aucun journal (ou je ne sais pas comment l'afficher).

Merci d'avance pour toute réponse.

MODIFIER

Thx to mc0e, j'ai réussi à faire répondre le serveur hack.chat à la 101. En comparant ce qui se passe réellement entre nginx et node.js avec ce qui se passe sur une connexion directe, j'ai constaté que sur un en-tête direct Upgrade: websocket est défini mais que nginx le fait ne pas. Alors j'ai corrigé mes sites / permis de chat pour:

server{
    listen 0.0.0.0:80;
    server_name chat.axellink.fr;

    location / {
        proxy_pass http://127.0.0.1:6060;
        proxy_http_version 1.1;
        proxy_set_header Upgrade "websocket";
        proxy_set_header Connection "Upgrade";
    }

    access_log /var/log/nginx/chat_access;
    error_log /var/log/nginx/chat_error debug;
}

J'ai également supprimé le bloc de carte car il permettait de définir l'en-tête de connexion sur fermer au lieu de mettre à niveau.

Cela ne fonctionne toujours pas. hack.chat rend 101 avec Connection: Upgrade et Upgrade: websocket mais en quelque sorte nginx rend 101 avec Connection: keep-alive (comme ce que je vois dans firefox): /

MODIFIER

A fait un ngrep sur les communications nginx, il envoie le paquet hack.chat lui renvoie et firefox se plaint de l'origine croisée. Je vais essayer d'éviter les origines croisées.

Dernière édition

Ok, maintenant que je suis chez moi, j'ai fait un test qui a fonctionné à merveille. Assez sur que mon dernier problème était à cause de mon proxy de travail, espérons que c'est cache, sinon tout aurait été inutile.

Voici le dernier de mes conf qui évite l'origine croisée:

server{
        listen 0.0.0.0:80;
        server_name chat.axellink.fr;

        location / {
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Host $http_host;
                proxy_set_header X-NginX-Proxy true;
                proxy_pass http://127.0.0.1:8081;
        }

        location /chat/ {
                proxy_pass http://127.0.0.1:6060;
                proxy_http_version 1.1;
                proxy_set_header Upgrade "websocket";
                proxy_set_header Connection "Upgrade";
        }

        access_log /var/log/nginx/chat_access;
        error_log /var/log/nginx/chat_error debug;
}

6
2017-07-31 12:41


origine


Commencez par mettre à jour la version stable actuelle de nginx. Deuxièmement, commencez à déboguer votre application. Nginx ne peut transmettre que ce que votre application envoie. - Michael Hampton♦
nginx 1.7.6 est la dernière version stable disponible dans gentoo repo, je peux utiliser la version 1.9.3 mais cela me fera prendre le risque de disposer d’un système instable. Je ne peux pas déboguer l'application car ce n'est pas la mienne. De plus, cela fonctionne à merveille si j'utilise un port différent et que je me connecte directement à celui-ci. - axellink
1.7.6 n'est pas une version stable, c'est sur la piste de développement! Avez-vous accidentellement mis ACCEPT_KEYWORDS="~amd64"? - Michael Hampton♦
selon packages.gentoo.org/package/www-servers/nginx 1.7.6 est stable sur amd64. Je n'accepte pas ~ amd64 (du moins sur mon serveur). - axellink
Eh bien, c'est évidemment un problème, car 1.7.6 n'est pas réellement une version stable, et 1.8.0 est la version stable actuelle. Je pense qu'il est temps d'abandonner Gentoo. Ou au moins, contactez le responsable de cet ebuild et demandez-lui ce qu'il fume. - Michael Hampton♦


Réponses:


À la lecture du dock websocket de nginx, lorsque votre proxy nginx voit les en-têtes de mise à niveau, il les transmet à hack.chat. hack.chat doit ensuite répondre avec la réponse 101.

Tout d'abord, vous souhaitez pouvoir déboguer les transactions HTTP et hack.chat réelles, afin de savoir si le problème se situe dans votre application client, sur le serveur Web ou avec les communications hack.chat. Cela vous permettra également d’obtenir la réponse HTTP exacte, que vous dites ne pas savoir comment obtenir. SI le problème concerne le serveur, vous pouvez toujours chercher à obtenir de meilleurs journaux de ce qui ne va pas.

Vous pouvez capturer le trafic http avec tcpdump ou ngrep. J'irais pour Ngrep. En procédant ainsi, vous obtiendrez une sortie dans votre terminal.

ngrep 'Host: chat.axellink.fr' port 80

Vous voudrez probablement l'exécuter sur votre serveur Web. Toutefois, si vous avez un environnement de bureau capable d'exécuter ngrep, vous pouvez choisir de l'exécuter ici. Si vous l'exécutez sur le serveur, vous pouvez également capturer l'interaction entre nginx et votre serveur de discussion.

ngrep '.' port 6060

La sortie du terminal est souvent suffisante pour voir ce dont vous avez besoin, mais vous pouvez également utiliser l'indicateur '-O' pour que ngrep écrive les données dans un fichier de vidage pcap, comme le fait tcpdump avec '-w'. Vous pouvez ensuite ramener ce fichier sur votre bureau pour l'examiner avec un client graphique tel que Wirehark.

Vous pourrez peut-être identifier le problème à partir de ceci, mais sinon, capturez les diverses interactions et ajoutez-les à votre question.

Existe-t-il un problème lorsque javascript demande la communication hack.chat sur un domaine différent de celui à partir duquel le javascript est servi? Cela pourrait être pertinent: https://stackoverflow.com/questions/20093070/unable-to-create-cross-domain-websocket-connection-to-node-js-socket-io-server


2
2017-08-07 09:04



En suivant vos conseils, j'ai réussi à obtenir une bonne requête de nginx à hack.chat et une bonne réponse de hack.chat à nginx (voir mon édition), mais maintenant, nginx ne renvoie pas la réponse à hack.chat ... - axellink
Vous ne voyez pas la réponse HTTP de nginx car elle ne contient pas le texte "Host: chat.axellink.fr". Vous pourriez peut-être juste assortir n'importe quoi (c'est-à-dire".") ou s'il y a trop de trafic autour de choses confuses, vous pouvez ajouter host 83.173.69.3 à la fin de sorte que vous ne voyez que les paquets associés à l’IP de votre navigateur (prenant l’IP de la liste que vous avez donnée). - mc0e
s'il vous plait, tuez-moi pour avoir été aussi retardé ... essayé avec '.' tout à fait mieux maintenant. Il faut beaucoup de temps pour réagir mais le fait. Cela ne fonctionne pas, car normalement, la réponse devrait également indiquer Connection: Upgrade et Upgrade: websocket, mais dans mon cas, elle n’a que Connection: keep-alive. Je vais éditer la question - axellink
Oui, avoir un proxy dans le chemin sans la logique websocket l'empêchera de fonctionner. Cependant, si vous utilisiez la syntaxe recommandée et transmettez simplement l'en-tête de mise à niveau et les en-têtes de connexion fournis par le client (comme dans votre exemple de code d'origine), le serveur de discussion pourrait alors détecter le problème et fournir une réponse utile pour expliquer la situation. - Bien que je ne sache pas si oui ou non. Je suggèrerais de le laisser tel quel et de faire une suggestion au hack.chat les gens à ce sujet. - mc0e