Hallo
I've moved fhemweb behind a reverse proxy using nginx. I setup fhem web to listen only on localhost. I can access fhemweb normally via the local address : https://fhem.lan
this is my nginx config for this domain :
server {
listen 80 default_server;
server_name fhem.lan;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
##listen [::]:443 ssl;
include snippets/self-signed.conf;
include snippets/ssl-params.conf;
server_name fhem.lan;
location / {
# Enable Basic Auth
auth_basic "Restricted Area";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://127.0.0.1:8083;
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;
}
# WebSocket support
location /ws {
proxy_pass http://127.0.0.1:8085;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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;
}
}
fhemweb is setup to listen only on http://127.0.0.1:8083 so I must use the reverse proxy to access the interface when connecting via my lan. fhemweb have ssl off because it's now managed by nginx, less workload on fhem... (attr WEB HTTPS 0) . Until now, I also used websocket (attr WEB longpoll websocket) to update fhemweb. But now, this doesn't work anymore, the changes I do in fhemweb aren't updated until I refresh the entire page. The live log doesn't work anymore, no updates.
In the browser log, I see that "fhemweb.js" try to access fhem websocket at "wss://fhem.lan/fhem?XHR=1&inform=....." which seem incorrect since the websocket is on another path : "wss://fhem.lan/ws" However there is no option to use another path for websocket in fhemweb.
How should I proceed ?
ZitatHowever there is no option to use another path for websocket in fhemweb.
This is correct, please configure nginx to support websocket with the same prefix as the plain html.
As an alternative you could revert to using longpoll, by setting "attr WEB longpoll 1"
Yeah, the nginx config for fhem is a bit weird. For most servicesproxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
is enough in nginx to get websockets to work but for FHEM you needset $my_http_upgrade "";
set $my_connection "Connection";
if ($http_upgrade = "websocket") {
set $my_http_upgrade $http_upgrade;
set $my_connection "upgrade";
}
proxy_set_header Upgrade $my_http_upgrade;
proxy_set_header Connection $my_connection;
I can't remember where I saw this (maybe the wiki?), but it works (even though it's using evil if; I should probably sit down and convert this to map ...).
Here's a sample config, similar to what I am using:server {
server_name fhem.somehost.lan;
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
include conf.d/ssl;
location / {
set $my_http_upgrade "";
set $my_connection "Connection";
if ($http_upgrade = "websocket") {
set $my_http_upgrade $http_upgrade;
set $my_connection "upgrade";
}
proxy_set_header Upgrade $my_http_upgrade;
proxy_set_header Connection $my_connection;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host:$server_port;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
set $upstream 127.0.0.1:8083;
proxy_pass http://$upstream;
}
}
Note that for authentication, I am not relying on nginx's basic auth but I am still using the allowed device (and passing the basic auth header from upstream via proxy_set_header Authorization "Basic xyz";, since I am using SSO/nginx's auth_request module). But if you don't want to use the allowed device anymore, I am sure you can adopt this to use nginx basic auth, just like you did in your example.
Further note, that, if you are using Safari, basic auth and websockets don't play nicely with each other. For that, I'd recommend using nginx's auth_request module with some kind of SSO provider, like I described. FWIW I am using oauth2-proxy. Has been very reliable so far. If you're interested, I am happy to share that nginx config as well.
By the way, if you're proxying other services than FHEM, you can also reference this stuff:
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host:$server_port;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
via an include (e.g. include snippets/proxy-default.conf;). Makes the config a bit tidier and most other services tend to be happy with this config as well.
Zitat von: passibe am 20 Oktober 2025, 21:16:43Yeah, the nginx config for fhem is a bit weird.
Yes ! thanks you so much for your great response, your exemple worked at first try ! I just added my basic auth and deleted "http2 on;" which caused an error on my nginx.
So I'm confused now : what is the purpose of the modules :
define MyWebsocket
websocket 8085
and
define MyWebsocket_json
websocket_jsonI though they were necessary for the websocket, but I just deleted them and the websocket continue to work ...
Anyway, thanks again !
Ah yes, you're probably running an older nginx version, so if you want to use http2 (which I would recommend), you need to include it in the listen directive. For the http2 directive, version 1.25.1 or later is needed. So for your version it is:listen 443 ssl http2;
listen [::]:443 ssl http2;
(source (https://nginx.org/en/docs/http/ngx_http_core_module.html#listen))
As far as the other "websocket" FHEMWEB devices are concerned, I'm not sure where those appeared from or why you would need them. Probably you set them up at some point for some purpose and they are no longer relevant?
yes I set them up some long time ago, I think I believed it was mandatory for websocket to work.. :P
I use the latest nginx (1.18.0-6ubuntu14.7) proposed by the distro (Ubuntu 22.04.4 LTS) on a raspberry pi 4.
For now, I don't see the need for an OS upgrade yet, especially considering the work to be done and the fact that the os is not directly connected to the internet (cloud free ;D )
As a quick note and for thoses who are concerned, I end up with this config and replaced the "Evil if" with the map keyword
in the nginx.conf, under the existing http block, just add :
map $http_upgrade $my_http_upgrade {
default "";
websocket "websocket";
}
map $http_upgrade $my_connection {
default "close";
websocket "upgrade";
}
then, in your website conf (in site-enabled or site-available), in the location block use something like this :
# Ensure Websocket proxying works
proxy_set_header Upgrade $my_http_upgrade;
proxy_set_header Connection $my_connection;
# Standard reverse proxy headers
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host:$server_port;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:8083;
Very nice, thanks!
Although, I just did some testing, and I am not sure this is even necessary.
I think my statement that "FHEM is weird" in this regard was just wrong.
I just tested it with the regularproxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
so no if/map, not even proxy_http_version 1.1; is required. I am really not sure what I did wrong years ago when I first tried to set this up, but it seems like it works just like every other service and doesn't, in fact, require anything special.
I'll report back if I notice anything weird, but so far, this seems to be working just fine. The websocket stays connected and all events are received as they should be.
Let me know if this solution also works for you.
For the sake of completeness:# Ensure Websocket proxying works
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
# Standard reverse proxy headers
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host:$server_port;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
set $upstream 127.0.0.1:8083;
proxy_pass http://$upstream;
(By the way, you should always set the upstream address and port with a variable, so nginx doesn't refuse to start up if the upstream server isn't reachable, see here (https://sandro-keil.de/blog/let-nginx-start-if-upstream-host-is-unavailable-or-down/).)