
Si eres como yo, tienes un blog, un canal de YouTube, un podcast, y publicas en cuatro o cinco redes sociales diferentes. Y odias hacerlo manualmente. Abres Telegram, copias el enlace, escribes el texto, vas a Mastodon, repites, vas a X, repites, vas a LinkedIn, repites… es una pesadilla. Y encima se te olvida programar las publicaciones de los fines de semana, o publicas todo a la vez y saturas a tu audiencia. Pues de eso va este episodio, el número 830, el primero de una serie de cuatro donde voy a contaros herramientas que he implementado y estoy utilizando en mi día a día. Popuplatrs es un proyecto que he estado desarrollando los últimos meses, escrito en Rust, que se encarga de todo eso por ti. Monitoriza tus fuentes RSS, detecta contenido nuevo, y lo publica automáticamente donde tú quieras. Y al final de este artículo sabrás exactamente qué es, cómo funciona, cómo lo he diseñado, y cómo puedes tenerlo corriendo en tu propio servidor en cinco minutos.
El problema que quería resolver
Llevo años con el atareao, publicando en el blog, en YouTube, y con presencia en varias redes. El problema es que cada vez que publicaba algo tenía que hacer el mismo ritual: escribir el artículo en el blog, ir red por red compartiendo el enlace, personalizar el texto para cada plataforma (porque no es lo mismo un tuit que un post de LinkedIn) y programar recordatorios para no saturar a la gente publicando todo a la vez.
Y claro, con el tiempo esto se vuelve insostenible. Además, si tienes varios proyectos como es mi caso, gestionar los tiempos de publicación, evitar el spam, y mantener la consistencia es un trabajo en sí mismo. Te voy a poner un ejemplo: cuando publico un artículo en el blog, quiero que aparezca en Telegram, en Mastodon, en X, en LinkedIn, en Bluesky y en Threads. Seis plataformas. Y no todas al mismo tiempo, porque si publicas todo a la vez pareces un spammer. Así que tienes que espaciar las publicaciones, programar recordatorios, y acordarte de qué has publicado y dónde.
Menudo rollo, ¿verdad? Pues a mí me tenía harto.
Existen herramientas como Buffer, Hootsuite, IFTTT o Zapier, pero todas tienen pegas: son de pago, tus datos pasan por servidores de terceros, y no siempre soportan las redes que tú usas. Por ejemplo, Bluesky no está en casi ninguna. Y Mastodon, aunque aparece, la integración suele ser limitada. Además, ninguna de ellas se alimenta de tu propio RSS para publicar automáticamente. Son herramientas de programación de publicaciones, no de detección de contenido nuevo.
Así que pensé: ¿y si me construyo mi propio publicador? Que sea mío, que corra en mi servidor, que soporte exactamente las plataformas que uso, y que además tenga un panel web para gestionarlo todo cómodamente. Y así nació Popuplatrs.
Qué es Popuplatrs
Popuplatrs (el nombre es un juego de palabras entre populate y Rust, la verdad es que no me he calentado mucho la cabeza) es un servidor web escrito íntegramente en Rust que monitoriza fuentes RSS, Atom y YouTube, y publica automáticamente el contenido nuevo en las redes sociales que configures. Con panel web, plantillas personalizables por feed y por publicador, planificación cron, y soporte para 9 plataformas incluyendo Telegram, Mastodon, X, Bluesky, LinkedIn, Threads, Discord y más.
Está licenciado como MIT, el código lo tienes en mi GitHub en github.com/atareao/popuplatrs, y la imagen Docker está disponible en ghcr.io/atareao/popuplatrs:latest. La versión actual es la 0.4.12, así que está en desarrollo activo, pero te puedo asegurar que ya va muy bien (lo uso yo mismo a diario para mis proyectos).
Alternativas existentes y sus limitaciones
Antes de meterme en harina con la arquitectura, veamos qué alternativas hay y por qué ninguna me convencía.
Buffer es probablemente la más conocida. Es un SaaS que te permite programar publicaciones en múltiples redes. Tiene un plan gratuito muy limitado (tres canales y diez posts programados) y el de pago no es barato. Además, no es self-hosted, tus datos pasan por sus servidores, y no soporta RSS feeds como fuente. Es decir, tú tienes que ir manualmente a Buffer a programar cada publicación.
Hootsuite es otro clásico, pero es caro (desde 99 dólares al mes) y tampoco es self-hosted. No soporta bien Bluesky ni Mastodon, que son las redes que a mí más me interesan.
IFTTT y Zapier son herramientas de automatización más generales. Te permiten conectar RSS con redes sociales, pero son limitadas: IFTTT solo te permite cinco applets en el plan gratis, y Zapier se vuelve caro rápidamente si tienes muchas tareas. Además, ninguna de las dos tiene un panel web unificado para gestionar todas tus publicaciones, ni te permite personalizar plantillas por plataforma.
Fedica es la que más redes soporta —14 plataformas— pero tampoco es self-hosted, y su interfaz no es tan pulida como Buffer.
La cuestión es que todas estas herramientas comparten el mismo problema: no son tuyas. Dependes de un servicio externo, pagas una suscripción, y tus datos pasan por servidores que no controlas. Y ninguna de ellas está diseñada específicamente para publicar desde feeds RSS con plantillas personalizables.
Arquitectura general de Popuplatrs
Veamos cómo está montado esto. Popuplatrs es un servidor web con el backend en Rust usando Axum como framework web, SQLite con rusqlite para la base de datos, y el frontend está hecho con React y TypeScript usando Vite como bundler. En producción, el frontend compilado se sirve directamente desde el binario de Rust, así que no necesitas un servidor web aparte.
La arquitectura es bastante sencilla y sigue un flujo lineal:
Scheduler (cron interno)
↓
Feed Manager (RSS / Atom / YouTube)
↓
Publisher Manager (9 plataformas)
↓
SQLite (histórico, logs, config)
Tenemos un scheduler que corre en el mismo proceso del servidor web. No necesitas cron externo ni systemd timers —él mismo se gestiona. Tiene una expresión cron configurable con zona horaria, y se queda durmiendo hasta el siguiente tick. Esto simplifica muchísimo el despliegue porque todo es un solo proceso.
El Feed Manager es el encargado de ir a buscar las novedades. Saca el contenido del feed, lo parsea, y lo compara con lo que ya tiene publicado en la base de datos para evitar duplicados. Usa los crates rss para RSS 2.0 y feed-rs para Atom, intentando primero con RSS y cayendo a Atom si falla.
Luego el Publisher Manager toma los posts nuevos, renderiza las plantillas con minijinja —un motor de plantillas compatible con Jinja2 escrito en Rust por Armin Ronacher, el mismo creador de Flask— y los envía a cada plataforma configurada. Cada publicador va por separado, así que si uno falla, los demás siguen adelante.
Y todo queda registrado en SQLite: qué se publicó, cuándo, en qué plataforma, si hubo error, cuántos reintentos se hicieron… La base de datos tiene tablas para feeds, publicadores, la relación N:M entre ellos, los posts publicados, los resultados de cada publicación, la caché de feeds con ETags, y los tokens de actualización OIDC.
Una cosa que me gusta de esta arquitectura es que todo corre en un solo proceso. No necesitas Redis, ni colas de mensajes, ni nada de eso. El scheduler, el servidor web, y los publicadores comparten el mismo espacio de memoria y la misma base de datos. Esto simplifica muchísimo el despliegue. Eso sí, si tienes muchos feeds y muchas redes, obviamente el ciclo de comprobación puede tardar un poco. Pero para un uso doméstico o de pequeño proyecto, va más que sobrado.
Stack tecnológico en detalle
El backend usa tokio como runtime asíncrono, Axum 0.8 como framework web (el más moderno del ecosistema Rust, construido sobre tower para middleware), rusqlite 0.32 para SQLite en modo WAL (Write-Ahead Logging) para concurrencia, reqwest 0.12 con rustls para las peticiones HTTP, minijinja 2.19 para las plantillas, y jsonwebtoken 10 para la validación de JWT.
El frontend es un SPA (Single Page Application) con React 19, TypeScript 5.5 y Vite 6. Usa Ant Design como librería de componentes de UI. En desarrollo, Vite hace de proxy al backend en el puerto 3044. En producción, el frontend compilado se sirve desde el binario de Rust usando tokio::fs::read desde el directorio dist/.
Fuentes que soporta: RSS, Atom y YouTube
Popuplatrs soporta tres tipos de fuentes, y cada una tiene su particularidad.
RSS 2.0 es el clásico. Casi todos los blogs y sitios de noticias lo generan. Popuplatrs usa el crate rss de Rust para parsearlo, y la infraestructura está preparada para caché condicional con ETag y Last-Modified, aunque todavía no está operativa del todo. Esto es importante para ser respetuoso con los servidores de los que te alimentas.
Atom es el formato más moderno, usado por muchos sitios. Se parsea con el crate feed-rs. La estrategia de Popuplatrs es intentar parsear como RSS primero, y si falla, prueba como Atom.
YouTube API v3 es la más interesante. Le das la URL de un canal de YouTube o de una lista de reproducción, y Popuplatrs resuelve automáticamente el channel ID. Soporta tres formas de identificar un canal: por channel ID, por playlist ID, o por @username. Luego usa la API de YouTube para traerse los últimos vídeos. Necesitas una API Key de Google, que te la dan gratis con una cuota de 10.000 unidades al día, y con eso tienes.
¿Por qué YouTube y no simplemente el RSS de YouTube? Porque YouTube tiene feed RSS para canales, pero el formato que usan no incluye toda la información. Con la API obtienes descripciones completas, miniaturas, duración, etc. Además, el feed RSS de YouTube a veces falla o no se actualiza correctamente. La API es mucho más fiable.
Un detalle importante: los feeds se pueden activar y desactivar desde el panel web. Si un feed está caído temporalmente, puedes desactivarlo sin perder su configuración. Y desde el panel puedes disparar manualmente la comprobación del feed para forzar una publicación inmediata sin esperar al siguiente ciclo del cron.
Los 9 publicadores
Y ahora lo que más os va a interesar: los publicadores. Popuplatrs soporta actualmente 9 plataformas. Cada una tiene su propio tipo de autenticación y su propia configuración, y todas se gestionan desde el panel web.
Telegram —vía Bot Token. Creas un bot con @BotFather en Telegram, obtienes el token, y le dices el chat ID (puede ser un grupo, un canal o tu chat personal). Es de los más sencillos de configurar. El bot envía mensajes con formato Markdown y tiene un límite de 4096 caracteres.
X (antes Twitter) —con OAuth 2.0 PKCE. El flujo OAuth se hace desde la propia interfaz web de Popuplatrs, sin necesidad de herramientas externas. Publica en dos pasos: primero el tweet principal con el título (sin URL, para maximizar caracteres) y luego un reply con el enlace. Esto mejora la legibilidad y aprovecha mejor el límite de 280 caracteres. Además, tiene refresh automático de token si recibe un 401.
Mastodon —con Access Token. Necesitas la URL de tu instancia y el token que genera la propia interfaz de Mastodon. Si no hay client_id, Popuplatrs registra la app automáticamente en el servidor. El límite de caracteres depende de la instancia, normalmente 500.
LinkedIn —con OAuth 2.0. Publica en tu perfil personal o en páginas de empresa. Obtiene automáticamente el user_id del perfil. También tiene refresh automático de token.
Bluesky —con App Password. Es el más sencillo de configurar: tu handle (ej: usuario.bsky.social) y un App Password generado desde Settings → App Passwords. Bluesky tiene un límite estricto de 300 caracteres, así que Popuplatrs trunca automáticamente con ... y detecta URLs para añadir facets (enlaces clickables).
Threads —con OAuth 2.0 de Meta. El recién llegado. El token corto se canjea automáticamente por uno long-lived de 60 días. Si falla el canje, usa fallback al token corto.
Matrix —con Access Token. Publica en salas usando formato HTML. Necesitas un homeserver, un access token, y un room ID.
Discord —vía Webhook. Es el más sencillo de todos. Creas un webhook en Ajustes del canal → Integraciones → Webhooks, copias la URL, y la pegas en Popuplatrs. No necesita tokens ni OAuth. El límite es de 2000 caracteres.
OpenObserve —con API Key. Este no es una red social, es un sistema de logging. Popuplatrs lo incluye para centralizar logs de publicación. Útil si usas OpenObserve como central de logs.
Cada publicador tiene su propia autenticación y su propia configuración. Se gestionan desde el panel web, y hay dos cositas que me parecen especialmente interesantes.
Primero, el OAuth integrado. Para X, LinkedIn, Mastodon y Threads, el flujo OAuth se hace entero desde Popuplatrs. Le das al botón Autorizar, se abre una ventana, inicias sesión en la plataforma, y Popuplatrs guarda automáticamente los tokens. Y si el token expira, los publicadores de X y LinkedIn tienen refresh token automático. No tienes que preocuparte de renovar nada.
Segundo, el test de publicación. Cada publicador tiene un botón Probar que envía un mensaje de prueba a la plataforma para verificar que todo funciona. Muy útil cuando estás configurando.
Panel web y sistema de plantillas
El panel web es donde realmente se maneja todo. El frontend está hecho con React y TypeScript, y es un SPA que se comunica con el backend a través de una API RESTful. En producción, ejecutas Popuplatrs y ya tienes el panel web en http://localhost:3044, sin necesidad de servir archivos estáticos por separado.
El panel tiene varias secciones:
Dashboard con estadísticas: cuántos feeds tienes, cuántos publicadores, la última vez que se ejecutó el ciclo, la próxima ejecución programada…
Feeds: aquí añades, editas y gestionas tus fuentes. Puedes activar/desactivar, ejecutar manualmente, forzar la publicación de posts pendientes.
Publishers: creas y configuras tus plataformas. Cada publicador tiene su propio formulario con los campos específicos que necesita. Aquí es donde haces el flujo OAuth y los tests de publicación.
Schedule: configuras la expresión cron y la zona horaria. Puedes usar presets o escribir tu propia expresión.
Logs: un histórico completo con todo lo que ha ido pasando. Además, los logs se muestran en tiempo real vía Server-Sent Events. Abres la página de logs y ves en directo cómo se van publicando los posts. Te permite depurar al instante si algo falla.
Y luego está el sistema de plantillas, que es de lo que estoy más orgulloso. Cada publicador tiene una plantilla por defecto, pero puedes personalizarla por feed. Es decir, el mismo publicador de Telegram puede tener una plantilla diferente para cada feed que monitorice.
Las plantillas usan minijinja, un motor de plantillas compatible con Jinja2 escrito en Rust. Las variables disponibles son {{ title }}, {{ description }} y {{ url }}. Y además hay filtros útiles como truncate(N) que corta el texto a N caracteres, word_limit(N) que corta a N palabras, y strip_html que elimina etiquetas HTML.
Por ejemplo, una plantilla típica para Telegram sería:
**{{ title }}**
{{ description | truncate(480) }}
🔗 [Leer más]({{ url }})
Y para Mastodon o Bluesky, como tienen límite de caracteres más restrictivo, puedes hacer:
{{ title }}
{{ description | strip_html | truncate(200) }}
{{ url }}
Te permite adaptar el mensaje al tono y formato de cada red automáticamente. Y la jerarquía de plantillas es: primero busca una plantilla específica del feed, si no usa la del publicador, y si no usa la plantilla por defecto del código.
Demo rápida: de RSS a Telegram en 6 pasos
Hagamos una demo rápida para ver cómo es el flujo. Imaginad que queremos conectar el feed RSS de un blog a Telegram. Aquí tienes el script completo para la demo, con docker-compose incluido:
Paso 1: Arrancamos Popuplatrs. En modo desarrollo basta con un:
cd backend && HOST=0.0.0.0 PORT=3044 RUST_LOG=info cargo run
O si prefieres Docker:
docker run -p 3044:3044 -v $(pwd)/data:/app/data ghcr.io/atareao/popuplatrs:latest
Sin variables OIDC, el servidor activa el modo desarrollo con bypass de autenticación. Vamos a http://localhost:3044/auth/dev-login?email=dev@test.com y obtenemos un token JWT.
Paso 2: En el panel, vamos a Publishers y creamos un publicador de Telegram. Necesitamos el token del bot —lo obtienes de @BotFather en Telegram— y el chat ID —puede ser un grupo, un canal, o tu chat personal. Le damos a Probar para verificar que funciona, y guardamos.
Paso 3: Vamos a Feeds y añadimos un feed RSS. Le ponemos un nombre, la URL del feed —por ejemplo https://atareao.es/feed.xml—, y seleccionamos el publicador de Telegram que acabamos de crear.
Paso 4: Opcionalmente, personalizamos la plantilla para este feed. Si no lo hacemos, usará la plantilla por defecto del publicador.
Paso 5: Vamos a Schedule y configuramos el cron. Por ejemplo, 0 */2 * * * para comprobar cada dos horas. O podemos dejar la que viene por defecto.
Paso 6: Y ya está. Volvemos al feed y le damos a Ejecutar ahora para forzar la primera comprobación. Popuplatrs va al feed, encuentra las novedades, renderiza la plantilla, y publica en Telegram.
Y lo mejor de todo es que en la página de logs ves el proceso en tiempo real. Ves cómo se conecta al feed, cómo parsea los posts, cómo filtra los que ya están publicados, cómo renderiza cada plantilla, y el resultado de cada publicación. Si algo falla, ves exactamente el error.
Dockerización y despliegue en producción
Ahora, ¿cómo desplegamos esto en un servidor de verdad? Muy sencillo. Popuplatrs está dockerizado con un Dockerfile multi-etapa que se construye en tres fases.
La primera fase compila el binario de Rust en Alpine. La segunda construye el frontend con Node y pnpm. Y la tercera genera la imagen Alpine final de solo unos 30 megas aproximadamente, con el binario y los archivos estáticos. Y lo mejor es que la imagen usa un usuario no-root (app, UID 1000), así que es segura.
Para ejecutarlo con Docker, el comando es tan sencillo como:
docker run -p 3044:3044 \
-v $(pwd)/data:/app/data \
ghcr.io/atareao/popuplatrs:latest
Y para los que usáis Podman con Quadlet —que es mi caso— tengo un archivo .container de ejemplo. Simplemente lo copias a ~/.config/containers/systemd/, ajustas las variables de entorno, y lo ejecutas como un servicio systemd:
cp populatrs.container ~/.config/containers/systemd/
cp populatrs.env ~/.config/containers/systemd/
systemctl --user daemon-reload
systemctl --user start populatrs
El contenedor incluye health check en el endpoint /health, reinicio automático, y persistencia de datos en un volumen. Y la autenticación en producción se hace mediante OIDC con Pocket ID —que ya cubrimos en episodios anteriores—, así que puedes integrarlo con tu propio proveedor de identidad.
Las variables de entorno clave son:
| Variable | Descripción | Default |
|---|---|---|
HOST | IP de escucha | 0.0.0.0 |
PORT | Puerto | 3044 |
DATABASE_URL | Ruta SQLite | ./data/populatrs.db |
TIMEZONE | Zona horaria scheduler | UTC |
RUST_LOG | Nivel de log | info |
OIDC_ISSUER_URL | PocketID URL | — (dev mode si ausente) |
Si no configuras las variables OIDC, Popuplatrs arranca en modo desarrollo con bypass de autenticación. Para producción, necesitas configurar OIDC_ISSUER_URL, OIDC_CLIENT_ID, OIDC_CLIENT_SECRET y OIDC_REDIRECT_URL.
Lo que viene en el futuro
Popuplatrs está en versión 0.4.12, así que aún está en desarrollo activo. Pero ya es perfectamente usable —lo uso yo mismo a diario para mis proyectos.
¿Qué viene en el futuro? No tengo ni idea, porque lo que hay ahora a mi me funciona perfecto, casi que es cuestión de que tu lo comiences a utilizar y me digas lo que te falta o lo que necesitas o lo que sea.
Solución de problemas habituales
Como cualquier herramienta que habla con servicios de terceros, Popuplatrs tiene sus momentos. Te cuento los tres problemas con los que me he encontrado más a menudo y cómo los resuelvo, por si te sirven de guía.
El primero, y el más común, es el token de LinkedIn que caduca. LinkedIn es de las plataformas más quisquillosas con la autenticación, y de vez en cuando el token se agota sin previo aviso. La solución es tan sencilla como entrar en el panel, ir al publicador de LinkedIn y pulsar el botón de Reconnect. El flujo OAuth se vuelve a abrir, inicias sesión, y en un minuto vuelves a estar operativo. Por eso insistía tanto en que el panel web merecía la pena: antes, cuando todo corría en background, este tipo de fallos pasaban desapercibidos durante días.
El segundo es el que te contaba en el episodio: de repente Popuplatrs encuentra posts antiguos que nunca llegó a publicar y se pone a publicarlos todos de golpe. A mí me pasó hace unas semanas y fue un poco caótico. La solución está en la configuración del scheduler, donde puedes indicar que solo publique contenido con fecha posterior a un día concreto. Así evitas que un feed con historial largo te inunde las redes de golpe.
Y el tercero tiene que ver con YouTube. Si usas el feed RSS de un canal, tarde o temprano te dará problemas: o no se actualiza, o devuelve datos incompletos. Por eso Popuplatrs usa la API v3 de YouTube. Si ves que un canal no publica nada nuevo, revisa que la API Key sea correcta y que no hayas agotado la cuota diaria de 10.000 unidades. Con la API, además, obtienes descripciones completas y miniaturas, que el RSS de YouTube no incluye.
Conclusiones
Después de meses usando Popuplatrs en mi día a día, te diré que es una de esas herramientas que no sabes que necesitas hasta que la pruebas. El tiempo que me ahorra cada semana es considerable. Ya no tengo que estar pendiente de publicar manualmente cada artículo en cada red. Popuplatrs lo hace por mí, con el formato adecuado para cada plataforma, y respetando los tiempos de publicación.
Lo mejor de todo es que es self-hosted. Los datos son míos, no pasan por servidores de terceros, y puedo tenerlo funcionando con Docker en cualquier VPS por poco más de lo que cuesta un café al mes… bueno, digamos que tes o cuatro cafés. Y al ser código abierto con licencia MIT, puedo modificarlo y adaptarlo a mis necesidades, claro, es mío.
Si te gusta la idea, pásate por el repositorio en github.com/atareao/popuplatrs, dale una estrella, haz un fork, o simplemente pruébalo. El Docker compose que te he mostrado arriba te lo pone muy fácil. En cinco minutos tienes tu propio publicador de redes sociales funcionando.
Más información,
- Repositorio de Popuplatrs en GitHub — Código fuente, documentación y ejemplos
- Popuplatrs README — Documentación principal del proyecto
- Popuplatrs CHANGELOG — Historial de versiones y cambios
- Popuplatrs Docker packages — Imagen Docker oficial en GitHub Container Registry
- Telegram Bot API — Documentación oficial de la API de Bots de Telegram
- X API (Twitter) Documentation — Documentación oficial de la API de X/Twitter
- Mastodon API Documentation — Documentación oficial de la API de Mastodon
- Bluesky API (AT Protocol) — Documentación oficial del AT Protocol de Bluesky
- Threads API (Meta) — Documentación oficial de la API de Threads
- Discord Webhooks Documentation — Documentación oficial de Webhooks de Discord
- Matrix Client-Server API — Especificación oficial de la API de Matrix
- YouTube Data API v3 — Documentación oficial de la API de YouTube
- Axum Web Framework — Documentación del framework web Axum para Rust
- MiniJinja Template Engine — Documentación del motor de plantillas MiniJinja
- Pocket ID — Proveedor de identidad OIDC para autenticación sin contraseñas
- Buffer — Alternativa SaaS para programación de publicaciones en redes sociales
- IFTTT — Alternativa SaaS para automatización de tareas entre servicios