docs(apps): expand configuration and integration guides
This commit is contained in:
@@ -2,6 +2,21 @@
|
||||
|
||||
Base de conocimiento y documentación desplegada con MariaDB, acceso por Traefik y envío de correo mediante `mail-relay`.
|
||||
|
||||
## Arquitectura y propósito
|
||||
|
||||
`bookstack` sirve la aplicación y guarda adjuntos/configuración en `BOOKSTACK_DATA_PATH`; `bookstack-db` conserva páginas, permisos y estructura en MariaDB. La base sólo usa la red interna `bookstack`. La aplicación se añade a `proxy` para Traefik y a `mail_internal` para enviar correo sin publicar la base de datos ni el relay.
|
||||
|
||||
## Configuración
|
||||
|
||||
- `BOOKSTACK_DOMAIN` y `APP_URL` deben coincidir para que enlaces, cookies y redirecciones HTTPS sean válidos.
|
||||
- `APP_KEY` cifra datos de aplicación: genérala una vez, mantenla estable y respáldala como secreto.
|
||||
- Las variables `BOOKSTACK_DB_*` conectan ambos contenedores; las contraseñas deben existir sólo en `.env`.
|
||||
- `BOOKSTACK_PUID` y `BOOKSTACK_PGID` deben tener acceso a `BOOKSTACK_DATA_PATH`.
|
||||
- `BOOKSTACK_LANG` y `BOOKSTACK_DARK_MODE` fijan los valores iniciales de interfaz.
|
||||
- `BOOKSTACK_MAIL_FROM*` identifica el remitente; el transporte usa el servicio interno `mail-relay`.
|
||||
|
||||
Separar datos y base permite actualizar la imagen sin perder contenido y respaldar cada componente con el método adecuado.
|
||||
|
||||
## Requisitos
|
||||
|
||||
- Docker Compose
|
||||
|
||||
@@ -2,9 +2,22 @@
|
||||
|
||||
changedetection.io published at `https://changedetection.sherlockhomeless.net`.
|
||||
|
||||
Deploy with:
|
||||
## Qué hace y cómo funciona
|
||||
|
||||
Supervisa páginas y avisa cuando cambia su contenido. `changedetection` guarda reglas e histórico en `CHANGEDETECTION_DATA_PATH`; `changedetection-browser` renderiza sitios con JavaScript mediante Playwright. El navegador sólo está en `changedetection_internal`, porque su puerto de depuración no debe exponerse.
|
||||
|
||||
## Configuración
|
||||
|
||||
- `CHANGEDETECTION_DOMAIN` forma `BASE_URL` y debe coincidir con Traefik.
|
||||
- `CHANGEDETECTION_IMAGE` y `CHANGEDETECTION_BROWSER_IMAGE` fijan las versiones de aplicación y navegador.
|
||||
- `CHANGEDETECTION_DATA_PATH` contiene toda la configuración que debe respaldarse.
|
||||
- `PLAYWRIGHT_DRIVER_URL` ya apunta al sidecar; elige el fetcher Playwright dentro de la UI sólo para páginas que lo necesiten, ya que consume más recursos.
|
||||
- El router dinámico combina CrowdSec, Authentik y Sablier: seguridad, control de identidad y arranque bajo demanda, respectivamente.
|
||||
|
||||
## Despliegue
|
||||
|
||||
```bash
|
||||
docker compose --env-file .env config
|
||||
docker compose --env-file .env up -d
|
||||
```
|
||||
|
||||
|
||||
+14
-1
@@ -2,9 +2,22 @@
|
||||
|
||||
Actual Budget published at `https://finance.sherlockhomeless.net`.
|
||||
|
||||
Deploy with:
|
||||
## Qué hace y cómo funciona
|
||||
|
||||
Actual Budget permite administrar presupuesto personal con un modelo local-first y sincronización mediante el servidor. Los datos del servidor se guardan en `ACTUALBUDGET_DATA_PATH`; no hay base de datos separada.
|
||||
|
||||
## Configuración
|
||||
|
||||
- `ACTUALBUDGET_DOMAIN` define el dominio publicado.
|
||||
- `ACTUALBUDGET_IMAGE` controla la versión que se despliega.
|
||||
- `ACTUALBUDGET_DATA_PATH` debe incluirse en backups y tener permisos de escritura.
|
||||
- La red interna aísla el servicio y `proxy` permite a Traefik alcanzarlo.
|
||||
- El router externo aplica CrowdSec, Authentik y Sablier. Authentik protege el acceso al servidor, pero no sustituye las credenciales/cifrado que configure Actual Budget.
|
||||
|
||||
## Despliegue
|
||||
|
||||
```bash
|
||||
docker compose --env-file .env config
|
||||
docker compose --env-file .env up -d
|
||||
```
|
||||
|
||||
|
||||
+12
-1
@@ -2,10 +2,21 @@
|
||||
|
||||
Lector RSS personal publicado en `rss.sherlockhomeless.net`.
|
||||
|
||||
## Qué hace y arquitectura
|
||||
|
||||
FreshRSS agrega feeds, actualiza artículos mediante cron y ofrece una API compatible con clientes móviles. Este despliegue usa SQLite: datos, usuarios y configuración viven en `FRESHRSS_DATA_PATH`; las extensiones se separan en `FRESHRSS_EXTENSIONS_PATH`.
|
||||
|
||||
## Configuración
|
||||
|
||||
- `FRESHRSS_DOMAIN` define el dominio usado por Traefik.
|
||||
- `FRESHRSS_CRON_MIN` controla la frecuencia de actualización; una frecuencia agresiva aumenta carga y peticiones a los sitios origen.
|
||||
- `FRESHRSS_ENV` debe permanecer en producción.
|
||||
- La web pasa por Authentik, pero la ruta de API no puede usar ese forward-auth porque los clientes móviles no completan el flujo web. Activa la API en el perfil de FreshRSS y usa una contraseña API distinta de la contraseña principal.
|
||||
- No usa Sablier para que cron pueda actualizar feeds incluso sin visitas.
|
||||
|
||||
## Despliegue
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
docker compose --env-file .env config
|
||||
docker compose --env-file .env up -d
|
||||
```
|
||||
|
||||
+17
-1
@@ -4,9 +4,25 @@ Ghost publication for the personal site currently exposed as:
|
||||
|
||||
- `https://me.thehomelesssherlock.com`
|
||||
|
||||
Deploy with Docker Compose from this directory:
|
||||
## Qué hace y arquitectura
|
||||
|
||||
Es el sitio personal y portfolio. `ghost-me-db` conserva contenido en MySQL y `ghost-me` sirve Ghost con el tema local `theme-source-personal`. `routes.yaml` separa inicio, blog y proyectos mediante colecciones y etiquetas.
|
||||
|
||||
## Configuración
|
||||
|
||||
- `GHOST_ME_DOMAIN` es el dominio canónico; `GHOST_ME_DOMAIN_ALT` redirige permanentemente al principal.
|
||||
- `GHOST_ME_DB_*` configura MySQL y debe permanecer sólo en `.env`.
|
||||
- `GHOST_ME_CONTENT_PATH` conserva uploads y configuración de Ghost.
|
||||
- `GHOST_ME_ROUTES_PATH` monta las rutas de contenido y debe apuntar a `./routes.yaml`.
|
||||
- `GHOST_ME_MAIL_FROM` y `mail_internal` permiten correo mediante `mail-relay`.
|
||||
- El tema se monta desde el repositorio para poder versionarlo; valida sus cambios con `npm test` dentro de `theme-source-personal` antes de actualizarlo.
|
||||
|
||||
La base queda aislada en `ghost_me_internal`; únicamente Ghost se conecta a `proxy` y `mail_internal`.
|
||||
|
||||
## Despliegue
|
||||
|
||||
```bash
|
||||
docker compose --env-file .env config
|
||||
docker compose --env-file .env up -d
|
||||
```
|
||||
|
||||
|
||||
@@ -2,6 +2,18 @@
|
||||
|
||||
Ghost publica `news.sherlockhomeless.net` como archivo de informes diarios.
|
||||
|
||||
## Arquitectura y configuración
|
||||
|
||||
- `ghost-db` conserva contenido y miembros en MySQL; sólo pertenece a `ghost_internal`.
|
||||
- `ghost` sirve la publicación, persiste temas y medios en `GHOST_CONTENT_PATH`, usa `mail-relay` y se publica mediante `proxy`.
|
||||
- `ghost-ops-gate` protege el índice privado `/ops` comprobando el miembro autenticado contra `GHOST_OPS_ALLOWED_EMAIL` y consultando posts con `GHOST_CONTENT_API_KEY`.
|
||||
|
||||
`GHOST_DOMAIN` fija la URL canónica; las variables `GHOST_DB_*` deben coincidir entre Ghost y MySQL. `GHOST_MAIL_FROM` controla el remitente. La Content API key sólo permite lectura, pero sigue siendo secreta y debe vivir únicamente en `.env`.
|
||||
|
||||
Los overrides de `theme-overrides/headline` ocultan publicaciones etiquetadas `#private-ops`. Deben aplicarse sobre la versión compatible del tema; tras actualizar Ghost o Headline, revisa diferencias antes de copiarlos.
|
||||
|
||||
La capa `/ops` no reemplaza la seguridad de cada post: usa miembros de Ghost, etiqueta interna y visibilidad adecuada, además del gate.
|
||||
|
||||
## Despliegue
|
||||
|
||||
```bash
|
||||
|
||||
@@ -8,3 +8,25 @@ Guacamole runs in Docker and connects to the host XFCE desktop through local `xr
|
||||
- Backend RDP target: `host.docker.internal:3389`
|
||||
|
||||
Use a local host account that is allowed to start an XRDP session.
|
||||
|
||||
## Qué hace y arquitectura
|
||||
|
||||
Apache Guacamole ofrece escritorio remoto desde el navegador. `guacamole` gestiona usuarios y conexiones, `guacd` traduce el protocolo web a RDP y PostgreSQL conserva la configuración. Sólo la aplicación web llega a `proxy`; guacd y PostgreSQL permanecen en la red interna.
|
||||
|
||||
## Configuración
|
||||
|
||||
- `GUACAMOLE_DOMAIN` define el acceso publicado por Traefik.
|
||||
- `GUACAMOLE_DB_*` debe coincidir en PostgreSQL y Guacamole.
|
||||
- `GUACAMOLE_DATA_PATH` persiste la base; `initdb` sólo inicializa una base vacía.
|
||||
- `host.docker.internal` se fija a `10.0.4.1` para alcanzar XRDP del host. Si cambia la IP del bridge/host, actualiza ambos servicios.
|
||||
- `WEBAPP_CONTEXT=ROOT` elimina el prefijo `/guacamole`.
|
||||
|
||||
Authentik protege el perímetro, pero Guacamole mantiene sus propios usuarios y permisos sobre conexiones. Evita cuentas compartidas y no publiques el puerto RDP en la zona pública.
|
||||
|
||||
## Despliegue
|
||||
|
||||
```bash
|
||||
cd guacamole
|
||||
docker compose --env-file .env config
|
||||
docker compose --env-file .env up -d
|
||||
```
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
Stack para desplegar [Homepage](https://gethomepage.dev/) detrás de Traefik como dashboard principal en `www.sherlockhomeless.net`.
|
||||
|
||||
## Qué hace y arquitectura
|
||||
|
||||
Homepage crea un portal a partir de los YAML guardados en `HOMEPAGE_CONFIG_PATH` y descubre servicios mediante labels `homepage.*`. El socket Docker está montado en sólo lectura para descubrir contenedores, pero ese acceso sigue revelando metadatos sensibles; la UI se protege con CrowdSec y Authentik.
|
||||
|
||||
## 🚀 Despliegue con Docker Compose
|
||||
|
||||
Asegurate de tener `homepage/.env` configurado y despliega:
|
||||
@@ -31,3 +35,7 @@ mkdir -p /opt/homepage/config
|
||||
```
|
||||
|
||||
Homepage leerá su configuración desde `/opt/homepage/config` y expondrá la UI interna en el puerto `3000`, publicado externamente a través de Traefik y protegido con Authentik mediante `ths-authentik@docker`.
|
||||
|
||||
`HOMEPAGE_ALLOWED_HOSTS` evita peticiones con cabeceras Host inesperadas y debe incluir el dominio público. `TRAEFIK_AUTH_MIDDLEWARE` referencia un middleware existente, no credenciales de Authentik. El router adicional redirige el dominio raíz a `www`; se mantiene separado para no mezclar la redirección con el servicio real.
|
||||
|
||||
Respalda los YAML de configuración, pero no incluyas tokens de widgets directamente: usa el mecanismo de secretos/variables admitido por Homepage.
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
Coleccion de herramientas tecnicas self-hosted.
|
||||
|
||||
## Qué hace y configuración
|
||||
|
||||
IT-Tools reúne conversores, generadores y utilidades que se ejecutan principalmente en el navegador. `IT_TOOLS_BASE_IMAGE` fija la imagen upstream usada por el build y `IT_TOOLS_IMAGE` nombra la imagen local resultante. `IT_TOOLS_DOMAIN` y `TRAEFIK_DOCKER_NETWORK` controlan la publicación por Traefik.
|
||||
|
||||
La imagen se construye localmente porque el `Dockerfile` aplica un parche al generador FIGlet. Esta decisión evita depender de una URL rota del upstream; al actualizar la imagen base, verifica si el parche sigue siendo necesario y que aplique sin ocultar cambios incompatibles.
|
||||
|
||||
- URL: `https://it.sherlockhomeless.net/`
|
||||
- Contenedor: `it-tools`
|
||||
- Red externa: `proxy`
|
||||
|
||||
@@ -2,6 +2,22 @@
|
||||
|
||||
Servicio para guardar, buscar y enriquecer enlaces. Incluye Karakeep, un navegador Chromium para capturas y Meilisearch para indexación.
|
||||
|
||||
## Arquitectura y propósito
|
||||
|
||||
Karakeep guarda el contenido principal en `/opt/karakeep/data`, delega la búsqueda a `karakeep-meilisearch` y usa `karakeep-chrome` para renderizar páginas dinámicas y generar capturas. Sólo la aplicación se une a `proxy`; Chrome y Meilisearch permanecen en `karakeep_internal`.
|
||||
|
||||
## Configuración
|
||||
|
||||
- `KARAKEEP_DOMAIN` define la URL canónica usada por NextAuth.
|
||||
- `NEXTAUTH_SECRET` firma sesiones; debe ser aleatorio y estable.
|
||||
- `MEILI_MASTER_KEY` protege el índice. Debe coincidir en Karakeep y Meilisearch y nunca contener un valor real en `stack.env`.
|
||||
- `DISABLE_SIGNUPS` debe permanecer activado tras crear las cuentas necesarias.
|
||||
- `OCR_LANGS` controla los idiomas de reconocimiento.
|
||||
- Las variables `INFERENCE_*`, `OPENAI_API_KEY` y `EMBEDDING_TEXT_MODEL` habilitan etiquetado, resumen y embeddings. Si se usa LiteLLM, configura una URL compatible soportada por Karakeep y entrega una clave de LiteLLM, nunca `auth.json` de Codex.
|
||||
- `INFERENCE_NUM_WORKERS` y los límites de contexto/salida controlan consumo y concurrencia; aumenta estos valores sólo después de medir memoria y cuota.
|
||||
|
||||
Chrome se ejecuta con `--no-sandbox`; por eso no debe exponerse a redes externas.
|
||||
|
||||
## Requisitos
|
||||
|
||||
- Docker Compose
|
||||
|
||||
+86
-9
@@ -1,14 +1,83 @@
|
||||
# LiteLLM
|
||||
|
||||
Proxy unificado para proveedores de modelos LLM, con configuración en `config.yaml`, proveedor local en `codex_provider.py` y PostgreSQL para persistencia.
|
||||
LiteLLM es la pasarela central de modelos del repositorio. Ofrece una API compatible con OpenAI a aplicaciones como Open WebUI, n8n y Paperless AI, mientras mantiene las credenciales reales de los proveedores en un único servicio.
|
||||
|
||||
## Requisitos
|
||||
## Qué despliega
|
||||
|
||||
- Docker Compose
|
||||
- Red externa `proxy`
|
||||
- Un archivo `.env` local con las claves de proveedores, claves maestras de LiteLLM y credenciales PostgreSQL
|
||||
- El archivo de autenticación de Codex montado en la ruta definida por el Compose
|
||||
- Enrutamiento dinámico de Traefik configurado fuera de esta aplicación
|
||||
- `litellm`: proxy, catálogo de modelos y proveedor personalizado de Codex.
|
||||
- `litellm-db`: PostgreSQL para configuración y estado persistente de LiteLLM.
|
||||
- `config.yaml`: alias públicos y proveedor asociado a cada modelo.
|
||||
- `codex_provider.py`: adaptación entre la API de LiteLLM y la API Responses de Codex.
|
||||
|
||||
Esta separación evita configurar una credencial de OpenAI o Codex distinta en cada consumidor. Las aplicaciones sólo conocen la URL de LiteLLM, una clave de acceso de LiteLLM y el alias del modelo.
|
||||
|
||||
## Redes y exposición
|
||||
|
||||
LiteLLM pertenece a su red interna `litellm` y a la red externa `proxy`. PostgreSQL sólo está en la red interna. Los consumidores conectados a `proxy` pueden usar:
|
||||
|
||||
```text
|
||||
http://litellm:4000/v1
|
||||
```
|
||||
|
||||
El acceso público y la interfaz se enrutan mediante la configuración dinámica de Traefik en `/opt/traefik/dynamic/litellm.yml`. La API debe exigir `LITELLM_MASTER_KEY`; la protección SSO de la interfaz no sustituye esa clave.
|
||||
|
||||
## Configuración
|
||||
|
||||
El `.env` local debe definir, como mínimo:
|
||||
|
||||
| Variable | Función | Motivo |
|
||||
| --- | --- | --- |
|
||||
| `LITELLM_MASTER_KEY` | Autentica a los consumidores de la API | Impide usar los modelos sólo por alcanzar la red |
|
||||
| `LITELLM_SALT_KEY` | Cifra datos sensibles almacenados por LiteLLM | Debe permanecer estable tras el primer arranque |
|
||||
| `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_DB` | Base de datos interna | No se exponen fuera de la red `litellm` |
|
||||
| `LITELLM_DB_DATA_PATH` | Persistencia de PostgreSQL | Permite recrear contenedores sin perder estado |
|
||||
| `DEEPSEEK_API_KEY` | Acceso directo a DeepSeek | Sólo se necesita para los alias `thsllm-*` |
|
||||
|
||||
`config.yaml` publica alias estables. Los consumidores deben pedir el alias, no el identificador interno del proveedor. Así se puede cambiar el backend sin reconfigurar cada aplicación.
|
||||
|
||||
## Autenticación de Codex
|
||||
|
||||
El Compose monta:
|
||||
|
||||
```text
|
||||
/home/felidae/.codex/auth.json -> /root/.codex/auth.json
|
||||
```
|
||||
|
||||
La variable `CODEX_AUTH_FILE` apunta a la ruta interior. El montaje es de lectura y escritura porque `codex_provider.py` renueva el access token mediante el refresh token y guarda el resultado en el mismo archivo.
|
||||
|
||||
Flujo:
|
||||
|
||||
1. El usuario inicia sesión con Codex en el host y genera `~/.codex/auth.json`.
|
||||
2. Docker monta ese archivo únicamente dentro de LiteLLM.
|
||||
3. El proveedor lee `access_token`, `refresh_token` y `account_id`.
|
||||
4. Si el JWT vence en menos de 60 segundos, solicita un token nuevo y actualiza el archivo montado.
|
||||
5. LiteLLM envía la petición a Codex y devuelve una respuesta compatible con OpenAI al consumidor.
|
||||
|
||||
El archivo contiene credenciales reutilizables. No debe copiarse al repositorio, incluirse en imágenes, logs, backups sin cifrar ni montarse en Paperless, n8n u Open WebUI. `.gitignore` excluye `.codex`, pero conviene comprobar antes de cada commit:
|
||||
|
||||
```bash
|
||||
git status --ignored --short | grep codex
|
||||
```
|
||||
|
||||
El usuario que ejecuta Docker debe poder leer y escribir el archivo. Si el host o usuario cambia, actualiza la ruta del volumen en `docker-compose.yml`; una ruta inexistente puede terminar creada como directorio y provocar errores de autenticación.
|
||||
|
||||
## Modelos Codex
|
||||
|
||||
Los alias `gpt-*` configurados con `custom_llm_provider: codex` pasan por `codex_provider.py`. Internamente se usa el prefijo `cx-` para evitar colisiones con los modelos OpenAI nativos de LiteLLM; el proveedor vuelve a convertirlo antes de llamar a Codex.
|
||||
|
||||
El proveedor admite llamadas síncronas, asíncronas y streaming. Codex responde siempre mediante streaming; para una llamada no streaming, el proveedor agrega los fragmentos antes de responder.
|
||||
|
||||
## Configurar consumidores
|
||||
|
||||
Un consumidor compatible con OpenAI necesita:
|
||||
|
||||
```text
|
||||
Base URL: http://litellm:4000/v1
|
||||
API key: valor de LITELLM_MASTER_KEY
|
||||
Model: gpt-5.6-sol
|
||||
```
|
||||
|
||||
Usa la URL interna cuando ambos contenedores compartan `proxy`. Usa la URL HTTPS sólo para clientes externos. Nunca uses el token de Codex como API key del consumidor.
|
||||
|
||||
## Despliegue
|
||||
|
||||
@@ -18,11 +87,19 @@ docker compose --env-file .env config
|
||||
docker compose --env-file .env up -d
|
||||
```
|
||||
|
||||
## Operación
|
||||
## Verificación
|
||||
|
||||
```bash
|
||||
docker compose --env-file .env ps
|
||||
docker compose --env-file .env logs -f litellm
|
||||
curl -sS http://127.0.0.1:4000/v1/models \
|
||||
-H "Authorization: Bearer $LITELLM_MASTER_KEY"
|
||||
```
|
||||
|
||||
La API se autentica con `LITELLM_MASTER_KEY`; no publiques esa clave ni el `.env`.
|
||||
Si no se publica el puerto en el host, ejecuta la prueba desde un contenedor unido a `proxy` o usa el dominio HTTPS.
|
||||
|
||||
Errores `401` que mencionen Codex suelen indicar que `auth.json` falta, no tiene permisos o ya no puede renovarse. Errores `401` devueltos antes de seleccionar modelo suelen indicar una `LITELLM_MASTER_KEY` incorrecta.
|
||||
|
||||
## Persistencia y copias de seguridad
|
||||
|
||||
Respalda la ruta `LITELLM_DB_DATA_PATH`. Trata `auth.json` como un secreto independiente: si se respalda, debe hacerse cifrado y con acceso restringido. No restaures simultáneamente versiones distintas del archivo desde varios hosts, porque la rotación del refresh token puede invalidar la copia anterior.
|
||||
|
||||
@@ -2,6 +2,20 @@
|
||||
|
||||
Aplicación de notas ligeras respaldada por PostgreSQL. El contenedor `memos-proxy` actúa como punto de entrada hacia Memos.
|
||||
|
||||
## Arquitectura y propósito
|
||||
|
||||
`memos-db` conserva usuarios y notas, `memos` ofrece la aplicación en la red interna y `memos-proxy` aplica la adaptación HTTP necesaria antes del enrutamiento externo. La base y Memos no se publican directamente.
|
||||
|
||||
## Configuración
|
||||
|
||||
- `MEMOS_DB_NAME`, `MEMOS_DB_USER` y `MEMOS_DB_PASSWORD` deben coincidir entre PostgreSQL y el DSN generado por el Compose.
|
||||
- `MEMOS_DOMAIN` establece la URL pública que Memos usa en enlaces y respuestas.
|
||||
- `TZ` mantiene consistencia en fechas y tareas.
|
||||
- `/opt/memos/postgres` contiene la base y `/opt/memos/data` los recursos propios de la aplicación.
|
||||
- `proxy/server.js` se monta en sólo lectura; cualquier cambio requiere recrear `memos-proxy`.
|
||||
|
||||
El proxy tiene `traefik.enable=false` porque el routing se administra externamente. No actives un segundo router sin comprobar prioridades y autenticación.
|
||||
|
||||
## Requisitos
|
||||
|
||||
- Docker Compose
|
||||
|
||||
@@ -1,11 +1,43 @@
|
||||
# n8n Observability Toolkit
|
||||
|
||||
Carpeta dedicada para automatizar en n8n:
|
||||
|
||||
- Resumen diario de estado del servidor
|
||||
- Alertas de caida real de servicios
|
||||
- Informes automaticos de logs y errores
|
||||
- Resumen IA (texto ejecutivo)
|
||||
|
||||
No despliega un contenedor propio. Los scripts se ejecutan en el host porque necesitan consultar systemd, Docker, certificados y endpoints locales; n8n los invoca mediante una credencial SSH con permisos limitados.
|
||||
|
||||
## Configuración
|
||||
|
||||
- Copia `config/services.example.json` a una ubicación local no versionada y define los endpoints que deben comprobarse.
|
||||
- `HEALTH_ENDPOINTS` permite pasar endpoints directamente; `HEALTH_EXPECTED_CODES` ajusta los códigos aceptados.
|
||||
- `TARGET_CONTAINERS` limita los contenedores incluidos en el resumen de logs.
|
||||
- `SINCE` fija la ventana temporal, por ejemplo `24 hours ago`.
|
||||
- `CERT_EXCLUDE_DOMAINS` omite dominios que no deban auditarse.
|
||||
- Las variables `OPENCLAW_*` configuran únicamente la comprobación/renovación OAuth del proveedor indicado; no deben imprimirse tokens.
|
||||
|
||||
Se recomienda un usuario SSH dedicado que pueda ejecutar estos scripts y los comandos de lectura necesarios, sin shell administrativa general. Si requiere `sudo`, limita comandos y argumentos en `sudoers`.
|
||||
|
||||
## Integración con LiteLLM y Codex
|
||||
|
||||
El nodo de IA de n8n debe consumir LiteLLM mediante su API compatible con OpenAI, usando una clave de LiteLLM y un alias de modelo. n8n no necesita acceso al archivo `auth.json` de Codex. LiteLLM mantiene y renueva esa sesión, mientras n8n sólo envía el digest ya filtrado.
|
||||
|
||||
```text
|
||||
n8n -> http://litellm:4000/v1 -> alias de modelo -> proveedor Codex
|
||||
```
|
||||
|
||||
Esta separación permite revocar el acceso de n8n sin cerrar la sesión de Codex y evita distribuir el refresh token. El chequeo `openclaw_codex_oauth` de este toolkit es independiente del montaje usado por LiteLLM; no asumas que validar uno valida automáticamente el otro.
|
||||
|
||||
## Instalación
|
||||
|
||||
No se usa Docker Compose. Conserva el directorio en el host, da permisos de ejecución a los scripts y configura en n8n la conexión SSH:
|
||||
|
||||
```bash
|
||||
chmod +x n8n-observability/scripts/*.sh n8n-observability/scripts/ops-report
|
||||
```
|
||||
|
||||
## Estructura
|
||||
|
||||
- `scripts/ops-report`: motor Python unificado para `summary`, `logs`, `health` y `all`
|
||||
|
||||
@@ -2,6 +2,21 @@
|
||||
|
||||
Plataforma de archivos y colaboración con MariaDB, Redis, tareas cron y OnlyOffice Document Server.
|
||||
|
||||
## Arquitectura y propósito
|
||||
|
||||
MariaDB guarda metadatos, Redis aporta bloqueo y caché, `nextcloud` sirve la web y `nextcloud-cron` ejecuta tareas en segundo plano sobre los mismos volúmenes. OnlyOffice es un servicio independiente para editar documentos y se integra mediante JWT.
|
||||
|
||||
## Configuración
|
||||
|
||||
- `NC_DOMAIN`, `TRUSTED_PROXIES` y las variables `OVERWRITE*` hacen que Nextcloud genere HTTPS correctamente detrás de Traefik.
|
||||
- `MYSQL_*` debe coincidir en Nextcloud, cron y MariaDB.
|
||||
- `NEXTCLOUD_ADMIN_*` sólo inicializa la primera instalación; después administra usuarios desde Nextcloud.
|
||||
- `SMTP_*` configura notificaciones a través de `mail_internal`.
|
||||
- `OO_DOMAIN`, `OO_JWT_SECRET` y `OO_SECURE_LINK_SECRET` protegen la comunicación con OnlyOffice; el JWT configurado en la app de Nextcloud debe ser idéntico.
|
||||
- `/opt/nextcloud/html`, `config`, `data`, `custom_apps` y `themes` se comparten con cron para ejecutar el mismo código y configuración.
|
||||
|
||||
Redis no sustituye una copia de seguridad. Respalda MariaDB, configuración y datos de forma consistente, preferiblemente activando antes el modo mantenimiento.
|
||||
|
||||
## Requisitos
|
||||
|
||||
- Docker Compose
|
||||
|
||||
@@ -2,6 +2,20 @@
|
||||
|
||||
Servicio para compartir secretos de un solo uso, con Redis para persistencia temporal y autenticación OIDC mediante Authentik.
|
||||
|
||||
## Arquitectura y propósito
|
||||
|
||||
OneTimeSecret cifra y entrega secretos temporales; Redis mantiene su estado. El navegador recibe el enlace, pero la política de acceso exige autenticación OIDC. El Compose usa `AUTH_SSO_ONLY=true`, desactiva altas y evita cuentas locales como vía habitual.
|
||||
|
||||
## Configuración
|
||||
|
||||
- `OTS_SECRET` alimenta las distintas claves criptográficas internas. Debe ser largo, aleatorio, estable y exclusivo de esta app.
|
||||
- `OTS_DOMAIN` debe coincidir con `OIDC_REDIRECT_URI` y con el cliente creado en Authentik.
|
||||
- `OTS_OIDC_ISSUER`, `OTS_OIDC_CLIENT_ID` y `OTS_OIDC_CLIENT_SECRET` enlazan el cliente OIDC.
|
||||
- `OTS_DATA_PATH` conserva datos de aplicación y `OTS_REDIS_PATH` el estado de Redis.
|
||||
- Las imágenes se fijan con `OTS_IMAGE` y `OTS_REDIS_IMAGE` para controlar actualizaciones.
|
||||
|
||||
Un secreto de un solo uso sigue siendo sensible mientras exista. Restringe backups, logs y acceso administrativo a Redis.
|
||||
|
||||
## Requisitos
|
||||
|
||||
- Docker Compose
|
||||
|
||||
@@ -2,6 +2,20 @@
|
||||
|
||||
Repositorio privado de gists y fragmentos de código, publicado mediante Traefik y autenticado por OIDC.
|
||||
|
||||
## Arquitectura y propósito
|
||||
|
||||
OpenGist concentra snippets versionados en un único contenedor. La ruta `OPENGIST_DATA_PATH` almacena repositorios, configuración y base de datos, mientras `proxy` proporciona acceso HTTPS.
|
||||
|
||||
## Configuración
|
||||
|
||||
- `OPENGIST_DOMAIN` se usa como URL externa y debe coincidir con el dominio de Traefik.
|
||||
- `OPENGIST_OIDC_PROVIDER_NAME` define el texto mostrado al iniciar sesión.
|
||||
- `OPENGIST_OIDC_CLIENT_ID`, `OPENGIST_OIDC_CLIENT_SECRET` y `OPENGIST_OIDC_DISCOVERY_URL` conectan Authentik mediante discovery OIDC.
|
||||
- `OPENGIST_DATA_PATH` debe ser escribible por el contenedor y estar incluido en las copias de seguridad.
|
||||
- `TRAEFIK_DOCKER_NETWORK` debe apuntar a `proxy` para que Traefik elija la interfaz correcta.
|
||||
|
||||
OIDC centraliza identidad, pero los permisos sobre cada gist siguen administrándose en OpenGist.
|
||||
|
||||
## Requisitos
|
||||
|
||||
- Docker Compose
|
||||
|
||||
+30
-28
@@ -1,40 +1,42 @@
|
||||
# Open WebUI — Interfaz web para LLMs
|
||||
# Open WebUI
|
||||
|
||||
Open WebUI conectado al stack de Ollama. Expone una UI de chat accesible en `chat.sherlockhomeless.net`, protegida por CrowdSec. Tiene su propio sistema de login, no usa Authentik.
|
||||
Interfaz de chat para los modelos publicados por LiteLLM. Ollama está deshabilitado explícitamente; este despliegue usa únicamente la API compatible con OpenAI.
|
||||
|
||||
## Prerequisitos
|
||||
## Arquitectura
|
||||
|
||||
- Stack **Ollama** desplegado y en la red `proxy`
|
||||
- DNS + Tunnel registrado para `chat.sherlockhomeless.net`
|
||||
Open WebUI se une a `proxy`, desde donde Traefik lo publica y puede alcanzar `litellm:4000`. Los chats, usuarios y ajustes se guardan en `OPENWEBUI_DATA_PATH`.
|
||||
|
||||
```bash
|
||||
cd cloudflared
|
||||
./add-domain.sh chat
|
||||
```
|
||||
## Configuración
|
||||
|
||||
| Variable | Uso |
|
||||
| --- | --- |
|
||||
| `OPENAI_API_BASE_URL` | `http://litellm:4000/v1` para tráfico interno |
|
||||
| `OPENAI_API_KEY` | Valor de `LITELLM_MASTER_KEY`, no una credencial de Codex |
|
||||
| `WEBUI_SECRET_KEY` | Firma sesiones; debe ser aleatoria y estable |
|
||||
| `OPENWEBUI_DOMAIN`, `WEBUI_URL` | URL pública detrás de Traefik |
|
||||
| `ENABLE_SIGNUP` | Debe desactivarse salvo durante un alta controlada |
|
||||
| `ENABLE_LOGIN_FORM` | Mantiene o elimina el login local según la estrategia SSO |
|
||||
| `WEBUI_AUTH_TRUSTED_*_HEADER` | Cabeceras de identidad entregadas por el proxy autenticado |
|
||||
|
||||
Las cabeceras de usuario sólo son seguras si Open WebUI no puede alcanzarse evitando Traefik y si el proxy elimina cualquier cabecera equivalente enviada por el cliente. `WEBUI_SECRET_KEY` no debe cambiarse en cada recreación porque invalidaría sesiones.
|
||||
|
||||
## Relación con Codex
|
||||
|
||||
Open WebUI nunca monta ni lee `auth.json`. Envía una petición OpenAI-compatible a LiteLLM; LiteLLM valida su clave, selecciona el alias y, si corresponde, usa su proveedor Codex. Esto limita la exposición del refresh token a un único contenedor.
|
||||
|
||||
## Despliegue
|
||||
|
||||
```bash
|
||||
mkdir -p /opt/openwebui/data
|
||||
# Editar openwebui/.env: cambiar WEBUI_SECRET_KEY por un valor aleatorio
|
||||
openssl rand -hex 32
|
||||
docker compose --env-file openwebui/.env -f openwebui/docker-compose.yml up -d
|
||||
cd openwebui
|
||||
docker compose --env-file .env config
|
||||
docker compose --env-file .env up -d
|
||||
```
|
||||
|
||||
## Primer acceso
|
||||
## Verificación
|
||||
|
||||
La primera cuenta registrada se convierte en administrador. Después de crearla, pon `ENABLE_SIGNUP=false` en `.env` y redespliega para bloquear nuevos registros.
|
||||
```bash
|
||||
docker compose --env-file .env ps
|
||||
docker compose --env-file .env logs -f openwebui
|
||||
```
|
||||
|
||||
## Conexión con Ollama
|
||||
|
||||
OpenWebUI se conecta a Ollama via red interna Docker: `http://ollama:11434`.
|
||||
Ambos contenedores deben estar en la red `proxy`.
|
||||
|
||||
## Variables clave
|
||||
|
||||
| Variable | Descripción |
|
||||
|----------|-------------|
|
||||
| `WEBUI_SECRET_KEY` | Clave para firmar sesiones — generar con `openssl rand -hex 32` |
|
||||
| `OLLAMA_BASE_URL` | URL interna de Ollama (`http://ollama:11434`) |
|
||||
| `ENABLE_SIGNUP` | `false` para bloquear nuevos registros |
|
||||
| `WEBUI_NAME` | Nombre mostrado en la interfaz |
|
||||
Si no aparecen modelos, prueba primero `/v1/models` contra LiteLLM con la misma clave. Si los modelos aparecen pero fallan sólo los alias Codex, revisa el montaje y renovación de `auth.json` en LiteLLM.
|
||||
|
||||
+81
-10
@@ -1,14 +1,83 @@
|
||||
# Paperless-ngx
|
||||
|
||||
Gestión documental con PostgreSQL, Redis, Tika y Gotenberg. El despliegue también incluye Paperless AI y una sincronización unidireccional desde una carpeta de Nextcloud.
|
||||
Paperless-ngx convierte documentos en un archivo digital consultable. Importa ficheros, extrae texto, ejecuta OCR, clasifica metadatos y conserva el original junto con su versión procesada.
|
||||
|
||||
## Requisitos
|
||||
## Qué despliega
|
||||
|
||||
- Docker Compose
|
||||
- Redes externas `proxy` y `mail_internal`
|
||||
- Un archivo `.env` local con dominios, credenciales, correo, proxy de confianza y acceso WebDAV a Nextcloud
|
||||
- Directorios persistentes bajo `/opt/paperless`, `/opt/paperless-ai` y `/opt/rclone`
|
||||
- Script `/opt/paperless/rclone-sync.sh`
|
||||
- `paperless`: aplicación principal y consumidor de documentos.
|
||||
- `paperless-db`: PostgreSQL para metadatos.
|
||||
- `paperless-redis`: cola y caché.
|
||||
- `paperless-tika`: extracción de texto de formatos Office y similares.
|
||||
- `paperless-gotenberg`: conversión de documentos a PDF.
|
||||
- `paperless-ai`: clasificación y enriquecimiento asistido por un LLM.
|
||||
- `paperless-inbox-sync`: copia periódica desde una carpeta WebDAV de Nextcloud hacia `consume`.
|
||||
|
||||
Los servicios de datos viven en `paperless_internal`. Paperless y Paperless AI también se unen a `proxy` para ser alcanzables por Traefik y por servicios compartidos como LiteLLM.
|
||||
|
||||
## Configuración principal
|
||||
|
||||
El `.env` local agrupa:
|
||||
|
||||
| Grupo | Variables principales | Por qué existe |
|
||||
| --- | --- | --- |
|
||||
| PostgreSQL | `PAPERLESS_DBNAME`, `PAPERLESS_DBUSER`, `PAPERLESS_DBPASS` | Conserva índices, usuarios y metadatos |
|
||||
| URL y seguridad | `PAPERLESS_DOMAIN`, `PAPERLESS_SECRET_KEY`, `PAPERLESS_ALLOWED_HOSTS`, `TRUSTED_PROXIES` | Genera enlaces correctos y valida peticiones tras Traefik |
|
||||
| Administrador | `PAPERLESS_ADMIN_USER`, `PAPERLESS_ADMIN_PASSWORD`, `PAPERLESS_ADMIN_MAIL` | Crea el usuario inicial; cambia la contraseña tras el alta |
|
||||
| Correo | variables `PAPERLESS_EMAIL_*` | Notificaciones mediante `mail_internal` |
|
||||
| Nextcloud | `NC_DOMAIN`, `NC_WEBDAV_USER`, `NC_WEBDAV_PASS` | Lee la bandeja de entrada remota |
|
||||
| Sincronización | `RCLONE_SYNC_INTERVAL`, `PAPERLESS_INBOX_DIR` | Controla frecuencia y carpeta origen |
|
||||
|
||||
`PAPERLESS_CONSUMER_POLLING` hace la importación más fiable cuando los archivos llegan por sincronización o montaje y no generan eventos `inotify` normales.
|
||||
|
||||
## Persistencia
|
||||
|
||||
| Ruta | Contenido |
|
||||
| --- | --- |
|
||||
| `/opt/paperless/pgdata` | PostgreSQL |
|
||||
| `/opt/paperless/data` | Índices y estado de Paperless |
|
||||
| `/opt/paperless/media` | Originales y documentos procesados |
|
||||
| `/opt/paperless/export` | Exportaciones |
|
||||
| `/opt/paperless/consume` | Bandeja de importación |
|
||||
| `/opt/paperless-ai/data` | Configuración y estado de Paperless AI |
|
||||
| `/opt/rclone` | Configuración auxiliar de rclone |
|
||||
|
||||
La copia de seguridad debe mantener coherencia entre PostgreSQL, `data` y `media`. Respaldar sólo la base de datos no conserva los documentos.
|
||||
|
||||
## Integración de Paperless AI con LiteLLM y Codex
|
||||
|
||||
Paperless AI no se conecta directamente a Codex. Se configura como cliente compatible con OpenAI y llama a LiteLLM:
|
||||
|
||||
```text
|
||||
API provider: OpenAI compatible
|
||||
Base URL: http://litellm:4000/v1
|
||||
API key: valor de LITELLM_MASTER_KEY
|
||||
Model: gpt-5.6-sol
|
||||
```
|
||||
|
||||
Ambos contenedores comparten la red externa `proxy`, por lo que `litellm` se resuelve por DNS interno. La configuración de Paperless AI se guarda en `/opt/paperless-ai/data`; actualmente no se declara mediante variables en el Compose y debe introducirse desde su interfaz.
|
||||
|
||||
Flujo de una clasificación:
|
||||
|
||||
```text
|
||||
Paperless -> Paperless AI -> LiteLLM -> proveedor Codex -> Codex
|
||||
```
|
||||
|
||||
Esta arquitectura es intencionada:
|
||||
|
||||
- `auth.json` y el refresh token de Codex permanecen sólo en LiteLLM.
|
||||
- Paperless AI recibe una clave de LiteLLM revocable, no la sesión de Codex.
|
||||
- El alias de modelo puede cambiar de proveedor sin reconfigurar Paperless AI.
|
||||
- LiteLLM centraliza control, logs y futuros límites de consumo.
|
||||
|
||||
No montes `/home/felidae/.codex/auth.json` en Paperless AI. Tampoco uses el dominio público de LiteLLM desde Docker salvo que necesites atravesar Traefik; la URL interna evita una vuelta innecesaria por DNS público y TLS.
|
||||
|
||||
Antes de activar clasificación automática, prueba con pocos documentos y revisa qué contenido se envía al modelo. Los documentos pueden contener datos personales o confidenciales.
|
||||
|
||||
## Sincronización desde Nextcloud
|
||||
|
||||
`paperless-inbox-sync` usa WebDAV y el script `/opt/paperless/rclone-sync.sh` para copiar la carpeta configurada hacia `/consume`. Es un flujo unidireccional; comprueba el comportamiento exacto del script antes de cambiarlo por una sincronización con borrado.
|
||||
|
||||
La contraseña WebDAV debe ser una contraseña de aplicación dedicada, con el mínimo acceso necesario. No uses la contraseña principal del usuario de Nextcloud.
|
||||
|
||||
## Despliegue
|
||||
|
||||
@@ -18,11 +87,13 @@ docker compose --env-file .env config
|
||||
docker compose --env-file .env up -d
|
||||
```
|
||||
|
||||
## Operación
|
||||
## Verificación y operación
|
||||
|
||||
```bash
|
||||
docker compose --env-file .env ps
|
||||
docker compose --env-file .env logs -f paperless paperless-ai paperless-inbox-sync
|
||||
docker compose --env-file .env logs -f paperless
|
||||
docker compose --env-file .env logs -f paperless-ai
|
||||
docker compose --env-file .env logs -f paperless-inbox-sync
|
||||
```
|
||||
|
||||
La sincronización copia documentos desde Nextcloud a `/opt/paperless/consume`; revisa sus logs antes de cambiar rutas o credenciales WebDAV.
|
||||
Comprueba que PostgreSQL, Redis, Tika y Gotenberg estén sanos antes de diagnosticar la aplicación. Si no entran documentos, revisa primero el sync, después `/opt/paperless/consume` y finalmente los logs del consumidor.
|
||||
|
||||
@@ -2,6 +2,19 @@
|
||||
|
||||
Servicio self-hosted para manipular PDF.
|
||||
|
||||
## Qué hace y configuración
|
||||
|
||||
Stirling PDF combina, divide, convierte, firma y transforma documentos desde una interfaz web. `SECURITY_ENABLELOGIN=false` deja la autenticación en Traefik + Authentik; no debe publicarse una ruta alternativa que evite ese middleware.
|
||||
|
||||
- `STIRLING_PDF_IMAGE` fija la versión.
|
||||
- `STIRLING_PDF_DOMAIN` define el dominio público.
|
||||
- `STIRLING_PDF_CONFIG_PATH` guarda configuración.
|
||||
- `STIRLING_PDF_CUSTOM_PATH` contiene personalización.
|
||||
- `STIRLING_PDF_LOGS_PATH` conserva logs y debe tener rotación.
|
||||
- `STIRLING_PDF_PIPELINE_PATH` guarda automatizaciones.
|
||||
|
||||
Los documentos procesados pueden ser confidenciales. Revisa retención de temporales, permisos de los volúmenes y evita registrar nombres o contenido sensible.
|
||||
|
||||
- URL: `https://pdf.sherlockhomeless.net/`
|
||||
- Contenedor: `stirling-pdf`
|
||||
- Datos persistentes: `/opt/stirling-pdf/`
|
||||
|
||||
@@ -2,6 +2,20 @@
|
||||
|
||||
Pastebin con cifrado de extremo a extremo en el navegador, ejecutado en modo de sólo lectura y publicado mediante Traefik.
|
||||
|
||||
## Arquitectura y propósito
|
||||
|
||||
PrivateBin cifra y descifra en el navegador: el servidor almacena ciphertext, no el texto claro. El contenedor tiene sistema raíz de sólo lectura, usuario sin privilegios y únicamente escribe en `PRIVATEBIN_DATA_PATH`.
|
||||
|
||||
## Configuración
|
||||
|
||||
- `PRIVATEBIN_DOMAIN` define la URL expuesta por Traefik.
|
||||
- `PRIVATEBIN_IMAGE` debe fijarse a una versión revisada para evitar cambios inesperados.
|
||||
- `PRIVATEBIN_DATA_PATH` conserva los pastes cifrados y necesita permisos para UID/GID `65534`.
|
||||
- `nginx-site.conf` separa las operaciones públicas de lectura de las rutas de creación/borrado protegidas por autenticación externa.
|
||||
- `TRAEFIK_DOCKER_NETWORK` debe coincidir con la red `proxy` existente.
|
||||
|
||||
El cifrado del navegador no protege metadatos, disponibilidad ni clientes comprometidos. Mantén TLS y revisa la política de expiración.
|
||||
|
||||
## Requisitos
|
||||
|
||||
- Docker Compose
|
||||
|
||||
@@ -2,6 +2,19 @@
|
||||
|
||||
Proveedor de arranque bajo demanda para servicios Docker. Se conecta al socket de Docker y a la red externa `proxy`.
|
||||
|
||||
## Arquitectura y propósito
|
||||
|
||||
Sablier recibe peticiones desde el middleware correspondiente y arranca contenedores que estaban detenidos, permitiendo reducir consumo de servicios esporádicos. La versión se controla con `SABLIER_VERSION`.
|
||||
|
||||
## Configuración
|
||||
|
||||
- La red `proxy` permite comunicación con Traefik y los servicios activables.
|
||||
- El socket Docker se monta en sólo lectura, pero sigue otorgando capacidad de inspección y control significativo sobre el host.
|
||||
- Los servicios gestionados necesitan sus propias etiquetas/middleware de Sablier y una política de parada coherente.
|
||||
- No gestiones con Sablier bases de datos u otros componentes con arranque lento sin ajustar timeouts y dependencias.
|
||||
|
||||
La etiqueta `prune.protect` debe aplicarse a servicios bajo demanda para que una limpieza no elimine contenedores detenidos que Sablier espera arrancar.
|
||||
|
||||
## Requisitos
|
||||
|
||||
- Docker Compose
|
||||
|
||||
@@ -2,6 +2,21 @@
|
||||
|
||||
Gestor de tareas y proyectos con PostgreSQL, soporte CalDAV y envío de recordatorios por correo.
|
||||
|
||||
## Arquitectura y propósito
|
||||
|
||||
`vikunja` ofrece interfaz, API y CalDAV; `vikunja-db` guarda usuarios, proyectos y tareas. PostgreSQL sólo está en `vikunja_internal`; Vikunja se conecta además a `proxy` y `mail_internal`.
|
||||
|
||||
## Configuración
|
||||
|
||||
- `VIKUNJA_DOMAIN` forma `VIKUNJA_SERVICE_PUBLICURL`; incluye HTTPS y la barra final esperada.
|
||||
- `VIKUNJA_JWT_SECRET` firma sesiones. Debe ser aleatorio, exclusivo y estable.
|
||||
- `VIKUNJA_DB_*` debe coincidir en aplicación, healthcheck y PostgreSQL.
|
||||
- Las variables `VIKUNJA_MAILER_*` configuran SMTP y recordatorios.
|
||||
- El registro público está desactivado; crea usuarios de forma administrativa.
|
||||
- `/opt/vikunja/files` guarda adjuntos y `/opt/vikunja/postgres` la base; ambos son necesarios para una restauración completa.
|
||||
|
||||
CalDAV está activado para clientes externos; publica siempre mediante HTTPS y revoca credenciales de clientes perdidos.
|
||||
|
||||
## Requisitos
|
||||
|
||||
- Docker Compose
|
||||
|
||||
Reference in New Issue
Block a user