Ankündigung

Einklappen
Keine Ankündigung bisher.

Reverse Proxy - Kein Zugriff auf Websocket

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

    Reverse Proxy - Kein Zugriff auf Websocket

    Hallo,

    ich habe mir für das Alexa Plugin einen Reverse Proxy nach der Anleitung "NGINX als ReverseProxy" installiert.

    Alexa Plugin läuft auch problemlos.

    Nun bekomme ich jedoch beim Zugriff auf die DynDNS Adresse nur die Visu angezeigt aber keine Werte (Temperaturen etc.), schalten kann ich auch nicht. D.h. dass die Visu m.e. keinen Zugriff auf das Websocket hat.

    In den Log´s von smarthomeNG und vom Reverse Proxy kann ich keinen Hinweis nix finden.

    Hat jemand eine Idee was ich da noch vergessen habe. Muss ich in der SmartVisu noch etwas umstellen?

    Grüße

    Martin


    smarthomeNG v 1.4.1
    SmartVisu 2.8

    #2
    Apple Gerät? Da geht das leider nicht.

    Ansonsten: mehr Infos bitte wie das eingerichtet ist, v.a. in der SmartVISU.. Und welche Versionen der Komponenten!!!!
    Ich bin leider kein zertifizierter Hellseher...

    Kommentar


      #3
      Hallo Martin!

      Ich habe bei mir die "io_smarthome.py.js" so geändert.
      Code:
      if (!io.address || io.address.indexOf('://') < 0) {
                  // adopt websocket security to current protocol (https -> wss and http -> ws)
                  // if the protocol should be forced, add it to the address
                  protocol = location.protocol === 'https:' ? 'wss://' : 'ws://';
      
                  if (!io.address) {
                      // use url of current page if not defined
                      io.address = location.hostname;
      
                  }
                  if (!io.port) {
                      // use port of current page if not defined and needed
                      if (  (location.protocol == 'http:') ) {
                          io.port = '2424';
                      }
                      if (  (location.protocol == 'https:') ) {
                          io.port = '443';
                      }
      
                  }
              }
              io.socket = new WebSocket(protocol + io.address + ':' + io.port);
      In der smartVISU (bei mir 2.9) Host und Port einfach leer lassen.
      Funktioniert bei mir bestens.

      Gruß, Max

      Kommentar


        #4
        Mit HTTPS müsste die SV aber direkt umgehen können. HTTP nutzt Du dann für den Zugriff via lokaler IP?

        Kommentar


          #5
          Zitat von psilo Beitrag anzeigen
          Mit HTTPS müsste die SV aber direkt umgehen können. HTTP nutzt Du dann für den Zugriff via lokaler IP?
          Ja genau.

          Kommentar


            #6
            Hallo,

            @Max: Danke für Dein Tipp. Der hat leider in der smartVISU 2.8 so nicht auf die Schnelle geklappt. Aber ich werde an diesem Ansatz mal weiter experimentieren.

            @psilo:
            Den Zugiff habe ich mit Noetppok und WIndows 7 mit Firefox und Chrome sowie über Android mit Chrome probiert.

            Aktuell habe ich in der SmartVISU bei IO_Connection bei Host die 192.168.168.37 stehen und bei Port 2424

            Meine SmarthomeNG version die die 1.4.1.master (5240008)
            Meine SmartVISU Version ist die 2.8

            Kommentar


              #7
              bamus007 wie soll das denn mit Port 2424 und der Netzwerk IP gehen, wenn Du gar nicht im Netzwerk bist wenn Du zugreifst (VPN wäre ja bspw. aus)? Da muss natürlich die DynDNS URL und die 443 (HTTPS) hin. 2424 ist nach meiner Anleitung nach außen ja gar nicht offen... Die SV 2.8 könnte allerdings Probleme mit Port 443 haben, ich bin aber nicht sicher... Bin leider schon auf 2.9

              Kommentar


                #8
                Zitat von psilo Beitrag anzeigen
                Apple Gerät? Da geht das leider nicht.
                Hi,

                habe gerade hier etwas probiert: Es liegt am Zugriff vom https (proxy) auf den Unsecure Websocket. Beim alten Safari konnte man hier eine Einstellung setzen, dann lief es.

                Diese Einstellung hat auf dem Mac noch Chrome. Wenn ich dort die smartvisu Seite aufrufe und dann oben rechts Security wähle, dann muss man für diese Seite insecure Scripts ausschalten, dann geht es.

                Vielleicht bringt das die AppleWelt auf den Weg, da noch etwas hinzubekommen, bzw. vielleicht hilft es dann smarthome hinter smartvisu auch secure aufzurufen.
                Da habe ich aber zu wenig Ahnung von.

                Wie oben geschrieben, geht es damit mit Chrome erst mal auch auf dem Mac.

                Gruss Andreas

                Kommentar


                  #9
                  Heureka, es funktioniert.. auf Safari und IOS! Habe diese beiden Webseiten als Anleitung genutzt:
                  https://www.smarthomeng.de/nginx-als-reverseproxy
                  https://blog.christophermullins.com/...t-certificates

                  Und hier ist das entsprechende Ansible-File:
                  https://github.com/smarthomeNG/ansib...n/04_nginx.yml

                  Auch wenn ihr nicht Ansible nutzt, kann es gut als Vorlage herangezogen werden. Freue mich über eure Erfolgsmeldungen

                  Kommentar


                    #10
                    Onkelandy könntest du noch etwas detaillierter zusammenschreiben, was du gemacht hast? geht es am handy auch? würde das gerne dem artikel ergänzen.
                    Zuletzt geändert von psilo; 25.07.2018, 05:44.

                    Kommentar


                      #11
                      Soda, hier nun die volle Dröhnung als Ergänzung zur Komplettanleitung. Hoffe, du kannst damit die Anleitung updaten.. Laut ssl-Lab ist alles A+

                      Installieren der notwendigen Pakete:
                      apt-get install "certbot" "gzip" "nginx-full" "geoip-database" "libgeoip1" "php7.0-fpm" "lua5.1" "luarocks" "liblua5.1-dev" "apache2-utils" "libnginx-mod-http-lua" "libssl-dev" "cmake"

                      Hinweis: php und gzip ist nur notwendig, wenn die SmartVisu auf dem gleichen Server gehostet wird wie der Reverse Proxy.
                      Nach Installieren von PHP ist weiters das Ändern des Eintrags in der Datei /etc/php/7.0/fpm/php.ini nötig:
                      cgi.fix_pathinfo=0

                      Installieren der Build Tools um das Crypto Modul für lua kompilieren zu können. Dies ist nur notwendig, wenn mittels Apple Geräten via Safari auf den Reverse Proxy bzw. Websocket von Smarthome zugegriffen werden soll.
                      apt-get install "git-core" "build-essential" "autoconf" "pkg-config" "cmake"

                      nginx Headers Datei anlegen /etc/nginx/headers.conf, mit folgendem Inhalt:
                      Code:
                      add_header Strict-Transport-Security "max-age=31536000; includeSubdomains" always;
                      add_header X-Cache $upstream_cache_status;
                      add_header X-Frame-Options "SAMEORIGIN" always;
                      add_header X-Xss-Protection "1; mode=block" always;
                      add_header X-Content-Type-Options "nosniff" always;
                      add_header X-Proxy-Cache $upstream_cache_status;
                      Datei /etc/nginx/proxy_params anlegen bzw. anpassen:
                      Code:
                      proxy_set_header        Host            $host;
                      proxy_set_header        X-Real-IP       $remote_addr;
                      proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
                      client_max_body_size    10m;
                      client_body_buffer_size 128k;
                      proxy_connect_timeout   90;
                      proxy_send_timeout      90;
                      proxy_read_timeout      90;
                      proxy_buffers           32 4k;
                      proxy_set_header        Upgrade $http_upgrade;
                      proxy_set_header        Connection $connection_upgrade;
                      proxy_set_header        Host $host;
                      proxy_buffering         on;
                      proxy_redirect          http:// https://;
                      proxy_set_header        X-Forwarded-Proto $scheme;
                      proxy_http_version      1.1;
                      
                      proxy_cache_path /var/lib/nginx/cache levels=1:2 keys_zone=backcache:8m max_size=50m;
                      proxy_cache_key "$scheme$request_method$host$request_uri$is_args$args";
                      proxy_cache_valid 200 302 60m;
                      proxy_cache_valid 404 1m;
                      proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
                      proxy_cache_revalidate on;
                      proxy_cache_min_uses 3;
                      proxy_cache backcache;
                      Wenn php-7.0-fpm verwendet wird, sollte noch diese Zeile am Ende des Files /etc/nginx/fastcgi_params eingesetzt werden:
                      Code:
                      fastcgi_param SCRIPT_FILENAME     $document_root$fastcgi_script_name;
                      nginx.conf: Hier muss in die oberste Zeile das eingefügt werden, falls es nicht schon ist:
                      Code:
                      include /etc/nginx/modules-enabled/*.conf;
                      Außerdem:
                      Code:
                      http {
                      
                              ##
                              # Basic Settings
                              ##
                              map $http_upgrade $connection_upgrade {
                                      default upgrade;
                                      ''      close;
                              }
                              include    /etc/nginx/proxy_params;
                              include    /etc/nginx/fastcgi_params;
                      Rest wie gehabt laut Anleitung.

                      Optional: Ticketkey erstellen: sudo openssl rand 48 > /etc/nginx/nginx_ticketkey

                      Folgendes ist für den Zugriff via Safari notwendig:
                      sudo mkdir /etc/nginx/scripts/
                      nano /etc/nginx/scripts/hass_access.lua mit folgendem Inhalt:
                      Code:
                      local HMAC_SECRET = "<SECRETKEY from OPENSSL>"
                      local crypto = require "crypto"
                      
                      function ComputeHmac(msg, expires)
                        return crypto.hmac.digest("sha256", string.format("%s%d", msg, expires), HMAC_SECRET)
                      end
                      
                      verify_status = ngx.var.ssl_client_verify
                      
                      if verify_status == "SUCCESS" then
                        client = crypto.digest("sha256", ngx.var.ssl_client_cert)
                        expires = ngx.time() + 3600
                      
                        ngx.header["Set-Cookie"] = {
                          string.format("AccessToken=%s; path=/", ComputeHmac(client, expires)),
                          string.format("ClientId=%s; path=/", client),
                          string.format("AccessExpires=%d; path=/", expires)
                        }
                        return
                      elseif verify_status == "NONE" then
                        client = ngx.var.cookie_ClientId
                        client_hmac = ngx.var.cookie_AccessToken
                        access_expires = ngx.var.cookie_AccessExpires
                      
                        if client ~= nil and client_hmac ~= nil and access_expires ~= nil then
                          hmac = ComputeHmac(client, access_expires)
                      
                          if hmac ~= "" and hmac == client_hmac and tonumber(access_expires) > ngx.time() then
                            return
                          end
                        end
                      end
                      
                      ngx.exit(ngx.HTTP_FORBIDDEN)
                      Die Datei /etc/nginx/sites-available/default sollte so aussehen:
                      Code:
                      upstream websocket {
                          server localhost:2424;
                      }
                      
                      upstream sv {
                          server localhost;
                          keepalive 20;
                      }
                      
                      server {
                      
                          listen 80 default_server;
                          listen [::]:80 default_server;
                          include /etc/nginx/snippets/letsencrypt.conf;
                          root /var/www/html;
                      
                          # Add index.php to the list if you are using PHP
                          index index.html index.htm index.nginx-debian.html index.php;
                      
                          server_name _;
                      
                          # Skip^1 caching variable init
                          set $nocache 0;
                          # Bypass^2 caching variable init
                          set $purgecache 0;
                      
                          # Bypass^2 cache on no-cache (et al.) browser request
                          if ($http_cache_control ~ "max-age=0")
                              { set $purgecache 1; }
                          if ($http_cache_control ~ "no-cache")
                              { set $purgecache 1; }
                          # Bypass^2 cache with custom header set on request
                          if ($http_x_cache_purge ~* "true")
                              { set $purgecache 1; }
                      
                          location / {
                                  # First attempt to serve request as file, then
                                  # as directory, then fall back to displaying a 404.
                                  try_files $uri $uri/ =404;
                                  if ($http_upgrade = websocket) {
                                          proxy_pass http://websocket;
                                  }
                          }
                      
                          # pass PHP scripts to FastCGI server
                      
                          location ~ \.php$ {
                              try_files $uri =404;
                              fastcgi_split_path_info ^(.+\.php)(/.+)$;
                              fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
                              fastcgi_index index.php;
                              fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                              include fastcgi_params;
                      
                          }
                      
                          location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
                              include /etc/nginx/headers.conf;
                              expires 7d;
                              add_header Cache-Control "public, no-transform";
                          }
                      }
                      Die Datei /etc/nginx/conf.d/<mydomain> sollte das hier beinhalten. Das ssl_client_verify kann man sich prinzipiell schenken, da das lua Script eben das Zertifikat testet. Bei der root-location muss die if-Abfrage auf jeden Fall weg, da sonst die Websocket-Verbindung nicht funktioniert!
                      Code:
                      server {
                          server_tokens off;
                          ## Blocken, wenn Zugriff aus einem nicht erlaubten Land erfolgt ##
                          if ($allowed_country = no) {
                              return 403;
                          }
                      
                          # https://www.cyberciti.biz/tips/linux-unix-bsd-nginx-webserver-security.html
                          ## Block download agents ##
                          if ($http_user_agent ~* LWP::Simple|BBBike|wget) {
                              return 403;
                          }
                      
                          ## Block some robots ##
                          if ($http_user_agent ~* msnbot|scrapbot) {
                              return 403;
                          }
                      
                          ## Deny certain Referers ##
                          if ( $http_referer ~* (babes|forsale|girl|jewelry|love|nudit|organic|poker|porn|sex|teen) )
                          {
                              return 403;
                          }
                      
                          listen 443 ssl http2;
                          listen [::]:443 ssl http2;
                          server_name DOMAIN_HERE;
                          ##
                          # SSL
                          ##
                      
                          ## Activate SSL, setze SERVER Zertifikat Informationen ##
                          # Generiert via Let's Encrypt!
                          #ssl_certificate /etc/letsencrypt/live/DOMAIN_HERE/fullchain.pem;
                          #ssl_certificate_key /etc/letsencrypt/live/DOMAIN_HERE/privkey.pem;
                          #ssl_trusted_certificate /etc/letsencrypt/live/DOMAIN_HERE/fullchain.pem;
                          ssl_session_cache builtin:1000 shared:SSL:60m;
                          ssl_prefer_server_ciphers on;
                          # unsichere SSL Ciphers deaktivieren!
                          ssl_ciphers    HIGH:!aNULL:!eNULL:!LOW:!3DES:!MD5:!RC4;
                          ssl_protocols TLSv1.2;
                          ssl_session_timeout 60m;
                          ssl_session_tickets on;
                          ssl_session_ticket_key /etc/nginx/nginx_ticketkey;
                          #ssl_buffer_size 16k;   #for throughput, video applications
                          ssl_buffer_size 4k;     #for quick first byte delivery
                      
                          # Client Zertifikat spezifisch
                          #ssl_client_certificate /etc/openvpn/easy-rsa/keys/ca.crt;
                          #ssl_crl /etc/openvpn/easy-rsa/keys/ca.crl;
                          #ssl_verify_client optional;
                          #ssl_dhparam /etc/openvpn/easy-rsa/keys/dh2048.pem;
                      
                          # OCSP Stapling ---
                          # fetch OCSP records from URL in ssl_certificate and cache them
                          ssl_stapling on;
                          ssl_stapling_verify on;
                          resolver 8.8.8.8 8.8.4.4 valid=300s;
                      
                      
                          client_body_buffer_size 8K;
                          client_max_body_size 20m;
                          client_body_timeout 10s;
                          client_header_buffer_size 1k;
                          large_client_header_buffers 2 16k;
                          client_header_timeout 5s;
                      
                          ##
                          # global
                          ##
                      
                          root /var/www/html;
                      
                          # Add index.php to the list if you are using PHP
                          index index.html index.htm index.php;
                      
                          # Proxy Caching
                          # Skip^1 caching variable init
                          set $nocache 0;
                          # Bypass^2 caching variable init
                          set $purgecache 0;
                      
                          # Bypass^2 cache on no-cache (et al.) browser request
                          if ($http_cache_control ~ "max-age=0")
                              { set $purgecache 1; }
                          if ($http_cache_control ~ "no-cache")
                              { set $purgecache 1; }
                          # Bypass^2 cache with custom header set on request
                          if ($http_x_cache_purge ~* "true")
                              { set $purgecache 1; }
                      
                      
                          location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|xml)$ {
                              include /etc/nginx/headers.conf;
                              expires 7d;
                              add_header Cache-Control "public, no-transform";
                              access_by_lua_file /etc/nginx/scripts/hass_access.lua;
                          }
                      
                          # Weiterleitung zu SmartHomeNG (Websocket Schnittstelle) mit Basic Auth
                          location / {
                              include /etc/nginx/headers.conf;
                              satisfy any;
                      #        auth_basic "Restricted Area: smartVISU2.9";
                      #        auth_basic_user_file /etc/nginx/.smartvisu;
                              allow 127.0.0.1;
                              allow 192.168.0.0/16;
                              allow 10.0.0.0/16;
                              deny all;
                      
                              access_by_lua_file /etc/nginx/scripts/hass_access.lua;
                      
                              if ($allowed_country = no) {
                                  return 403;
                              }
                              # Nur Websocket Verbindungen gegen "/" durchlassen!
                              if ($http_upgrade = websocket) {
                                      proxy_pass http://websocket;
                              }
                      
                          }
                      
                          # Zugriff auf die smartVISU mit Basic Auth
                          location /smartVISU {
                              include /etc/nginx/headers.conf;
                              satisfy any;
                      #        auth_basic "Restricted Area: smartVISU2.9";
                      #        auth_basic_user_file /etc/nginx/.smartvisu;
                              allow 127.0.0.1;
                              allow 192.168.0.0/16;
                              allow 10.0.0.0/16;
                              deny all;
                              access_by_lua_file /etc/nginx/scripts/hass_access.lua;
                              if ($allowed_country = no) {
                                  return 403;
                              }
                              if ($ssl_client_verify != SUCCESS) {
                                  return 403;
                              }
                              proxy_pass http://sv/smartVISU;
                          }
                      }
                      Jetzt geht es ans Eingemachte. Ohne lua cyrpto Modul geht leider nix. Eventuell kann man es mit einem openssl Modul für lua probieren und das Skript oben entsprechend anpassen. Aber auf frischem debian stretch hat folgendes Prozedere einwandfrei funktioniert:
                      Code:
                      git clone https://github.com/evanlabs/luacrypto.git
                      luarocks install /root/luacrypto/rockspecs/luacrypto-git-1.rockspec
                      mkdir /usr/local/lib/lua/5.1/
                      ln -s /usr/local/lib/lua/crypto.so /usr/local/lib/lua/5.1/crypto.so
                      systemctl restart php7.0-fpm.service
                      systemctl restart nginx
                      In der SmartVISU wird als Quelle SmarthomeNG angegeben, allerdings IP und Port LEER gelassen.
                      Zuletzt geändert von Onkelandy; 11.09.2018, 17:34.

                      Kommentar


                        #12
                        Wer es hinbekommt, das Backend über den Reverse Proxy anzusteuern, möge das hier bitte posten. Problem ist irgendwie der andere Port, Ich habe das zwar zB für monit so hinbekommen, aber beim Backendplugin habe ich keine Chance, egal was ich probiere..

                        /etc/nginx/sites-available/default:
                        Code:
                        upstream monithost {
                            server localhost:2812;
                        }
                        
                        server {
                          # Weiterleitung zu Monit
                            location /monit/ {
                                satisfy any;
                                allow 127.0.0.1;
                                allow 10.0.0.0/8;
                                allow 192.168.0.0/16;
                        #        auth_basic "Restricted Area: Monit";
                        #        auth_basic_user_file /etc/nginx/.monit;
                                deny all;
                        
                                if ($allowed_country = no) {
                                    return 403;
                                }
                                rewrite ^/monit/(.*) /$1 break;
                                proxy_pass   http://monithost;
                                proxy_redirect  http://monithost /monit;
                                proxy_cookie_path / /monit/;
                                include /etc/nginx/headers.conf;
                            }
                        /etc/nginx/conf.d/<mydomain>
                        Code:
                          # Weiterleitung zu Monit
                            location /monit/ {
                                satisfy any;
                                allow 127.0.0.1;
                                allow 10.0.0.0/8;
                                allow 192.168.0.0/16;
                        #        auth_basic "Restricted Area: Monit";
                        #        auth_basic_user_file /etc/nginx/.monit;
                                deny all;
                                rewrite ^/monit/(.*) /$1 break;
                                proxy_pass   http://monithost;
                                proxy_redirect  http://monithost /monit;
                                proxy_cookie_path / /monit/;
                                include /etc/nginx/headers.conf;
                                access_by_lua_file /etc/nginx/scripts/hass_access.lua;
                            }
                        Any ideas?

                        Kommentar


                          #13
                          das Problem mit dem Backend ist, dass du den gstatic ordner noch umleiten musst

                          Mit zertifikatebasierter Auth geht es bei mir so - basic auth crendetials als base64 nicht vergessen:

                          Code:
                              location /gstatic {
                                  if ($ssl_client_verify != SUCCESS) {
                                          return 403;
                                  }
                                  if ($allowed_country = no) {
                                          return 403;
                                  }
                                  proxy_pass http://192.168.178.100:1234;
                                  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_set_header Authorization "Basic YxxxxxxxxTIzNA==";
                              }
                          
                              location /backend {
                                  if ($ssl_client_verify != SUCCESS) {
                                          return 403;
                                  }
                                  if ($allowed_country = no) {
                                          return 403;
                                  }
                                  proxy_pass http://192.168.178.100:1234;
                                  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_set_header Authorization "Basic YxxxxxxxxTIzNA==";
                              }
                          Allerdings noch OHNE Apple Fix. Ich glaube aber nicht, dass das Weiterleiten auf einen Port hier wirklich das Problem ist. Dann ginge Alexa ja auch nicht bspw.
                          Zuletzt geändert von psilo; 28.07.2018, 06:14.

                          Kommentar


                            #14
                            Juhu, das geht in die richtige Richtung.. Andere Services funktionieren eigentlich alle mit localhost, hier muss ich aber $server_addr angeben. Außerdem hatte ich noch ein Problem mit dem Cache-Header für Javascript und Co.. Somit lautet die funktionierende Variante...:
                            Code:
                                location /backend/ {
                                    include /etc/nginx/headers.conf;
                                    satisfy any;
                                    #auth_basic "Restricted Area: Smarthome NG Backend";
                                    #auth_basic_user_file /etc/nginx/.shng;
                                    allow 127.0.0.1;
                                    allow 192.168.0.0/16;
                                    allow 10.0.0.0/16;
                                    deny all;
                            access_by_lua_file /etc/nginx/scripts/hass_access.lua;
                            
                                     index index.html index.htm index.php;
                                    if ($allowed_country = no) {
                                        return 403;
                                    }
                            
                                location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
                                    include /etc/nginx/headers.conf;
                                    expires 7d;
                                    add_header Cache-Control "public, no-transform";
                                    proxy_pass http://$server_addr:8383;
                            access_by_lua_file /etc/nginx/scripts/hass_access.lua;
                                    }
                            
                                    proxy_pass http://$server_addr:8383;
                                }
                            Und das Gleiche für /gstatic

                            Kommentar


                              #15
                              das backend waere bei dir im lan aber nicht sep. basic auth geschuetzt, oder? ich vermisse den base64 string

                              Kommentar

                              Lädt...
                              X