Openhab con NGINX (reverseproxy)

Configurazione Proxy NGINX per Openhab

L'obiettivo è configurare una connessione sicura (HTTPS) su Openhab per permettere l'esposizione diretta su internet del vostro Openhab senza usare il servizio Cloud.

Condizione essenziale è avere un IP pubblico fisso o una configurazione DDNS e permettere il portforwarding della porta 443 (o quella che volete configurare) sul vostro router verso l'host di openhab.

Inoltre servirà avere dei certificati digitali che possono essere autoprodotti (selfsigned) oppure possono essere generati con il servizio di Letsencrypt che genererà certificati gratuiti della durata di 3 mesi ma con una CA riconosciuta dai principali browser.

Configurazione DNS

Per usare un DDNS ho trovato comodo DukeDns, creare un account e registrare il nome host corrispondente al vostro host.

Alla pagina DuckDNS installa il client adatto al tuo host.

Generazione dei certificati (sceglierne uno)

Certificati SELFSIGNED

Installare OpenSSL:

sudo apt-get install openssl

Una volta completato, è necessario creare una directory in cui posizionare i nostri certificati:

sudo mkdir -p /etc/ssl/certs

Generiamo con OpenSSL una chiave RSA lunga 2048 bit e un certificato valido per un anno (ci metterà diverso tempo):

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/openhab.key -out /etc/ssl/openhab.crt

Ti verranno chieste alcune informazioni che dovrai compilare per il certificato, quando ti verrà richiesto un nome comune , puoi inserire il tuo indirizzo IP: Nome comune (es. FQDN del server o TUO nome) []: xx.xx. xx.xx

Certificati Letsencrypt(https://letsencrypt.org/)

Usando il servizio DDNS di DuckDns abbiamo bisogno di creare i certificati digitali con il metodo trovato da jmorahan, quindi creiamo questo due script nella HOME di openhabian sostituendo il valore del tuo TOKEN preso da DuckDns:

auth.sh

#!/bin/bash 
DUCKDNS_TOKEN="your_token_here" 
[[ "$(curl -s "https://www.duckdns.org/update?domains=${CERTBOT_DOMAIN%.duckdns.org}&token=${DUCKDNS_TOKEN}&txt=${CERTBOT_VALIDATION}")" = "OK" ]]

cleanup.sh

#!/bin/bash 
DUCKDNS_TOKEN="your_token_here" 
[[ "$(curl -s "https://www.duckdns.org/update?domains=${CERTBOT_DOMAIN%.duckdns.org}&token=${DUCKDNS_TOKEN}&txt=${CERTBOT_VALIDATION}&clear=true")" = "OK" ]]

Concediamo le autorizzazioni di esecuzioni:

chmod +x auth.sh cleanup.sh

Procediamo con il processo di verifica lanciando:

sudo certbot certonly --manual --preferred-challenges dns --manual-auth-hook ./auth.sh --manual-cleanup-hook ./cleanup.sh

Installazione e configurazione NGINX

Usiamo lo strumento di configurazione di Openhab:

sudo openhabian-config

Scegliere una USERNAME e una PASSWORD e concludere la procedura con l'installazione automatica dei pacchetti necessari.

Il file di configurazione che ne consegue dovrebbe essere una cosa del genere sotto il path /etc/nginx/sites-enabled/openhab:

#################################
# openHABian NGINX Confiuration #
#################################

## Redirection
server {
   listen                          80;
   server_name                     hostname.duckdns.org;
   return 301                      https://$server_name$request_uri;
}

## Reverse Proxy to openHAB
server {
#    listen                          80;
   listen                          443 ssl;
    server_name                     hostname.duckdns.org;
   add_header                      Strict-Transport-Security "max-age=31536000; includeSubDomains";

    # Cross-Origin Resource Sharing.
 add_header 'Access-Control-Allow-Origin' 'http://localhost:8080/rest';
    add_header 'Access-Control-Allow_Credentials' 'true';
    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';
    add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH';

## Secure Certificate Locations
   ssl_certificate                 /etc/letsencrypt/live/hostname.duckdns.org/fullchain.pem;
   ssl_certificate_key             /etc/letsencrypt/live/hostname.duckdns.org/privkey.pem;

   ssl_protocols                   TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers       on;
    ssl_dhparam                     /etc/nginx/ssl/dhparam.pem;
    ssl_ciphers                     ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:HIGH:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!CBC:!EDH:!kEDH:!PSK:!SRP:!kECDH;
    ssl_session_timeout             1d;
    ssl_session_cache               shared:SSL:10m;
    keepalive_timeout               70;


location / {
        proxy_pass                              http://localhost:8080/;
#        proxy_buffering                         off;  # openHAB supports non-buffering specifically for SSEs now
        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;

# Password Protection
       auth_basic                              "Username and Password Required";
       auth_basic_user_file                    /etc/nginx/.htpasswd;
    }

## Let's Encrypt webroot location
#   location /.well-known/acme-challenge/ {
#       root                                    /var/www/hostname.duckdns.org;
#   }
}

# vim: filetype=conf

Verifica impostazioni di sicurezza

Puoi testare le tue impostazioni di sicurezza su SSLLABS (assicurati di selezionare "Non mostrare i risultati nelle schede" se non desideri che il tuo dominio venga visualizzato)

Se vogliamo raggiungere migliori livelli di sicurezza dobbiamo generare delle chiavi più sicure:

sudo mkdir -p /etc/nginx/ssl
sudo openssl dhparam -out /etc/nginx/ssl/dhparam.pem 4096

Inseriamo nella parte degli SSL certificate queste direttive (assicurati che siano sopra le location)

ssl_protocols                   TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers       on;
ssl_dhparam                     /etc/nginx/ssl/dhparam.pem;
ssl_ciphers                     ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:HIGH:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!CBC:!EDH:!kEDH:!PSK:!SRP:!kECDH;
ssl_session_timeout             1d;
ssl_session_cache               shared:SSL:10m;
keepalive_timeout               70;

Gestione NGINX

Per aggiungere un nuovo utente:

sudo htpasswd /etc/nginx/.htpasswd {username}

Per rimuovere un utente:

sudo htpasswd -D /etc/nginx/.htpasswd {username}

Per rilanciare il NGINX:

sudo systemctl restart nginx.service    

Link utili

Massimiliano Casini (Coordinatore tecnico Service Assurance presso www.kenamobile.it)
Sono cresciuto nel modo IT di aziende ad alto contenuto tecnologico e da sempre ho acquisto esperienze nel settore della domotica e sicurezza residenziale. Negli ultimi dieci anni ho acquisito competenze specifiche nel campo delle TLC in particolare sulla rete GSM e sui protocolli ad essa collegati.