> 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/docs.facephi-en/sdks/backend-sdk/iad/installation/installation_instructions.md).

# Service installation and deployment

## Prerequisites

Before installing IAD Service, make sure you have:

* Docker installed and running
* A valid Facephi license file
* Access to the Facephi Docker registry

## Access to the Docker registry

Log in to the Facephi Docker registry:

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

You will need the credentials provided by Facephi.

## Installation

{% hint style="danger" %}
**Breaking change notice (2.0.0)** Version 2.0.0 is not backward compatible with 1.x.x integrations. Before upgrading a deployed client, review and update:

* the public endpoint paths
* the multipart request field names (`file` -> required `capture`; requests that only include `file` are rejected)
* the parsing of correct responses (the fields `capture_liveness` and related fields are no longer returned)
  {% endhint %}

### Download the Docker image

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

Replace `2.2.0` with the desired version.

### Prepare the directories

Create the directories for the license, configuration, and logs:

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

### Place the license file

Copy your license file into the license directory:

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

## Deployment with Docker Compose

Create `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
```

### Start the service

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

### Verify the deployment

```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
```

## Experimental replay attack mitigation

The service can apply a freshness window to incoming capture payloads. This experimental protection is disabled by default.

* Enable it with `FACEPHI_IAD_REPLAY_ATTACK_CHECKER_ENABLED=true`
* Adjust the freshness window with `FACEPHI_IAD_REPLAY_ATTACK_TOLERANCE_TIME=<seconds>`
* Default freshness window: `300` seconds
* When the freshness window is exceeded, the public API returns HTTP `400` with `message` equal to `Replay attack detected`

This feature is configured at startup through environment variables. It is not part of `config.json` or exposed through `GET|POST /api/v1/iad/config`.

Example with `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
```

Example with Docker Compose:

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

## License configuration

The license file must be located at `/app/license/license.lic` inside the container.

### License file format

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

**Optional fields:**

* `LICENSE_URLS=` — comma-separated license server URLs (required for LOCAL type)
* `LICENSE_PATH_OFFLINE=` — Path to the offline activation file (required for MACHINE + OFFLINE)

`LICENSE_ID` and `LICENSE_DATA`, if present, are ignored by the service as of version 2.0.0. IAD product credentials are embedded at build time, so these fields must be omitted from deployment templates.

## Public API summary

{% hint style="danger" %}
**Compatibility note** The following paths correspond to the version 2.0.0 contract. Clients built for 1.x.x must be migrated before they can call this version correctly.
{% endhint %}

Operational endpoints exposed by the service:

* `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`

## JWT authentication

JWT authentication is optional and disabled by default.

* Configure it at startup in `/app/config/config.json` with `auth_enabled`, `auth_jwt_secret`, `auth_accept_authorization_header`, `auth_accept_api_key_header` and `auth_api_key_header_name`
* Override those values with the environment variables `FACEPHI_IAD_REST_AUTH_*`
* `GET /api/v1/iad/config` never returns the JWT authentication keys
* `POST /api/v1/iad/config` rejects the JWT authentication keys; manage them only at startup

Startup configuration example:

```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"
}
```

Environment variables example:

```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
```

### Firewall configuration for license validation

Add firewall rules to allow outgoing HTTPS traffic to Facephi license servers:

| IP           | Port | Protocol |
| ------------ | ---- | -------- |
| 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   |

**Allow HTTPS traffic to:**

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

## Service configuration

Create `/app/config/config.json` to customize the service behavior.

### Configuration file location

* **Default location:** `/app/config/config.json` (inside the container)
* **Mount an external file:** Use the volume mapping in docker-compose

### Full configuration example (current default values)

```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"
}
```

### Service parameters

| Parameter                          | Type    | Default     | Description                                                  |
| ---------------------------------- | ------- | ----------- | ------------------------------------------------------------ |
| `port`                             | integer | 6982        | Service listening port                                       |
| `number_of_threads`                | integer | 1           | Worker threads for request processing                        |
| `connection_timeout`               | integer | 60          | Connection timeout in seconds (0 = no timeout)               |
| `keep_alive_request_number`        | integer | 0           | Keep-alive requests (0 = disabled)                           |
| `client_max_body_size`             | integer | 100         | Maximum request body size in MB                              |
| `logger_path`                      | string  | ""          | Log file path (empty = stdout)                               |
| `logger_level`                     | string  | "info"      | Log level: trace, debug, info, warn, error                   |
| `logger_rotation`                  | string  | "daily"     | Log rotation: daily, hourly, size                            |
| `logger_max_files`                 | integer | 7           | Maximum number of log files to keep                          |
| `auth_enabled`                     | boolean | false       | Requires JWT authentication for protected endpoints          |
| `auth_jwt_secret`                  | string  | ""          | HS256 shared secret used to validate JWTs                    |
| `auth_accept_authorization_header` | boolean | true        | Accepts `Authorization: Bearer <jwt>`                        |
| `auth_accept_api_key_header`       | boolean | true        | Accepts JWT in the configured API key header                 |
| `auth_api_key_header_name`         | string  | "x-api-key" | Header name used when token extraction by API key is enabled |

### Engine parameters

| Parameter                   | Type    | Default                 | Description                                        |
| --------------------------- | ------- | ----------------------- | -------------------------------------------------- |
| `engine_connection_timeout` | integer | 10000                   | Connection timeout (ms)                            |
| `engine_request_timeout`    | integer | 60000                   | Request timeout (ms)                               |
| `engine_max_retries`        | integer | 3                       | Maximum number of retries                          |
| `engine_retry_delay`        | integer | 1000                    | Delay between retries (ms)                         |
| `engine_verify_ssl`         | boolean | false                   | Verifies SSL certificates for capture analysis     |
| `engine_verbose`            | boolean | false                   | Enables detailed HTTP logging for capture analysis |
| `engine_pool_size`          | integer | 4                       | Connection pool size                               |
| `engine_url`                | string  | `http://localhost:8080` | Base URL of the capture analysis runtime           |

### Production configuration

For production deployments:

```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"
}
```

### Development configuration

For local development:

```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"
}
```

### Dynamic configuration updates

Update the configuration without restarting:

```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` expects a JSON object with the field `config_json_string`, which contains the full configuration serialized as a JSON string. JWT authentication keys are rejected by this endpoint and must be configured only at startup.

**Note:** Runtime updates are not persisted automatically. To make permanent changes, update the configuration file on disk and restart the service if necessary.

## Troubleshooting

### The service does not start

**Check the license file:**

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

**Check the logs:**

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

### License validation fails

* Verify the license file permissions: `chmod 644 license.lic`
* Make sure the firewall allows outgoing HTTPS traffic to the license servers
* Check the license expiration date
* Confirm that the license corresponds to the IAD Service product

### Performance issues

* Increase `engine_pool_size` to handle more concurrent requests
* Adjust `number_of_threads` according to the available CPU cores
* Monitor resource usage: `docker stats facephi-iad-service`
* Review the logs for timeout or retry errors

## Upgrade

To upgrade to a new version:

{% hint style="warning" %}
**Important** Upgrading from 1.x.x to 2.0.0 is an API migration with incompatible changes, not a direct replacement. Validate all client calls against the new endpoint names and request/response examples before promoting the deployment.
{% 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
```

**Always review the release notes before upgrading.**
