Installation & Deployment
This guide covers deploying the UI Backend — the Spring Boot REST API service of the OneIoT Web
platform (hub.friendly-tech.com/ui/backend) — on a dedicated host with Docker.
|
For HTTPS/TLS setup, see SSL Certificate Configuration. For image lifecycle details, see Docker Image Management Guide. |
1. Overview
This guide deploys a single container, ui-backend, from the image
hub.friendly-tech.com/ui/backend. Docker is the only supported deployment method — the repository
builds no distribution archive, and the JRE is bundled in the image.
All persistent infrastructure (database, Hazelcast, FTACS, ClickHouse) is a prerequisite: it must already be running and reachable. This guide does not deploy it — it wires the backend to it via environment variables. See Required External Dependencies and Full System Deployment for deploying that infrastructure.
The UI Backend is the only service deployed here. Its companions are documented and released separately:
-
UI Portals (Support Center & Management Console — Angular / Nginx) — the browser-facing web applications that call this backend. Released from the portals repository; see All-in-One Deployment for a combined single-host layout.
-
AI Agent — optional assistant service. See AI Agent Service Deployment.
The backend exposes a dual-datasource REST API (FTACS schema + IOTW schema), talks to FTACS over SOAP for device operations, uses Hazelcast for distributed caching/session sharing, and queries ClickHouse for QoE analytics.
2. Prerequisites
2.1. Host Requirements
| Component | Minimum | Recommended | Notes |
|---|---|---|---|
Docker Engine |
20.10+ |
Latest stable |
The shipped |
Docker Compose |
2.0+ |
Latest stable |
All commands in this guide use the |
RAM |
3 GB free |
verify with the deployment owner |
The backend JVM defaults to |
Disk space |
15 GB free |
verify with the deployment owner |
Image, configuration under |
|
Java is not required on the host — the JRE is bundled inside the container image
( |
2.2. Required External Dependencies
These services must be installed, running, and reachable from this host before the UI Backend starts. None of them are deployed by this guide.
| Component | Minimum Version | Why It Is Needed | Port | Required |
|---|---|---|---|---|
MySQL or Oracle |
MySQL 8.0+ / Oracle 21c+ |
Main application database. Without it the backend cannot start — both the FTACS and the IOTW schema must be reachable. |
3306 (TCP, MySQL) / 1521 (TCP, Oracle) |
Yes |
Hazelcast |
5.5 |
Distributed cache and session sharing between backend instances. Without it the backend has no shared cache or session store. |
5701 (TCP) |
Yes |
FTACS |
verify with the FTACS release owner |
ACS SOAP web service. Without it device provisioning, parameter reads and firmware management fail. |
8080 (HTTP) |
Yes |
ClickHouse |
26.2 |
QoE analytics store. Queries use the native protocol; Flyway migrates the analytics schema over HTTP at startup. |
9000 (native TCP) / 8123 (HTTP) |
No (optional) |
UI Portals (companion) |
Released with the backend version |
Angular front-ends that consume this backend’s REST API. Released separately; the backend starts without them. |
8880 (HTTP) / 8843 (HTTPS) |
No (optional) |
|
Hazelcast 5.5 is the client library version compiled into the backend ( ClickHouse 26.2 is the supported version. The development reference compose in this repository
( |
2.3. Supported Operating Systems
| Deployment | Operating system |
|---|---|
Docker (Compose or |
Linux (recommended), macOS, or Windows with WSL2 |
2.4. Registry Access
Network access to the hub.friendly-tech.com Docker registry (or offline image archives — see
Offline Servers).
Access to the
FT_DISK on SharePoint
for the deployment files (compose.yml, the shared .env, and the per-service ui-backend/.env)
and the pre-configured ui-backend-conf package.
3. Network Requirements
The backend opens the following outbound connections. Ports are the defaults shipped in the
shared .env and in ui-backend/.env.
| Destination | Port | Protocol | Purpose |
|---|---|---|---|
MySQL or Oracle database |
3306 / 1521 |
TCP (JDBC) |
FTACS and IOTW schemas ( |
Hazelcast members |
5701 |
TCP |
Cluster membership, distributed cache and sessions ( |
FTACS application server |
8080 |
HTTP (SOAP) |
Device provisioning, parameter reads, firmware management ( |
ClickHouse |
9000 |
native TCP |
QoE analytics queries ( |
ClickHouse |
8123 |
HTTP |
Flyway migration of the analytics schema at startup ( |
Inbound traffic is limited to the published REST API port — see Port Reference.
|
If FTACS is configured to push event notifications back to this backend, the address in
|
3.1. Docker Networking
If the database, Hazelcast, FTACS, or ClickHouse runs on the same host but outside Docker, use
host.docker.internal as the hostname in the .env file instead of localhost:
DB_HOST=host.docker.internal
HZ_MEMBERS=host.docker.internal:5701
ACS_WEB_SERVICE_HOST=host.docker.internal
CLICKHOUSE_HOST=host.docker.internal
Inside a container, localhost points to the container itself, not the host. host.docker.internal
resolves to the host’s gateway address. The provided compose.yml already maps it:
extra_hosts:
- "host.docker.internal:host-gateway"
On Docker Desktop (macOS, Windows) this works out of the box; on Linux the extra_hosts mapping
above is required (and is already present in the shipped compose.yml). Alternatively, use the
host’s real LAN IP address.
4. Registry Authentication
All UI Backend images are pulled from hub.friendly-tech.com as
hub.friendly-tech.com/ui/backend:<version>.
Authenticate once per host before the first docker compose up.
docker login hub.friendly-tech.com
Enter the read-only pull credentials when prompted:
| Field | Value |
|---|---|
Username |
|
Password |
|
|
The |
Alternatively, log in non-interactively:
echo "fokxuw-fymte1-taSxyc" | docker login hub.friendly-tech.com -u readonly --password-stdin
Verify authentication:
docker info | grep -A 5 Registry
4.1. Offline Servers
When the UI Backend host cannot reach hub.friendly-tech.com, pull the image on a machine that
does have registry access, export it to an archive, transfer it, and load it on the offline host.
The connected machine can run Linux, macOS, or Windows — commands are given for both shells below. It does not need to be the same platform as the offline host.
|
An explicit |
-
On the offline host, find out which architecture it runs — this is the value you will pass as
PLATFORMbelow. Ask Docker itself, since it reports what the daemon will actually accept:docker version --format '{{.Server.Arch}}'If Docker is not installed there yet, use the operating system instead —
uname -mon Linux, orecho $env:PROCESSOR_ARCHITECTUREin PowerShell on Windows. Map the result:docker versionreportsuname -m/ Windows reportsUse as PLATFORMamd64x86_64/AMD64linux/amd64arm64aarch64/ARM64linux/arm64On Windows with Docker Desktop,
{{.Server.Arch}}reports the architecture of the Linux VM that actually runs the containers — which is the value you want, not the Windows host’s own architecture. -
On a machine with registry access, log in. Run this on its own — it prompts for a password, so anything pasted after it on the same go would be swallowed as input:
docker login hub.friendly-tech.com -
Pull and export the image. Paste the whole block as-is; the only lines to change are
PLATFORMandTAGon top.Linux / macOS (bash):
PLATFORM=linux/amd64 TAG=<version> docker pull --platform "$PLATFORM" "hub.friendly-tech.com/ui/backend:$TAG" docker save "hub.friendly-tech.com/ui/backend:$TAG" | gzip > "ui-backend-$TAG.tar.gz"Windows (PowerShell):
$PLATFORM = "linux/amd64" $TAG = "<version>" docker pull --platform $PLATFORM "hub.friendly-tech.com/ui/backend:$TAG" docker save -o "ui-backend-$TAG.tar" "hub.friendly-tech.com/ui/backend:$TAG"On Windows, always write the archive with
docker save -o <file>. Piping or redirectingdocker savefrom PowerShell (docker save … > file.tar) corrupts the archive, because the PowerShell pipeline re-encodes the stream as text instead of passing raw bytes.docker loadthen fails withunexpected EOForinvalid tar header. To compress for transfer, use the bundledtar.exe(Windows 10 1803+ / Server 2019+):tar.exe -czf ui-backend.tar.gz ui-backend-$TAG.tar. -
Transfer the archive to the offline host, together with
compose.yml, the shared.env, the per-serviceui-backend/.env, and the pre-configuredui-backend-confpackage that populatesui-backend/config/. -
On the offline host, load the archive and start the service. Set
TAGto the same value you used above:Linux (bash):
TAG=<version> gzip -dc "ui-backend-$TAG.tar.gz" | docker load docker compose up -d ui-backendWindows (PowerShell):
$TAG = "<version>" docker load -i "ui-backend-$TAG.tar" docker compose up -d ui-backend
Confirm the image is present before starting, so a missing or mis-architected image fails here rather than mid-startup:
docker images hub.friendly-tech.com/ui/backend
Upgrades use the same flow: pull the new tag on the connected machine, transfer and load the
archive, then docker compose up -d ui-backend. See Updating UI Backend.
|
This covers the UI Backend image only.
The database, Hazelcast, FTACS, and ClickHouse are separate images on their own hosts — for the
offline procedure covering a whole stack, see
All in one server deployment — Offline Servers,
which derives the image list from |
5. Preparation
5.1. Directory Structure
Create the base directory and the backend’s config / logs folders.
|
|
mkdir -p /usr/local/ft-system/ui-backend/{config,logs}
cd /usr/local/ft-system
Every volume in compose.yml is written as ${DATA_FOLDER:-.}/…, so with DATA_FOLDER unset the
mounts resolve against the current directory — which is why the cd above is what actually fixes
the install root. Setting DATA_FOLDER in the shell is not required, and relying on it is fragile:
the value is lost in the next login shell, and ui-backend/.env does not supply it either,
because Compose reads env_file: into the container environment, not into its own variable
interpolation. To pin the path independently of the working directory, put DATA_FOLDER in the
shared .env next to compose.yml — that one Compose does read for interpolation.
Download compose.yml and the shared .env from the
FT_DISK on SharePoint
into /usr/local/ft-system, and the per-service ui-backend/.env into
/usr/local/ft-system/ui-backend/. Download the pre-configured backend config files from the
ui-backend-conf package
into /usr/local/ft-system/ui-backend/config/.
5.1.1. Directory Layout
The tree shows the baseline layout plus common environment-dependent entries. Not every deployment needs every entry — some are default runtime config, some are loaded only when present, and some are used only for specific integrations.
/usr/local/ft-system/ # DATA_FOLDER
├── compose.yml # from FT_DISK
├── .env # shared stack environment (from FT_DISK)
└── ui-backend/
├── .env # per-service environment (from FT_DISK)
├── config/ # -> /opt/app/conf (backup required)
│ ├── hazelcast-client.xml # Hazelcast client configuration
│ ├── logback-spring.xml # External logging configuration
│ ├── ftacs.keystore # Backend keystore (only if backend serves HTTPS)
│ ├── interfaceItems.json # Interface seed data, loaded if present
│ ├── sc-idp.crt / mc-idp.crt # SAML IdP certificates (SAML only)
│ ├── customization/ # Portal customization JSON
│ │ ├── def/ # Default system-wide customizations
│ │ ├── mc/ # Management Console customizations
│ │ └── sc/ # Support Center customizations
│ ├── ssl/ # TLS certificates for the portals companion
│ └── keys/ # Integration credentials (when used)
└── logs/ # -> /opt/app/logs (created automatically)
| Path | Content | Backup |
|---|---|---|
|
Stack definition: the |
Yes |
|
Shared stack environment: database connection, ClickHouse, Hazelcast, inter-service hosts. |
Yes |
|
Per-service environment: host port, JVM settings, log level, connection pools, optional integrations. |
Yes |
|
Backend configuration. At minimum |
Yes |
|
Backend application logs. |
No |
|
The backend container merges configuration on startup: files you place in |
5.2. Environment Configuration
The stack uses a two-layer environment file architecture — there is no per-database-vendor
environment file. compose.yml loads both layers, in this order:
env_file:
- .env # shared stack environment
- ./ui-backend/.env # per-service environment
| File | Purpose |
|---|---|
|
Database connection ( |
|
Backend host port, JVM settings, log level, |
MySQL is the default. Switching to Oracle is not a file swap: change DB_PROFILE,
SPRING_PROFILES_ACTIVE, DB_HOST, DB_PORT (and the remaining variables listed in
Switching to Oracle)
inside the single shared .env. compose.yml maps the generic DB_* names to the vendor-specific
ones the backend expects (MYSQL_HOST, ORACLE_HOST, …) through the x-db-env YAML anchor.
5.2.1. Host Variables
Edit the shared .env and replace every ~PLACEHOLDER~ value with a real hostname or
IP address before starting the service.
| Placeholder | Variable | Description |
|---|---|---|
|
|
Public hostname or IP of this server, reachable from end-user browsers and from FTACS. Use a real IP or DNS name, not |
|
|
Hazelcast cluster member address(es). Format |
|
|
Hostname or IP of the FTACS application server. |
|
|
Hostname or IP of the ClickHouse server. Leave the placeholder if ClickHouse is not deployed — analytics features are skipped. |
|
|
Hostname or IP of the MySQL server (when |
|
|
Hostname or IP of the Oracle server (when |
Example (shared .env):
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
|
Replace the default passwords ( |
5.2.2. Environment Variable Reference
Shared .env — stack variables
| Variable | Description | Default | Required |
|---|---|---|---|
|
Base directory for persistent data and configuration on the host. Set it to the install root used by this guide, |
|
Yes |
|
Container timezone. |
|
Yes |
|
Database vendor: |
|
Yes |
|
Activates the database-specific Spring configuration in the backend. Keep it equal to |
|
Yes |
|
FTACS application host. |
|
Yes |
|
FTACS application port. |
|
Yes |
|
Backend base URL as reachable by FTACS for webhook event notifications. Set to the externally published host and port. |
No (optional) |
|
|
Hazelcast cluster members (comma-separated |
|
Yes |
|
ClickHouse server address. |
|
No (optional) |
|
ClickHouse native protocol port used for analytics queries. |
|
No (optional) |
|
ClickHouse HTTP port used by Flyway for analytics schema migrations. |
|
No (optional) |
|
ClickHouse database name (mapped to |
|
No (optional) |
|
ClickHouse credentials. Read directly only by the Flyway migration datasource; |
|
No (optional) |
|
The backend reads ClickHouse credentials under two different names. The Flyway migration
datasource reads Setting only |
ui-backend/.env — per-service variables
| Variable | Description | Default | Required |
|---|---|---|---|
|
Host port published for the backend REST API (maps to internal |
|
No (optional) |
|
Backend JVM heap settings. |
|
No (optional) |
|
Backend log level: |
|
No (optional) |
|
Internal keyword the backend accepts for service-to-service calls (the portals companion uses it to upload permissions). |
|
Yes |
|
Superset instance the backend queries for embedded dashboards. |
No (optional) |
|
|
Superset credentials. Not present in the shipped env files — the backend falls back to these built-in defaults, so add both lines to |
|
No (optional) |
HikariCP pool tuning (FTACS_MAX_POOL, IOTW_MAX_POOL, CLICKHOUSE_MAX_POOL, HIKARI_*), the SSL
keystore variables and the optional LDAP/SAML settings also live in this file — see the collapsible
blocks below.
Database variables in the shared .env — MySQL (DB_PROFILE=mysql)
| Variable | Description | Default | Required |
|---|---|---|---|
|
MySQL server address. |
|
Yes |
|
MySQL port. |
|
Yes |
|
Database username (FTACS schema). |
|
Yes |
|
Database password (shared across schemas). |
|
Yes |
Optional overrides let you split the FTACS and IOTW schemas onto separate hosts
(MYSQL_HOST_IOTW, MYSQL_PORT_IOTW, MYSQL_SCHEMA_IOTW, and the _FTACS equivalents) or supply
a full JDBC URL (MYSQL_URL_FTACS, MYSQL_URL_IOTW). All are commented out by default.
Database variables in the shared .env — Oracle (DB_PROFILE=oracle)
| Variable | Description | Default | Required |
|---|---|---|---|
|
Oracle server address. |
|
Yes |
|
Oracle listener port. |
|
Yes |
|
Oracle PDB service name. |
|
Yes |
|
Database username for the FTACS schema. |
|
Yes |
|
Oracle username for the IOTW schema. |
|
Yes |
|
Database password (shared across schemas). |
|
Yes |
Optional integrations in ui-backend/.env (commented out by default)
-
LDAP —
LDAP_URL,LDAP_BASE_DN,LDAP_USER_DN, search bases/filters, and role/domain mappings. See LDAP Login via Keycloak (OIDC). -
SAML SSO —
SAML_ENABLED(defaultfalse),SAML_REDIRECT_HOST, per-portal SP/IdP entity IDs and SSO URLs, and attribute mappings. When enabled, also mountsc-idp.crt/mc-idp.crt(see the compose snippet in Docker Compose). See SAML SSO Login. -
SSL —
SSL_KEYSTORE,SSL_KEYSTORE_PASSWORD,SSL_KEY_ALIAS,SSL_KEY_PASSWORD,SSL_KEYSTORE_TYPE. Only needed when the backend serves HTTPS directly (see TLS Keystore (optional)). -
Connection pools / async — HikariCP (
FTACS_MAX_POOL,IOTW_MAX_POOL,CLICKHOUSE_MAX_POOL,HIKARI_*) and executor tuning (ASYNC_*,SCHED_POOL). Defaults suit most deployments.
5.3. TLS Keystore (optional)
TLS termination for browsers is normally handled by the portals reverse proxy, so the backend serves
plain HTTP on 8880 internally. Configure a backend keystore only when the backend must serve HTTPS
directly.
The keystore file is method-neutral — any JKS or PKCS12 keystore works, however you obtain it
(CA-issued, internal PKI, or self-signed for testing). Place it in ui-backend/config/ and point the
backend at it:
SSL_KEYSTORE=${APP_HOME}/conf/ftacs.keystore
SSL_KEYSTORE_PASSWORD=<your-keystore-password>
SSL_KEYSTORE_TYPE=JKS
For full guidance across deployment scenarios, see SSL Certificate Configuration.
6. Deployment
6.1. Startup Dependencies
The backend does not manage its infrastructure and must not depends_on external containers. Before
starting it, confirm each prerequisite is reachable. A simple wait-loop blocks until a dependency
accepts connections.
The loops below read DB_HOST, HZ_MEMBERS and ACS_WEB_SERVICE_HOST from the shared .env.
Compose reads that file for the container, but your shell does not — load it first, otherwise the
variables expand to empty and the loops never terminate:
cd /usr/local/ft-system
set -a; . ./.env; set +a
# Wait for the database (MySQL example; use 1521 for Oracle)
until nc -z ${DB_HOST:-host.docker.internal} 3306; do
echo "waiting for database..."; sleep 3
done
# Wait for Hazelcast (host taken from HZ_MEMBERS, whose format is host:port)
until nc -z ${HZ_MEMBERS%%:*} 5701; do
echo "waiting for hazelcast..."; sleep 3
done
# Wait for FTACS
until curl -sf http://${ACS_WEB_SERVICE_HOST:-host.docker.internal}:8080 >/dev/null; do
echo "waiting for FTACS..."; sleep 3
done
|
ClickHouse is optional — skip its wait-loop if analytics are not deployed. The backend starts without it and disables analytics features. |
6.2. Docker Compose
The backend is defined in compose.yml. The relevant service block:
services:
ui-backend:
image: hub.friendly-tech.com/ui/backend:<version> # <-- pin a released tag
ports:
- "${FT_UI_BACKEND_HTTP_PORT:-8881}:8880" # host -> internal
env_file:
- .env # shared stack environment
- ./ui-backend/.env # per-service environment
environment:
USE_NOHUP: 0
APP_HOME: "/opt/app"
CLICKHOUSE_SCHEMA: "${CLICKHOUSE_DATABASE}"
# The analytics datasource reads CLICKHOUSE_USER / CLICKHOUSE_PASWORD (single S);
# only Flyway reads CLICKHOUSE_USERNAME / CLICKHOUSE_PASSWORD. Map both.
CLICKHOUSE_USER: "${CLICKHOUSE_USERNAME}"
CLICKHOUSE_PASWORD: "${CLICKHOUSE_PASSWORD}"
JAVA_OPTS: "${FT_UI_BACKEND_JAVA_RAM:--Xms512m -Xmx2g} -Duser.timezone=${TZ}"
volumes:
- ${DATA_FOLDER:-.}/ui-backend/config:/opt/app/conf
- ${DATA_FOLDER:-.}/ui-backend/logs:/opt/app/logs
# SAML certificates (uncomment when SAML is enabled):
# - ${DATA_FOLDER:-.}/ui-backend/config/sc-idp.crt:/opt/app/conf/sc-idp.crt
# - ${DATA_FOLDER:-.}/ui-backend/config/mc-idp.crt:/opt/app/conf/mc-idp.crt
extra_hosts:
- "host.docker.internal:host-gateway"
restart: unless-stopped
healthcheck:
test: [ "CMD", "curl", "-f", "http://127.0.0.1:8880/iot-webservice/swagger-ui/index.html" ]
interval: 10s
timeout: 5s
retries: 5
stop_grace_period: 45s
|
The SharePoint |
Start the backend:
cd /usr/local/ft-system
docker compose up -d ui-backend
Monitor startup:
docker compose logs -f ui-backend
6.2.1. Docker Run (Standalone)
To run the backend without Compose:
cd /usr/local/ft-system
docker run -d \
--name ui-backend \
--env-file .env \
--env-file ui-backend/.env \
-e USE_NOHUP=0 -e APP_HOME=/opt/app \
-p 8881:8880 \
--add-host host.docker.internal:host-gateway \
-v /usr/local/ft-system/ui-backend/config:/opt/app/conf \
-v /usr/local/ft-system/ui-backend/logs:/opt/app/logs \
--restart unless-stopped \
hub.friendly-tech.com/ui/backend:<version>
|
Ensure |
7. Verification
7.1. Startup Log
Check the container status first:
docker compose ps
Expected output:
NAME STATUS PORTS
ui-backend healthy 0.0.0.0:8881->8880/tcp
Allow 30—60 seconds after start, then inspect the logs:
docker compose logs ui-backend | tail -30
The backend prints a startup banner (from AcsAppConfig) followed by the Spring Boot ready marker.
Values in angle brackets vary per deployment:
==================================================
HTTP ports: 8880
HTTPS ports: 8843
ACS WS URL: http://<ftacs-host>:8080/ACSServer-ACS/ACSWebService?wsdl
Swagger UI: /iot-webservice/swagger-ui/index.html
==================================================
INFO ... Started FtIotWebApp in <seconds> seconds (process running for <seconds>)
7.2. Endpoint Checks
# Swagger UI (also the container health endpoint)
curl -I http://localhost:8881/iot-webservice/swagger-ui/index.html
# OpenAPI document
curl http://localhost:8881/iot-webservice/v3/api-docs
# Actuator health (exposed endpoints: health, prometheus)
curl http://localhost:8881/actuator/health
Expected: HTTP 200 responses.
7.3. Database Connectivity
Both the FTACS and the IOTW schema must be reachable from the container:
# MySQL
docker compose exec ui-backend sh -c 'nc -zv "$DB_HOST" 3306'
# Oracle
docker compose exec ui-backend sh -c 'nc -zv "$DB_HOST" 1521'
The single quotes matter: $DB_HOST must be expanded by the shell inside the container, which has
the env files loaded, not by your host shell.
Check the remaining external dependencies the same way:
# Hazelcast
docker compose exec ui-backend nc -zv <hazelcast-host> 5701
# FTACS SOAP endpoint
curl http://<ftacs-host>:8080
# ClickHouse (optional): 9000 native TCP for queries, 8123 HTTP for Flyway migrations
docker compose exec ui-backend nc -zv <clickhouse-host> 9000
docker compose exec ui-backend nc -zv <clickhouse-host> 8123
8. Port Reference
Ports are written as published → container. Across hosts you connect to the published port;
inside the Docker bridge you connect to the container port.
8.1. HTTP / HTTPS
| Port | Protocol | Purpose | Exposure |
|---|---|---|---|
|
HTTP |
UI Backend REST API under |
Public (portals and FTACS) |
|
HTTPS |
Backend HTTPS connector ( |
Internal (bridge only) |
Verify the published port is listening:
netstat -tlnp | grep 8881
|
The companion UI Portals publish |
8.2. Outbound Connections
| Destination | Port | Protocol | Purpose |
|---|---|---|---|
MySQL or Oracle database |
3306 / 1521 |
TCP (JDBC) |
FTACS and IOTW schemas. |
Hazelcast members |
5701 |
TCP |
Distributed cache and session sharing. |
FTACS application server |
8080 |
HTTP (SOAP) |
Device provisioning, parameter reads, firmware management. |
ClickHouse |
9000 |
native TCP |
QoE analytics queries. |
ClickHouse |
8123 |
HTTP |
Flyway migration of the analytics schema at startup. |
8.3. HTTP Endpoints
| Method | Path | Purpose | Auth |
|---|---|---|---|
GET |
|
Swagger UI (also the container health check target). |
None |
GET |
|
OpenAPI 3 document. |
None |
GET |
|
Actuator health status. |
None |
GET |
|
Prometheus metrics. |
None |
9. Stack Management
9.1. Logs
# Container logs
docker compose logs -f ui-backend
# On-disk application log
tail -f /usr/local/ft-system/ui-backend/logs/application.log
To raise the log level, set it in ui-backend/.env and restart:
FT_UI_BACKEND_LOG_LEVEL=debug
docker compose restart ui-backend
9.2. Start, Stop, Restart
docker compose stop ui-backend
docker compose start ui-backend
docker compose restart ui-backend
To stop and remove the container:
# Stop (keeps data and config)
docker compose down
# Stop and remove named volumes (does NOT touch bind-mounted config/logs)
docker compose down -v
9.3. Shell Access
docker compose exec ui-backend bash
# Inspect loaded environment
docker compose exec ui-backend env | grep -E 'DB_|HZ_|ACS_|CLICKHOUSE_'
9.4. Updating UI Backend
# 1. Back up the config directory
tar -czf ui-backend-config-$(date +%Y%m%d).tar.gz /usr/local/ft-system/ui-backend/config/
# 2. Pull the new tag (registry-connected hosts)
docker compose pull ui-backend
# 3. Recreate the container with the new image
docker compose up -d ui-backend
|
For offline servers, replace step 2 with the manual image transfer flow in Offline Servers, then
run |
10. Production Checklist
-
Change all default passwords:
DB_PASSWORDandCLICKHOUSE_PASSWORDin the shared.env;SSL_KEYSTORE_PASSWORD,FT_UI_BACKEND_KEYWORDand — when Superset is used —SUPERSET_PASSWORDinui-backend/.env. -
Set
FT_UI_HOSTto an address reachable by end-user browsers and by FTACS — notlocalhost. -
Verify
FTACS_WEBHOOK_BASE_URLuses the backend’s externally published host and port (default8881) when FTACS pushes webhooks. -
Pin an explicit image tag (
hub.friendly-tech.com/ui/backend:<version>) rather thanlatest. -
Confirm external dependencies are reachable: database (FTACS + IOTW schemas), Hazelcast, FTACS, and ClickHouse if analytics are used.
-
Configure firewall rules — restrict inbound
8881to the portals/reverse proxy and FTACS; restrict database access to backend hosts. -
Enable auto-restart —
restart: unless-stoppedis set incompose.yml; add--restart unless-stoppedto standalonedocker run. -
Configure TLS — terminate HTTPS at the portals reverse proxy, or configure the backend keystore (see TLS Keystore (optional)).
-
Set up monitoring — scrape
/actuator/prometheus. -
Configure backups — back up
ui-backend/config/; rely on the external DB’s own backup strategy. -
Tune the JVM — set
FT_UI_BACKEND_JAVA_RAMto match host memory.
11. Troubleshooting
11.1. Container Fails to Start
- Cause
-
Configuration error, missing environment file, or an unreachable dependency.
- Fix
-
docker compose logs ui-backend docker inspect ui-backend docker compose exec ui-backend env | grep -E 'DB_|HZ_|ACS_'
11.2. Database Connection Failure
- Cause
-
Database not running, wrong host/port, or bad credentials. Both FTACS and IOTW schemas must be reachable.
- Fix
-
telnet <DB_HOST> 3306 # MySQL telnet <DB_HOST> 1521 # Oracle docker compose exec ui-backend env | grep -E 'DB_HOST|MYSQL_PORT|ORACLE_PORT|SPRING_PROFILES_ACTIVE'Check that
DB_HOST,DB_PORT,DB_PASSWORD,DB_PROFILE/SPRING_PROFILES_ACTIVE, and the service name in the shared.envmatch the database.
11.3. Hazelcast Connection Failure
- Cause
-
The Hazelcast cluster is not running or not reachable.
- Fix
-
telnet <HAZELCAST_HOST> 5701 docker compose exec ui-backend env | grep HZ_MEMBERS cat /usr/local/ft-system/ui-backend/config/hazelcast-client.xmlUpdate
HZ_MEMBERSwith the correct addresses and confirmhazelcast-client.xmlreferences$\{env.HZ_MEMBERS}.
11.4. Device Operations Fail (FTACS Unreachable)
- Cause
-
The backend cannot reach the FTACS SOAP web service.
- Fix
-
curl http://<ACS_WEB_SERVICE_HOST>:8080 docker compose exec ui-backend env | grep ACS_WEB_SERVICEConfirm
ACS_WEB_SERVICE_HOSTandACS_WEB_SERVICE_PORTare correct and FTACS is running.
11.5. Port Already in Use
- Cause
-
Another process is bound to the host port.
- Fix
-
sudo lsof -i :8881 # Either free the port, or change the mapping: # FT_UI_BACKEND_HTTP_PORT=9881 in ui-backend/.env
11.6. Permission Denied on Mounted Volumes
- Cause
-
Host directory permissions do not allow the container user to read/write.
- Fix
-
sudo chown -R $(whoami):$(whoami) /usr/local/ft-system chmod -R 755 /usr/local/ft-system
11.7. Out of Memory
- Cause
-
JVM heap exceeds available memory, or the Docker memory limit is too low. The symptom is
java.lang.OutOfMemoryErrorin the log or a container killed by the OOM killer. - Fix
-
-
Increase the Docker memory limit (Docker Desktop: Settings → Resources → Memory: 4 GB+).
-
Adjust the heap in
ui-backend/.env:FT_UI_BACKEND_JAVA_RAM=-Xms1g -Xmx4g -
Restart:
docker compose restart ui-backend.
-
11.8. Container Not Reachable From Host
- Cause
-
The host firewall blocks traffic on Docker bridge interfaces (
br-*) in the host INPUT/OUTPUT path. This is not a Compose or application issue.
Signs:
-
The container is healthy and responds on
localhostinside the container. -
Published ports look correct (
0.0.0.0:8881→8880/tcp). -
Requests from the host hang / time out (no
ECONNREFUSED).- Fix
-
# IPv4 (all Docker bridges) iptables -I INPUT 1 -i br+ -j ACCEPT iptables -I OUTPUT 1 -o br+ -j ACCEPT # IPv6 (separate stack) ip6tables -I INPUT 1 -i br+ -j ACCEPT ip6tables -I OUTPUT 1 -o br+ -j ACCEPT
|
IPv4 working does not imply IPv6 works — they are separate firewall stacks. Docker programs NAT and FORWARD rules but does not override host INPUT/OUTPUT policies. |
11.9. Getting Support
Collect the following before contacting Friendly Technologies support:
-
The image tag in use (
docker compose images ui-backend). -
Container logs (
docker compose logs ui-backend > ui-backend.log). -
The loaded environment with secrets removed (
docker compose exec ui-backend env | grep -E 'DB_|HZ_|ACS_|CLICKHOUSE_'). -
The on-disk application log from
/usr/local/ft-system/ui-backend/logs/.