Servidor propio
Layers en tu servidor
Una aplicación y unos pocos servicios en un solo docker-compose.yml. También se instala en una red aislada; tus datos nunca salen de tu infraestructura.
La imagen hissih/layers en Docker Hub: más de 20.000 descargas. 90 días de prueba; después se necesita una licencia.
Instalar con IA
Instálalo con un asistente de IA
Pega el prompt en ChatGPT, Claude o cualquier otro asistente. Lee la guía completa y te acompaña paso a paso: dominio, correo, llamadas, editores, modelo de IA.
Guía para IA y para personas: layers.md/self-hosted/llms.txt
Ayúdame a instalar Layers en mi servidor. Guía: https://layers.md/self-hosted/llms.txt (versión completa: https://layers.md/self-hosted/llms-full.txt). Guíame paso a paso y pregúntame primero por el dominio, el correo y el modelo de IA. De qué está hecho
Una aplicación y unos pocos servicios a su lado
Todo va en un solo docker-compose.yml. Solo Layers y PostgreSQL son obligatorios; añade el resto según lo necesites.
Layers
8080
Todo el espacio de trabajo, la API y el panel de administración God Mode: una sola aplicación Java, un solo puerto.
PostgreSQL
5432
Base de datos. Incluida en compose, o tu propio servidor externo.
Búsqueda: Manticore
9308
Búsqueda en tareas, páginas, chats y archivos. Manticore es un contenedor ligero aparte, ya incluido en compose. ¿Ya tienes un clúster de Elasticsearch? Layers también funciona con él.
Sin un servicio aparte: Lucene integrado, con el índice en el directorio de archivos.
LiveKit
7880 · 7881 · UDP 50000–50100
Llamadas y compartir pantalla. Para grabar hace falta el servicio LiveKit Egress, que se instala aparte.
Sin él, no hay llamadas; los chats siguen funcionando.
SMTP
587 / 465
Tu servidor de correo: invitaciones, confirmación de registro, restablecimiento de contraseña.
Sin él, no se envían correos.
SumDoc
8090 · /sumdoc
Edita .docx en el navegador.
Sin él, los documentos se abren como una tarjeta de descarga.
SumSheet
8092 · /sumsheet
Edita .xlsx y .xlsm en el navegador.
Sin él, las hojas de cálculo se abren como una tarjeta de descarga.
Servidor MCP
8091 · /mcp
El asistente y los agentes externos (Claude, Cursor) trabajan con tareas y páginas.
Sin él, el asistente solo responde, sin realizar acciones.
LLM
/v1 compatible con OpenAI
Tu modelo: Ollama o cualquier servidor compatible con OpenAI, o un proveedor en la nube con clave.
Sin él, no hay funciones de IA.
Linux x86-64 + Docker
Las imágenes se compilan para linux/amd64. Docker y Docker Compose.
Layers: 2 GB de RAM
Mínimo para la aplicación, más PostgreSQL.
Editores: 2 GB + ~250 MB
por documento abierto. Cada documento se ejecuta en su propio proceso.
Archivos de hasta 900 MB
por defecto. El límite se cambia con una variable.
Instalación
De un servidor vacío al primer inicio de sesión
Trece pasos, cada uno con código listo. Las contraseñas y claves de los ejemplos son marcadores change-me: sustitúyelos.
- 1
Prepara el servidor
Linux x86-64 con Docker y Docker Compose. Un dominio que apunte al servidor, por ejemplo
example.com. Dentro de una red privada puedes usarhttp://IP:8080en su lugar.Genera tu propia contraseña para cada marcador
change-me.Terminaldocker --version docker compose version mkdir -p /opt/layers && cd /opt/layers openssl rand -hex 24 - 2
Crea docker-compose.yml
Un solo archivo para toda la instalación. Sustituye
example.compor tu dominio y cadachange-me-…por tu propio valor. Quita los servicios que no necesites (llamadas, editores, MCP) junto con sus variables.El volumen de Layers debe ser
/root/layers_data: ahí viven los archivos, la configuración de God Mode y los secretos. La contraseña de la base de datos aparece dos veces y debe coincidir; lo mismo con la clave de LiveKit.Las imágenes de Layers y de los editores están en Docker Hub: hissih/layers.
docker-compose.ymlname: layers services: db: image: postgres:16-alpine restart: unless-stopped environment: POSTGRES_DB: layers POSTGRES_USER: layers POSTGRES_PASSWORD: change-me-db volumes: - pg_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U layers -d layers"] interval: 5s retries: 20 manticore: image: manticoresearch/manticore:latest restart: unless-stopped volumes: - manticore_data:/var/lib/manticore layers: image: hissih/layers:latest platform: linux/amd64 restart: unless-stopped depends_on: db: { condition: service_healthy } manticore: { condition: service_started } ports: - "127.0.0.1:8080:8080" volumes: - layers_data:/root/layers_data environment: SPRING_PROFILES_ACTIVE: server # Base de datos DB_SERVER_URL: jdbc:postgresql://db:5432/layers DB_SERVER_USERNAME: layers DB_SERVER_PASSWORD: change-me-db # Panel de administración /godmode ADMIN_USERNAME: admin ADMIN_PASSWORD: change-me-admin # Dominio LAYERS_DOMAIN: example.com LAYERS_APP_DOMAIN: example.com APP_REDIRECT_URL: https://example.com APP_CORS_ALLOWED_ORIGINS: https://example.com # Búsqueda SEARCH_PROVIDER: manticore SEARCH_MANTICORE_ENABLED: "true" SEARCH_MANTICORE_URL: http://manticore:9308 SEARCH_ELASTICSEARCH_ENABLED: "false" # Llamadas LIVEKIT_ENABLED: "true" LIVEKIT_URL: ws://livekit:7880 LIVEKIT_PUBLIC_URL: wss://example.com/livekit/ LIVEKIT_API_KEY: change-me-livekit-key LIVEKIT_API_SECRET: change-me-livekit-secret-min-32-characters # Correo (saliente) MAIL_PROVIDER: smtp SPRING_MAIL_HOST: smtp.example.com SPRING_MAIL_PORT: "587" SPRING_MAIL_USERNAME: noreply@example.com SPRING_MAIL_PASSWORD: change-me-smtp SPRING_MAIL_SMTP_AUTH: "true" SPRING_MAIL_SMTP_STARTTLS_ENABLE: "true" # Editores SumDoc y SumSheet (direcciones que ve el navegador) LAYERS_FASTDOC_URL: https://example.com/sumdoc LAYERS_FASTSHEET_URL: https://example.com/sumsheet # IA: el modelo se conecta en God Mode → IA AI_ENABLED: "true" ASSISTANT_MCP_URL: http://mcp:8091/mcp AI_USER_MODEL_CHOICE: "true" livekit: image: livekit/livekit-server:latest restart: unless-stopped environment: LIVEKIT_CONFIG: | port: 7880 bind_addresses: [""] rtc: tcp_port: 7881 port_range_start: 50000 port_range_end: 50100 use_external_ip: true keys: change-me-livekit-key: change-me-livekit-secret-min-32-characters webhook: api_key: change-me-livekit-key urls: - http://layers:8080/v1/livekit/webhook ports: - "7880:7880" - "7881:7881" - "7882:7882/udp" - "50000-50100:50000-50100/udp" sumdoc: image: hissih/sumdoc-webhost:latest platform: linux/amd64 restart: unless-stopped command: ["--base-path", "/sumdoc", "--max-cabins", "12", "--idle-min", "20", "--auth-url", "http://layers:8080/v1/me", "--attach-url", "http://layers:8080/v1/attachments/{id}/content"] ports: - "127.0.0.1:8090:8090" volumes: - sumdoc_cabins:/data/cabins sumsheet: image: hissih/sumsheet-webhost:latest platform: linux/amd64 restart: unless-stopped command: ["--base-path", "/sumsheet", "--max-cabins", "12", "--idle-min", "20", "--auth-url", "http://layers:8080/v1/me", "--attach-url", "http://layers:8080/v1/attachments/{id}/content"] ports: - "127.0.0.1:8092:8092" volumes: - sumsheet_cabins:/data/cabins mcp: image: layers-mcp-server:from-distribution # Imagen del servidor MCP de la distribución restart: unless-stopped depends_on: [layers] environment: SPRING_PROFILES_ACTIVE: server SERVER_PORT: "8091" LAYERS_BACKEND_BASEURL: http://layers:8080 LAYERS_BACKEND_FORWARDINCOMINGAUTH: "true" LAYERS_BACKEND_REQUIREINCOMINGAUTH: "true" ports: - "127.0.0.1:8091:8091" volumes: pg_data: manticore_data: layers_data: sumdoc_cabins: sumsheet_cabins: - 3
Elige el motor de búsqueda
Layers incluye tres motores de búsqueda, que se eligen con
SEARCH_PROVIDER(auto,manticore,elasticsearch,lucene).Manticore, el recomendado: un contenedor ligero aparte, ya incluido en compose. Elasticsearch, si tu empresa ya tiene un clúster: quita el servicio
manticorey configura las variables de la derecha. Lucene, integrado, sin servicio aparte: el índice vive en el directorio de archivos de Layers (el volumenlayers_data); adecuado para una instalación pequeña.Tras cambiar de motor, reindexa: God Mode → Plataforma → Búsqueda.
Elasticsearch: en lugar de las variables de Manticore en layersSEARCH_PROVIDER: elasticsearch SEARCH_ELASTICSEARCH_ENABLED: "true" SEARCH_MANTICORE_ENABLED: "false" ES_HOST: elasticsearch.example.com ES_PORT: "9200" ES_PROTOCOL: https ES_USERNAME: layers ES_PASSWORD: change-me-esLucene: integrado, sin el servicio manticoreSEARCH_PROVIDER: lucene SEARCH_MANTICORE_ENABLED: "false" SEARCH_ELASTICSEARCH_ENABLED: "false" - 4
Arráncalo
El primer arranque tarda entre 15 y 60 segundos. Cuando el log muestre
Started LayersApplication, abre tu dominio y crea la primera cuenta.Terminaldocker compose up -d docker compose logs -f layers curl -s http://127.0.0.1:8080/health # OK - 5
Activa HTTPS con nginx
Layers sirve todo desde el puerto 8080: nginx solo termina TLS y hace de proxy para las llamadas, los editores y MCP. Los editores se quedan en el mismo dominio para recibir la cookie de inicio de sesión.
Sin
limit_reqni archivos estáticos en nginx: la protección contra fuerza bruta y la caché vienen integradas.Terminalsudo apt install nginx certbot python3-certbot-nginx sudo certbot certonly --nginx -d example.com/etc/nginx/sites-available/layers.confserver { listen 80; server_name example.com; location /.well-known/acme-challenge/ { root /var/www/certbot; } location / { return 301 https://example.com$request_uri; } } server { listen 443 ssl http2; server_name example.com; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; client_max_body_size 1000m; add_header X-Content-Type-Options nosniff always; add_header X-Frame-Options SAMEORIGIN always; # Layers: web, API, God Mode location / { proxy_pass http://127.0.0.1:8080; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto https; proxy_read_timeout 300; } # LiveKit: señalización (la barra final en proxy_pass importa) location /livekit/ { proxy_pass http://127.0.0.1:7880/; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 86400s; } # LiveKit REST: el SDK del servidor llama a /twirp/ en la raíz location /twirp/ { proxy_pass http://127.0.0.1:7880/twirp/; proxy_set_header Host $host; proxy_read_timeout 86400s; } # Editores: en el mismo dominio, para que reciban la cookie de inicio de sesión de Layers location /sumdoc { proxy_pass http://127.0.0.1:8090; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 3600s; } location /sumsheet { proxy_pass http://127.0.0.1:8092; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 3600s; } # MCP para agentes externos (opcional) location /mcp { proxy_pass http://127.0.0.1:8091/mcp; proxy_http_version 1.1; proxy_set_header Host $host; proxy_buffering off; proxy_read_timeout 3600s; } }Terminalsudo ln -s /etc/nginx/sites-available/layers.conf /etc/nginx/sites-enabled/ sudo rm -f /etc/nginx/sites-enabled/default sudo nginx -t && sudo systemctl reload nginx - 6
Abre los puertos para las llamadas
LiveKit transmite audio y video por UDP. En God Mode → Aplicaciones → Integraciones → LiveKit indica
wss://example.com/livekit/(la barra final es obligatoria), prueba la conexión y actívalo.Si el log dice
could not validate external IP, sustituyeuse_external_ip: truepornode_ip: <IP del servidor>. Usanode_iptambién en una red cerrada.Terminalsudo ufw allow 7881/tcp sudo ufw allow 7882/udp sudo ufw allow 50000:50100/udp - 7
Configura el correo
Los correos de Layers (invitaciones, confirmaciones, restablecimiento de contraseñas) salen por tu servidor SMTP desde compose. La misma configuración está en God Mode → Plataforma → Correo, con correo de prueba y plantillas.
El módulo Correo es un cliente dentro de Layers: las personas conectan los buzones que ya tienen por IMAP y SMTP. Layers no tiene servidor de correo propio.
Puerto 465 en lugar de 587SPRING_MAIL_PORT: "465" SPRING_MAIL_SMTP_STARTTLS_ENABLE: "false" SPRING_MAIL_PROPERTIES_MAIL_SMTP_SSL_ENABLE: "true" - 8
Comprueba los editores SumDoc y SumSheet
El editor no guarda usuarios ni archivos: pregunta a Layers quién es la persona (
/v1/me) y obtiene el archivo por id (/v1/attachments).skewMin: 0significa que el editor y el motor son de la misma versión.Un documento abierto ocupa unos 250 MB de RAM;
--max-cabinsfija cuántos pueden estar abiertos a la vez.Terminalcurl -s http://127.0.0.1:8090/sumdoc/health # "status": "ok", "skewMin": 0 curl -s http://127.0.0.1:8092/sumsheet/health # "status": "ok", "skewMin": 0 curl -s https://example.com/v1/capabilities # {"fastdoc":{"enabled":true,"url":"https://example.com/sumdoc"}, # "fastsheet":{"enabled":true,"url":"https://example.com/sumsheet"}, …} - 9
Conecta un modelo de IA
God Mode → IA → Proveedores → Añadir proveedor. Los tipos integrados son OpenAI, OpenRouter y Gonka; Conexión propia acepta cualquier servidor con API compatible con OpenAI, como Ollama, sin clave. «Probar» muestra los modelos del servidor: elige los que quieras y actívalos.
Nuestra instalación de prueba usa así un Ollama local con
gpt-oss:20b. La dirección debe ser accesible desde el contenedor de Layers: un nombre de servicio o una IP, nolocalhost.docker-compose.yml: añadir en servicesollama: image: ollama/ollama:latest restart: unless-stopped volumes: - ollama_data:/root/.ollama # y en volumes: # ollama_data:Terminaldocker compose up -d ollama docker compose exec ollama ollama pull gpt-oss:20b # dirección para «Conexión propia»: http://ollama:11434/v1 # Servidor compatible con OpenAI en otra máquina: http://<host>:8000/v1 - 10
Conecta agentes por MCP
El servidor MCP ya está en compose: a través de él, el asistente de Layers realiza acciones (crea tareas, escribe páginas). Los agentes externos (Claude, Cursor y otros) se conectan a
https://example.com/mcpcon un token personal: en Layers → Configuración → Tokens de acceso, de solo lectura o de lectura y escritura.Terminalcurl -s http://127.0.0.1:8091/actuator/health # {"status":"UP", …} - 11
Inicia sesión en God Mode
https://example.com/godmode/login, usuarioadminy tuADMIN_PASSWORD. «Primeros pasos» es la lista de comprobación del servidor: dominios, correo, inicio de sesión, módulos, marca. Cada punto se marca como hecho según el estado real del servidor.
- 12
Introduce la clave de licencia
El periodo de prueba es de 90 días; después se necesita una licencia. La clave es una sola línea: God Mode → Sistema → Licencia → «Aplicar clave». Se verifica en el propio servidor.
Terminalcurl -s https://example.com/layers/license/status # {"mode":"MISSING", …, "node":{"regime":"evaluation","evaluationDaysLeft":89, …}} # con una clave: "regime":"full" - 13
Actualiza y haz copias de seguridad
Actualizar significa una imagen nueva; la base de datos, los archivos y la configuración se quedan en los volúmenes. Fija una etiqueta en lugar de
latestpara que las actualizaciones sean predecibles: la etiqueta en uso se muestra en God Mode → Operación → Estado del sistema.El panel no tiene copia de seguridad integrada de la base de datos: copia la base de datos con
pg_dump, y los archivos y la configuración como un archivo comprimido del volumenlayers_data.Actualizarcd /opt/layers docker compose pull docker compose up -dCopia de seguridadcd /opt/layers docker compose exec -T db sh -c 'pg_dump -U $POSTGRES_USER $POSTGRES_DB' | gzip > layers-db-$(date +%F).sql.gz docker run --rm -v layers_layers_data:/data -v "$PWD":/backup alpine \ tar czf /backup/layers-data-$(date +%F).tar.gz -C /data .
Red aislada
Instalación en red aislada: imágenes como archivo comprimido
Descarga las imágenes en una máquina con acceso a internet y llévalas como un solo archivo. La licencia se verifica en el propio servidor; el catálogo de módulos se conecta al registro y, dentro de una red cerrada, la IA solo funciona con un modelo local.
docker pull hissih/layers:latest
docker save hissih/layers:latest postgres:16-alpine manticoresearch/manticore:latest \
livekit/livekit-server:latest hissih/sumdoc-webhost:latest hissih/sumsheet-webhost:latest \
| gzip > layers-images.tar.gz
# en el servidor dentro de la red cerrada
gunzip -c layers-images.tar.gz | docker load
docker compose up -d Probado en nuestra instalación
Cómo lo tenemos montado
Cada captura y cada video de este sitio salen de una instalación de prueba local con exactamente estos servicios. Los puertos se desplazan a 18xxx para evitar conflictos; Mailpit y GreenMail están solo para probar el correo.
| Servicio | Imagen | Puerto en nuestra instalación | En tu servidor |
|---|---|---|---|
| Layers | hissih/layers 2.1.184 (el mismo jar) | 18080 | 8080 detrás de nginx |
| PostgreSQL | postgres:16-alpine | 18432 | db:5432, interno |
| Manticore | manticoresearch/manticore | 18308 | manticore:9308, interno |
| LiveKit | livekit/livekit-server | 18880 · 18881 · UDP 18900–18950 | 7880 · 7881 · UDP 50000–50100 |
| Mailpit (trampa de correo) | axllent/mailpit | SMTP 18125 | tu servidor SMTP |
| GreenMail (buzones de prueba) | greenmail/standalone:2.1.3 | IMAP 18143 · SMTP 18325 | los buzones que las personas ya tienen |
| SumDoc | sumdoc-webhost | 18290 · /sumdoc | 8090 · /sumdoc |
| SumSheet | sumsheet-webhost | 18292 · /sumsheet | 8092 · /sumsheet |
| Servidor MCP | de la distribución | 18091 · /mcp | 8091 · /mcp |
| LLM | Ollama, gpt-oss:20b | 11434 · /v1 | tu modelo o proveedor |
Comprobado el 2 de octubre de 2026: /health → OK, licencia: prueba (quedan 89 días), editores: status ok, MCP: UP.
Por qué así
Control sin concesiones
Red cerrada
Se instala en una red aislada: las imágenes y las actualizaciones llegan como un archivo comprimido.
Licencia en el servidor
La clave se verifica en el propio servidor.
Sin bloqueos por número de personas
El servidor nunca bloquea a las personas que superan el tamaño de la licencia. Almacenamiento: todo lo que quepa en tu hardware; las cuotas por espacio las fijas tú.
Tu marca
Nombre, logotipo, color, idioma predeterminado y tus propios documentos legales.
Tu IA
OpenAI, OpenRouter, cualquier servidor compatible con OpenAI o modelos locales.
Editores al lado
SumDoc y SumSheet funcionan junto a Layers, también en la red aislada.
Licencia
Precio bajo consulta
Prueba
90 días
90 días a velocidad máxima. Sin clave, el servidor sigue funcionando: las personas y los datos no se limitan, solo la transcripción de reuniones va con retraso.
Licencia
Bajo consulta
Hablaremos del tamaño de tu equipo, el soporte y las condiciones de la licencia.
Hablar del servidor propioEl servidor nunca bloquea a las personas que superan la licencia. La instalación, la implantación, las actualizaciones, la personalización y el soporte van aparte, según lo acordado y de pago.
Preguntas frecuentes
¿Necesito internet?
No: ni para instalar desde un archivo, ni para funcionar, ni para verificar la licencia. La IA en una red cerrada funciona con un modelo local.
¿Cuánto hardware hace falta?
Layers necesita al menos 2 GB de RAM más PostgreSQL. Los editores necesitan 2 GB más unos 250 MB por documento abierto. Las imágenes son linux/amd64.
¿Cómo actualizo?
docker compose pull y docker compose up -d. Los datos y la configuración se quedan en los volúmenes.
¿Cómo hago copias de seguridad?
La base de datos con pg_dump; los archivos y la configuración, como un archivo comprimido del volumen layers_data. El panel no tiene copia de seguridad integrada de la base de datos.
La llamada se conecta, pero no hay audio ni video
El puerto UDP 50000–50100 o 7882 está cerrado en el firewall, o LiveKit no encuentra su IP externa: configura node_ip.
¿Qué pasa tras 90 días sin clave?
El servidor sigue funcionando: el inicio de sesión, las personas y los datos no se limitan, no se cierra nada. Solo se ralentiza la transcripción de reuniones: se ejecuta con prioridad baja y unos segundos de retraso. Con una clave, todo vuelve a la velocidad máxima.
¿Se puede iniciar sesión con el directorio corporativo?
Todavía no: SAML, LDAP y SCIM no están soportados. Está disponible el inicio de sesión con contraseña, Google, Yandex, VK y Gosuslugi.
Reúne el trabajo de tu equipo en Layers
Empieza gratis en la nube, hasta 20 personas y sin límite de tiempo, o instala Layers en tu propio servidor.