Nginx als Reverse Proxy mit SSL vor FHEM

Begonnen von mareb, 30 November 2016, 12:11:12

Vorheriges Thema - Nächstes Thema

mareb

Hallo,

ich möchte mal meine Nginx-Konfiguration zur Diskussion stellen.

Die Idee ist, den Zugang von außen (also ausserhalb des Hosts) grundsätzlich nur per SSL/TLS zuzulassen, unabhängig vom verwendeten Device.

- Nginx als Reverse Proxy
- Http-Calls werden auf HTTPS weitergeleitet
- vorerst self-signed-Zertifikate(die Erstellung ist hier nicht beschrieben)
- Eine Adresse für alle Typen von Devices - keine explizite Port-Angabe ('Respnsiveness by port-redirecting')
- FHEM-Ports nur vom Host selbst erreichbar
- User-Realms in FHEM selbst

Das Ganze mündet in folgender Nginx-Konfiguration:

/etc/nginx/conf.d/useragent_map.conf:
map $http_user_agent $port {
    default 8083;
    ~(?i)iphone 8084;
    ~(?i)ipad 8085;
    ~(?i)android.*(mobile|mini) 8084;
    ~Mobile.+Firefox 8084;
    ~^HTC 8084;
    ~Fennec 8084;
    ~IEMobile 8084;
    ~BB10 8084;
    ~SymbianOS.*AppleWebKit 8084;
    ~Opera\sMobi 8084;
}

/etc/nginx/conf.d/fhem_upstream.conf:
upstream fhem-web {
  server 127.0.0.1:8083;
}

upstream fhem-phone {
  server 127.0.0.1:8084;
}

upstream fhem-tablet {
  server 127.0.0.1:8085;
}

/etc/nginx/sites-enabled/fhem:
server {
  listen 80 default_server;
  listen [::]:80 default_server;
  server_name _;
  return 301 https://$host$request_uri;
}

server {
  listen 443 default_server ssl;
  listen [::]:443 default_server ssl;

  server_name mein.server.de;
  ssl_certificate /etc/nginx/ssl/nginx.crt;
  ssl_certificate_key /etc/nginx/ssl/nginx.key;

  access_log /var/log/nginx/mein_server_ssl.access.log;
  error_log  /var/log/nginx/mein_server_ssl.error.log;

  location / {
    if ($port = 8084) {
      proxy_pass http://fhem-phone;
    }
    if ($port = 8085) {
      proxy_pass http://fhem-tablet;
    }
    if ($port = 8083) {
      proxy_pass http://fhem-web;
    }

    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_redirect http://mein.server.de:$port/ https://mein.server.de/;
    proxy_read_timeout 2073600;
    proxy_buffering off;
    proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;

    include /etc/nginx/mime.types;
  }
}


Da Nginx und FHEM auf der gleichen VM liegen reicht es, dass die fhem-ports nur lokal erreichbar ist - also nicht 'global' definiert.
define WEB FHEMWEB 8083
...
define WEBphone FHEMWEB 8084
...
define WEBtablet FHEMWEB 8085
...


Da ich diese Ports nach draußen nun nicht mehr brauche, lasse ich nur noch 80/443 für http(s) zu:
# ufw status
Status: active

To                         Action      From
--                         ------      ----
...
80                         ALLOW       Anywhere
443                        ALLOW       Anywhere
...
80 (v6)                    ALLOW       Anywhere (v6)
443 (v6)                   ALLOW       Anywhere (v6)



Egal mit welchem Device (Web, Telefon, Tablet) habe ich jetzt eine Adresse:
http(s)://mein.server.de


Vielleicht dient es dem einen oder anderen als Blueprint.

Was vergessen?
Was könnte man noch 'verbessern'?

Gruß,
Markus

Wernieman

Wenn man jetzt die Weiterleitung nicht auf oberster ebene, also z.B. unter "http(s)://mein.server.de/fhem" haben möchte?

Und noch etwas wichtiges: Eventuell währe es gut (für den Laien), das man ngix bitte kann, vor der Weiterleitung nach einem PW zu fragen (authentifizierung), sonst steht eben fhem seeeehr frei (und unsicher) im Netz!
"- User-Realms in FHEM selbst" ist leider Sicherheitstechnisch nicht ausreichend :o(
- Bitte um Input für Output
- When there is a Shell, there is a Way
- Wann war Dein letztes Backup?

Wie man Fragen stellt: https://tty1.net/smart-questions_de.html

mareb

Zitat von: Wernieman am 30 November 2016, 15:04:03
Wenn man jetzt die Weiterleitung nicht auf oberster ebene, also z.B. unter "http(s)://mein.server.de/fhem" haben möchte?

Und noch etwas wichtiges: Eventuell währe es gut (für den Laien), das man ngix bitte kann, vor der Weiterleitung nach einem PW zu fragen (authentifizierung), sonst steht eben fhem seeeehr frei (und unsicher) im Netz!
"- User-Realms in FHEM selbst" ist leider Sicherheitstechnisch nicht ausreichend :o(

Meinst Du damit eine zusätzliche Realm-Abfrage im Proxy oder würdest Du die in FHEM abschalten? - Letzteres würde bedeuten, dass ich von localhost ohne Authentifizierung dran komme.
Wie ich es verstehe, ist in FHEM auch "nur" ein HTTP-Basic-Realm implementiert. Sehe da keinen Unterschied zum nginx.

ich mach mich mal dran... Danke!

Wernieman

Naja .. FHEM ist Sicherheitstechnisch nie überprüft, nginx (oder apache) dagegen schon. Welche Systeme man im Internet erreichbar macht, sollte man sich immer überlegen (nicht nur aus aktuellen Gründen ;o) )
- Bitte um Input für Output
- When there is a Shell, there is a Way
- Wann war Dein letztes Backup?

Wie man Fragen stellt: https://tty1.net/smart-questions_de.html

mareb

Nja, "frei" verfügbar sollte er generell nicht stehen, oder?


Aber zu Deinen ursprünglichen Fragen: So müsste es dann Aussehen:

- Basic-Auth im Nginx (passwd file erzeugen, bspw. mit htpasswd)
- Weiterleitung nur im /fhem Context


server {
  listen 80 default_server;
  listen [::]:80 default_server;
  server_name _;

  location /fhem {
    return 301 https://$host$request_uri;
  }
}

server {
  listen 443 default_server ssl;
  listen [::]:443 default_server ssl;

  server_name mein.server.de;
  ssl_certificate /etc/nginx/ssl/nginx.crt;
  ssl_certificate_key /etc/nginx/ssl/nginx.key;

  access_log /var/log/nginx/smart_ssl.access.log;
  error_log  /var/log/nginx/smart_ssl.error.log;

  location /fhem {

    auth_basic            "FHEM";
    auth_basic_user_file  conf/passwd;

    if ($port = 8084) {
      proxy_pass http://fhem-phone;
    }
    if ($port = 8085) {
      proxy_pass http://fhem-tablet;
    }
    if ($port = 8083) {
      proxy_pass http://fhem-web;
    }

    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_redirect http://mein.server.de:$port/fhem https://mein.server.de/fhem;
    proxy_read_timeout 2073600;
    proxy_buffering off;
    proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;

    include /etc/nginx/mime.types;
  }
}