Markdown source

# Openhab con NGINX (reverseproxy)

<abstract>
Configurazione Proxy NGINX per Openhab
</abstract>

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](https://letsencrypt.org/) 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 [DuckDNS](https://duckdns.org), creare un account e registrare il nome host corrispondente al vostro host.

Alla pagina [DuckDNS](https://www.duckdns.org/install.jsp) 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/private/openhab.key -out /etc/ssl/certs/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

Rinominare il certificato in .pem

	sudo mv /etc/ssl/certs/openhab.crt /etc/ssl/certs/openhab.pem


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

Usando il servizio DDNS di DuckDns abbiamo bisogno di creare i certificati digitali con il metodo trovato da [jmorahan](https://community.letsencrypt.org/t/raspberry-pi-with-duckdns-ddns-failing-to-verify/53567/8), quindi creiamo questo due 
script nella HOME di openhabian sostituendo il valore del tuo TOKEN preso da DuckDns:
		
<img src="./REVERSE_PROXY_IMAGE_15.jpg" class="img-responsive center-block">
		
		
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

I certificati avranno scadenza 90 giorni, potranno essere rinnovati con il comando:
	
	certbot renew --pre-hook "service nginx stop" --post-hook "service nginx start"

## Installazione e configurazione NGINX

Usiamo lo strumento di configurazione di Openhab:
	
		
	sudo openhabian-config
		
<img src="./REVERSE_PROXY_IMAGE_1.jpg" class="img-responsive center-block">
<img src="./REVERSE_PROXY_IMAGE_2_2.jpg" class="img-responsive center-block">
<img src="./REVERSE_PROXY_IMAGE_2_3.jpg" class="img-responsive center-block">
	
	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 (caso SELFSIGNED):	

		#################################
		# openHABian NGINX Confiuration #
		#################################
		
		## Redirection
		server {
		   listen                          80;
		   server_name                     IPPUBBLICO;
		   return 301                      https://$server_name$request_uri;
		}
		
		## Reverse Proxy to openHAB
		server {
		#    listen                          80;
		   listen                          443 ssl;
		   server_name                     IPPUBBLICO;
		   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/ssl/certs/openhab.pem;
		   ssl_certificate_key             /etc/ssl/private/openhab.key;
		
		    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;
		    }
		
		}

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

	

	#################################
	# 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;
	    }
	}
	
	

## Eventuali problemi
Se la chiave ssl_dhparam non è presente generarla:

	sudo openssl dhparam 2048 -out /etc/nginx/ssl/dhparam.pem

## Verifica impostazioni di sicurezza	

Puoi testare le tue impostazioni di sicurezza su [SSLLABS](https://www.ssllabs.com/ssltest/)
(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

* [OpenhabDoc](https://www.openhab.org/docs/installation/security.html)	
* [OpenhabRemoteAccess](https://www.smarthomeblog.net/openhab-reverse-proxy/)
* [SSLLABS](https://www.ssllabs.com/ssltest/)
* [Letsencrypt](https://letsencrypt.org/)

@include='bio_massimiliano_casini'