UI Services Separate Host Deployment

Overview

This deployment runs UI services (Backend + Portals) on a dedicated host. The deployment includes:

  • UI Backend - Spring Boot REST API service

  • UI Portals - Angular web applications on Nginx (Support Center & Management Console)

Architecture

ui-services-architecture

Prerequisites

For detailed information about Docker registry and image management, see Docker Image Management Guide.

For HTTPS configuration, see Ssl certificate configuration.

Required External Components

The following components must be installed and accessible:

Component Purpose Default Port

MySQL or Oracle

Main application database

3306 (MySQL) / 1521 (Oracle)

Hazelcast

Distributed cache

5701

FTACS Application

ACS web service

8080

Clickhouse

Analytics database

9000

System Requirements

  • Docker Engine 20.10+

  • Docker Compose 2.0+

  • Minimum 3GB RAM

  • 15GB free disk space

Preparation

1. Prepare Configuration Directory

Create the required directory structure:

mkdir -p /usr/local/ft-services/{ui-backend-conf,ft-data/ui-portals/{backend,nginx}/logs}

Download the deployment files (compose.yml, .env.mysql, .env.oracle) from the FT_DISK on SharePoint and place them into /usr/local/ft-services/.

Volume Mounts & Directory Layout

The ui-backend-conf folder contains essential configuration files for the backend service. Download pre-configured files from the FT_DISK on SharePoint and place them into the directory.

The tree below shows the baseline layout plus common environment-dependent entries. Not every deployment needs every entry, but the standard SharePoint package can include them because some are default runtime config, some are loaded only when present, and some are used only for specific integrations.

/usr/local/ft-services/
├── ui-backend-conf/                    # Configuration (backup required)
│   ├── hazelcast-client.xml            # Main Hazelcast client configuration
│   ├── ftacs.keystore                  # Backend keystore used when HTTPS is enabled
│   ├── logback-spring.xml              # Default external logging configuration
│   ├── interfaceItems.json             # Interface seed data, loaded if present
│   ├── customization/                  # Portal customization JSON files
│   │   ├── def/                        # Default system-wide customizations
│   │   ├── mc/                         # Management Console customizations
│   │   └── sc/                         # Support Center customizations
│   ├── ssl/                            # TLS certificates for Nginx/portals when configured
│   └── keys/                           # Integration credentials (when used)
└── ft-data/ui-portals/                 # Runtime data (created automatically)
    ├── backend/logs/
    └── nginx/logs/
Path Content Backup Required

ui-backend-conf/

Configuration files. At minimum this includes hazelcast-client.xml and customizations; the SharePoint package may also include additional service-specific files and directories.

Yes

ft-data/ui-portals/backend/logs/

Backend application logs

No

ft-data/ui-portals/nginx/logs/

Nginx access and error logs

No

2. Prepare Environment File

The compose.yml references the env file via env_file directive. Make sure it points to the file matching your database:

MySQL
env_file:
  - .env.mysql
Oracle
env_file:
  - .env.oracle

3. Configure Host Variables

Edit .env.mysql or .env.oracle and replace all ~PLACEHOLDER~ values with actual hostnames or IP addresses.

The env files contain placeholders in the format ~NAME~ that must be replaced before starting the services:

Placeholder Variable in .env Description

~HOST~

FT_UI_HOST

Public hostname or IP address of this server (the machine where UI services are being deployed). Used by the Portals entrypoint to patch Angular app-config.json so that browsers know where to send API requests. Must be accessible from end-user browsers — use a real IP or DNS name, not localhost.

~HAZELCAST_HOST~

HZ_MEMBERS

Hazelcast cluster member address(es). Format: host:port (comma-separated for multiple members). The backend connects to this cluster for distributed caching and session sharing.

~FTACS_HOST~

ACS_WEB_SERVICE_HOST

Hostname or IP of the FTACS application server. The backend uses this to make SOAP calls for device provisioning, parameter reads, and firmware management.

~CLICKHOUSE_HOST~

CLICKHOUSE_HOST

Hostname or IP of the ClickHouse server. Used for QoE analytics queries. If ClickHouse is not deployed, leave the default value — the application will skip analytics features.

~MYSQL_HOST~

DB_HOST

Hostname or IP of the MySQL server (only in .env.mysql). Both FTACS and IOTW schemas must be accessible at this address.

~ORACLE_HOST~

DB_HOST

Hostname or IP of the Oracle server (only in .env.oracle). Both FTACS and IOTW schemas must be accessible at this address.

Example (.env.mysql):

FT_UI_HOST=192.168.1.100
HZ_MEMBERS=192.168.1.50:5701,192.168.1.51:5701
ACS_WEB_SERVICE_HOST=192.168.1.60
CLICKHOUSE_HOST=192.168.1.70
DB_HOST=192.168.1.80

FT_UI_HOST must be the address that end-user browsers can reach. If users access the portal through a load balancer or public DNS (e.g., iot.example.com), use that value instead of the server’s internal IP.

Docker Networking: host.docker.internal

If the database, Hazelcast, FTACS, or ClickHouse runs on the host machine (not inside Docker), use host.docker.internal as the hostname in .env variables (DB_HOST, HZ_MEMBERS, ACS_WEB_SERVICE_HOST, etc.):

DB_HOST=host.docker.internal
HZ_MEMBERS=host.docker.internal:5701
ACS_WEB_SERVICE_HOST=host.docker.internal
CLICKHOUSE_HOST=host.docker.internal

Why this is needed:

  • Inside a Docker container, localhost and 127.0.0.1 point to the container itself, not to the host machine. Any connection attempt to a host-side service via localhost will fail.

  • host.docker.internal is a special DNS name that Docker resolves to the host’s internal IP address.

  • The provided compose.yml already includes the required mapping:

    extra_hosts:
      - "host.docker.internal:host-gateway"
  • On Docker Desktop (macOS, Windows) this works out of the box. On Linux the extra_hosts directive above is required (already present in compose.yml).

Alternatively, use the host machine’s real IP address (e.g., 192.168.1.10) instead of host.docker.internal.

Environment Variables

Service Configuration

Variable Description Default Required

HOST

Public hostname for UI access (used in Angular configs)

HOST

Yes

FT_UI_HTTP_PORT

UI Portals HTTP port

8880

Yes

FT_UI_HTTPS_PORT

UI Portals HTTPS port

8843

Yes

FT_UI_BACKEND_HTTP_PORT

Backend API port

8881

Yes

FT_GRAFANA_API_URL

Grafana url for dashboards exporting (http://IP:PORT/)

No

SUPERSET_URL

Superset base URL for dashboard embedding

https://superset.friendly-tech.com

No

SUPERSET_USERNAME

Superset API username for backend authentication

superset

No

SUPERSET_PASSWORD

Superset API password for backend authentication

superset-12345

No

FT_UI_BACKEND_JAVA_RAM

Backend JVM memory settings

-Xms512m -Xmx2g

No

FT_UI_BACKEND_LOG_LEVEL

Backend log level (info, debug, warn, error)

info

No

FT_UI_BACKEND_KEYWORD

Internal authentication keyword for cross-service communication (entrypoint uses this for permissions upload)

ft12Internal%^

Yes

Common Configuration

Variable Description Default Required

DATA_FOLDER

Base directory for persistent data and configurations

/usr/local/ft-services

Yes

TZ

Timezone for all services

Europe/Kiev

Yes

Database Configuration

MySQL
Variable Description Default Required

DB_HOST

MySQL server address

MYSQL_HOST

Yes

MYSQL_PORT

MySQL port

3306

Yes

MYSQL_USER

MySQL username

ftacs

Yes

DB_PASSWORD

MySQL password

ftacs

Yes

DB_VENDOR

Database type

mysql

Yes

Oracle
Variable Description Default Required

DB_HOST

Oracle server address

ORACLE_HOST

Yes

ORACLE_PORT

Oracle port

1521

Yes

ORACLE_SERVICE

Oracle service name

XEPDB1

Yes

ORACLE_USER_FTACS

Oracle username for FTACS schema

ftacs

Yes

ORACLE_USER_IOTW

Oracle username for IOTW schema

iotw

Yes

DB_PASSWORD

Oracle password

ftacs

Yes

DB_VENDOR

Database type

oracle

Yes

External Dependencies

Variable Description Default Required

HZ_MEMBERS

Hazelcast cluster members (comma-separated HOST:PORT)

HAZELCAST_HOST:5701

Yes

ACS_WEB_SERVICE_HOST

FTACS application host

FTACS_HOST

Yes

ACS_WEB_SERVICE_PORT

FTACS application port

8080

Yes

CLICKHOUSE_HOST

Clickhouse server address

CLICKHOUSE_HOST

Yes

CLICKHOUSE_PORT

Clickhouse port

9000

Yes

CLICKHOUSE_DATABASE

Clickhouse database name

ftacs_qoe_ui_data

Yes

CLICKHOUSE_USERNAME

Clickhouse username

ftacs

Yes

CLICKHOUSE_PASSWORD

Clickhouse password

ftacs

Yes

Deployment

Deploy Services

docker compose up -d

Verify Deployment

Check service status:

docker compose ps

Expected output:

NAME                STATUS              PORTS
ui-backend          healthy             0.0.0.0:8881->8880/tcp, 0.0.0.0:5005->5005/tcp
portals             healthy             0.0.0.0:8880->80/tcp

Container Startup Process

UI Backend Startup

The backend container starts with the following initialization:

  1. Loads configuration from /app/conf (mounted from ui-backend-conf)

  2. Connects to Hazelcast cluster using hazelcast-client.xml

  3. Connects to MySQL/Oracle database

  4. Initializes REST API endpoints

  5. Health check becomes available at /iot-webservice/swagger-ui/index.html

UI Portals Startup (Entrypoint)

The portals container runs an entrypoint script that performs the following actions:

1. Configuration Patching

Patches Angular application configuration files with backend API endpoints:

# Support Center
/usr/share/nginx/html/support-center/assets/app-config.json
  → .server.api = "http://${HOST}:8881/iot-webservice/"

# Management Console
/usr/share/nginx/html/management-console/assets/app-config.json
  → .server.api = "http://${HOST}:8881/iot-webservice/"

This ensures the Angular apps know where to send API requests.

2. Permissions Upload

Uploads portal-specific permissions to the backend:

# Support Center permissions
curl -X PUT http://ui-backend:8880/iot-webservice/iotw/Setting/userGroup/permissions \
  -H "X-Internal-Keyword: ${FT_UI_BACKEND_KEYWORD}" \
  -H "X-Internal-Client-Type: sc" \
  -F "config=@/usr/share/nginx/html/support-center/assets/app-permissions-config.json"

# Management Console permissions
curl -X PUT http://ui-backend:8880/iot-webservice/iotw/Setting/userGroup/permissions \
  -H "X-Internal-Keyword: ${FT_UI_BACKEND_KEYWORD}" \
  -H "X-Internal-Client-Type: mc" \
  -F "config=@/usr/share/nginx/html/management-console/assets/app-permissions-config.json"

Purpose: Synchronizes user group permissions from Angular apps to the backend database.

Authentication: Uses FT_UI_BACKEND_KEYWORD header for internal service-to-service authentication.

3. Start Nginx

After patching and upload, Nginx starts serving the Angular applications.

Startup Dependencies

Services start in this order:

  1. UI Backend - Waits for database and Hazelcast connectivity

  2. UI Portals - Waits for backend health check, then runs entrypoint script

Service Access

After successful deployment:

Service URL Description

Support Center

http://<FT_UI_HOST>:8880/support-portal/

End-user support portal

Management Console

http://<FT_UI_HOST>:8880/management-console/

Administrator console

Backend API

http://<FT_UI_HOST>:8881/iot-webservice/swagger-ui/index.html

API documentation

Exposed Ports

Port Service Protocol Purpose Configurable Via

8880

UI Portals (Nginx)

HTTP

Web interface

FT_UI_HTTP_PORT

8843

UI Portals (Nginx)

HTTPS

Web interface

FT_UI_HTTPS_PORT

8881

UI Backend

HTTP

REST API

FT_UI_BACKEND_HTTP_PORT

Verify ports are listening:

netstat -tlnp | grep -E '8880|8881'

Troubleshooting

Check Service Logs

# All services
docker compose logs -f

# Backend only
docker compose logs -f ui-backend

# Portals only
docker compose logs -f portals

Common Issues

Portals Container Fails to Start

Symptom: Portals container exits or restarts repeatedly.

Check entrypoint logs:

docker compose logs portals | grep -E "Patched|Upload|WARN"

Common causes:

  1. Backend not healthy:

    • Portals depends on backend health check

    • Wait for backend to become healthy first

  2. Permissions upload failed:

    • Check FT_UI_BACKEND_KEYWORD matches between services

    • Verify backend API is accessible from portals container

  3. Missing permissions files:

    • Ensure portals image contains app-permissions-config.json files

    • Check entrypoint logs for "WARN: permissions file not found"

Backend Cannot Connect to Hazelcast

Symptom: Backend logs show Hazelcast connection errors.

Check:

# Verify Hazelcast is reachable
telnet <HAZELCAST_HOST> 5701

# Check hazelcast-client.xml
cat /usr/local/ft-services/ui-backend-conf/hazelcast-client.xml

# Check HZ_MEMBERS environment variable
docker compose exec ui-backend env | grep HZ_MEMBERS

Solution: - Update HZ_MEMBERS in .env with correct Hazelcast addresses - Verify hazelcast-client.xml references ${env.HZ_MEMBERS}

Angular Apps Cannot Reach Backend API

Symptom: UI shows connection errors or 404 responses.

Check:

# Verify backend API is accessible
curl http://<FT_UI_HOST>:8881/iot-webservice/swagger-ui/index.html

# Check patched configuration
docker compose exec portals cat /usr/share/nginx/html/support-center/assets/app-config.json | jq .server.api

Expected output:

"http://<FT_UI_HOST>:8881/iot-webservice/"

Solution: - Verify FT_UI_HOST is set correctly in .env - Ensure FT_UI_HOST is accessible from user browsers

Permissions Not Applied

Symptom: Users cannot access expected features.

Check entrypoint logs:

docker compose logs portals | grep -i "upload"

Verify permissions in database:

# Access backend API to check permissions
curl -X GET http://<FT_UI_HOST>:8881/iot-webservice/iotw/Setting/userGroup/permissions

Solution: - Restart portals to re-upload permissions: docker compose restart portals - Verify FT_UI_BACKEND_KEYWORD is correct

Database Connection Issues

Check connection:

# MySQL
telnet <DB_HOST> 3306

# Oracle
telnet <DB_HOST> 1521

# Check database vendor setting
docker compose exec ui-backend env | grep DB_VENDOR

Verify External Dependencies

Test connectivity to all external services:

# Database
telnet <DB_HOST> 3306    # MySQL
telnet <DB_HOST> 1521    # Oracle

# Hazelcast
telnet <HAZELCAST_HOST> 5701

# FTACS
curl http://<ACS_WEB_SERVICE_HOST>:8080

# Clickhouse
telnet <CLICKHOUSE_HOST> 9000

Restart Services

# Restart all
docker compose restart

# Restart specific service
docker compose restart ui-backend
docker compose restart portals

# Full restart (recreate containers)
docker compose down
docker compose up -d

Debugging

Enable Debug Logging

Edit .env.mysql or .env.oracle:

FT_UI_BACKEND_LOG_LEVEL=debug

Restart backend:

docker compose restart ui-backend

View Backend Logs

# Real-time logs
tail -f /usr/local/ft-services/ft-data/ui-portals/backend/logs/application.log

# Or via Docker
docker compose logs -f ui-backend

View Nginx Logs

# Access logs
tail -f /usr/local/ft-services/ft-data/ui-portals/nginx/logs/access.log

# Error logs
tail -f /usr/local/ft-services/ft-data/ui-portals/nginx/logs/error.log

Maintenance

Update Services

# Pull latest images
docker compose pull

# Restart with new images
docker compose up -d

Force Repull Images

docker compose down
docker compose pull --ignore-pull-failures
docker compose up -d

Backup Configuration

# Backup ui-backend-conf folder
tar -czf ui-backend-conf-backup-$(date +%Y%m%d).tar.gz \
  /usr/local/ft-services/ui-backend-conf/

# Restore
tar -xzf ui-backend-conf-backup-YYYYMMDD.tar.gz -C /

Stop Services

# Stop (keeps data)
docker compose down

# Stop and remove all data
docker compose down -v