msgbartop
Ïa! Ïa! Cthulhu Fthagn! Ph’nglui mglw’nfah Cthulhu R’lyeh wgah’nagl fhtagn!
msgbarbottom

29 dic 22 Uso de un servidor público y ZeroTier para publicar servicios hacia Internet desde una red con CG-NAT

Desde hace algunos días vengo experimentando problemas con mi conexión doméstica a Internet. Esto es un problema bastante molesto para mí, porque hago uso de una serie de servicios en un servidor casero que publico hacia el exterior. El principal de ellos es este sitio web, pero hay algunos adicionales, como algunos servicios de domótica y una conexión VPN para acceder de manera segura desde el exterior. Hasta ahora, venía publicándolo todo de manera directa, ya que disponía de una IPv4 con mi conexión, pero desde la semana pasada han pasado a darme acceso a Internet detrás de un CG-NAT. Esto implica que ya no dispongo de una IPv4 propia, sino que salgo a través de una NAT del operador, por lo que no es posible acceder de manera remota a dichos servicios.

Mientras me lo solucionan, he optado por poner en pie un mecanismo para poder seguir publicando servicios, basado en el uso de un pequeño servidor público que se encarga de redireccionar los servicios hacia mi sistema detrás del CG-NAT. Y para ello, hago uso de una plataforma que permite establecer redes securizadas mediante una combinación de SG-NAT y VPN, llamada ZeroTier. La gracia de ZeroTier es que el entorno funciona como un concentrador de VPNs, de tal manera que entre los clientes que necesitemos conectar se establece una red privada, con lo que es posible dotar de conectividad entre ellos a los mismos, tan sólo instalando un agente del propio ZeroTier entre ellos, y establecer la visibilidad oportuna entre nodos. Haciendo que el servidor publicado en Internet sea uno de los nodos, puedo proporcionar servicios utilizándolo de pasarela pública.

La segunda pata del asunto es conseguir este servidor frontal público, y hacer que funcione de pasarela. En mi caso, he optado por hacer uso de Oracle Cloud Infrastructure, donde se puede desplegar de manera gratuita un servidor basado en Linux. Y una vez que me he hecho con este servidor, he montado la pasarela con un servidor NGINX, debido a que me permite redireccionar tanto servicios publicados por TCP (mi servidor web y mi servidor MQTT) como UDP (mi servidor VPN), con lo que me ahorro tener que andar instalando y gestionando servicios duplicados en este frontal. Sencillo y eficiente. El diagrama general de cómo ha quedado el entorno es el siguiente:

Configuración de acceso remoto con ZeroTier y Oracle Cloud

Configuración de acceso remoto con ZeroTier y Oracle Cloud

La configuración a nivel interno sí que tiene algunos puntos a tener en cuenta:

  • El primero de ellos es relativo a la instalación de ZeroTier. Ésta es bastante sencilla, se trata de descargar el cliente VPN que proporciona el propio proveedor. A nivel Linux se instala con un simple wget desde la plataforma, y el despliegue se basa en indicarle la red privada que hemos registrado en la misma, y los propios nodos se añaden a ella. El registro en la plataforma es gratuito para redes de hasta 25 nodos, y también permite desplegar sistemas autogestionados para entornos profesionales. Una vez añadidos los nodos, es preciso darles permiso para conectarse a la red privada que hemos creado al registrarnos. Una vez hecho, podrán verse entre ellos. A nivel de sistema operativo, esta conexión aparece como una nueva IP virtual, vinculada a la conexión VPN establecida con ZeroTier. En mi caso, lo he desplegado en dos sitios: el servidor VPS que he creado en Oracle Cloud, y en el servidor que hace de frontal web para las conexiones entrantes a mis sistemas, que actúa de proxy inverso para el resto de servidores.
  • El segundo es el relativo al NGINX en el VPN de Oracle Cloud. Como comentaba, he optado por utilizar NGINX como frontal para publicar servicios. Dado que publico servicios HTTP y HTTPS, no tenía ganas de andar gestionando el tema de un proxy inverso convencional, teniendo que duplicar certificados y gestionar las redirecciones entre ellos. En este caso, he optado por realizar una simple redirección mediante el uso de la directiva stream en nginx.conf, que viene a funcionar como un balanceador de carga, estilo F5 o HAProxy. La idea es que puedes definir un servicio upstream, en el que se indica a qué dirección IP y qué puerto de tu entorno interno quieres proporcionar acceso, y luego se define un server que publica los servicios. En mi caso, en el upstream declaro la IP interna correspondiente a mi servidor doméstico proporcionada por ZeroTier (que, recordemos, es privada y accesible sólo para mi VPS), con lo que me estoy saltando las limitaciones del CG-NAT, y en el server publico los servicios. La gracia del asunto, además, es que vale para conexiones TCP y UDP. Como lo que quiero publicar es un servidor HTTPS, un servidor MQTT y un servidor VPN, todo queda de la siguiente manera:

    stream {
    upstream web_server {
    server IP_PRIVADA_REMOTA_ZEROTIER:443;
    }

    server {
    listen 443;
    ssl_preread on;
    proxy_pass web_server;
    }

    upstream mqtt_server {
    server IP_PRIVADA_REMOTA_ZEROTIER:1883;
    }
    server {
    listen 1883;
    proxy_pass mqtt_server;
    proxy_connect_timeout 1s;
    }

    upstream vpn_server {
    server IP_PRIVADA_REMOTA_ZEROTIER:1194;
    }
    server {
    listen 1194 udp;
    proxy_pass vpn_server;
    }

    }

  • El tercer punto es la redistribución de servicios en el lado del servidor doméstico. Esto es importante para mí, dado que no hago uso de un solo servidor a nivel doméstico, sino de una serie de servidores desplegados en un entorno de virtualización. Mientras que el frontal web (que es un NGINX, a su vez) y mi servidor MQTT residen en el servidor que he conectado a ZeroTier, el servidor WordPress y el servidor de VPN están en sistemas distintos. Esto implica que tengo que encargarme de redirigir las conexiones provenientes del nuevo frontal en Oracle a estos sistemas. La parte de WordPress ya la tenía resuelta, pero quedaba por solucionar la parte del servidor VPN. En este caso, como en el anterior, la idea es utilizar un stream. Siguiendo con la idea anterior:

    stream {

    upstream vpn_server {
    server IP_SERVIDOR_LOCAL_VPN:1194;
    }
    server {
    listen 1194 udp;
    proxy_pass vpn_server;
    }

    }

  • Y por último, he tenido que jugar un poco con mi servidor DNS. He creado un nuevo nombre en mi dominio eniac2000.com para el frontal VPS de Oracle Cloud, y he redireccionado los alias que uso habitualmente (www, bitacora…) hacia este nuevo nombre. Con ello, todo queda configurado de manera transparente.

En realidad, me gusta tanto cómo ha quedado configurado, que es posible que lo deje así incluso cuando se solucione el tema del CG-NAT, ya que añade una capa extra de seguridad y disponibilidad a mis sistemas.

Referencias:
How to bypass CGNAT and expose your server to the internet using ZeroTier, a VPS and NGINX
Bypassing a CGNAT with Wireguard (Especialmente útil para la parte de configuración del entorno en Oracle Cloud)
How to set nginx reverse proxy to an SSL site without certificate?

VN:F [1.9.20_1166]
Rating: 10.0/10 (2 votes cast)

Etiquetas: , , , , , , , ,

02 abr 22 Monitorización de precios de gasolineras con Node Red y Home Assistant

Con el nivel tan disparatado de precios que están alcanzando los combustibles en estas fechas, es interesante tener una manera rápida de consultar los precios en diferentes estaciones de servicio, a fin de poder reposar en la que más nos convenga. Por razones de trabajo y sus subsecuentes desplazamientos, hay varias gasolineras que nos interesa a Ana y a mí tener monitorizadas. Existe una página del Ministerio para la Transición Ecológica (Geoportal de Gasolineras) que permite acceder a los precios de todas las estaciones de servicio de España, pero que no es especialmente usable para hacer consultas rápidas y recurrentes de las mismas estaciones, ya que lo que hace es desplegar un mapa y un buscador, pero que no proporciona URLs de acceso directo ni nada que se le parezca.

Captura de pantalla del Geoportal de Gasolineras

Captura de pantalla del Geoportal de Gasolineras

Al menos, no lo hace a la vista del usuario. Pero si trasteas un poco con el funcionamiento de la página, es posible ver que sí se hace uso a nivel interno de URLs únicas que proporcionan en el mapa los valores de cada una de las gasolineras en formato XML, para poder reflejar dichos valores al pulsar sobre las gasolineras, con un aspecto como este:

Información en XML de una gasolinera de Santiponce

Información en XML de una gasolinera de Santiponce

Y ya teniendo esta información, haciendo uso de Node Red es sencillo procesar los parámetros, jugar un poco con ellos, e insertarlos en topics MQTT. En mi caso, me quedo con el valor de la gasolina sin plomo 95, de tres estaciones de servicio determinadas, realizando consultas una vez a la hora para cada una de ellas.

Flujo de procesamiento definido en Node Red

Flujo de procesamiento definido en Node Red

Por último, al existir esta información en un topic MQTT, es sencillo consumirla desde Home Assistant. En mi caso, he optado por mostrarla en tres diales, para que sea sencillo comparar los precios entre estaciones. Además, como valor añadido, me guarda el histórico de cotizaciones y cuándo se produjeron cambios en las mismas.

Precios de la gasolina 95 en tres estaciones, mostrados en Home Assistant

Precios de la gasolina 95 en tres estaciones, mostrados en Home Assistant

Histórico de cambios

Histórico de cambios

Con todo esto, es sencillo comprobar el precio de los combustibles en nuestro Home Assistant, al que accedemos desde nuestro móvil, de un solo vistazo, y escoger el sitio óptimo para repostar. Estoy pensando en darle una vuelta de tuerca, e integrar un sistema de consulta en los sistemas de infoentretenimiento de los coches, pero eso quedará para otra ocasión.

VN:F [1.9.20_1166]
Rating: 10.0/10 (1 vote cast)

Etiquetas: , ,

25 jul 21 Codificación y envío de imágenes por MQTT, y uso de las mismas en WhatsApp

En fechas recientes he realizado un aprovechamiento interesante de las capacidades de comunicación que proporciona el servidor MQTT que tengo instalado para diversos temas: el envío de imágenes a través del mismo. en principio no es algo para lo que esté pensado un servidor MQTT, que actúa como servidor de mensajería, mediante la suscripción a una serie de topics, mediante los cuales clientes del servidor MQTT pueden intercambiar información en formato texto. Pero como al fin y al cabo, las imágenes no dejan de transmitirse como información codificada, es posible ponerse algo creativo para conseguir su procesamiento correcto.

En mi escenario, se trataba de compartir información proveniente de una webcam, para integrarla en mi sistema de domótica. En otras circunstancias, consumiría la información directamente de la webcam, pero el servidor de domótica y la webcam se encuentran en ubicaciones geográficas distintas, y la red de la webcam se encuentra tras un CG-NAT, por lo que no es posible establecer una publicación directa de puertos. Existe la posibilidad de establecer una VPN, pero esta opción me parecía bastante más interesante. La webcam se trata de una ESP32-CAM, con capacidad para publicar imágenes tanto en formato streaming como imágenes individuales, y acceder a ellas a través de una URL concreta. Mi idea era aprovechar la capacidad de Python de convertir imágenes a arrays de bytes, y volcar la información a un topic MQTT específico, para su posterior consumo. Consumo que en una primera instancia sería una publicación directa en Home Assistant, pero que posteriormente se vio complementado con una idea adicional interesante.

Esquema general del envío de imágenes por MQTT

Esquema general del envío de imágenes por MQTT

Codificación y envío de la imagen por MQTT

La primera parte de este proyecto consiste en el volcado de la información de la imagen en un topic MQTT. En mi caso, aprovechando que dispongo de un servidor Orange Pi Zero instalada en Forcarey para controlar diversos dispositivos Zigbee, creé un pequeño script en Python que toma una captura de imagen de la ESP32-CAM, la vuelca en un fichero temporal, y posteriormente la codifica como un bytearray, para enviarla a un topic MQTT concreto. El código sería el siguiente:

mport paho.mqtt.publish as publish
from PIL import Image
import requests
from io import BytesIO

MQTT_SERVER = “xxx.xxx.xxx.xxx” #Write Server IP Address, or your server FQDN
MQTT_PATH = “path” #Write your MQTT topic path

response = requests.get(“http://xxx.xxx.xxx.xxx/capture”) #Write your ESP32-CAM IP address
f=open(“/tmp/image_test.jpg”,”wb”)
f.write(response.content)
f.close

f=open(“/tmp/image_test.jpg”, “rb”)
fileContent = f.read()
byteArr = bytearray(fileContent)
publish.single(MQTT_PATH, byteArr, hostname=MQTT_SERVER)
f.close

Bastante sencillo. Para no andarme loco con servicios en linux, me limito a invocarlo desde /etc/crontab una vez cada 5 minutos, aunque se puede programar la frecuencia que se desee.

Captura y publicación en Home Assistant

Una vez tenemos nuestra imagen siendo volcada en el topic MQTT correspondiente, se trata de explotarla de manera adecuada. Y en este caso, Home Assistant nos lo pone bastante sencillo, ya que existe una integración de tipo cámara MQTT directamente incorporada a Home Assistant. Su uso es tan sencillo como indicar el topic del que tendremos que recoger la imagen:

camera:
– platform: mqtt
name: MQTT Cam
topic: MQTT_TOPIC_PATH

El resultado es el que sigue:

Captura de cámara MQTT en Home Assistant

Captura de cámara MQTT en Home Assistant

En mi caso, una topa del recibidor del piso de Forcarey.

Otros usos: sistema de alarma mediante correo electrónico con Node-Red

Pero estando ya este sistema montado, y merced a algunos detectores de apertura de puertas y ventanas Zigbee que ya tenía previamente instalados, es posible dar una vuelta de tuerca, y hacer algo más interesante: un sistema que detecte aperturas no deseadas de la puerta de la entrada, que tome varias imágenes, y las envíe por correo electrónico a un buzón previamente definido. El proceso es el siguiente: tengo instalado en la puerta un sensor de apertura Zigbee. La información de este sensor es procesada por un servidor Zigbee2MQTT, que vuelca en un topic MQTT la información de cuándo se activa este sensor. Este topic es procesado mediante una automatización en Home Assistant que, cuando se encuentra activada, envía una señal de alarma mediante un segundo topic MQTT. A su vez, tengo un script en Python en la Orange Pi Zero de Forcarey que se encuentra suscrito a este topic, y que cuando detecta una activación del mismo, toma tres imágenes a intervalos regulares, y las envía codificadas como bytearray por un tercer topic MQTT. Y por último, tengo creado en Node-Red un flujo que está suscrito a este último topic, descodifica las imágenes, y las envía a una cuenta de correo como un adjunto.

Flujo de Node Red de envío de correo

Flujo de Node Red de envío de correo

Admito que tiene que haber maneras más sencillas de hacerlo, pero esta resulta bastante instructiva. :mrgreen:

VN:F [1.9.20_1166]
Rating: 0.0/10 (0 votes cast)

Etiquetas: , , , , , , ,

12 jun 21 Explotación de datos abiertos mediante Node Red: Colegios de Galicia

Estos días he estado jugando un poco con una fuente de datos abiertos proporcionada por el Gobierno de España para resolver un pequeño problema que teníamos en casa: cómo priorizar la elección de centro para el curso que viene que tiene que realizar Ana. El caso es que ha estado este año trabajando de interina en un colegio de la zona de Carballiño, y para el curso que viene tiene que indicar su prioridad de centros. Tiene la posibilidad de escoger cualquiera de las provincias, pero una de las posibilidades es escogerlos de manera individual. Y para nosotros, teniendo en cuenta que tenemos un piso en Forcarey, un criterio bastante importante es el de la proximidad geográfica, y el de la facilidad de desplazamiento en carretera.

El problema a priori se planteaba complicado, ya que en la zona interior de Galicia donde está Forcarey, cerca de los límites de las cuatro provincias, ninguno de los dos teníamos nociones de cuáles podían ser los centros más apropiados. Mirarlos de manera individual podía ser un dolor de cabeza, por lo que me puse a pensar en maneras de optimizar la elección, y di con algo bastante interesante. Existe en el catálogo de datos puestos a disposición por parte del Gobierno una categorización de todos los Centros Educativos de Galicia. Categorización que incluye el tipo de centro (público, privado, CEIP, IES…) así como (y esta era la clave del asunto) sus coordenadas geográficas.

Información XML de los colegios de Galicia

Información XML de los colegios de Galicia

Exactamente lo que estaba buscando. A partir de ahí, la idea era poder representarlos en un mapa, para poder determinar los más convenientes para nuestra ubicación. ¿Y cómo hacerlo? Por suerte, tengo experiencia con Node Red y su estupendo plugin para mapas. No tardé en realizar un flujo, que extrae de las fuentes en XML (una por provincia) la información de cada colegio, clasificarlo, filtrarlos por tipo, y crear una entrada en el mapa para cada colegio, con información relevante:

Flujo de procesamiento en Node Red

Flujo de procesamiento en Node Red

¿El resultado? Estupendo. Un mapa en el que se puede observar los centros, clasificados por los tipos que nos interesan, y con la información relativa a código de centro, dirección y algunos datos adicionales.

CEIPS y CPIs en las cercanías de Forcarey

CEIPS y CPIs en las cercanías de Forcarey

Este ejercicio, aparte de lo obvio, me ha permitido sacar una información derivada adicional bastante interesante, y es el conocer las zonas más despobladas o con población más envejecida de Galicia. Y es que si se observa el mapa completo de la Comunidad, es fácil ver que hay zonas muy extensas en las que no existe colegio alguno de Primaria. Es decir, zonas sin habitantes, o al menos sin niños (lo que suele ser parejo):

CEIPs y CPIs de Galicia

CEIPs y CPIs de Galicia

Esta es la maravilla de poder usar datos abiertos.

VN:F [1.9.20_1166]
Rating: 10.0/10 (1 vote cast)

Etiquetas: , , ,

07 may 21 Una webcam con Arduino: el ESP32-Cam

No voy a descubrir nada nuevo si afirmo que los sistemas Arduino son pequeñas maravillas. Se pueden hacer con ellos cosas increíbles en el ámbito de la domótica, e incluso con sistemas IoT y transmisión de radiofrecuencia. El problema habitual que suelen tener es que tienen unos recursos ciertamente limitados, pero para su ámbito de actuación, son más que correctos. Sin embargo, existen placas específicas que tienen algo más de potencia y capacidades, y que permiten dar un paso más allá: es el caso de las placas basadas en el ESP32. Ya he hablado de ellas en otro ámbito, en concreto en lo que se refiere a capacidades LoRa y LoRaWAN, pero hay un desarrollo específico, basado en el ESP32, que da bastante juego: las cámaras web. Y pensando en esto fue para lo que nació la ESP32-Cam.

Placa ESP32-CAM

Placa ESP32-CAM

La placa fue originalmente desarrollada por Espressif, y se compone de un micro ESP32-S, una cámara VO2640, y varios GPIOs que permiten conectar periféricos. Dispone de capacidad Bluetooth, así como conector microSD para utilizar tarjetas de memoria. Y todo ello por un precio ridículo, inferior a los 8€ (menos aún en el caso de las placas clónicas que se pueden encontrar en Aliexpress). De lo que no dispone es de un conector microUSB ni miniUSB, lo que implica que para programarlo es preciso utilizar un programador FTDI, pero no es nada tampoco cosa del otro mundo.

Diagrama de conexionado ESP32-CAM-Programador FTDI

Diagrama de conexionado ESP32-CAM-Programador FTDI

Desde el punto de vista físico, hay que alimentar el dispositivo utilizando los pines de 5v y GND del programador, interconectar los puertos UOR-TX y OUT-RX, y para iniciar el dispositivo en formato de grabación, puentear el GPIO0 y el GND de la propia placa. Una vez conectado de esta manera, se puede conectar el programador al PC, e iniciar la subida del firmware.

Comentaba antes que la placa es un desarrollo de Espressif, y ellos mismos proporcionan el código para subir un servidor de video en streaming a la ESP32-Cam. Este código es interesante, pues -entre otras funcionalidades- incorpora una funcionalidad de detección de rostros y detección de intrusos basado en las caras registradas.

Reconocimiento facial con el ESP32-CAM

Reconocimiento facial con el ESP32-CAM

El código es interesante, pero tiene algunos defectos. Entre ellos, que no permite hacer uso del pequeño LED que trae incorporado para hacer las veces de flash. Tras buscar un poco, encontré otro desarrollo que incorpora una serie de mejoras sobre el código original.. Tras haber utilizado ambos, recomiendo de manera clara este último.

Y para cerrar, comentar que es posible hacer uso de este servidor web dentro de HomeAssistant. Basta con crear una entrada de tipo cámara genérica, apuntando a la URL de captura de imágenes estáticas:

camera
– platform: generic
name: ESP32-Cam
still_image_url: http://192.168.0.XXX/capture?_cb.png
verify_ssl: false

ESP32-CAM integrada con HomeAssistant. Vista de mi patio

ESP32-CAM integrada con HomeAssistant. Vista de mi patio

Las pegas principales de la cámara son dos: la primera es que el módulo de la cámara no es ninguna maravilla. Sin embargo, al ser de un tipo estandarizado, es bastante sencillo encontrar mejores módulos, con cable más largo, y lentes ojo de pez, entre otras flipadas. La segunda es que no dispone de ninguna carcasa. Tampoco es problema, es posible encontrar bastantes diseños en Thingiverse para imprimir una carcasa en 3D.

Referencias:

VN:F [1.9.20_1166]
Rating: 10.0/10 (1 vote cast)

Etiquetas: , , ,