# Solución de problemas

> Diagnostica problemas de instalación, acceso, alta, recolección y terminal.

## Dónde mirar

| Fuente | Comando o lugar |
|---|---|
| Estado de los contenedores | `docker compose ps` |
| Logs de un servicio | `docker compose logs --tail 100 api` (o `worker`, `gateway`, `web`, `openbao`) |
| Trabajos fallidos y su error | **Actividad**, filtro **Fallidas** |
| Quién hizo qué | **Ajustes → Auditoría** |
| Salud de la API | `curl -s http://127.0.0.1:8080/api/health` |

## Instalación

### `init.sh`: Falta .env

Ejecuta `cp .env.example .env` y edítalo antes de `init.sh`.

### `docker compose up` falla con `… es obligatoria`

Compose no arranca cuando una variable obligatoria está vacía:

- `POSTGRES_PASSWORD`, `ADMIN_EMAIL`, `ADMIN_PASSWORD` o `INFRAWARD_REGISTRY`: rellénalas en `.env`.
- `OPENBAO_ROLE_ID`, `VAULT_OPENBAO_ROLE_ID` o `TERMINAL_OPENBAO_ROLE_ID` (*la escribe init.sh*): ejecuta `./init.sh`. También ocurre tras una actualización que añade una AppRole nueva.

### `init.sh`: OpenBao ya está inicializado pero falta secrets/openbao/init.json

OpenBao está configurado y el fichero con su token root se ha retirado, como se recomienda. Si no hay nada que cambiar, no hace falta ejecutar `init.sh`. Si una actualización lo exige, devuelve `init.json` desde donde lo guardaste, ejecuta `init.sh` y vuelve a borrarlo.

### Podman: `unknown mount option "uid=70"`

Algunas versiones de Podman no aceptan las opciones `uid=` y `gid=` que `compose.yml` usa en sus montajes `tmpfs`. Cámbialas por la opción `U` de Podman, que asigna el tmpfs al usuario del contenedor:

```bash
sed -i -E 's/:uid=[0-9]+,gid=[0-9]+,mode=/:U,mode=/' compose.yml
```

Tenlo en cuenta cuando actualices `compose.yml` en las actualizaciones.

### La API se reinicia en bucle

Mira `docker compose logs api`. La API valida su configuración al arrancar y se detiene con `Configuración de entorno inválida: …`, indicando la variable. Causas habituales:

- `PUBLIC_URL tiene que ser https en producción`: pon en `INFRAWARD_PUBLIC_URL` una URL `https://`.
- Una variable añadida en un fichero de override con un valor fuera de rango. Consulta los valores admitidos en [Variables de configuración](/es/docs/configuration.md).

### OpenBao muestra un error en Ajustes

**Ajustes → Secretos** muestra `openbao` con problemas cuando la API o el worker no pueden autenticarse con su AppRole:

1. Comprueba que `docker compose ps openbao` está `healthy`. Si tras un reinicio está sellado y quitaste el desellado estático, desséllalo.
2. Revisa los role ID de `.env` y los ficheros de `secrets/openbao/`. Ante la duda, ejecuta `./init.sh --rotate-secret-id` y `docker compose restart api worker gateway`.

## Acceso y sesiones

### Al entrar, vuelve a la página de login

El navegador ha descartado la cookie de sesión, que es `Secure`. Pasa cuando InfraWard se abre por HTTP sin cifrar en un host que no es `localhost`. Sírvelo por HTTPS. Consulta [HTTPS y proxy inverso](/es/docs/reverse-proxy.md).

### Safari no mantiene la sesión en localhost

Safari rechaza las cookies `Secure` en `http://localhost`. Usa Chrome o Firefox para las pruebas locales, o pon InfraWard detrás de HTTPS.

### Las escrituras fallan con 403

La API rechaza las escrituras cuyo `Origin` no coincide con `INFRAWARD_PUBLIC_URL`. Comprueba que la URL de `.env` es exactamente la de la barra de direcciones del navegador (esquema, host y puerto) y ejecuta `docker compose up -d`.

### El acceso por OIDC dice que el email no está verificado

El mensaje *… no marca tu email como verificado* significa que el proveedor no envió `email_verified: true`, así que InfraWard no crea la cuenta. Verifica el email en el proveedor. Si tu proveedor nunca envía ese claim (Microsoft Entra ID), define `OIDC_ALLOW_UNVERIFIED_SIGNUP: "true"` en `api`. Consulta [Cómo se crean y actualizan las cuentas](/es/docs/authentication.md#cómo-se-crean-y-actualizan-las-cuentas).

### La auditoría muestra la IP del proxy para todos los usuarios

`INFRAWARD_TRUSTED_PROXY` no está definida o no coincide con el proxy inverso. Consulta [Averigua la dirección del proxy](/es/docs/reverse-proxy.md#averigua-la-dirección-del-proxy).

### No se ha creado el primer administrador

`ADMIN_EMAIL` y `ADMIN_PASSWORD` solo se leen cuando la base de datos no tiene usuarios, y la contraseña necesita al menos 12 caracteres. Busca un aviso en `docker compose logs api`. Si ya existe algún usuario, cambiar estas variables no tiene efecto.

### Un administrador ha perdido la app y los códigos de recuperación

Otro administrador restablece su segundo factor desde **Ajustes → Usuarios**. No hay forma de hacerlo desde la línea de comandos; por eso conviene tener siempre al menos dos cuentas de administrador (o una cuenta local de emergencia si usas OIDC).

## Alta de servidores

### `curl: (6) Could not resolve host` o `(7) Failed to connect`

El servidor no llega a `INFRAWARD_PUBLIC_URL`. Revisa el DNS y los cortafuegos desde el servidor, o usa la pestaña **Script embebido (VPN/NAT)**, que no necesita conexión con InfraWard.

### La página se queda en **Esperando clave**

El script no terminó o no pudo avisar. Lee la salida del script en el servidor: cada línea empieza por `[infraward]` y la última antes del error lo explica. El token es de un solo uso: genera un comando nuevo para volver a intentarlo.

### El script se detiene porque el reloj va atrasado

En el modo con certificados, los certificados son válidos desde 30 segundos antes de crearse. Un servidor con el reloj más de 5 minutos atrasado los rechazaría. Activa NTP (`timedatectl set-ntp true`) y vuelve a ejecutar el comando.

### `sshd -t` falla y el script deshace los cambios

El script valida sshd antes de recargarlo. La causa habitual es un `sshd_config` sin `Include /etc/ssh/sshd_config.d/*.conf`, o un fichero anterior que ya fija `TrustedUserCAKeys` o `AuthorizedPrincipalsFile` para todos los usuarios. Corrige la configuración y vuelve a ejecutar el comando, o da de alta el servidor con clave estática.

### El script se detiene en `~/.ssh` o `authorized_keys`

Con clave estática, el script escribe `authorized_keys` como el usuario `inventory` y antes comprueba las rutas. Se detiene sin cambiar nada cuando:

- `~/.ssh` o `authorized_keys` son un enlace simbólico. El script no lo sigue, porque un enlace como `~/.ssh -> /root/.ssh` haría que root escribiera en otro sitio. InfraWard nunca crea esos enlaces: revisa el servidor, puede que alguien haya entrado como `inventory`.
- `~/.ssh` o `authorized_keys` pertenecen a otro usuario, o `authorized_keys` no es un fichero normal o tiene más de un enlace duro.
- La cuenta ya existía y su directorio personal no es suyo (`'inventory' no puede crear …/.ssh`). Haz que el usuario sea dueño de su directorio personal, o borra la cuenta y deja que el script la cree.

Corrige la causa y vuelve a ejecutar el comando, o genera uno nuevo si el token ha caducado.

### **Conectando** falla con un error de host key

La host key que recibe el worker no coincide con las huellas que envió el script. Comprueba que la dirección que escribiste llega a la máquina correcta (y no a un balanceador o a otro host detrás de un NAT).

## Recolección y escaneos

### Averigua por qué falló una recolección o un escaneo

Abre la pestaña **Recolecciones** del asset, o el trabajo en **Actividad**, y elige la ejecución fallida. Su log muestra el paso y el comando que fallaron, con el final de su salida de error. Consulta [Logs de las ejecuciones](/es/docs/inventory.md#logs-de-las-ejecuciones).

### La recolección falla con `Failed to create temporary directory`

Corregido en InfraWard 0.5.2: actualiza. En la 0.5.0 y la 0.5.1, Ansible no puede escribir su directorio temporal en el worker, cuyo sistema de ficheros raíz es de solo lectura. Añade un tmpfs escribible en un fichero de override (y añade el fichero a `COMPOSE_FILE`):

```yaml title="compose.override.yml"
services:
  worker:
    tmpfs:
      - /tmp:uid=1000,gid=1000,mode=0700
      - /home/node/.ansible:uid=1000,gid=1000,mode=0700
```

Después ejecuta `docker compose up -d worker` y pulsa **Recolectar de nuevo** en los servidores afectados.

### La recolección es parcial

La ficha del asset muestra *La última recolección fue parcial* con el motivo. Por ejemplo, sin `ss` ni `netstat` en el servidor, los puertos se leen de `/proc/net` sin el proceso que los abre. Instala `iproute2` para tener el nombre del proceso.

### Faltan paquetes en un CT de Proxmox

Instala `python3` en el CT. La recolección dentro de los CT se hace con `pct exec` desde el nodo y necesita Python.

### Los escaneos tardan mucho en empezar tras instalar

En el primer arranque, el worker descarga unos 3 GB de datos de Trivy y los escaneos esperan a que termine. Síguelo con `docker compose logs -f worker | grep -i trivy`.

### No aparecen los contenedores de Podman

- El servidor muestra **sudoers desactualizado**: Podman necesita la versión 8 del sudoers. Regenera el comando de alta y vuelve a ejecutarlo.
- Contenedores rootless: el usuario tiene que estar habilitado en la tarjeta **Usuarios de Podman**, y después hay que volver a recolectar. Un usuario en **Sin socket** está habilitado pero no tiene activo `podman.socket`: vuelve a pulsar **Habilitar**, que además activa linger para que el socket siga vivo al cerrar sus sesiones.
- Un usuario sin contenedores en marcha, sin socket y con el almacén fuera de `~/.local/share/containers` no se detecta. Añádelo con `--podman-users`.

### Un servidor muestra cientos de vulnerabilidades del kernel

Actualiza a InfraWard 0.6.0 o posterior. Las versiones anteriores contaban los hallazgos de los kernels instalados que no están en ejecución, que dnf conserva en los servidores de la familia RHEL.

### Una imagen aparece como no escaneada

El motivo aparece en la imagen: supera `TRIVY_MAX_IMAGE_SIZE` (4 GiB) o tarda más de `TRIVY_SCAN_TIMEOUT` (15 minutos). Sube los límites en el worker o excluye la imagen del escaneo.

## Alertas

### **Enviar prueba** falla en un webhook

El último error aparece en el canal. Causas habituales:

- La URL resuelve a una dirección privada o usa `http:`: el worker la rechaza salvo que `ALERTS_WEBHOOK_ALLOW_PRIVATE` o `ALERTS_WEBHOOK_ALLOW_HTTP` estén a `true` en el worker.
- El receptor redirige: las redirecciones no se siguen. Usa la URL final.
- El receptor tarda en responder más de `ALERTS_TIMEOUT_MS` (10 segundos).

### Los canales de correo no envían

El worker no tiene servidor SMTP configurado (`SMTP_HOST`), o el servidor no ofrece TLS. Consulta [Variables de configuración](/es/docs/configuration.md#alertas).

## Terminal web

### **Abrir terminal** no está disponible

El servidor necesita el modo con certificados y el acceso de administración activado, OpenBao tiene que estar en marcha y necesitas permiso sobre el asset. Consulta [Terminal web](/es/docs/terminal.md#requisitos).

### La terminal dice *No se pudo cargar la terminal*

Corregido en InfraWard 0.6.0: en las compilaciones de producción de las versiones anteriores no se cargaba el componente de la terminal. Actualiza.

### Confirmar la identidad con authentik falla la segunda vez

Corregido en InfraWard 0.6.0. authentik ignora `max_age=0`, que enviaban las versiones anteriores, y devolvía una hora de inicio de sesión antigua a partir de la segunda confirmación en la misma sesión del navegador. Actualiza.

### La terminal se cierra nada más abrirse

El proxy inverso no reenvía la actualización a WebSocket en `/gateway/`, o cierra demasiado pronto las conexiones inactivas. Consulta [HTTPS y proxy inverso](/es/docs/reverse-proxy.md#qué-tiene-que-hacer-el-proxy).

---

Página HTML: https://infraward.net/es/docs/troubleshooting/
