Thinger.io es una infraestructura en la nube escalable que permite conectar millones de dispositivos conectados a Internet (Internet of Things). Esto permite controlarlos a través de una consola de administración simple de utilizar, o integrarlos en la lógica de nuestro negocio mediante una API REST.
A su vez, Thinger.io es un proyecto open source que permite instalar el servidor en nuestra propia nube y utilizar las librerías (también open source) para conectar nuestros dispositivos. Thinger.io soporta todo tipo de dispositivos como Arduino, ESP8266, Raspberry Pi, Intel Edison y muchos otros.
Veamos entonces cómo montar nuestro propio servidor Thinger.io en un servidor corriendo Debian Stretch (9).
Ahora bien, luego de esta bonita y breve introducción a Thinger.io que destaca todas sus cualidades, la realidad es que a simple vista el proyecto tiene poco de open source (mas bien "obfuscated source" diría, si es que existe dicho término). Basta con ver la página oficial del proyecto en GitHub:

Al menos al 16 de febrero de 2018 no hay un sólo archivo fuente en el repositorio del servidor. No entiendo cómo se puede llamar a un proyecto open source sin publicar el código fuente, ¿no se trata de justamente eso el openness? En fin, de todas formas vamos a instalarlo.
Por otro lado debo decir que la documentación es escasa e incompleta. Especialmente la sección de instalación y configuración del servidor. Es por ello que decidí escribir este artículo.
El motivo de usar un proxy reverso con Nginx consiste en permitir el uso de Certbot para generar certificados TLS gratuitos y a su vez mejorar la implementación de HTTPS (hardening).
Instalación del servidor Thinger.io
Como requisito para instalar un servidor Thinger.io en Debian, se debe partir de la versión 9 ("Stretch") o superior. Lamentablemente no es posible partir desde una instalación de Devuan (hasta el momento), ya que el servidor Thinger.io se distribuye sólo como paquete snap, y el utilitario para instalar dichos paquetes (snapd) depende de systemd.
El primer paso entonces consiste en actualizar el sistema operativo:
root@iot:~# apt-get -y update && apt-get -y upgrade
Luego instalar el servidor de bases de datos NoSQL MongoDB:
root@iot:~# apt-get -y install mongodb-server
Verificar que MongoDB esté levantado y aceptando peticiones en el puerto 27017
:
root@iot:~# netstat -tulpn | grep mongo tcp 0 0 127.0.0.1:27017 0.0.0.0:* LISTEN 2490/mongod
A su vez es posible comprobar el estado del demonio a través de systemctl
:
root@iot:~# systemctl status mongodb.service ● mongodb.service - An object/document-oriented database Loaded: loaded (/lib/systemd/system/mongodb.service; enabled; vendor preset: enabled) Active: active (running) since Thu 2018-02-15 21:05:26 UTC; 4min 48s ago Docs: man:mongod(1) Main PID: 2490 (mongod) Tasks: 16 (limit: 4915) CGroup: /system.slice/mongodb.service └─2490 /usr/bin/mongod --unixSocketPrefix=/run/mongodb --config /etc/mongodb.conf Feb 15 21:05:26 iot systemd[1]: Started An object/document-oriented database.
El siguiente paso consiste en instalar snapd:
root@iot:~# apt-get -y install snapd
Ahora es posible instalar el paquete snap "thinger-maker-server", simplemente ejecutando snap install thinger-maker-server
:
root@iot:~# snap install thinger-maker-server thinger-maker-server 1.3.0 from 'thinger' installed
Una vez más, verificar el funcionamiento del servidor Thinger.io mediante systemctl
:
root@iot:~# systemctl status snap.thinger-maker-server.thingerd.service ● snap.thinger-maker-server.thingerd.service - Service for snap application thinger-maker-server.thingerd Loaded: loaded (/etc/systemd/system/snap.thinger-maker-server.thingerd.service; enabled; vendor preset: enabled) Active: active (running) since Thu 2018-02-15 21:08:24 UTC; 1min 13s ago Process: 3048 ExecStart=/usr/bin/snap run thinger-maker-server.thingerd (code=exited, status=0/SUCCESS) Main PID: 3060 (thingerd) Tasks: 2 (limit: 4915) CGroup: /system.slice/snap.thinger-maker-server.thingerd.service └─3060 thingerd --fork --runpath=/var/snap/thinger-maker-server/common Feb 15 21:08:20 iot systemd[1]: Starting Service for snap application thinger-maker-server.thingerd... Feb 15 21:08:20 iot /usr/bin/snap[3048]: cmd.go:105: DEBUG: restarting into "/snap/core/current/usr/bin/snap" Feb 15 21:08:24 iot systemd[1]: Started Service for snap application thinger-maker-server.thingerd.
Y comprobar que esté aceptando peticiones en los puertos 80
, 443
, 25200
y 25202
:
root@iot:~# netstat -tulpn | grep thinger tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 3060/thingerd tcp 0 0 0.0.0.0:25200 0.0.0.0:* LISTEN 3060/thingerd tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 3060/thingerd tcp 0 0 0.0.0.0:25202 0.0.0.0:* LISTEN 3060/thingerd
En este punto es posible acceder al servidor desde cualquier navegador Web:

La configuración del servidor se encuentra en el directorio /var/snap/thinger-maker-server/common/
, dentro del archivo config.json
:
root@iot:~# cd /var/snap/thinger-maker-server/common/ root@iot:/var/snap/thinger-maker-server/common# ll total 24 drwxr-xr-x 2 root root 4096 Feb 15 21:08 certificates -rw-r--r-- 1 root root 2446 Feb 15 21:08 config.json drwxr-xr-x 2 root root 4096 Feb 15 21:08 data drwxr-xr-x 2 root root 4096 Feb 15 21:08 email drwxr-xr-x 2 root root 4096 Feb 15 21:08 exports drwxr-xr-x 2 root root 4096 Feb 15 21:08 logs
Editar el archivo a fin de modificar la configuración por defecto:
root@iot:/var/snap/thinger-maker-server/common# nano config.json
Definir el acceso al un servidor de correo SMTP dentro de nuestra red (necesario para enviar notificaciones por correo electrónico, reseteos de contraseña y confirmación de nuevas cuentas):
"email" : { "domain" : "linuxito.com", "type" : "smtp", "smtp" : { "host" : "smtp.linuxito.com", "port" : "465", "username" : "linuxito", "password" : "1234", "secure" : true } },
También es útil habilitar el log, especialmente para diagnosticar problemas con el servidor:
"log" : { "enabled" : true, "level" : "debug", [...]
Cerrar el archivo y guardar los cambios. Reiniciar el servidor Thinger.io para que tome la nueva configuración:
# systemctl restart snap.thinger-maker-server.thingerd.service
Desde el navegador Web, acceder al servidor nuevamente y crear una cuenta de usuario:

Configuración de un proxy reverso con Nginx
Tal como mencioné anteriormente, el objetivo principal de implementar un proxy reverso es poder generar certificados TLS con Certbot. Además, proveer una implementación más segura de HTTPS.
En artículos anteriores expliqué cómo compilar e instalar la última versión de Nginx en Debian con soporte para SSL, y cómo implementar un balanceador de carga con Nginx. Un balanceador de carga es un proxy reverso hacia varias instancias de un mismo servicio, con lo cual la configuración es similar.
Los pasos necesarios para descargar, extraer, compilar e instalar la última versión de Nginx con su script de inicio son los siguientes:
# cd # wget http://nginx.org/download/nginx-1.12.2.tar.gz # tar axf nginx-1.12.2.tar.gz # cd nginx-1.12.2/ # apt-get install gcc make libpcre3-dev zlib1g-dev git libssl-dev # ./configure --with-http_ssl_module # make && make install && make clean # cd # git clone https://github.com/Fleshgrinder/nginx-sysvinit-script.git # cd nginx-sysvinit-script/ # make # ln -s /usr/local/nginx/sbin/nginx /sbin/nginx
Elijo Nginx porque es mi predilecto, aunque podría utilizarse cualquier otro servidor HTTP, como por ejemplo Apache.
A continuación se debe configurar el archivo que almacenará el PID del servidor Nginx para el script de inicio. Editar el archivo de configuración del servidor Nginx:
root@iot:/usr/local/nginx/conf# nano /usr/local/nginx/conf/nginx.conf
Habilitar la siguiente línea:
pid logs/nginx.pid;
Luego editar el script de inicio e indicar la ubicación de dicho archivo:
root@iot:/usr/local/nginx/conf# nano /etc/init.d/nginx
PIDFILE="/usr/local/nginx/logs/nginx.pid"
Antes de poder iniciar Nginx, es necesario detener el servidor Thinger, pues está ocupando el puerto 80:
# systemctl stop snap.thinger-maker-server.thingerd.service
Finalmente iniciar Nginx:
root@iot:/usr/local/nginx/conf# systemctl start nginx.service
Verificar el puerto 80:
root@iot:~/nginx-sysvinit-script# netstat -tulpn | grep nginx tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 26495/nginx: master
El siguiente paso consiste en cambiar la configuración del servidor Thinger para que escuche sólo en el puerto 8080 (HTTP) y no abra ningún puerto para HTTPS:
"http_server" : { "address" : "0.0.0.0", "port" : "8080", "ssl_port" : "", [...]
Cerrar el archivo y guardar los cambios. Reiniciar el servidor Thinger.io para que tome la nueva configuración:
# systemctl start snap.thinger-maker-server.thingerd.service
Llegado este punto está todo listo para poder montar nuestro proxy reverso, sólo falta hacer que Nginx redirija todo el tráfico de un alias específico (por ejemplo "/thinger") hacia el servidor Thinger.
Editar la configuración de Nginx:
root@iot:/usr/local/nginx/conf# nano nginx.conf
Agregar las siguientes directivas location
para redirigir el tráfico hacia el servidor Thinger (ahora escuchando en el puerto 8080):
server { listen 80; [...] location /thinger { proxy_pass http://localhost:8080/; proxy_set_header Host localhost; proxy_set_header X-Real-IP $remote_addr; proxy_http_version 1.1; } location /v1 { proxy_pass http://localhost:8080; proxy_set_header Host localhost; proxy_set_header X-Real-IP $remote_addr; proxy_http_version 1.1; } location /oauth { proxy_pass http://localhost:8080; proxy_set_header Host localhost; proxy_set_header X-Real-IP $remote_addr; proxy_http_version 1.1; } [...]
Notar que además se necesitan redirigir los aliases /v1
y /oauth
. Esto se debe a que Thinger arma las URLs desde JavaScript de forma absoluta (en ves de relativas a la URL actual). Pésima práctica de programación, siendo que además no se provee una forma de configurar la ruta base de la aplicación (o al menos no está documentado).
Por otro lado, notar las sutiles diferencias en la configuración del reenvío: en las directivas location
para /v1
y /oauth
, la configuración proxy_pass
no incluye una barra al final (sino que termina en la definición del puerto). Esto significa que la URI del pedido se pasa completa al servidor backend. No así para /thinger
, donde se fuerza el acceso al recurso raíz (/
).
Reiniciar el servidor Nginx y verificar el acceso a la aplicación desde la nueva URI "/thinger":
root@iot:/usr/local/nginx/conf# systemctl restart nginx.service
En caso de errores consultar los logs de Nginx y Thinger.
Generar un certificado SSL/TLS con Certbot
El artículo Cómo generar un certificado SSL/TLS gratis con certbot explica detalladamente cómo generar un certificado SSL/TLS gratuito con Certbot, utilizando la versión descargada desde el sitio Web oficial de la EFF. Sin embargo también es posible instalarlo desde paquete:
root@iot:/usr/local/nginx/conf# apt-get install certbot
Al igual que antes, generar el certificado de manera manual ejecutando:
root@iot:/usr/local/nginx/conf# certbot certonly
Seguir los pasos tal como explica el mencionado artículo, tanto para generar el certificado como para instalarlo en Nginx:
# HTTPS server # server { listen 443 ssl; server_name iot.linuxito.com; ssl_certificate /etc/letsencrypt/live/iot.linuxito.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/iot.linuxito.com/privkey.pem; ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; location / { root html; index index.html index.htm; } location /thinger { proxy_pass http://localhost:8080/; proxy_set_header Host localhost; proxy_set_header X-Real-IP $remote_addr; proxy_http_version 1.1; } location /v1 { proxy_pass http://localhost:8080; proxy_set_header Host localhost; proxy_set_header X-Real-IP $remote_addr; proxy_http_version 1.1; } location /oauth { proxy_pass http://localhost:8080; proxy_set_header Host localhost; proxy_set_header X-Real-IP $remote_addr; proxy_http_version 1.1; } } }
Por último, no olvidar recargar Nginx automáticamente luego de renovar alguno de los certificados de Let's Encrypt.
A partir de ahora es posible acceder al panel de control de Thinger y comenzar a agregar dispositivos:

Siguientes pasos
Esto es todo lo necesario para poner nuestro servidor Thinger seguro en funcionamiento. Sin embargo resta todo el trabajo necesario para endurecer la seguridad y persistencia de los datos:
Referencias
- Thinger.io
- Thinger.io - Server Deployment: Install on Ubuntu (starting from 16.04)
- The snapd system
- Instalación y configuración de Nginx con PHP-FPM
- Cómo compilar Nginx con soporte para SSL
- Cómo implementar un balanceador de carga con Nginx
- Module ngx_http_proxy_module - proxy_pass
- Cómo generar un certificado SSL/TLS gratis con certbot
- Automatically enable HTTPS on your website with EFF's Certbot, deploying Let's Encrypt certificates
- Hardening de servidores Nginx sobre FreeBSD
- Recargar Nginx automáticamente luego de renovar los certificados de Let's Encrypt
Tal vez pueda interesarte