openHAB2 + Apache2 reverse-proxy + LDAP authentication + HTTPS + URL-path-prefix
This tutorial describes how to get openHAB2 running with
- LDAP-authentication
- HTTPS
- URL-path-prefix (e.g. “https://myserver/openhab/” instead of directly “https://myserver/”)
using an Apache2 reverse-proxy (to be precise, my system is: Apache 2.4.7 on Ubuntu-server 14.04.5).
According to this forum thread it is not possible to configure a path-prefix with NGINX. With Apache2, however, I succeeded in doing so.
Apache2 modules
You can see in /etc/apache2/mods-enabled/
which modules are already enabled. To see what’s installed, look into /etc/apache2/mods-available/
.
To install a module, you should use your OS package manager – in case of Debian/Ubuntu and the like, that’s apt-get
. I’m sorry, but I can’t tell you for sure what packages you need to install, but based on dpkg -S xxx
, I think all you need is:
apt-get install apache2 libldap-2.4-2
If you follow this tutorial with a vanilla installation from scratch, please provide feedback, if this is fine or if you need more.
To enable a module, which is already installed, use:
a2enmod xxx
…for example:
a2enmod proxy_wstunnel
Here’s the content of my /etc/apache2/mods-enabled/
(created with ls|sort
):
- access_compat.load
- alias.conf
- alias.load
- auth_basic.load
- authn_core.load
- authn_file.load
- authnz_ldap.load
- authz_core.load
- authz_groupfile.load
- authz_host.load
- authz_svn.load (not needed)
- authz_user.load
- autoindex.conf
- autoindex.load
- dav.load (not needed)
- dav_svn.conf (not needed)
- dav_svn.load (not needed)
- deflate.conf
- deflate.load
- dir.conf
- dir.load
- env.load
- filter.load
- headers.load
- ldap.conf
- ldap.load
- mime.conf
- mime.load
- mpm_prefork.conf
- mpm_prefork.load
- negotiation.conf
- negotiation.load
- php5.conf (not needed)
- php5.load (not needed)
- proxy.conf
- proxy_html.load
- proxy_http.load
- proxy.load
- proxy_wstunnel.load
- rewrite.load
- setenvif.conf
- setenvif.load
- socache_shmcb.load
- ssl.conf
- ssl.load
- status.conf
- status.load
- substitute.load
- xml2enc.load
My Apache2 is used for other stuff, too, hence there are modules that are probably not needed for you to run openHAB. Because I have no time to disable them and test, if openHAB still runs, I have simply listed all my modules above and marked those that I believe to be unnecessary.
Apache2 config file default-ssl.conf
I assume you already configured /etc/apache2/sites-enabled/default-ssl.conf
properly and are able to access “https://yourserver/” with a browser. If no, please consult other docs on how to set up HTTPS.
IMHO the easiest editor is mcedit
– if you don’t have it, install it:
apt-get install mc
Then edit the configuration file:
mcedit /etc/apache2/sites-enabled/default-ssl.conf
At the end, before </VirtualHost>
, you add one Include
line:
# ... lots of other stuff ... leave this unchanged!
Include /etc/apache2/openhab/openhab-ssl.conf
</VirtualHost>
</IfModule>
Apache2 config file openhab-ssl.conf
The include-file needs to be created by you. First create the directory:
mkdir /etc/apache2/openhab/
Then create the file:
mcedit /etc/apache2/openhab/openhab-ssl.conf
…and put the following content:
<Location "/openhab">
Options SymLinksIfOwnerMatch
AuthType Basic
AuthName "openHAB"
## BEGIN LDAP
AuthLDAPURL "ldap://localhost:389/ou=person,dc=codewizards,dc=co?cn?sub?(objectClass=person)"
AuthLDAPBindDN "cn=____________,ou=daemon,ou=person,dc=codewizards,dc=co"
AuthLDAPBindPassword "___________________________________"
AuthBasicProvider ldap
Require valid-user
## END LDAP
RewriteEngine On
RewriteRule "/openhab/openhab/(.*)" "/openhab/$1" [R,L]
RewriteRule "/openhab/?(.*)" "http://localhost:10080/$1" [P,L]
# LogLevel alert rewrite:trace8
## We cannot use ProxyPass, because this implicitly adds its own rewrite-rules *before* ours!
## Hence, we cannot redirect the browser from .../openhab/openhab/... to .../openhab/...!
# ProxyPass http://localhost:10080
ProxyPassReverse http://localhost:10080
ProxyHTMLEnable On
## The ProxyHTMLExtended can be used to work on *embedded* JavaScript. It does not work
## on separate .js-files. Thus, I now use SUBSTITUTE instead -- which works on both separate
## and embedded. Thus, this ProxyHTML* is not needed, anymore.
# ProxyHTMLExtended On
# ProxyHTMLURLMap / /openhab/ [e]
# ProxyHTMLURLMap /basicui /openhab/basicui
# ProxyHTMLURLMap /openhab/basicui /openhab/basicui
## Seems the suppression of gzip is not needed. Found this hint in the web,
## before, but the problem was actually another one. Thus, commented the following line
## again.
## UPDATE: IT IS NEEDED! My smarthome.js was obviously cached, before.
RequestHeader unset Accept-Encoding
AddOutputFilterByType SUBSTITUTE text/html
AddOutputFilterByType SUBSTITUTE text/css
AddOutputFilterByType SUBSTITUTE application/javascript
AddOutputFilterByType SUBSTITUTE application/json
Substitute "s|/basicui/|/openhab/basicui/|n"
Substitute "s|/rest/|/openhab/rest/|n"
Substitute "s|'/rest'|'/openhab/rest'|n"
Substitute "s|/paperui/|/openhab/paperui/|n"
Substitute "s|/inbox/|/openhab/inbox/|n"
Substitute "s|/icon/|/openhab/icon/|n"
Substitute "s|http://|https://|n"
</Location>
You must adapt all the stuff between ## BEGIN LDAP
and ## END LDAP
to your local environment. Please consult mod_authnz_ldap for details. Btw. I’m using the Apache Directory Server (not allowed to link it) listening on localhost:389
(using setcap 'cap_net_bind_service=+ep' /usr/lib/jvm/java-8-oracle/jre/bin/java
).
Additionally, you must either change your openHAB2 server to listen on localhost:10080
(see below) or change the port 10080 to the default 8080.
You probably do not need to change anything else. However, I left a few comments from my experiments to give a bit more background info.
For explanation:
-
We need the rewrite-rule
RewriteRule "/openhab/openhab/(.*)" "/openhab/$1" [R,L]
, because some URLs are sent relative and then resolve to a duplicate “openhab/openhab/”. This rule sends the browser a redirect to the proper (non-duplicate) path. -
The rule
RewriteRule "/openhab/?(.*)" "http://localhost:10080/$1" [P,L]
replaces the simpleProxyPass
directive. As you can see, this is the 2nd rule. If we use the easierProxyPass
instead (which I first did), then the rewrite-engine gets only proxied URLs to see, because the proxying happens first. However, our deduplication-rewrite-rule (see above) must be first, before any proxying is done. That’s why, we do not useProxyPass
and instead “manually” configure the proxying using this “RewriteRule” directive. -
We still keep the
ProxyPassReverse
though. It rewrites URLs into the opposite direction – e.g. if the openHAB server responds with a HTTP redirect, this makes sure our client does not get the internal URL, but the correct, external one. -
I’m not sure whether the
ProxyHTMLEnable On
is still needed or whether theSUBSTITUTE
would be sufficient. This directive causes links in HTML documents to be rewritten. It currently works this way and I have no time to experiment with it being omitted. Please feel free to test and give feedback! -
The
RequestHeader unset Accept-Encoding
suppresses compression. Without it, openHAB would return gzipped data and ourSUBSTITUTE
would not work (because its rules don’t match the compressed content). -
All the
SUBSTITUTE
stuff below causes the entire content (HTML, CSS, JavaScript, JSON) to be string-replaced so that the URLs returned to the browser contain the “openhab/” URL-path-prefix. Maybe this list is still not complete – however it seems to work fine for me for a few days, already.
It seriously sucks that openHAB does not support to configure an URL-path-prefix or at least uses a hard-coded one. To write string-replacement-rules for replacing one single path-prefix by another one (e.g. to map “openhab/” to “oh/”) would be far easier and more reliable than to deal with all the paths individually ("/basicui/", “/rest”, “/icon/” etc.). But this is the way, it currently is, and the list of replacement-rules seems pretty complete. This might easily break with the next openHAB-release, though
Make openHAB2 listen on localhost:10080 only
By default, openHAB2 listens on all network interfaces on the ports 8080 (HTTP) and 8443 (HTTPS). In order to make it listen only on localhost
(more secure!) and on another port (to prevent collisions with other services) you do the following:
Create the file openhab/conf/services/org.ops4j.pax.web.cfg
and put the following content:
## See: https://ops4j1.jira.com/wiki/display/paxweb/Basic+Configuration
## We listen on localhost only, because we use the Apache2 as a facade proxy.
## This way, we can use Apache's LDAP authentication and Apache's HTTPS.
org.ops4j.pax.web.listening.addresses=127.0.0.1
## We disable SSL, because our facade-proxy (Apache) is doing SSL with the proper cert.
org.osgi.service.http.secure.enabled=false
## We listen on port 10080 internally (on localhost), while the facade proxy does
## HTTPS on 443 and HTTP for the intellihouse-OpenPGP-encrypted stuff on 80.
org.osgi.service.http.port=10080
After restarting openHAB2, it should listen on port 10080 on IP 127.0.0.1 (localhost), only. You can check this with netstat -lntp
.
It is important that the port configured here matches the reverse-proxy-configuration of your openhab-ssl.conf
above!
Restart Apache2
When your configuration is complete, you must restart the server:
service apache2 restart
That’s it. If there are no errors and your openHAB2 server is running, you should now be able to access it with your browser.
I hope this tutorial is helpful!
Cheers, Marco