Se abre en una pestaña nueva

Estrategia digital

Cómo instalar OpenReply en Coolify paso a paso: la alternativa gratis a ManyChat

Guía paso a paso para instalar OpenReply en Coolify y responder por DM a quien comenta una palabra clave en Instagram, con la API oficial y en tu propio servidor.
Smartphone con comentarios de Instagram convertidos en mensajes directos frente a un servidor

Si usas Instagram para vender, ya conoces el truco: “Comenta GUÍA y te lo mando por DM”. Funciona muy bien, pero responder a mano a cada comentario es imposible, y herramientas como ManyChat cobran más cuantos más contactos tienes.

OpenReply es una alternativa de código abierto (licencia MIT) que hace exactamente eso: cuando alguien comenta una palabra clave en tu publicación o reel, le envía un mensaje privado de forma automática, usando la API oficial de Instagram. Sin compartir tu contraseña y sin automatizar el navegador. La ventaja es que corre en tu propio servidor, así que no pagas por contacto.

En esta guía te cuento, paso a paso, cómo lo instalé en Coolify (el panel self-hosted con el que gestiono mis servidores), con capturas de la instalación real y los errores que conviene evitar.

Página de inicio de OpenReply instalado en un subdominio propio
OpenReply funcionando en un subdominio propio.

Qué vas a montar

Todo vive dentro de un único servicio Docker Compose en Coolify, con cinco contenedores:

  • web: el panel de OpenReply y el endpoint que recibe los webhooks de Meta. Es el único que se expone a internet.
  • worker: el proceso que envía los DMs desde una cola.
  • cron: renueva los tokens de Instagram y lanza las tareas periódicas.
  • PostgreSQL 16: la base de datos de campañas, contactos y registros.
  • Redis 7: la cola de envíos.

El flujo es sencillo: Meta avisa a OpenReply cada vez que alguien comenta. Si el comentario contiene la palabra clave de una campaña, la web pone el envío en la cola de Redis y el worker manda el DM por la API oficial. El cron se encarga de que los tokens no caduquen.

Lo que necesitas antes de empezar

  • Un servidor (VPS) con Coolify instalado.
  • Un dominio con acceso a su DNS para crear un subdominio, por ejemplo reply.tudominio.com.
  • Una cuenta de Instagram profesional (Business o Creator). Las cuentas personales no se pueden conectar.
  • Una cuenta en Meta for Developers con acceso al portafolio de Meta Business de la marca.
  • Una cuenta de Resend con tu dominio verificado (o un servidor SMTP propio). OpenReply no usa contraseñas: entras con un enlace mágico que llega al correo, así que sin email nadie puede iniciar sesión.

Parte 1: instalación en Coolify

Paso 1. Apunta el subdominio al servidor

En el panel DNS de tu dominio crea un registro A con el nombre reply y, como valor, la IP pública del servidor donde corre Coolify. Espera a que propague (normalmente unos minutos): Coolify solo podrá sacar el certificado SSL cuando el dominio ya resuelva.

Paso 2. Genera los secretos

Necesitas cuatro valores aleatorios. Puedes generarlos en cualquier terminal con OpenSSL y guardarlos en tu gestor de contraseñas (nunca en un documento compartido):

openssl rand -base64 32   # NEXTAUTH_SECRET
openssl rand -base64 32   # CRON_SECRET
openssl rand -hex 32      # ENCRYPTION_KEY (64 caracteres hex)
openssl rand -hex 16      # WEBHOOK_VERIFY_TOKEN

Atención: ENCRYPTION_KEY cifra los tokens de Instagram. Si la cambias o la pierdes, tendrás que volver a conectar todas las cuentas. Además, tiene que ser la misma en la web y en el worker.

Paso 3. Crea el servicio Docker Compose

OpenReply no tiene una imagen publicada en Docker Hub. La forma más cómoda es que Coolify la construya directamente desde el repositorio de GitHub con build.context: así no tienes que entrar por SSH ni compilar nada a mano. La imagen resultante (openreply-app:latest) se reutiliza en la web, el worker y el cron.

En Coolify entra en tu proyecto, pulsa + New, elige Docker Compose Empty, ponle de nombre openreply y pega este compose:

services:
  web:
    build:
      context: 'https://github.com/diwenne/openreply.git#main'
    image: 'openreply-app:latest'
    restart: unless-stopped
    command: ['sh', '-c', 'npx prisma migrate deploy && npm run start']
    environment:
      - SERVICE_FQDN_WEB_3000
      - 'NEXTAUTH_URL=https://reply.tudominio.com'
      - 'NEXTAUTH_SECRET=${NEXTAUTH_SECRET}'
      - 'CRON_SECRET=${CRON_SECRET}'
      - 'ENCRYPTION_KEY=${ENCRYPTION_KEY}'
      - 'DATABASE_URL=postgresql://openreply:${SERVICE_PASSWORD_POSTGRES}@postgres:5432/openreply'
      - 'REDIS_URL=redis://redis:6379'
      - 'RESEND_API_KEY=${RESEND_API_KEY:-}'
      - 'EMAIL_SERVER=${EMAIL_SERVER:-}'
      - 'EMAIL_FROM=${EMAIL_FROM}'
      - 'ALLOWED_EMAILS=${ALLOWED_EMAILS}'
      - META_GRAPH_API_VERSION=v25.0
      - 'INSTAGRAM_APP_ID=${INSTAGRAM_APP_ID:-}'
      - 'INSTAGRAM_APP_SECRET=${INSTAGRAM_APP_SECRET:-}'
      - 'FACEBOOK_APP_SECRET=${FACEBOOK_APP_SECRET:-}'
      - 'WEBHOOK_VERIFY_TOKEN=${WEBHOOK_VERIFY_TOKEN}'
    depends_on:
      postgres: { condition: service_healthy }
      redis: { condition: service_healthy }
    healthcheck:
      test: ['CMD-SHELL', 'wget -q -O /dev/null http://127.0.0.1:3000/api/auth/csrf || exit 1']
      interval: 15s
      timeout: 10s
      retries: 10
      start_period: 60s

  worker:
    image: 'openreply-app:latest'
    restart: unless-stopped
    command: ['npm', 'run', 'worker']
    environment:
      - 'DATABASE_URL=postgresql://openreply:${SERVICE_PASSWORD_POSTGRES}@postgres:5432/openreply'
      - 'REDIS_URL=redis://redis:6379'
      - 'ENCRYPTION_KEY=${ENCRYPTION_KEY}'
      - 'NEXTAUTH_SECRET=${NEXTAUTH_SECRET}'
      - 'NEXTAUTH_URL=https://reply.tudominio.com'
      - META_GRAPH_API_VERSION=v25.0
      - 'INSTAGRAM_APP_ID=${INSTAGRAM_APP_ID:-}'
      - 'INSTAGRAM_APP_SECRET=${INSTAGRAM_APP_SECRET:-}'
      - 'FACEBOOK_APP_SECRET=${FACEBOOK_APP_SECRET:-}'
    depends_on:
      web: { condition: service_started }

  cron:
    image: 'openreply-app:latest'
    restart: unless-stopped
    command: ['sh', 'scripts/cron.sh']
    environment:
      - 'CRON_BASE_URL=http://web:3000'
      - 'CRON_SECRET=${CRON_SECRET}'
    depends_on:
      web: { condition: service_healthy }

  postgres:
    image: 'postgres:16'
    restart: unless-stopped
    environment:
      - POSTGRES_DB=openreply
      - POSTGRES_USER=openreply
      - 'POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRES}'
    volumes:
      - 'openreply-pgdata:/var/lib/postgresql/data'
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -U openreply -d openreply']
      interval: 5s
      timeout: 5s
      retries: 10

  redis:
    image: 'redis:7-alpine'
    restart: unless-stopped
    command: ['redis-server', '--appendonly', 'yes', '--maxmemory-policy', 'noeviction']
    volumes:
      - 'openreply-redisdata:/data'
    healthcheck:
      test: ['CMD', 'redis-cli', 'ping']
      interval: 5s
      timeout: 5s
      retries: 10
Editor de Docker Compose de Coolify con el servicio OpenReply
El compose en el editor de Coolify: la imagen se construye desde GitHub.

Algunos detalles de este compose que me ahorraron problemas:

  • SERVICE_PASSWORD_POSTGRES y SERVICE_FQDN_WEB_3000 los rellena Coolify solo: la primera es una contraseña aleatoria para la base de datos y la segunda le dice que la web escucha en el puerto 3000.
  • Las variables de Meta llevan :- (valor vacío por defecto) para que puedas desplegar antes de tener la app de Instagram creada.
  • Redis va con appendonly y noeviction: si Redis se reinicia o se llena, no pierdes envíos que estaban en la cola.
  • El healthcheck de la web consulta /api/auth/csrf, una ruta ligera que responde en cuanto la app arranca.

Al guardar, Coolify muestra los cinco recursos del servicio:

Servicio openreply en Coolify con web, worker, cron, Postgres y Redis
Los cinco contenedores del servicio en Coolify.

Paso 4. Carga las variables de entorno

En el servicio abre Environment Variables. Coolify ya habrá detectado todas las variables que usa el compose (aparecen con la etiqueta “Used by Compose”); solo tienes que rellenarlas. Marca como Literal las que generaste con OpenSSL para que Coolify no interprete sus símbolos.

Variables de entorno de OpenReply en Coolify marcadas como Used by Compose
Coolify detecta las variables del compose; los valores no se muestran.
VariablePara qué sirveDe dónde sale
NEXTAUTH_SECRETFirma las sesionesPaso 2 (OpenSSL)
CRON_SECRETProtege las tareas programadasPaso 2 (OpenSSL)
ENCRYPTION_KEYCifra los tokens de InstagramPaso 2 (64 hex)
WEBHOOK_VERIFY_TOKENVerifica el webhook de MetaPaso 2
RESEND_API_KEYEnvía el enlace mágico de accesoResend → API Keys
EMAIL_FROMRemitente del correoEj.: OpenReply <[email protected]>
EMAIL_SERVERAlternativa SMTP a Resend (opcional)Tu proveedor de correo
ALLOWED_EMAILSCorreos que pueden entrarTus correos, separados por comas
INSTAGRAM_APP_IDID de la app de InstagramParte 2
INSTAGRAM_APP_SECRETSecreto de la app de InstagramParte 2
FACEBOOK_APP_SECRETValida la firma de los webhooksParte 2

No dejes vacía ALLOWED_EMAILS. Si lo haces, cualquiera que entre en tu dominio puede pedir un enlace y crearse un espacio de trabajo en tu servidor.

Paso 5. Asigna el dominio y despliega

En Domains, asigna al contenedor web el dominio https://reply.tudominio.com con el puerto interno 3000. Solo la web lleva dominio: el worker, el cron, Postgres y Redis no se exponen a internet. Activa la redirección de HTTP a HTTPS.

Dominio del contenedor web de OpenReply en Coolify con puerto interno 3000
Solo el contenedor web lleva dominio, con el puerto interno 3000.

Pulsa Deploy. El primer despliegue tarda unos minutos porque Coolify clona el repositorio y construye la imagen. Al arrancar, la web aplica las migraciones de la base de datos (prisma migrate deploy). Cuando termine, Postgres, Redis y web deben aparecer como healthy. El worker y el cron salen como unknown porque no tienen healthcheck propio: es normal.

Paso 6. Comprueba que todo responde

Abre https://reply.tudominio.com/api/health en el navegador. Debe indicar que la base de datos, Redis, la cola y el worker están bien:

Respuesta del endpoint api/health de OpenReply con base de datos, Redis, cola y worker en ok
/api/health con todo en verde y el worker sano.

Si worker.healthy sale en false, los DMs no se enviarán: revisa los logs del contenedor worker en Coolify.

Paso 7. Primer acceso

Entra en https://reply.tudominio.com, pulsa Sign in y escribe un correo que esté en ALLOWED_EMAILS. Abre el enlace que te llega y ya estás dentro. Si el correo no llega, revisa que el dominio de EMAIL_FROM esté verificado en Resend.

Parte 2: la app de Instagram en Meta for Developers

Paso 1. Pasa Instagram a cuenta profesional

En la app de Instagram: Configuración → Tipo de cuenta y herramientas y cambia a cuenta Business o Creator.

Paso 2. Crea la app en Meta

  1. Entra en developers.facebook.com/apps y pulsa Crear app.
  2. Como caso de uso, filtra por Todos y elige Administrar mensajes y contenido en Instagram.
  3. Tipo de app: Negocio. Asóciala al portafolio de Meta Business de la marca y pon un correo de contacto que revises.

No elijas Marketing API ni Inicio de sesión con Facebook. OpenReply usa el inicio de sesión con Instagram; con la variante de Facebook te aparecerá después un error de cliente que no coincide.

Paso 3. Copia los identificadores a Coolify

  • INSTAGRAM_APP_ID e INSTAGRAM_APP_SECRET: en el producto Instagram → Configuración de la API con inicio de sesión de Instagram (pulsa Mostrar). Ojo: no es el mismo número que el ID de la app de Facebook.
  • FACEBOOK_APP_SECRET: Configuración de la app → Básica → Clave secreta de la app.

Pégalas en las variables del servicio y vuelve a desplegar.

Paso 4. Añade tu Instagram como evaluador

Mientras la app no pase la revisión de Meta, solo funciona con cuentas que tengan un rol en ella. Hay que completar las dos mitades:

  1. En la app de Meta: Roles de la app → Roles → Evaluadores de Instagram, añade el usuario exacto y envía la invitación.
  2. En el móvil, desde esa cuenta de Instagram: Perfil → menú → Configuración y actividad → Apps y sitios web → Invitaciones de evaluador y acepta.

Si falta una de las dos, al conectar verás el error «Insufficient Developer Role».

Paso 5. URL de redirección (OAuth)

En el producto Instagram → Configurar el inicio de sesión empresarial de Instagram, añade en URI de redireccionamiento de OAuth válidos exactamente esta dirección, sin barra final:

https://reply.tudominio.com/api/instagram/callback

Paso 6. Configura el webhook

  1. Producto Instagram → Configurar webhooks.
  2. URL de devolución de llamada: https://reply.tudominio.com/api/webhook
  3. Token de verificación: el mismo valor de WEBHOOK_VERIFY_TOKEN. Pulsa Verificar y guardar.
  4. Suscríbete a comments y messages. Con solo comments funciona el comentario → DM, pero no las respuestas a DMs ni a historias.
  5. Prueba con el botón Probar junto a comments → Enviar a mi servidor, y comprueba que llega en los logs del contenedor web.

Usa siempre el dominio exacto que pusiste en Coolify. Si el dominio redirige (por ejemplo, de www a sin www), Meta no sigue la redirección y los webhooks dejan de llegar sin avisar.

Paso 7. Páginas legales y publicar la app

En modo desarrollo, Meta solo envía los webhooks de prueba: los comentarios reales llegan cuando la app está en vivo. OpenReply ya trae las páginas legales que pide Meta, así que en Configuración de la app → Básica solo tienes que rellenar:

Política de privacidad:  https://reply.tudominio.com/privacy
Condiciones del servicio: https://reply.tudominio.com/terms
Eliminación de datos:     https://reply.tudominio.com/data-deletion

Después pulsa Publicar. La app usa los permisos instagram_business_basic, instagram_business_manage_comments e instagram_business_manage_messages. Para tus propias cuentas basta el acceso estándar; solo necesitas la revisión de Meta si vas a conectar cuentas de terceros.

Paso 8. Si venías de ManyChat, cédele el control a OpenReply

En Meta Business Suite → Configuración → Integraciones → Enrutamiento de conversaciones → Apps de socios, elimina ManyChat (o la herramienta anterior) y, en la app de OpenReply, activa Acceder a todas las conversaciones y Tomar el control de las conversaciones. Si no lo haces, los botones del DM fallan con el error «not the thread owner».

Parte 3: conecta Instagram y crea tu primera campaña

  1. En OpenReply ve a Settings → Connect Instagram y acepta los permisos.
  2. En Campaigns → New Campaign elige la publicación, la palabra clave (por ejemplo, GUIA) y el mensaje del DM. Opcionalmente, una respuesta pública al comentario y pedir que te sigan antes de enviar el enlace.
  3. Desde otra cuenta de Instagram comenta la palabra clave en esa publicación.
  4. Comprueba que llega el DM y que en DM Logs aparece como enviado.
Lista de campañas de OpenReply con palabras clave y mensaje del DM
Campañas con sus palabras clave, mensaje y estadísticas.

El panel te muestra de un vistazo las campañas activas, los DMs enviados, los clics y las palabras clave que más se usan:

Panel de OpenReply con campañas activas, DMs enviados y palabras clave
El panel de OpenReply.

Y en Diagnostics tienes el estado del worker, la cola y cualquier fallo de webhooks o de renovación de tokens. Es la primera pantalla que miro cuando algo no funciona:

Pantalla de diagnóstico de OpenReply con el worker sano y la cola vacía
Diagnostics: estado del worker, la cola y los fallos.

Mantenimiento

  • Tokens de Instagram: el contenedor cron los renueva solo, una vez al día. Si el cron se detiene, las automatizaciones se paran sin dar error.
  • Actualizar OpenReply: como la imagen se construye desde GitHub, basta con pulsar Redeploy en Coolify para traer la última versión de la rama main.
  • Copias de seguridad: programa backups del volumen de Postgres desde Coolify.

Problemas frecuentes

SíntomaCausa y solución
No llega el correo de accesoDominio de EMAIL_FROM sin verificar en Resend, RESEND_API_KEY vacía o el correo no está en ALLOWED_EMAILS.
«Insufficient Developer Role»La cuenta no aceptó la invitación de evaluador desde la app de Instagram.
Error de redirect_uri al conectarLa URL de OAuth en Meta no coincide exactamente con /api/instagram/callback.
Los comentarios reales no disparan nadaLa app sigue en modo desarrollo, falta suscribir comments o el dominio redirige.
Los DMs no salenWorker caído: revisa /api/health y los logs del worker. ENCRYPTION_KEY debe ser igual en web y worker.
«not the thread owner»ManyChat sigue controlando las conversaciones.
Dejó de funcionar a las semanasToken caducado porque el cron no corre: revisa el contenedor cron y CRON_SECRET.

Preguntas frecuentes

¿OpenReply es gratis?

El software es libre y gratuito (licencia MIT). Lo que pagas es el servidor donde lo instalas y, si lo usas, el plan de Resend para los correos de acceso. Si ya tienes un VPS con Coolify, el coste extra es prácticamente nulo.

¿Es seguro para mi cuenta de Instagram?

Sí, porque usa la API oficial de Meta con los permisos que tú apruebas. No guarda tu contraseña ni simula clics en el navegador, que es lo que suele provocar bloqueos.

¿Necesito saber programar?

No hace falta programar, pero sí sentirte cómodo con Coolify, DNS y el panel de Meta for Developers. Si sigues los pasos en orden, la instalación se hace en una tarde.

¿Puedo conectar varias cuentas de Instagram?

Sí. Con cuentas propias que tengan rol en la app basta el acceso estándar. Para conectar cuentas de clientes u otras personas, Meta exige pasar la revisión de la app.

¿Quieres que lo monte por ti?

Si prefieres tener tus respuestas automáticas funcionando sin pelearte con Docker ni con Meta, puedo instalarlo y dejarlo configurado con tus campañas. Mira mi servicio de automatizaciones e IA o escríbeme y pídeme una auditoría gratuita.

Newsletter

Estrategias que venden, directo a tu correo

Ideas prácticas de web, SEO e IA para conseguir más clientes. Sin relleno.

Fran García

Estratega de marketing digital. Diseño sistemas web con WordPress, WooCommerce, SEO y GEO para negocios locales y emprendedores que quieren vender más en Paraguay.

En este artículo

Newsletter

Estrategias que venden, directo a tu correo

Ideas prácticas de web, SEO e IA para conseguir más clientes. Sin relleno.

¿Tu web te trae clientes?

Te reviso la web y te digo, en lenguaje claro, qué está frenando tus ventas.
Auditoría gratuita

Sigue leyendo

Estrategia digital

Tienda online o vender solo por Instagram: cuándo dar el salto

Cuándo conviene pasar de vender solo por Instagram a tener tu propia tienda online: señales, límites de las redes, cómo…

WooCommerce

Cómo cobrar online en Venezuela: Pago Móvil, Zelle, Binance Pay y más

Cómo cobrar por internet en Venezuela con Pago Móvil, transferencias, Zelle, Binance Pay y efectivo en dólares, verificar pagos sin…

¿Tu página web trabaja para ti o solo existe?

Te reviso la web, tu perfil de Google y tus redes, y te digo en lenguaje claro qué está frenando tus ventas. Sin compromiso y hablando directo conmigo.
Quiero una auditoría gratuita de mi negocio.