> For the complete documentation index, see [llms.txt](https://docs.facephi.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.facephi.com/sdks/backend-sdk/iad/installation/installation_instructions.md).

# Instalación y despliegue del servicio

## Requisitos previos

Antes de instalar IAD Service, asegúrate de tener:

* Docker instalado y en ejecución
* Un archivo de licencia válido de Facephi
* Acceso al registro Docker de Facephi

## Acceso al registro Docker

Inicia sesión en el registro Docker de Facephi:

```bash
docker login facephicorp.jfrog.io
```

Necesitarás las credenciales proporcionadas por Facephi.

## Instalación

{% hint style="danger" %}
**Aviso de cambio incompatible (2.0.0)** La versión 2.0.0 no es retrocompatible con las integraciones 1.x.x. Antes de actualizar un cliente desplegado, revisa y actualiza:

* las rutas de los endpoints públicos
* los nombres de los campos de las solicitudes multipart (`file` -> obligatorio `capture`; las solicitudes que solo incluyen `file` se rechazan)
* el análisis de las respuestas correctas (los campos `capture_liveness` y relacionados ya no se devuelven)
  {% endhint %}

### Descargar la imagen Docker

```bash
docker pull facephicorp.jfrog.io/docker-pro-fphi/facephi-iad-service:2.2.0
```

Sustituye `2.2.0` por la versión deseada.

### Preparar los directorios

Crea los directorios para la licencia, la configuración y los logs:

```bash
mkdir -p ~/facephi_iad/{license,config,logs}
```

### Colocar el archivo de licencia

Copia tu archivo de licencia al directorio de licencia:

```bash
cp your-license.lic ~/facephi_iad/license/license.lic
chmod 644 ~/facephi_iad/license/license.lic
```

## Despliegue con Docker Compose

Crea `docker-compose.yml`:

```yaml
version: '3.7'

services:
  iad-service:
    image: facephicorp.jfrog.io/docker-pro-fphi/facephi-iad-service:2.2.0
    container_name: facephi-iad-service
    ports:
      - "6982:6982"
    volumes:
      - ~/facephi_iad/license:/app/license
      - ~/facephi_iad/config:/app/config
      - ~/facephi_iad/logs:/app/logs
    restart: unless-stopped
```

### Iniciar el servicio

```bash
docker compose up -d
```

### Verificar el despliegue

```bash
# Check container status
docker ps | grep iad-service

# Check service health
curl http://localhost:6982/api/v1/iad/health

# View logs
docker logs facephi-iad-service
```

## Mitigación experimental de ataques de repetición (replay)

El servicio puede aplicar una ventana de vigencia (freshness window) a los payloads de captura entrantes. Esta protección experimental está deshabilitada por defecto.

* Actívala con `FACEPHI_IAD_REPLAY_ATTACK_CHECKER_ENABLED=true`
* Ajusta la ventana de vigencia con `FACEPHI_IAD_REPLAY_ATTACK_TOLERANCE_TIME=<seconds>`
* Ventana de vigencia por defecto: `300` segundos
* Cuando se supera la ventana de vigencia, la API pública devuelve HTTP `400` con `message` igual a `Replay attack detected`

Esta funcionalidad se configura al inicio mediante variables de entorno. No forma parte de `config.json` ni se expone a través de `GET|POST /api/v1/iad/config`.

Ejemplo con `docker run`:

```bash
docker run -d \
  -p 6982:6982 \
  -e FACEPHI_IAD_REPLAY_ATTACK_CHECKER_ENABLED=true \
  -e FACEPHI_IAD_REPLAY_ATTACK_TOLERANCE_TIME=60 \
  -v /path/to/license:/app/license \
  -v /path/to/config:/app/config \
  --name iad-service \
  facephicorp.jfrog.io/docker-pro-fphi/facephi-iad-service:2.2.0
```

Ejemplo con Docker Compose:

```yaml
services:
  iad-service:
    environment:
      FACEPHI_IAD_REPLAY_ATTACK_CHECKER_ENABLED: "true"
      FACEPHI_IAD_REPLAY_ATTACK_TOLERANCE_TIME: "60"
```

## Configuración de la licencia

El archivo de licencia debe ubicarse en `/app/license/license.lic` dentro del contenedor.

### Formato del archivo de licencia

```ini
LICENSE_TYPE=         # MACHINE, SHARED, or LOCAL
LICENSE_BEHAVIOUR=    # ONLINE or OFFLINE
LICENSE_KEY=          # Your license key
```

**Campos opcionales:**

* `LICENSE_URLS=` — URLs de los servidores de licencia separadas por comas (obligatorio para el tipo LOCAL)
* `LICENSE_PATH_OFFLINE=` — Ruta al archivo de activación offline (obligatorio para MACHINE + OFFLINE)

`LICENSE_ID` y `LICENSE_DATA`, si están presentes, son ignorados por el servicio a partir de la versión 2.0.0. Las credenciales del producto IAD se incrustan en tiempo de compilación, por lo que estos campos deben omitirse en las plantillas de despliegue.

## Resumen de la API pública

{% hint style="danger" %}
**Nota de compatibilidad** Las rutas siguientes corresponden al contrato de la versión 2.0.0. Los clientes construidos para 1.x.x deben migrarse antes de poder llamar correctamente a esta versión.
{% endhint %}

Endpoints operativos expuestos por el servicio:

* `POST /api/v1/iad/liveness/evaluate`
* `POST /api/v1/iad/extract`
* `GET /api/v1/iad/version`
* `GET /api/v1/iad/health`
* `GET|POST /api/v1/iad/config`

## Autenticación JWT

La autenticación JWT es opcional y está deshabilitada por defecto.

* Configúrala al inicio en `/app/config/config.json` con `auth_enabled`, `auth_jwt_secret`, `auth_accept_authorization_header`, `auth_accept_api_key_header` y `auth_api_key_header_name`
* Sobrescribe esos valores con las variables de entorno `FACEPHI_IAD_REST_AUTH_*`
* `GET /api/v1/iad/config` nunca devuelve las claves de autenticación JWT
* `POST /api/v1/iad/config` rechaza las claves de autenticación JWT; gestiónalas únicamente al inicio

Ejemplo de configuración de inicio:

```json
{
  "auth_enabled": true,
  "auth_jwt_secret": "replace-with-secret",
  "auth_accept_authorization_header": true,
  "auth_accept_api_key_header": true,
  "auth_api_key_header_name": "x-api-key"
}
```

Ejemplo de variables de entorno:

```bash
export FACEPHI_IAD_REST_AUTH_ENABLED=true
export FACEPHI_IAD_REST_AUTH_JWT_SECRET=replace-with-secret
export FACEPHI_IAD_REST_AUTH_ACCEPT_AUTHORIZATION_HEADER=true
export FACEPHI_IAD_REST_AUTH_ACCEPT_API_KEY_HEADER=true
export FACEPHI_IAD_REST_AUTH_API_KEY_HEADER_NAME=x-api-key
```

### Configuración del firewall para la validación de la licencia

Añade reglas de firewall para permitir el tráfico HTTPS saliente hacia los servidores de licencia de Facephi:

| IP           | Puerto | Protocolo |
| ------------ | ------ | --------- |
| 52.223.22.71 | 443    | TCP/IP    |
| 35.71.188.31 | 443    | TCP/IP    |
| 75.2.113.112 | 443    | TCP/IP    |
| 99.83.149.57 | 443    | TCP/IP    |

**Permite el tráfico HTTPS hacia:**

* `https://api.cryptlex.com:443`
* `https://api.eu.cryptlex.com:443`

## Configuración del servicio

Crea `/app/config/config.json` para personalizar el comportamiento del servicio.

### Ubicación del archivo de configuración

* **Ubicación por defecto:** `/app/config/config.json` (dentro del contenedor)
* **Montar un archivo externo:** Usa el mapeo de volúmenes en docker-compose

### Ejemplo de configuración completa (valores por defecto actuales)

```json
{
  "port": 6982,
  "number_of_threads": 1,
  "connection_timeout": 60,
  "keep_alive_request_number": 0,
  "client_max_body_size": 100,
  "logger_level": "info",
  "logger_path": "",
  "logger_rotation": "daily",
  "logger_max_files": 7,
  "auth_enabled": false,
  "auth_jwt_secret": "",
  "auth_accept_authorization_header": true,
  "auth_accept_api_key_header": true,
  "auth_api_key_header_name": "x-api-key",
  "engine_connection_timeout": 10000,
  "engine_request_timeout": 60000,
  "engine_max_retries": 3,
  "engine_retry_delay": 1000,
  "engine_verify_ssl": false,
  "engine_verbose": false,
  "engine_pool_size": 4,
  "engine_url": "http://localhost:8080"
}
```

### Parámetros del servicio

| Parámetro                          | Tipo    | Por defecto | Descripción                                                                           |
| ---------------------------------- | ------- | ----------- | ------------------------------------------------------------------------------------- |
| `port`                             | integer | 6982        | Puerto de escucha del servicio                                                        |
| `number_of_threads`                | integer | 1           | Hilos de trabajo para el procesamiento de solicitudes                                 |
| `connection_timeout`               | integer | 60          | Timeout de conexión en segundos (0 = sin timeout)                                     |
| `keep_alive_request_number`        | integer | 0           | Solicitudes keep-alive (0 = deshabilitado)                                            |
| `client_max_body_size`             | integer | 100         | Tamaño máximo del cuerpo de la solicitud en MB                                        |
| `logger_path`                      | string  | ""          | Ruta del archivo de log (vacío = stdout)                                              |
| `logger_level`                     | string  | "info"      | Nivel de log: trace, debug, info, warn, error                                         |
| `logger_rotation`                  | string  | "daily"     | Rotación de logs: daily, hourly, size                                                 |
| `logger_max_files`                 | integer | 7           | Número máximo de archivos de log a conservar                                          |
| `auth_enabled`                     | boolean | false       | Requiere autenticación JWT para los endpoints protegidos                              |
| `auth_jwt_secret`                  | string  | ""          | Secreto compartido HS256 usado para validar los JWT                                   |
| `auth_accept_authorization_header` | boolean | true        | Acepta `Authorization: Bearer <jwt>`                                                  |
| `auth_accept_api_key_header`       | boolean | true        | Acepta JWT en la cabecera de API key configurada                                      |
| `auth_api_key_header_name`         | string  | "x-api-key" | Nombre de la cabecera usada cuando la extracción de token por API key está habilitada |

### Parámetros del engine

| Parámetro                   | Tipo    | Por defecto             | Descripción                                                 |
| --------------------------- | ------- | ----------------------- | ----------------------------------------------------------- |
| `engine_connection_timeout` | integer | 10000                   | Timeout de conexión (ms)                                    |
| `engine_request_timeout`    | integer | 60000                   | Timeout de solicitud (ms)                                   |
| `engine_max_retries`        | integer | 3                       | Número máximo de reintentos                                 |
| `engine_retry_delay`        | integer | 1000                    | Retardo entre reintentos (ms)                               |
| `engine_verify_ssl`         | boolean | false                   | Verifica los certificados SSL del análisis de capturas      |
| `engine_verbose`            | boolean | false                   | Habilita el logging HTTP detallado del análisis de capturas |
| `engine_pool_size`          | integer | 4                       | Tamaño del pool de conexiones                               |
| `engine_url`                | string  | `http://localhost:8080` | URL base del runtime de análisis de capturas                |

### Configuración de producción

Para despliegues en producción:

```json
{
  "port": 6982,
  "number_of_threads": 8,
  "connection_timeout": 60,
  "keep_alive_request_number": 1000,
  "client_max_body_size": 100,
  "logger_level": "info",
  "logger_path": "/app/logs",
  "logger_rotation": "daily",
  "logger_max_files": 30,
  "engine_connection_timeout": 10000,
  "engine_request_timeout": 60000,
  "engine_max_retries": 3,
  "engine_retry_delay": 1000,
  "engine_verify_ssl": true,
  "engine_verbose": false,
  "engine_pool_size": 20,
  "engine_url": "https://localhost:8080"
}
```

### Configuración de desarrollo

Para desarrollo local:

```json
{
  "port": 6982,
  "number_of_threads": 2,
  "logger_level": "debug",
  "logger_path": "/app/logs",
  "engine_connection_timeout": 5000,
  "engine_request_timeout": 30000,
  "engine_max_retries": 1,
  "engine_verify_ssl": false,
  "engine_verbose": true,
  "engine_pool_size": 2,
  "engine_url": "http://localhost:8080"
}
```

### Actualizaciones dinámicas de configuración

Actualiza la configuración sin reiniciar:

```bash
# Update configuration
curl -X POST http://localhost:6982/api/v1/iad/config \
  -H "Content-Type: application/json" \
  -d '{"config_json_string":"{\"engine_url\":\"http://localhost:8081\",\"engine_pool_size\":8}"}'

# Verify current configuration
curl http://localhost:6982/api/v1/iad/config
```

`POST /api/v1/iad/config` espera un objeto JSON con el campo `config_json_string`, que contiene la configuración completa serializada como una cadena JSON. Las claves de autenticación JWT son rechazadas por este endpoint y deben configurarse únicamente al inicio.

**Nota:** Las actualizaciones en tiempo de ejecución no se persisten automáticamente. Para realizar cambios permanentes, actualiza el archivo de configuración en disco y reinicia el servicio si es necesario.

## Solución de problemas

### El servicio no arranca

**Comprueba el archivo de licencia:**

```bash
docker exec facephi-iad-service ls -la /app/license/
```

**Comprueba los logs:**

```bash
docker logs facephi-iad-service
```

### Falla la validación de la licencia

* Verifica los permisos del archivo de licencia: `chmod 644 license.lic`
* Asegúrate de que el firewall permite el tráfico HTTPS saliente hacia los servidores de licencia
* Comprueba la fecha de caducidad de la licencia
* Confirma que la licencia corresponde al producto IAD Service

### Problemas de rendimiento

* Aumenta `engine_pool_size` para gestionar más solicitudes concurrentes
* Ajusta `number_of_threads` según los núcleos de CPU disponibles
* Monitoriza el uso de recursos: `docker stats facephi-iad-service`
* Revisa los logs en busca de errores de timeout o reintentos

## Actualización

Para actualizar a una nueva versión:

{% hint style="warning" %}
**Importante** Actualizar de 1.x.x a 2.0.0 es una migración de API con cambios incompatibles, no un reemplazo directo. Valida todas las llamadas del cliente frente a los nuevos nombres de endpoints y ejemplos de solicitud/respuesta antes de promover el despliegue.
{% endhint %}

```bash
# Pull new version
docker pull facephicorp.jfrog.io/docker-pro-fphi/facephi-iad-service:2.0.0
docker pull facephicorp.jfrog.io/docker-pro-fphi/facephi-iad-service:2.2.0

# Update docker-compose.yml with new version
# Stop current service
docker compose down

# Start new version
docker compose up -d

# Verify upgrade
curl http://localhost:6982/api/v1/iad/version
```

**Revisa siempre las notas de versión antes de actualizar.**
