Spanish only
This page has not been translated yet — the content below is in Spanish. It documents the reference deployment: three application containers (web, queue, scheduler) plus PostgreSQL 18, orchestrated with Docker Compose, installed from the infraestructura.zip delivery package.
Instalación con contenedores (Docker)
Despliegue de referencia de BIAM: tres contenedores de aplicación (web, cola y planificador) construidos a partir de una misma imagen, más PostgreSQL 18 en un cuarto contenedor, orquestados con Docker Compose. Es el despliegue con el que se instala BIAM en los clientes; la instalación nativa queda como alternativa para quien no quiera contenedores.
Esta página describe el procedimiento tal como funciona hoy (paquete biam-docker, septiembre 2026). Donde un paso es manual porque todavía no lo automatiza la imagen, se dice explícitamente.
Antes de empezar
Ten a mano el paquete de entrega (infraestructura.zip) y los requisitos de hardware. La URL con la que las personas abrirán BIAM (APP_URL) conviene decidirla antes: los enlaces de los correos salen de ahí.
1. Qué se entrega y dónde queda
El paquete es un único infraestructura.zip con tres piezas. En el servidor, el código y el estado viven fuera de los contenedores, en /data/biam/biam/: los contenedores solo montan esa carpeta.
infraestructura.zip En el servidor
├── app-biam.zip ──────────────► /data/biam/biam/html/ ← código (= /var/www/html en los 3 contenedores)
│ ├── .env ← configuración y secretos de ESTA instancia
│ ├── storage/ ← ESTADO: installed.json, licencia, paquetes, handlers, evidencia RPA, logs
│ └── public/ ← SPA ya construido (index.html + assets/)
├── db.env ──────────────► /data/biam/biam/db.env ← POSTGRES_USER / POSTGRES_PASSWORD / POSTGRES_DB
│ /data/biam/biam/postgres-data/ ← datos de PostgreSQL
└── infraestructura/ ──────────────► <carpeta del compose>/ ← p. ej. /opt/biam-infra
├── docker-compose.yaml
└── DockerFiles/{biam_app, biam.ini}Todo lo que hay que respaldar y lo que un cambio de versión jamás debe pisar está en /data/biam/biam/: el .env, storage/ y postgres-data/. El código de html/ se reemplaza; el estado se conserva.
2. Contenedores e imagen
| Contenedor | Imagen | Qué corre | Puerto | Detalles |
|---|---|---|---|---|
biam | bayoex/biam (se construye en el servidor desde DockerFiles/biam_app) | Apache + API + SPA; el «Probar conexión» de los conectores | 8005:80 | Apache arranca como root y atiende como www-data (uid 33) |
biam-queue | la misma | php artisan queue:work — tareas de aprovisionamiento, sincronización del AD, correos | — | corre como 33:33, HOME=/tmp (Chromium), shm_size: 1g, stop_grace_period: 11m |
biam-scheduler | la misma | php artisan schedule:work — tareas programadas (sync cada 15 min, ventanas de ciclo de vida, canarios) | — | corre como 33:33 |
biam-db (servicio dbbiam) | postgres:18 | PostgreSQL | 5445:5432 | credenciales en db.env; datos en /data/biam/biam/postgres-data |
La imagen (php:8.4-apache) trae las extensiones PHP que BIAM necesita (ldap, pdo_pgsql, intl, zip, gd, bcmath, opcache, pcntl), Chromium + chromedriver + Python 3 con Selenium para los conectores RPA, git, unzip y composer. biam.ini fija 512 MB de memoria, subidas de hasta 64 MB y OPcache con revalidación cada 60 s (como el código va montado desde /data, un cambio de código se ve en menos de un minuto sin reiniciar Apache).
La imagen no tiene script de arranque
El contenedor biam levanta Apache y nada más: no genera llaves, no ajusta permisos, no migra ni recachea la configuración. Todo eso se hace a mano, en el orden de esta guía. Saltarse un paso da el clásico «500 sin rastro» (ver Solución de problemas).
3. Paso 0 — Docker y Docker Compose
El servidor suele venir limpio. Instala Docker Engine y el plugin de Compose desde el repositorio oficial de Docker (no el docker.io/podman de la distribución):
# Podman y runc chocan con docker-ce: quitarlos si están
sudo dnf remove -y podman runc buildah 2>/dev/null
sudo dnf -y install dnf-plugins-core
sudo dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo
sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker
# Puerto de BIAM en firewalld (el tráfico publicado por Docker entra por su propia cadena;
# igual conviene declararlo)
sudo firewall-cmd --permanent --add-port=8005/tcp && sudo firewall-cmd --reloadsudo apt-get update && sudo apt-get install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now dockerComprobación: docker compose version (v2) y docker run --rm hello-world. Si el servidor no tiene salida a Internet, pide antes que se abra el acceso a Docker Hub, a los mirrors de Debian y a Packagist/GitHub: la imagen se construye en el servidor y composer install descarga las dependencias desde el servidor (sección 6).
SELinux (RHEL)
Con Docker CE el demonio corre por defecto sin confinamiento SELinux para los contenedores y los volúmenes funcionan tal cual. Si el demonio se configuró con "selinux-enabled": true (o usas Podman), añade la etiqueta :Z a los tres volúmenes del compose (/data/biam/biam/html:/var/www/html:Z, ídem postgres-data), o el contenedor verá «Permission denied».
4. Carpetas, db.env y código
sudo mkdir -p /data/biam/biam/{html,postgres-data} /opt/biam-infra
cd /tmp && unzip infraestructura.zip
# 1) el compose y la definición de la imagen
sudo cp -r infraestructura/* /opt/biam-infra/
# 2) credenciales de PostgreSQL — genera una contraseña PROPIA de esta instalación
sudo tee /data/biam/biam/db.env > /dev/null <<EOF
POSTGRES_USER=biam
POSTGRES_PASSWORD=$(openssl rand -base64 24 | tr -d '/+=')
POSTGRES_DB=biam
EOF
sudo chmod 600 /data/biam/biam/db.env
# 3) el código
sudo unzip -q app-biam.zip -d /data/biam/biam/html
# 4) dueño www-data (uid/gid 33 de la imagen) para TODO html/, no solo storage/:
# el asistente reescribe el .env de forma atómica y necesita escribir en su DIRECTORIO
sudo chown -R 33:33 /data/biam/biam/htmlSi el db.env del paquete ya trae una contraseña, cámbiala igual: cada instalación debe nacer con sus propios secretos (ver el aviso de la sección 5).
5. El .env de referencia
/data/biam/biam/html/.env es el único archivo de configuración de la aplicación. Esta es su estructura real, con valores de ejemplo:
APP_NAME=BIAM
APP_ENV=production
APP_DEBUG=false
# La URL con la que la gente abre BIAM: de aquí salen los enlaces de los correos
# (bienvenida, recuperación de contraseña). Con proxy TLS delante: https://…
APP_URL=http://10.0.0.10:8005
APP_TIMEZONE=America/La_Paz
APP_LOCALE=es
APP_FALLBACK_LOCALE=en
# Llaves PROPIAS de cada instalación (sección 6). Las líneas deben existir,
# aunque estén en blanco: `key:generate` solo reemplaza una línea existente.
APP_KEY=
JWT_SECRET=
LOG_CHANNEL=stack
LOG_STACK=app,critical
# `debug` mientras pruebas; nunca `error` si quieres ver los avisos (W)
LOG_LEVEL=info
# La conexión a la base (DB_HOST/PORT/DATABASE/USERNAME/PASSWORD) la escribe el
# asistente de instalación en el paso «Base de datos». No hace falta ponerla a mano.
DB_CONNECTION=main
DB_QUEUE_RETRY_AFTER=960
SESSION_DRIVER=array
QUEUE_CONNECTION=database
# `file` mientras dura el asistente; `database` después (sección 8)
CACHE_STORE=file
FILESYSTEM_DISK=local
# Licenciamiento y catálogo de conectores (BIAM Hub)
BIAM_HUB_URL=https://hub.b-iam.com
BIAM_HUB_PUBLIC_KEY=<la imprime `php artisan hub:public-key` en el Hub>
# Aprovisionamiento RPA
BIAM_RPA_EVIDENCE=/var/www/html/storage/app/rpa-evidence
# Handlers RPA propios del cliente (se cargan por zip desde la pantalla «Handlers RPA»):
# FUERA del árbol de código, para que un cambio de versión no los pise
BIAM_HANDLERS_PATH=/var/www/html/storage/app/handlers
# Presupuesto por tarea del worker (segundos); DB_QUEUE_RETRY_AFTER debe ser MAYOR
BIAM_TASK_TIMEOUT=900Lo que no va en el .env: el servidor SMTP, la conexión LDAP/AD, la licencia y las credenciales de los conectores se configuran desde la consola y quedan cifrados en la base de datos.
Secretos propios de cada instalación
APP_KEY, JWT_SECRET y la contraseña de PostgreSQL nunca se copian de otra instancia ni viajan dentro de un zip. Con la misma APP_KEY dos instalaciones comparten la llave que cifra las credenciales de los conectores y del directorio; con el mismo JWT_SECRET, una sesión de una instancia vale en la otra. Si el paquete que recibiste trae valores en esas líneas, regenéralos en la sección 6.
La APP_KEY de una instancia con datos no se regenera nunca (cifra credenciales, secretos TOTP y el fingerprint de la licencia); para rotarla existe php artisan biam:secrets-recrypt. Regenerar JWT_SECRET solo cierra todas las sesiones.
6. Construir, levantar y preparar la aplicación
cd /opt/biam-infra
# La imagen se construye aquí (Docker Hub + mirrors de Debian) — 5–10 minutos
docker compose build biam
# Solo la base y el contenedor web por ahora: la cola y el planificador van
# después del asistente (sección 8)
docker compose up -d dbbiam biam
# Dependencias PHP (Packagist/GitHub). Siempre como www-data y con HOME escribible
docker compose exec -u www-data -e HOME=/tmp biam \
composer install --no-dev --optimize-autoloader
# Llaves PROPIAS de esta instalación (las líneas APP_KEY= y JWT_SECRET= deben existir)
docker compose exec -u www-data biam php artisan key:generate --force
docker compose exec -u www-data biam php artisan jwt:secret --force
# Enlace público de storage
docker compose exec -u www-data biam php artisan storage:linkEdita ahora APP_URL en el .env si aún no lo hiciste. Comprobación antes de seguir: curl -s http://localhost:8005/up responde 200.
Siempre -u www-data
El servicio biam no define usuario, así que docker compose exec biam php artisan … corre como root: lo que artisan cree en storage/ (caché, logs, vistas) nace de root y Apache, que atiende como www-data, ya no puede escribirlo. Si te pasó, repara con chown -R 33:33 /data/biam/biam/html/storage /data/biam/biam/html/bootstrap/cache.
7. Asistente de instalación
Abre http://<host>:8005/install y sigue los tres pasos (no existe ningún usuario por defecto):
- Requisitos — el asistente comprueba versión de PHP, extensiones y escritura del
.envy destorage/. Todo debe estar en verde. - Base de datos — host
dbbiam(el nombre del servicio en el compose, no una IP), puerto5432(el interno del contenedor, no el5445publicado hacia fuera), y base, usuario y contraseña dedb.env. El asistente prueba la conexión antes de guardarla (INIT201Wsi no conecta) y escribe las variablesDB_*en el.env. - Migración — crea el esquema y los catálogos iniciales.
- Administrador — crea el primer usuario root con las credenciales que tú elijas y cierra la instalación en el mismo paso (marca
storage/app/installed.jsony cachea la configuración).
Desde ese momento el asistente queda bloqueado (INIT101W si alguien vuelve a intentarlo) y puedes entrar con el root recién creado.
8. Después del asistente: caché en base de datos y el resto de contenedores
Durante el asistente la caché de la aplicación vive en archivos (CACHE_STORE=file) porque la tabla cache todavía no existía. En operación debe estar en la base de datos: es lo que hace que los tres contenedores compartan los bloqueos de las corridas RPA, los contadores de intentos y la señal de reinicio del worker.
sudo sed -i 's/^CACHE_STORE=.*/CACHE_STORE=database/' /data/biam/biam/html/.env
# IMPRESCINDIBLE: el cierre del asistente dejó la configuración cacheada; sin este
# comando, editar el .env y reiniciar NO cambia nada
docker compose exec -u www-data biam php artisan config:cache
# Ahora sí, la cola y el planificador (nacen ya con la caché en base de datos)
docker compose up -d biam-queue biam-scheduler
# Comprobación: debe decir Cache: database
docker compose exec -u www-data biam php artisan about --only=driversEsta regla vale para cualquier cambio posterior del .env (LOG_LEVEL, BIAM_TASK_TIMEOUT, APP_URL…): editar → config:cache como www-data → docker compose restart biam-queue biam-scheduler.
9. Qué se configura, cuándo y quién
| Momento | Qué | Quién lo hace hoy |
|---|---|---|
| Antes de levantar | APP_URL, APP_TIMEZONE, BIAM_HUB_*, db.env | La persona que instala |
| Antes del primer request | APP_KEY | A mano (key:generate, sección 6) — sin ella la página del asistente ni carga |
| Antes del primer login | JWT_SECRET | A mano (jwt:secret); el asistente lo generaría en el paso «Base de datos» si está en blanco, pero conviene no depender de eso |
| Asistente, paso «Base de datos» | DB_HOST, DB_PORT, DB_DATABASE, DB_USERNAME, DB_PASSWORD | El asistente |
| Asistente, paso «Administrador» | installed.json, caché de configuración y rutas | El asistente |
| Justo después del asistente | CACHE_STORE=database + config:cache + levantar cola y planificador | La persona que instala (sección 8) |
| Operación | BIAM_TASK_TIMEOUT, DB_QUEUE_RETRY_AFTER, LOG_LEVEL | La persona, siempre seguido de config:cache y reinicio de cola y planificador |
10. Respaldo e identidad de la instancia
Inmediatamente después de instalar, guarda fuera del servidor lo que identifica a esta instancia:
# Bloque de respaldo de identidad (APP_KEY, id de instancia y fingerprint): sale por pantalla,
# no deja copia en el servidor. Guardarlo en la bóveda de la organización.
docker compose exec -u www-data biam php artisan biam:secrets-backup > biam-secretos-<cliente>-$(date +%F).txtReglas de custodia de ese archivo y el procedimiento de restauración (biam:secrets-restore) están en la documentación técnica Custodia de secretos.
Rutina de respaldo: pg_dump de la base (docker compose exec dbbiam pg_dump -U biam biam > biam-$(date +%F).sql) más la carpeta /data/biam/biam/html/storage/app/ (licencia, paquetes de conectores instalados, handlers cargados, evidencia RPA y el marcador de instalación) y el .env. Sin la APP_KEY original, un respaldo de la base no sirve: los secretos cifrados no se pueden leer.
11. Configuración desde la consola
Con el root creado, en este orden:
- Licencia (Configuración → Licencia): activación en línea contra el Hub o
.licemitido para esta instancia. - Directorio (LDAP/LDAPS al controlador de dominio del cliente).
- Correo saliente (Configuración → Sistema → SMTP) y prueba de envío.
- Conectores: instalar los paquetes del catálogo, crear las instancias con sus credenciales y, en los sistemas legacy, configurar la «Ejecución por defecto» (ejecutable + intérprete) y las semillas de
{sequence}. - Handlers RPA (Integración → Handlers RPA): si el cliente necesita ajustar el código de un conector RPA, se sube el zip de la carpeta del handler desde esa pantalla; la copia anterior queda en el servidor y se puede restaurar. La primera vez, siembra la carpeta con los handlers del release:
docker compose exec -u www-data biam php artisan biam:handlers-migrate
docker compose exec -u www-data biam php artisan permissions:sync # si vienes de una versión anterior- Marca (nombre, logos, acento) y zona horaria de las ventanas de ciclo de vida.
Ninguna carpeta de storage/ se crea a mano: rpa-evidence/ la crea BIAM al lanzar el primer handler, handlers/ y private/handler-uploads/ la pantalla de Handlers RPA en su primer uso, private/connectors/ la instalación de un paquete y los logs Laravel. Si alguna «falta», el problema es el dueño de storage/ (sección 6).
Salidas de red que necesita el servidor en operación: el controlador de dominio (389/636), el SMTP, el Hub (https://hub.b-iam.com) y los paneles web de los sistemas legacy que se aprovisionan por RPA (Chromium corre dentro de biam-queue).
12. Verificación
curl -s http://<host>:8005/up→200.docker compose ps: los cuatro contenedoresUp;docker logs -f biam-queuemuestra el worker atendiendo y la sincronización del directorio cada 15 minutos.- En cada conector, «Probar conexión» en verde.
docker compose exec -u www-data biam php artisan biam:sync-usersy un alta de prueba con el monitor de aprovisionamiento abierto.
13. Solución de problemas
| Síntoma | Causa | Qué hacer |
|---|---|---|
/install (y cualquier página) responde 500 antes de instalar | APP_KEY en blanco: la imagen no la genera y sin ella ninguna ruta web arranca | php artisan key:generate --force como www-data (la línea APP_KEY= debe existir en el .env) |
Requisitos en verde, pero el paso «Base de datos» falla con INIT202W («no se puede escribir el .env») | El asistente reescribe el .env de forma atómica y necesita escribir en /data/biam/biam/html, no solo en el archivo | chown -R 33:33 /data/biam/biam/html |
Paso «Base de datos» con INIT201W | Host o puerto equivocados | Host dbbiam, puerto 5432; credenciales de db.env |
| Instalación «exitosa» y el login da 500 | JWT_SECRET en blanco (alguien migró a mano y el asistente saltó el paso que lo genera) | php artisan jwt:secret --force + config:cache, ambos como www-data |
Cambié el .env y no pasa nada | La configuración está cacheada desde el cierre del asistente | php artisan config:cache como www-data y reiniciar biam-queue y biam-scheduler |
| 500 sin rastro en el log tras correr artisan | Se ejecutó artisan como root y storage/ tiene archivos de root | chown -R 33:33 /data/biam/biam/html/storage /data/biam/biam/html/bootstrap/cache |
«Probar conexión» o una tarea RPA fallan con «No se pudo crear la carpeta de evidencia RPA…» (o, en versiones anteriores, un PermissionError de Python sobre storage/app/rpa-evidence) | storage/app no es escribible por www-data: se corrió artisan/composer como root o el chown no cubrió storage/ | chown -R 33:33 /data/biam/biam/html/storage. No hace falta crear la carpeta a mano: BIAM la crea al lanzar el handler |
| Una tarea RPA falla con Chromium («session not created», «crashed») | HOME no escribible o /dev/shm pequeño en el worker | Confirmar HOME=/tmp y shm_size: 1g en biam-queue (vienen en el compose de referencia) |
| Una tarea queda «Ejecutando» tras reiniciar contenedores | El worker murió a mitad de corrida | docker compose stop respeta stop_grace_period; BIAM la marca interrumpida (CONN504W) al vencer su presupuesto y permite reintentarla |
| La subida de un zip de handler falla por tamaño | Límite del zip (30 MB por defecto) o upload_max_filesize (64 MB en biam.ini) | Ajustar BIAM_HANDLER_UPLOAD_MAX_KB (y biam.ini si supera 64 MB) |
14. Recomendaciones para producción
- HTTPS: por BIAM pasan contraseñas del directorio. Pon un proxy TLS (nginx, HAProxy o el balanceador de la organización) delante del puerto 8005 y usa
https://…enAPP_URL. - PostgreSQL fuera de la LAN: el compose de referencia publica
5445:5432hacia toda la red. Si no necesitas acceder a la base desde fuera del servidor, quita esa línea o limítala a127.0.0.1:5445:5432. - Rotación de logs de Docker: añade a cada servicio
logging: { driver: json-file, options: { max-size: "50m", max-file: "5" } }o configúralo global en/etc/docker/daemon.json; sin tope, los logs JSON crecen indefinidamente. - Cambio de versión: descomprime el nuevo
app-biam.zipsobrehtml/(conservando.envystorage/),composer install,php artisan migrate --forceyconfig:cachecomowww-data, y reinicia cola y planificador después de que el worker termine su tarea en curso (docker compose stop biam-queueespera hastastop_grace_period).