OH3 with NGINX Reverse Proxy and Authentication

Thanks Markus,
I thought about myopenhab but it will introduce another layer and breaks my philosophy (No cloud services if possible).
That’s why I prefer the reverse proxy…

Like the old :apple: saying goes: Been there, done that.
Moved on and didn’t regret when looking back.
OH foundation-run services are in fact safer and more reliable than to run your own, let alone the time they save you. And unlike with Home Assistant, they’re even for free.
And in this case optional. That’s something that doesn’t apply for most cloud services.

Sorry if I sound condescending, but if you are exposing the OH instance to the public internet, you are practically making it a cloud service. I agree with Markus, using myopenhab and having the OH instance completely behind a firewall is much more secure.

The other option is to only allow access via a VPN.

That’s what they also said about Lastpass. I’m not a fan of the “Put it all into the Cloud” mentality. A cloud service like that, giving access to thousand of Smart homes where some even have alarm systems is a big honey pot, just screaming to be breached.

And you are assuming that everyone who uses a Nginx as reverse proxy, wants to expose Nginx to the Internet. Let me tell you that there are plenty of scenarios where you would use a reverse proxy without exposing it to the Internet directly, one is having an SSO system (Single Sign On) system, inside a private network behind a VPN.
And sorry no, your cloud service is not more secure than something not directly exposed to the Internet.

So I would kindly ask you to not assume what people need and want and also respect their security concerns, even if your cloud service is super secure, but we can only assume how secure it is.

And asking how the authentication in Openhab works is a valid question and I think Openhab should have more documentation about how the UI authentication works, maybe even behind a reverse proxy.

I personally had a bad experience, I used a cloud VM advertised by a well know German internet provider (paid service). The service was shut down without any warning and the contract was not with the internet provider but a sub-company. I had no chance to access the VM one last time.
That’s why I don’t want any external dependencies.

The risks I see

  • API changes, breaking the deployment
  • No resources (financial and man power) to keep the services running
  • As Berni said: Honeypot

From a security concept: NGINX is only hosting the openhab instance and uses a letsencrypt certificate. My customer has a fixed Ip and a dns record pointing to it.
User access is htpasswd based.
All necessary software modules are in an isolated docker network.

Without being a security expert: If this is not secure we would have a problem with a lot of internet services.

So I am definitely interested in a NGINX user authentication solution.

There aren’t any? myopenhab is not a cloud service in that the openhab instance is running in the cloud.
It’s rather an application layer reverse proxy running on some cloud server but openHAB will keep running on your local system.
Local access to that will continue to work should the cloud service ever go down.
You can also still access it e.g. through VPN if you use openHABian.
Hell you could even setup nginx in addition to that if you’re afraid of that (not advisable from a price-use-ratio perspective, but possible).
That’s barely the same situation as the one you encountered, isn’t it.

The openHAB cloud connector (API) is a central part of the openHAB project, same developers work on both sides of the API and ensure it will keep working with every openHAB change.

myopenhab servers are financed and operated by the openHAB foundation. Yeah that organization you and I are a member of. We are paying these cloud servers.

Well if by all means you want to use that term, it’s a joint honeypot with tens of thousands of likewise potential victims behind.
It depends on the username which local oh instance an access attempt is proxied to (after successful auth only, of course).
Even if compromised, the probability of some bad guy hitting you is 1:x0000.

With being one (worked as one in years): complexity and domains all by themselves don’t help security, it’s rather the opposite, particularly if you’re alone in the wild supporting this the risk of making an unspotted error in maintaining that is a lot higher than if you have a group of experts doing this for you and some 10k others.

Well if you really want to spend your valueable time, feel free. You could check if the nginx install option in openHABian is still generating a working nginx setup. Last time I checked it did, but as said, been there, invested way too much time, and moved on (although it worked, but the cost ratio of that solution is extremely bad).

In the end only you (or rather your customer in this case) can decide what level of security is enough when considering the impact of someone gaining access to the OH instance. But the decision should be based on a proper risk analysis, and not on assumptions.

But to answer some of your assumptions:

This does nothing to increase the security of the OH instance from direct attacks (e.g., trying to brute-force passwords), it only prevents man-in-the-middle attacks (sniffing or modifying traffic already in transit). But it should of course be used since the passwords are otherwise sent in the clear.

This is the only thing standing between an attacker and the OH instance.

This prevents lateral movement inside the network if an attacker has already compromised OH (and can execute arbitrary code/commands). It doesn’t protect OH itself since there’s a port open for it.

Even with myopenhab.org I don’t think you can get away from this. You have two sets of user accounts which are completely separate and independently managed and authenticated against. You have one set that allows access to OH in the first place which, in your case, is controlled by NGINX. The second is the OH users themselves. This set is managed by OH and this is where you define whether someone is a user role or an admin role.

You can enable the implicit user role (it’s enabled by default) and eliminate the second login for regular users. They’d just have to enter the credentials for NGINX and be able to do all the normal user stuff (essentially they only have access to the Items and UI REST API endpoints of OH, none of the administration endpoints). However, the admin user would need to log in again to OH itself in order to access the admin features.

There is no way I know of to combine these two separate sets of credential subsystems so only one loging is allowed. Even with myopenhab.org and the phone apps you have to log in twice to access admin features.

The difference here is the software that runs myopenhab.org is itself also open source and you can find it here. Many can and do deploy their own instance of using the foundation provided cloud server instance. You’ll never be left without recourse if myopenhab.org closes down or you can deploy it yourself on a VPS.

All the API changes that occur are really outside our control. For example, Google changed up their GA API which required changes in the cloud server which impacted those users who use GA integration. If you don’t use that though, the cloud server API is very stable. But again, you can deploy your own “encased in amber” version that will never change. I can’t say I recommend doing so for anything Internet exposed but as @berni points out, we don’t know that’s what you are doing.

Do you mean the foundation or you? If you mean the foundation, then you have the option to deploy your own cloud server. If you mean you (or your client), well evey approach is going to require ongoing resources to keep running. If it’s internet exposed those resources are going to be significnatly more than for something not exposed to the internet (you must keep everything up to date, deal with breaking changes caused by keeping everything up to date, continuously monitor the service for signs of compromise, etc).

A better approach for something like this would be to host your own instance of the cloud server on a VSP. That way when/if it’s compromised there is no path for the attackers to get back to your LAN. If your NGINX instance gets compromised, the attacker is inside your network.

Ultimately though, because there are two sets of credentials processed by two separate mechanisms, I think you’ll always require two logins for the admin user, assuming you’;ve enabled the implicit user role.


At the risk of being pedantic, the use of the term “honeypot” on this thread is not technically correct (as a technical term in security engineering). A honeypot is a service whose only purpose is to be attacked so network defense analysts can detect and study attempts to attack a network or service. A honeypot never has operational data in it and it never actually performs any useful function. It’s entier reason for being is to look entiing to attackers and when attacked to report how it’s being attacked.

The myopenhab.org service might be an attractive target but that does not make it a honeypot. This is an example of a honeypot.

1 Like

Honey pot can have different meaning, but that’s just definition.

Anyways, I want to come back to @marco_hoefle’s original question and I have a working solution now that uses the simple API tokens for all API requests that go to Openhab.
My personal usecase for this is using my SSO login system with Openhab in combination with OAuth2proxy (my Openhab is not exposed to the Internet at all, just to mention it again). And of course after logging into my SSO, I don’t want to log in into Openhab additionally, but be auto-logged in. This is something that Myopenhab doesn’t provide and also Openhab doesn’t provide any support for Proxy managed authentication at the moment (Would be very nice to have that!).

So I did some analyzes in the Openhab Core Code, the Web-UI code and inspected the network requests.
Fun fact besides: During my research I found a vulnerability in the Main UI in the OAuth2 code. Will probably open up an issue for that.

So basically the Main UI uses OAuth2 authentication, to authenticate against the Openhab Backend. Unfortunately the UI only supports that way and doesn’t allow any proxy-controlled login (it seems).

So what the UI does is:

  • Send a login with POST to /auth
  • Openhab responds with a HTTP redirect to /?code=sometoken&state=someuigeneratedsecrettheuiwillcheck
  • Then the UI sends a POST HTTP request to /rest/auth/token?useCookie=true and the UI client receives an access_token and a refresh_token.
  • The UI will then periodically call that token endpoint again to refresh the token.

This is a rough overview of the authentication, but basically that’s how it works.

In order to make the automatic login with Nginx proxy works I’ve replaced the complicated Oauth2 login with the API tokens you can create in Openhab user profile.

In Nginx config I did the following:

  • Some Nginx config that tricks the UI into thinking that there is a successful login with an administrator account (not insecure because just UI stuff). Basically it will use Javascript to set a dummy value for the refresh token and satisfy the token request with a proper user info response.
  • Replace the X-Openhab-Token HTTP header with a static Bearer token generated on the /createApiToken page, that doesn’t require complicated OAuth2 mechanisms. This Authorization Bearer token will only be passed by Nginx to all calls to Openhab, so the client actually never receives that token.

Some warnings at this point:

  • This is only as secure as your Proxy authentication and your network infrastructure. It’s up to you to secure your Nginx with proper authentication.
  • There might be some way the logged in user can use the API to create new users or token, haven’t tested that. Keep that in mind when revoking access to some user.
  • This Nginx config can break with future Openhab versions, as it sets some variable in the Local browser storage that is used by the UI internally, this is not officially supported. Hopefully there will be some supported way to do proxy managed Openhab-authentication in the future.

I’ve used the existing Nginx config from the Doc and added some authentication config.

server {
    listen                          80;
    server_name                     mydomain_or_myip;
    return 301                      https://$server_name$request_uri;
}
server {
    listen                          443 ssl;
    server_name                     mydomain_or_myip;

    # Cross-Origin Resource Sharing.
    add_header 'Access-Control-Allow-Origin' '*' always;
    add_header 'Access-Control-Allow_Credentials' 'true' always;
    add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range' always;
    add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH' always;

    # openHAB 3 api authentication
    add_header Set-Cookie X-OPENHAB-AUTH-HEADER=1;

    ssl_certificate                 /etc/letsencrypt/live/mydomain/fullchain.pem; # or /etc/ssl/openhab.crt
    ssl_certificate_key             /etc/letsencrypt/live/mydomain/privkey.pem;   # or /etc/ssl/openhab.key
    add_header                      Strict-Transport-Security "max-age=31536000"; # Remove if using self-signed and are having trouble.

    location / {
        # Auto login
        if ($http_cookie !~* "X-OPENHAB-NGINX-PROXY-LOGGED-IN") {
            # Client hasn't visited our nice dummy token page yet
            return 302 /auth;
        }

        proxy_pass                              http://localhost:8080/;
        proxy_set_header Host                   $http_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 Upgrade                $http_upgrade;
        proxy_set_header Connection             "Upgrade";
        # Replace the token below with a real one from https://yourdomain/createApiToken
        proxy_set_header Authorization          "Bearer oh.tokenname.abcdefghjiklmnoqrstuvy";
        # The backend should not parse the X-Openhab-Token header the UI sends, unset it.
        proxy_set_header X-Openhab-Token        "";
        satisfy                                 any;
        allow                                   192.168.0.0/24;
        allow                                   127.0.0.1;
        deny                                    all;
        auth_basic                              "Username and Password Required";
        auth_basic_user_file                    /etc/nginx/.htpasswd;
    }

    location = /auth {
        # Using a cookie, remember that the client is already "logged in".
        add_header Set-Cookie "X-OPENHAB-NGINX-PROXY-LOGGED-IN=1; Path=/; Max-Age=31536000; HttpOnly";
        add_header Content-Type "text/html";
        # Don't cache this response
        add_header Cache-Control "no-cache, no-store, must-revalidate";
        add_header Pragma "no-cache";
        add_header Expires "0";

        # Set a dummy token in the clients browser and then redirect
        return 200 '<script>
                localStorage.setItem("openhab.ui:refreshToken", "dummy");
                window.location.href = "/";
            </script>';
    }

    location = /rest/auth/token {
        add_header Content-Type "application/json";
        return 200 '{
            "access_token": "dummy",
            "token_type": "bearer",
            "expires_in": 3600,
            "refresh_token": "dummy",
            "scope": "admin",
            "user": {
                "name": "admin",
                "roles": [
                    "administrator"
                ]
            }
        }';
    }

    #### When using Let's Encrypt Only ####
    location /.well-known/acme-challenge/ {
        root                                    /var/www/mydomain;
    }
}

The API token can be generated @ the /createApiToken. I think as scope you have to specify admin.
With some conditions in Nginx you could probably also use either an admin or user role depending on the user name, but for now only one user/role is supported.

There are many things that would be great to add to OH authentication that are only awaiting a volunteer to implement. Consider this reply and this entire thread a call for volunteers!

Please do. You can report security vulnerabilities through the Security tab in github for any of the openHAB repos.

2 Likes