Tuesday, January 17, 2017

OpenHAB nginx proxy based on user agent

This post will cover using an nginx server to conditionally proxy_pass to OpenHAB based on if the URL is being requested from the OpenHAB iOS App determined by the user agent of the request.
My setup has 3 machines of relevance:
  • Machine A hosts software known as BlueIris. This software records network enabled camera streams to disk, provides interfaces to review this footage, and can push alerts to iOS apps. This machine is not routable to the internet
  • Machine B is a Raspberry Pi 3 running OpenHAB 1.X. This machine is also not routable to the internet. 
  • Machine C is a Raspberry Pi 3 with nginx acting as a proxy. It has an SSL certificate from LetsEncrypt. It is routable to the internet, having dual homes. 
The desire is to route all traffic to Machine A, unless the request is coming from an application with the user agent containing "OpenHAB". This will be accomplished using "evil ifs". This method works for me, but your mileage may vary.



Configuring BlueIris or OpenHAB is not covered in this article. Nor is installing/compiling nginx. These tasks are documented elsewhere.
I strongly recommend you configure OpenHAB to have user authentication if you are opening this directly to the internet, as I show below.

Below is the configuration that works for me. It essentially does the following:
  1. Store 0 in $switch (the default behavior desired)
  2. If the user agent contains the case insensitive string "OpenHAB", store 1 in $switch
  3. If $switch is 0, route the request to Machine A
  4. If $switch is 1, route the request to Machine B 
Note all of the proxy header directives. For a while I was having issues where OpenHAB was returning a URL to the iOS client of "http://openhab/static/blah", causing the iOS client to give an error that the host would not be resolved. All of these settings appear important, but most important is the proxy_set_header   Host directive.

#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;
    keepalive_timeout  65;

    upstream BlueIris {
        server 10.0.0.5:80;
        keepalive 5;
    }
    upstream OpenHAB {
        server 10.0.0.4:8080;
        keepalive 5;
    }
    server {
        listen       80;
        server_name  localhost subdomain.domain.tld;

        location / {
                set $switch 0;
                if ($http_user_agent ~* OpenHAB) {
                    set $switch 1;
                }
                proxy_bind 10.0.0.100;
                if ($switch = 0) {
                    proxy_pass http://BlueIris;
                }
                if ($switch = 1 ) {
                    proxy_pass http://OpenHAB;
                }
                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_http_version 1.1;
                proxy_set_header Connection "";
        }
   
    listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/xxxxxx/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/xxxxxx/privkey.pem; # managed by Certbot
ssl_session_cache shared:le_nginx_SSL:1m; # managed by Certbot
ssl_session_timeout 1440m; # managed by Certbot

ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # managed by Certbot
ssl_prefer_server_ciphers on; # managed by Certbot

ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-ECDSA-AES128-SHA ECDHE-ECDSA-AES256-SHA ECDHE-ECDSA-AES128-SHA256 ECDHE-ECDSA-AES256-SHA384 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-RSA-AES256-GCM-SHA384 ECDHE-RSA-AES128-SHA ECDHE-RSA-AES128-SHA256 ECDHE-RSA-AES256-SHA384 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES128-SHA DHE-RSA-AES256-SHA DHE-RSA-AES128-SHA256 DHE-RSA-AES256-SHA256 EDH-RSA-DES-CBC3-SHA"; # managed by Certbot



    if ($scheme != "https") {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    }
}


No comments:

Post a Comment