Saltar al contenido principal

Guía de autoalojamiento

Pon en marcha tu propia instancia de Campbooks con Docker en unos minutos. Esta guía cubre la configuración completa: la pila, los secretos necesarios y cómo conectar cada integración externa.

¿Solo quieres probarlo en local? Ve directamente al Inicio rápido. Para usarlo en un servidor de verdad, lee también Ejecución en producción.

Qué obtienes

docker compose up ejecuta tres contenedores:

ServicioQué es
postgresPostgreSQL con la extensión pgvector (obligatorio)
webLa aplicación Rails (Puma detrás de Thruster)
workerTareas en segundo plano — análisis de correo, IA, indexación (Solid Queue)

Postgres contiene todo: datos de la app, caché, jobs y Action Cable (mediante los adaptadores Solid), además de las incrustaciones vectoriales para la búsqueda semántica (pgvector). Un cuarto servicio, opensearch, es opcional y solo alimenta el autocompletado de texto completo de contactos — consulta Búsqueda.

Los archivos subidos (adjuntos de correo guardados como Documentos) se almacenan en un volumen Docker local por defecto, o en almacenamiento de objetos compatible con S3 si lo configuras.

Requisitos previos

  • Docker y el plugin Docker Compose (Docker Desktop, o Docker Engine ≥ 24 con docker compose)
  • Unos 2 GB de RAM libres para la pila predeterminada (añade ~1 GB si activas OpenSearch)
  • openssl en tu máquina (ya disponible en macOS/Linux) para generar secretos
  • Opcional, para un despliegue real: un nombre de dominio y un proxy inverso que gestione el TLS (Caddy, Traefik, nginx)

Inicio rápido

git clone https://github.com/notacamp/campbooks.git
cd campbooks

cp .env.example .env
bin/generate-secrets # rellena SECRET_KEY_BASE, las claves AR y la contraseña de la BD

# (opcional) edita .env para añadir una clave de IA y las integraciones que quieras
docker compose up -d --build

# observa cómo levanta; el primer arranque crea las bases de datos y ejecuta las migraciones
docker compose logs -f web

Luego abre http://localhost:3000 y registra la primera cuenta — en una instancia autoalojada el registro está abierto, y el primer usuario crea el espacio de trabajo.

El primer arranque también inicializa un espacio de trabajo de demostración con el acceso admin@example.com / changeme123 (y partner@example.com). Cambia esa contraseña tras el primer inicio de sesión, o define SEED_PASSWORD en .env antes del primer arranque. Si no quieres los datos de demostración, simplemente registra tu propia cuenta y elimina el espacio de trabajo de demo.

La aplicación funciona completamente sin ninguna clave de API externa; las funciones de IA y las conexiones de buzón se activan a medida que añades credenciales (a continuación).

Para detenerla: docker compose down (añade -v para eliminar también la base de datos y los archivos subidos).

Configuración

Toda la configuración son variables de entorno en .env. bin/generate-secrets se encarga de los secretos obligatorios; todo lo demás es opcional. La lista anotada está en .env.example.

Obligatorias (generadas automáticamente)

VariableNotas
SECRET_KEY_BASEClave de sesión/firma de Rails. openssl rand -hex 64
ACTIVE_RECORD_PRIMARY_KEYCifra tokens OAuth y claves de IA en reposo. openssl rand -hex 16
ACTIVE_RECORD_DETERMINISTIC_KEYIgual que el anterior
ACTIVE_RECORD_KEY_DERIVATION_SALTIgual que el anterior
CAMPBOOKS_DATABASE_PASSWORDContraseña para el Postgres integrado

No necesitas config/master.key — el autoalojamiento lee SECRET_KEY_BASE del entorno.

Obligatorias (las defines tú)

VariableValor por defectoNotas
APP_HOSTlocalhostEl nombre de host con el que accedes a la app. Debe coincidir con la cabecera Host (localhost, una IP o tu dominio) — otros hosts se rechazan por seguridad.
FORCE_SSLfalseMantenlo en false para uso local sin HTTPS. Ponlo en true solo detrás de un proxy TLS (ver Producción).
SELF_HOSTED1Registro abierto + lee claves de IA desde el entorno.

Integraciones externas

Todas las integraciones son opcionales. Activa las que necesites; omite el resto.

Para cada proveedor OAuth debes registrar una app en la consola del proveedor y autorizar la URL de callback, que es <url-de-tu-app>/oauth/<proveedor>/callback — p. ej. http://localhost:3000/oauth/gmail/callback en local, o https://app.example.com/oauth/gmail/callback en producción.

Proveedores de IA

La IA es lo que hace que Campbooks sea Campbooks (organización automática, el asistente Scout, borradores de respuesta, análisis de documentos, búsqueda semántica) — pero todo es opcional y está desactivado hasta que añades una clave. Puedes definir claves aquí para toda la instancia, o dejar que cada usuario introduzca la suya en Configuración → IA (almacenada cifrada por espacio de trabajo).

VariableActiva
OPENAI_API_KEYIA de texto + análisis de documentos/visión + embeddings (búsqueda semántica). La clave única más completa.
ANTHROPIC_API_KEYIA de texto (Claude)
MISTRAL_API_KEYIA de texto (alojado en la UE)
DEEPSEEK_API_KEYIA de texto
GEMINI_API_KEYIA de texto + embeddings
  • Para el asistente/organización automática: define cualquier proveedor de texto.
  • Para el análisis de adjuntos/documentos y la mejor búsqueda: define OPENAI_API_KEY.
  • Sin proveedor de embeddings (OpenAI o Gemini), la búsqueda usa coincidencia por palabras clave.

Google — Gmail y Calendario

Permite que los usuarios inicien sesión con Google y conecten un buzón de Gmail (que también sincroniza su Google Calendar con el mismo permiso).

  1. Google Cloud Console → crea un proyecto → APIs y servicios → Credenciales → ID de cliente OAuth (tipo: Aplicación web).
  2. Activa la API de Gmail y la API de Google Calendar para el proyecto.
  3. Añade el URI de redireccionamiento: <url-de-tu-app>/oauth/gmail/callback.
  4. Define GOOGLE_CLIENT_ID y GOOGLE_CLIENT_SECRET.

Google Drive — "Enviar a Drive"

La exportación interactiva a Drive usa el scope completo de drive, un scope restringido de Google, por lo que necesita su propia app OAuth verificada por separado.

  1. Crea un segundo cliente OAuth (o un proyecto separado).
  2. Añade el scope https://www.googleapis.com/auth/drive y el URI de redireccionamiento <url-de-tu-app>/oauth/google/callback.
  3. Define GOOGLE_DRIVE_CLIENT_ID y GOOGLE_DRIVE_CLIENT_SECRET.

Zoho Mail

  1. Zoho API ConsoleAplicación basada en servidor.
  2. URI de redireccionamiento: <url-de-tu-app>/oauth/zoho/callback.
  3. Define ZOHO_CLIENT_ID, ZOHO_CLIENT_SECRET y ZOHO_REGION (eu, com, in, au, jp — debe coincidir con tu centro de datos Zoho).

Microsoft 365 / Outlook

  1. Centro de administración de EntraRegistros de aplicaciones → Nuevo registro. Tipos de cuenta admitidos: Cuentas en cualquier directorio organizacional (cuentas de trabajo/escuela; la app usa el endpoint /organizations/).
  2. Añade un URI de redireccionamiento web: <url-de-tu-app>/oauth/microsoft/callback.
  3. Crea un secreto de cliente.
  4. Define MICROSOFT_CLIENT_ID, MICROSOFT_CLIENT_SECRET y ENABLE_MICROSOFT_MAILBOX=1 (esto último muestra el botón "Conectar Microsoft 365").

Notion — "Enviar a Notion"

  1. notion.so/my-integrations → nueva integración, tipo Pública, con capacidades de lectura/inserción de contenido.
  2. URI de redireccionamiento: <url-de-tu-app>/oauth/notion/callback.
  3. Define NOTION_CLIENT_ID y NOTION_CLIENT_SECRET.

Si dejas estos valores sin definir, los usuarios aún pueden conectar Notion pegando un token de integración interna en Configuración.

Correo saliente (SMTP)

Sin SMTP, la app no envía correo (los códigos OTP de registro, las notificaciones y los informes se omiten — está bien para una prueba de un solo usuario, pero lo necesitarás para uso real).

SMTP_ADDRESS=smtp.example.com
SMTP_PORT=587
SMTP_USERNAME=you@example.com
SMTP_PASSWORD=your_smtp_password
MAILER_FROM=Campbooks <no-reply@example.com>

Almacenamiento de archivos (S3)

Por defecto, los archivos subidos viven en el volumen Docker storage. Para usar almacenamiento de objetos (recomendado si ejecutas varias réplicas web o quieres copias de seguridad más sencillas), define:

S3_ACCESS_KEY_ID=...
S3_SECRET_ACCESS_KEY=...
S3_BUCKET=campbooks-storage
S3_REGION=eu-central-1
# Para proveedores que no son AWS (MinIO, Hetzner, Backblaze B2, ...):
S3_ENDPOINT=https://...
S3_FORCE_PATH_STYLE=true

Búsqueda (OpenSearch)

OpenSearch es opcional y solo alimenta el autocompletado de texto completo de contactos. La búsqueda de correo, la búsqueda de documentos y la paleta Cmd+K usan Postgres + pgvector y funcionan sin él; la búsqueda de contactos usa coincidencia SQL como alternativa. Para activarlo:

# en .env
OPENSEARCH_URL=http://opensearch:9200
docker compose --profile search up -d

Monitorización de errores y notificaciones push

  • SENTRY_DSN — un DSN compatible con Sentry (p. ej. GlitchTip autoalojado). Desactivado si no se define.
  • APNS_* / FCM_* — solo necesario si compilas las apps nativas iOS/Android. Desactivado si no se define.

Ejecución en producción

Para cualquier uso más allá del local, gestiona el TLS con un proxy inverso y activa SSL.

  1. Apunta un dominio a tu servidor y define en .env:
    APP_HOST=app.example.com
    FORCE_SSL=true
    WEB_PORT=3000
  2. Pon un proxy con TLS delante. Con Caddy (HTTPS automático) basta con:
    app.example.com {
    reverse_proxy localhost:3000
    }
    El proxy habla HTTPS con el mundo y reenvía al contenedor en :3000; FORCE_SSL=true hace que Rails emita enlaces https, establezca cookies seguras y envíe HSTS. (El endpoint de salud /up sigue siendo accesible por HTTP plano para las comprobaciones.)
  3. docker compose up -d --build.

No expongas la aplicación por HTTP plano en internet. Con FORCE_SSL=false las sesiones y las cookies viajan sin cifrar. Usa siempre un proxy TLS en producción.

Copias de seguridad

Dos cosas guardan estado: el volumen de Postgres y los archivos subidos.

# Base de datos (la BD de la app; caché/cola/cable son regenerables)
docker compose exec -T postgres pg_dump -U campbooks_app cb_primary | gzip > campbooks-$(date +%F).sql.gz

# Archivos subidos (solo si usas almacenamiento en disco local, no S3)
docker run --rm -v campbooks_storage:/data -v "$PWD":/backup alpine \
tar czf /backup/campbooks-storage-$(date +%F).tar.gz -C /data .

Guarda las copias de seguridad fuera del servidor. Si usas S3 para el almacenamiento, aquí solo necesitas hacer copia de la base de datos.

Actualizaciones

git pull
docker compose up -d --build # el entrypoint ejecuta las migraciones al arrancar

Haz una copia de seguridad de la base de datos primero. Las migraciones se ejecutan automáticamente cuando arranca el contenedor web.

Consola y tareas

docker compose exec web bin/rails console
docker compose exec web bin/rails db:seed # datos de demo opcionales / inicio de sesión

Solución de problemas

Cada petición redirige a https:// y falla. FORCE_SSL está activado pero no hay proxy TLS. Pon FORCE_SSL=false para uso local, o instala un proxy TLS delante para producción.

"Blocked hosts" / 403 en todas las páginas. APP_HOST no coincide con cómo accedes a la app. Ponlo en el nombre de host/IP exacto de la barra de URL y recrea los contenedores.

web se reinicia continuamente con un error de base de datos/extensión. Asegúrate de que el servicio postgres usa la imagen pgvector/pgvector integrada (una imagen postgres estándar no puede ejecutar CREATE EXTENSION vector). Si la cambiaste, vuelve a la original.

worker registra errores justo después de arrancar. Espera a que web termine las migraciones; los errores transitorios durante el primer arranque se resuelven una vez que web está sano.

Falta un secreto obligatorio al ejecutar docker compose up. Saltaste bin/generate-secrets, o falta una clave en .env. Vuelve a ejecutar el script.