Installation & Deployment
This guide covers installing and running FTACS — the TR-069/TR-369 Auto Configuration Server. Two deployment methods are supported: Docker (recommended) and manual (bare-metal / VM).
The deployment includes:
-
FTACS — core ACS application (TR-069, USP, MQTT, SOAP, REST)
-
MySQL 8.4 or Oracle 19c+ — relational database
-
ClickHouse — analytics and QoE time-series data
-
Hazelcast — distributed cache cluster
-
JDBC Bridge — ClickHouse-to-RDBMS connector
For the full environment variables reference, see Supported Environment Variables.
1. Prerequisites
1.1. System Requirements
1.1.1. Hardware
| Component | Minimum Specification |
|---|---|
CPU |
4 cores (8+ recommended for production) |
RAM |
16 GB (64 GB recommended for production) |
Disk Space |
20 GB (50+ GB recommended with ClickHouse) |
Network |
1 Gbps network interface |
1.1.2. Software
| Component | Version |
|---|---|
Operating System (Docker) |
Linux with Docker Engine 20.10+, macOS, or Windows with WSL2 |
Operating System (Manual) |
Linux (recommended), Windows Server |
Java (Manual deployment only) |
JDK 25 |
Docker Engine |
20.10+ |
Docker Compose |
2.0+ (optional — for multi-service stacks) |
Database |
MySQL 8.0+ or Oracle 19c+ |
ClickHouse |
21.3+ |
Hazelcast |
5.3+ (external cluster) |
1.2. Required External Dependencies
The following components must be installed and configured before FTACS deployment:
-
Database — MySQL or Oracle with schema created
-
ClickHouse — for historical data and QoE storage
-
Hazelcast — external cluster (minimum 1 node; 2+ recommended for production)
1.3. Registry Access
Network access to hub.friendly-tech.com Docker registry (or offline image archives).
Access to Friendly Tech SharePoint (FT_DISK) for downloading configuration files.
2. Quick Start
For experienced users who already have Docker installed and configuration files ready.
# 1. Create working directory
export DATA_FOLDER=/usr/local/ftacs
mkdir -p ${DATA_FOLDER}/{ftacs-conf,ft-data/ftacs/logs}
# 2. Copy configuration files from FT_DISK to ${DATA_FOLDER}/ftacs-conf/
# 3. Authenticate with the Docker registry
docker login hub.friendly-tech.com
# 4. Create .env and compose.yml (see "Docker Deployment" section)
# or download from FT_DISK (see structure below)
# 5. Start all services
cd ${DATA_FOLDER}
docker compose up -d
# 6. Verify (allow 30-60 seconds for startup)
curl -s http://localhost:8080/acsstats
|
If the |
3. Prepare Working Directory
Create the following directory structure on the host.
|
|
export DATA_FOLDER=/usr/local/ftacs
mkdir -p ${DATA_FOLDER}/ftacs-conf # ACS configuration files
mkdir -p ${DATA_FOLDER}/ft-data/ftacs/logs # ACS runtime logs
mkdir -p ${DATA_FOLDER}/ft-data/mysql/{data,logs} # MySQL data and logs
mkdir -p ${DATA_FOLDER}/ft-data/clickhouse/{data,logs} # ClickHouse data and logs
mkdir -p ${DATA_FOLDER}/ft-data/hazelcast/logs # Hazelcast logs
mkdir -p ${DATA_FOLDER}/mysql-chain # MySQL init scripts
mkdir -p ${DATA_FOLDER}/mysql-conf # MySQL custom config
mkdir -p ${DATA_FOLDER}/clickhouse/{config.d,initdb.d} # ClickHouse config and init
mkdir -p ${DATA_FOLDER}/clickhouse/jdbc-bridge/{config,drivers} # JDBC Bridge
mkdir -p ${DATA_FOLDER}/hazelcast # Hazelcast config
chmod -R 755 ${DATA_FOLDER}
3.1. Directory Layout
/usr/local/ftacs/
├── compose.yml # Docker Compose definition (from FT_DISK)
├── .env # Shared environment variables (from FT_DISK)
│
├── ftacs-conf/ # from FT_DISK → ftacs-conf/
│ ├── acs_configuration.xml # Core ACS runtime behavior
│ ├── bulk_data.xml # Bulk data upload targets per model
│ ├── ctn_info.properties # CTN enrichment / RADIUS lookup rules
│ ├── external_trace.properties # RPC trace routing
│ ├── fcc.properties # Speed and latency test tuning
│ ├── force_qoe_stop.properties # QoE monitor stop switches
│ ├── ftacs.keystore # SSL keystore for HTTPS ports
│ ├── ftacs_task.properties # RPC retry and timeout rules
│ ├── ftacsws-roles.properties # Web service role mapping
│ ├── ftacsws-users.properties # Web service users (basic auth)
│ ├── hardcoded_event_soap_template.xml # SOAP event template
│ ├── hardcoded_event_soap_template (windstream).xml # Windstream variant
│ ├── hazelcast-client.xml # Hazelcast cluster client config
│ ├── logback-spring.xml # Logging configuration
│ └── parameterNamesCacheRules.yaml # Rules for parameter-name caching
│
├── ft-data/
│ ├── ftacs/logs/ # ACS runtime logs
│ ├── mysql/
│ │ ├── data/ # created by MySQL on first start
│ │ └── logs/
│ ├── clickhouse/
│ │ ├── data/ # created by ClickHouse on first start
│ │ └── logs/
│ └── hazelcast/logs/
│
├── mysql-chain/ # MySQL init scripts (run on first start)
│ └── *.sql
├── mysql-conf/ # MySQL custom configuration
│ └── custom.cnf
│
├── clickhouse/
│ ├── config.d/ # ClickHouse server config files
│ │ ├── config_new.xml
│ │ ├── users_new.xml
│ │ └── jdbc_bridge_<db>.xml # <-- replace <db> with mysql or oracle
│ └── initdb.d/ # Init SQL (run on first start)
│
├── clickhouse/jdbc-bridge/
│ ├── config/
│ │ └── datasource_mysql.json # DB datasource for JDBC Bridge
│ └── drivers/
│ └── mysql-connector-j-*.jar # JDBC driver
│
└── hazelcast/
├── hazelcast.xml # Hazelcast server config
└── log4j2.properties # Hazelcast logging
3.1.1. Manual (non-Docker) Distribution Layout
When deploying without Docker, the extracted distribution package has this structure:
dist/ ├── app/ # Compiled application (WAR exploded) -- do NOT modify │ ├── META-INF/ # JAR/WAR manifest and persistence descriptors │ ├── org/ # Java bytecode packages (ACS core classes) │ └── WEB-INF/ # Spring Boot web configuration and libraries │ ├── bin/ # Executable scripts and environment definitions │ ├── app.env # Main environment file (DB, ports, JVM, etc.) │ ├── env_to_cmd.cmd # Helper: .env → Windows CMD variables │ ├── start.cmd # Windows startup script │ ├── start.sh # Linux startup script │ ├── stop.cmd # Windows shutdown script │ └── stop.sh # Linux shutdown script │ ├── conf/ # Configuration files (editable by operators) │ ├── acs_configuration.xml │ ├── hazelcast-client.xml │ ├── logback-spring.xml │ ├── ftacs.keystore │ └── ... # (same files as ftacs-conf above) │ ├── ext/ # External extensions / JARs loaded dynamically ├── liquibase/ # Database migration scripts (managed by Liquibase) ├── logs/ # Runtime logs (created at startup) └── patches/ # Hot-fix patches
|
4. Configuration
4.1. Docker Deployment (Environment Files)
The stack uses a two-layer environment file architecture. MySQL is the default — if you are using MySQL, no changes are needed beyond replacing passwords.
Download all three files from FT_DISK and place them in the DATA_FOLDER root:
| File | Purpose |
|---|---|
|
Main environment file — FTACS ports, HikariCP pools, deployment mode, protocol settings (TR-069/MQTT/USP), TLS certificates, async executor tuning, JVM options. Shared across all deployment types. |
|
Database-specific overlay for MySQL — |
|
Database-specific overlay for Oracle — same structure as |
# Copy env files from FT_DISK:
cp .env ${DATA_FOLDER}/
cp .env.mysql ${DATA_FOLDER}/ # or .env.oracle for Oracle deployments
|
The |
4.1.1. Switching to Oracle
To switch from MySQL to Oracle, download .env.oracle from FT_DISK instead of .env.mysql and use compose-oracle.yml instead of compose-mysql.yml.
4.1.2. Main environment file (.env)
The .env file controls FTACS application behavior.
Download it from FT_DISK or customize using the reference below.
Click to expand .env reference
# =============================================================================
# FTACS - Core ACS Engine
# =============================================================================
# Host port exposed on the server for HTTP traffic.
# Maps to container internal port 8080 in compose.yml.
FTACS_HTTP_PORT=8080
# Host port exposed on the server for HTTPS traffic.
# Maps to container internal port 8443 in compose.yml.
FTACS_HTTPS_PORT=8443
# =============================================================================
# HikariCP Connection Pools
# =============================================================================
# Shared pool defaults (apply to all datasources unless overridden below)
DB_MAX_POOL_SIZE=10
DB_MIN_IDLE=5
DB_CONNECTION_TIMEOUT_MS=30000
# Main FTACS datasource pool. Handles CPE management, parameters,
# provisioning operations. Needs larger pool due to high concurrency.
FTACS_MAX_POOL=30
FTACS_MIN_POOL=5
# Quartz job scheduler datasource. Used for scheduled tasks persistence
# (UpdateGroup, QoE, Events). Lower load than main datasource.
QUARTZ_MAX_POOL=10
QUARTZ_MIN_POOL=2
# ClickHouse analytics datasource. Used for QoE data and statistics.
# Only active when CLICKHOUSE_HOST is configured (shared .env).
CLICKHOUSE_MAX_POOL=10
CLICKHOUSE_MIN_POOL=2
# =============================================================================
# ACS Deployment Mode
# Controls which functionality is active. Used for distributed deployments
# where provisioning and management run on separate nodes.
# =============================================================================
# ALL = full functionality (provisioning + management) — single-node default
# PROV = provisioning only (device bootstrap, session handling)
# MNGMNT = management only (device monitoring, configuration)
# In MNGMNT mode, FTACS connects to a separate Hazelcast "provision" cluster.
# FTACS_MODE=ALL
# =============================================================================
# Server IP Address
# Advertised to CPE devices for callbacks and connection requests.
# Auto-detected from hostname if not set. Set explicitly in Docker/NAT
# environments where auto-detection returns an unreachable address.
# =============================================================================
# IPv4 address advertised to CPE devices. Format: dotted decimal (e.g., 192.168.1.100)
# FTACS_IP_ADDRESS=
# IPv6 address for dual-stack deployments. Brackets added automatically if missing.
# Format: colon-hexadecimal (e.g., 2001:db8::1)
# FTACS_IPV6_ADDRESS=
# =============================================================================
# Event Subscription Parameters
# Control when parameter change notifications are sent to subscriber URLs.
# =============================================================================
# 0 = notify on every parameter update (EACH_VALUE trigger)
# 1 = notify only when parameter value actually changes (VALUE_CHANGE trigger)
# Reduces notification volume for high-frequency polling scenarios.
# FTACS_SUBSCRIPTION_PARAMETER_ONLY_VALUE_CHANGE=0
# 0 = include all parameter values (including null/empty)
# 1 = skip notifications for null or empty parameter values
# Filters out spurious empty values during device initialization.
# FTACS_SUBSCRIPTION_PARAMETER_NOT_NULL_ONLY=0
# =============================================================================
# TR-069 Endpoint URL Mappings
# Each defines the servlet URL path for a different authentication mode.
# Multiple paths can be comma-separated.
# =============================================================================
# No authentication — CPE connects without credentials
WEB_TR069_NO_AUTH=/ftacs/ACS
# HTTP Basic Authentication (RFC 7617) — CPE sends base64(user:password)
WEB_TR069_BASIC=/ftacs-basic/ACS
# HTTP Digest Authentication (RFC 2617) — challenge-response, no plaintext password
WEB_TR069_DIGEST=/ftacs-digest/ACS
# =============================================================================
# MQTT Protocol (optional)
# Activates the embedded MQTT broker for TR-369/USP MQTT-MTP transport.
# =============================================================================
# Enable/disable MQTT protocol support (true/false)
MQTT_ENABLE=false
# Additional MQTT transport connector URI (ActiveMQ format).
# Useful for binding MQTT on a custom IP/port beyond the standard ones.
# Format: mqtt+nio://<host>:<port> or mqtt+nio+ssl://<host>:<port>
# Example: mqtt+nio://0.0.0.0:9001
# FT_MQTT_ADDITIONAL_CONNECTOR_URI=
# Active MQTT API versions. Comma-separated list.
# Incoming requests are validated against this list.
# MQTT_ACTIVE_API=api-v1,api-v2
# =============================================================================
# USP Protocol (optional)
# =============================================================================
# Path to USP data model XML specification (BBF TR-181-2 standard).
# Loaded from filesystem first; falls back to classpath resource.
# USP_SERVER_DM_PATH=tr-181-2-16-0-usp-full.xml
# =============================================================================
# X509 Certificates - USP TLS/DTLS (optional)
# Used for secure USP MTP connections (WebSocket, STOMP, CoAP over DTLS).
# Format: JKS or PKCS12 keystore files.
# =============================================================================
# FT_USP_X509_KEYSTORE_PATH= # Server keystore with private key and certificate
# FT_USP_X509_KEYSTORE_PASSWORD= # Keystore file password
# FT_USP_X509_KEYSTORE_PK_PASSWORD= # Private key password (if differs from keystore)
# FT_USP_X509_TRUSTSTORE_PATH= # Truststore with trusted CA certificates
# FT_USP_X509_TRUSTSTORE_PASSWORD= # Truststore file password
# =============================================================================
# X509 Certificates - MQTT TLS (optional)
# Used for MQTTS (MQTT over TLS) on port 8883.
# Enables mutual TLS when truststore is configured.
# =============================================================================
# FT_MQTT_X509_KEYSTORE_PATH= # MQTT server keystore path
# FT_MQTT_X509_KEYSTORE_PASSWORD= # MQTT keystore password
# FT_MQTT_X509_PK_PASSWORD= # MQTT private key password
# FT_MQTT_X509_TRUSTSTORE_PATH= # MQTT truststore path
# FT_MQTT_X509_TRUSTSTORE_PASSWORD= # MQTT truststore password
# =============================================================================
# General Async Executor (used by @Async methods without explicit executor)
# =============================================================================
# Minimum threads always running. Idle core threads are reclaimed
# after ASYNC_KEEPALIVE seconds (allowCoreThreadTimeout=true).
ASYNC_CORE=10
# Maximum threads under load. When queue=0, threads spawn immediately
# up to this limit before tasks go to an external 10,000-task overflow queue.
ASYNC_MAX=200
# Internal queue capacity before spawning new threads.
# 0 = no internal queue (SynchronousQueue); tasks spawn threads immediately.
# An external OverflowingExecutor with 10,000-task queue wraps the pool
# as a safety net, blocking on overflow to provide backpressure.
ASYNC_QUEUE=0
# Seconds an idle thread stays alive before termination.
ASYNC_KEEPALIVE=60
# Thread pool size for @Scheduled methods (virtual threads enabled).
# Handles periodic tasks: statistics flush (every 60s), counter reset (daily).
# Quartz jobs use a separate JDBC-based scheduler, not this pool.
SCHED_POOL=300
# =============================================================================
# HikariCP Tuning (optional)
# Applies to ALL three datasources (ftacs, quartz, clickhouse).
# =============================================================================
# Max time (ms) a connection can sit idle before removal. Default: 60000 (1 min)
# HIKARI_IDLE_TIMEOUT_MS=60000
# Max time (ms) to wait for a connection from the pool. Default: 45000 (45 sec)
# HIKARI_CONN_TIMEOUT_MS=45000
# Max age (ms) of a connection before forced rotation. Default: 180000 (3 min)
# Must be greater than HIKARI_IDLE_TIMEOUT_MS.
# HIKARI_MAX_LIFETIME_MS=180000
# Max time (ms) for connection validation query (SELECT 1). Default: 3000 (3 sec)
# HIKARI_VALIDATION_TIMEOUT_MS=3000
# Register HikariCP pool metrics as JMX MBeans (true/false).
# Enables monitoring via JConsole/VisualVM. Minor performance overhead.
# HIKARI_REGISTER_MBEANS=false
# =============================================================================
# JVM Options
# Passed directly to the java command. Controls heap, GC, timezone.
# =============================================================================
JAVA_OPTS=-Xms512m -Xmx2g -Duser.timezone=${TZ}
4.1.3. Database-specific overlay (.env.mysql / .env.oracle)
These files contain infrastructure settings: database host, vendor, credentials, Hazelcast, ClickHouse, and host port mappings.
Click to expand .env.mysql
# Common vars
DATA_FOLDER=/usr/local/ftacs # <-- replace with your path
TZ=Europe/Kiev
FT_ACS_JAVA_RAM=-Xms1g -Xmx4g
# JVM tuning
JAVA_OPTS="-Xms1g -Xmx4g -Duser.timezone=Europe/Kiev"
# Hazelcast settings
HZ_MEMBERS=hazelcast:5701
# DB settings
DB_HOST=mysql
DB_PASSWORD=ftacs # <-- replace in production
# MySQL settings
DB_VENDOR=mysql
MYSQL_EXTERNAL_PORT=3306
MYSQL_PORT=3306
MYSQL_USER=ftacs
# ClickHouse
CLICKHOUSE_HOST=clickhouse
CLICKHOUSE_PORT=8123
CLICKHOUSE_SCHEMA=ftacs_qoe_ui_data
CLICKHOUSE_USERNAME=ftacs
CLICKHOUSE_PASSWORD=ftacs # <-- replace in production
# TR-069 device URL mappings
WEB_TR069_NO_AUTH=/ftacs/ACS
WEB_TR069_BASIC=/ftacs-basic/ACS
WEB_TR069_DIGEST=/ftacs-digest/ACS
# Ports
ACS_MQTT=1883
ACS_USP_WS=8025
ACS_HTTP_ADDITIONAL=8181
ACS_USP_MQTT=18881
ACS_USP_BULK=18891
ACS_USP_STOMP=61617
ACS_USP_CoAP=5783
ACS_USP_WSS=4430
ACS_HTTPS=8443
ACS_MQTT_TLS=8883
ACS_USP_MQTT_TLS=18882
ACS_USP_DTLS=5784
Click to expand .env.oracle
# Common vars
DATA_FOLDER=/usr/local/ftacs # <-- replace with your path
TZ=Europe/Kiev
FT_ACS_JAVA_RAM=-Xms1g -Xmx4g
# JVM tuning
JAVA_OPTS="-Xms1g -Xmx4g -Duser.timezone=Europe/Kiev"
# Hazelcast settings
HZ_MEMBERS=hazelcast:5701
# DB settings
DB_HOST=oracle
DB_PASSWORD=ftacs # <-- replace in production
# Oracle settings
DB_VENDOR=oracle
ORACLE_PORT=1521
ORACLE_EXTERNAL_PORT=1521
ORACLE_SERVICE=XEPDB1
ORACLE_USER_FTACS=ftacs
ORACLE_USER_QUARTZ=ftacs_quartz
# ClickHouse
CLICKHOUSE_HOST=clickhouse
CLICKHOUSE_PORT=8123
CLICKHOUSE_SCHEMA=ftacs_qoe_ui_data
CLICKHOUSE_USERNAME=ftacs
CLICKHOUSE_PASSWORD=ftacs # <-- replace in production
# TR-069 device URL mappings
WEB_TR069_NO_AUTH=/ftacs/ACS
WEB_TR069_BASIC=/ftacs-basic/ACS
WEB_TR069_DIGEST=/ftacs-digest/ACS
# Ports
ACS_MQTT=1883
ACS_USP_WS=8025
ACS_HTTP_ADDITIONAL=8181
ACS_USP_MQTT=18881
ACS_USP_BULK=18891
ACS_USP_STOMP=61617
ACS_USP_CoAP=5783
ACS_USP_WSS=4430
ACS_HTTPS=8443
ACS_MQTT_TLS=8883
ACS_USP_MQTT_TLS=18882
ACS_USP_DTLS=5784
4.2. Manual Deployment (app.env)
Edit bin/app.env in the extracted distribution package.
# === Base directories (all other paths derive from APP_HOME) ===
APP_HOME=/usr/local/ftacs/ # <-- replace with your dist path
CONF_DIR=${APP_HOME}/conf
LOG_DIR=${APP_HOME}/logs
EXT_DIR=${APP_HOME}/ext
PATCHES_DIR=${APP_HOME}/patches
DB_LIQUIBASE_DIR=${APP_HOME}/liquibase
# === Database connection ===
DB_HOST=localhost # <-- replace
DB_PASSWORD=ftacs # <-- replace in production
# --- MySQL (default) ---
DB_VENDOR=mysql
MYSQL_PORT=3306
MYSQL_USER=ftacs
# --- Oracle (uncomment to switch) ---
#DB_VENDOR=oracle
#ORACLE_PORT=1521
#ORACLE_SERVICE=XEPDB1
#ORACLE_USER_FTACS=ftacs
#ORACLE_USER_QUARTZ=ftacs_quartz
# === ClickHouse configuration ===
CLICKHOUSE_HOST=localhost # <-- replace
CLICKHOUSE_PORT=8123
CLICKHOUSE_SCHEMA=ftacs_qoe_ui_data
CLICKHOUSE_USER=ftacs
CLICKHOUSE_PASWORD=ftacs # <-- replace in production
# === Hazelcast ===
HZ_MEMBERS=127.0.0.1:5701 # <-- replace with cluster addresses
HZ_CLIENT_CONFIG=${CONF_DIR}/hazelcast-client.xml
# === TR-069 device URL mappings ===
WEB_TR069_NO_AUTH=/ftacs/ACS
WEB_TR069_BASIC=/ftacs-basic/ACS
WEB_TR069_DIGEST=/ftacs-digest/ACS
# === Web/SSL ===
HTTP_PORTS=8080,8181
HTTPS_PORTS=8443
SSL_KEYSTORE=${CONF_DIR}/ftacs.keystore
SSL_KEYSTORE_PASSWORD=friendly # <-- replace in production
# === JVM options ===
JAVA_OPTS='-Xms1g -Xmx4g'
# === Additional Configuration ===
SPRING_CONFIG_EXTRA=file:${CONF_DIR}/
LOGBACK_CONFIG=${CONF_DIR}/logback-spring.xml
CXF_PATH=/ACSServer-ACS
QUARTZ_PASSWORD=${DB_PASSWORD}
|
Set
On Windows, use forward slashes ( |
4.2.1. SSL Certificate Configuration (Optional)
The distribution includes a default self-signed certificate (conf/ftacs.keystore).
This is suitable for testing only.
To use a custom certificate:
-
Generate or obtain an SSL certificate.
-
Create a Java keystore:
keytool -genkey -alias ftacs -keyalg RSA -keystore ftacs.keystore -keysize 2048 -
Place the keystore in
conf/. -
Update
app.env:SSL_KEYSTORE=${CONF_DIR}/ftacs.keystore SSL_KEYSTORE_PASSWORD=<your-keystore-password> # <-- replace
5. Docker Deployment
5.1. Authenticate with Docker Registry
docker login hub.friendly-tech.com
Enter credentials when prompted.
Alternatively, use non-interactive login:
echo "<your-password>" | docker login hub.friendly-tech.com -u <your-username> --password-stdin
Verify authentication:
docker info | grep -A 5 Registry
5.2. Docker Compose File
Download compose-mysql.yml (or compose-oracle.yml) from FT_DISK and rename to compose.yml.
Click to expand compose.yml
version: "3.8"
name: ft-services-mysql
services:
mysql:
image: mysql:8.4.6
platform: linux/amd64
environment:
MYSQL_ROOT_PASSWORD: ftacs
MYSQL_DATABASE: ftacs
MYSQL_USER: ftacs
MYSQL_PASSWORD: ftacs
command: [ "mysqld", "--log_error_verbosity=3", "--general-log=1", "--general-log-file=/dev/stdout", "--slow-query-log=0" ]
ports:
- "${MYSQL_EXTERNAL_PORT:-3306}:3306"
volumes:
- ${DATA_FOLDER:-.}/ft-data/mysql/data:/var/lib/mysql
- ${DATA_FOLDER:-.}/ft-data/mysql/logs:/var/log
- ${DATA_FOLDER:-.}/mysql-chain:/docker-entrypoint-initdb.d:ro
- ${DATA_FOLDER:-.}/mysql-conf:/etc/mysql/conf.d
healthcheck:
test: [ "CMD-SHELL", "mysql -h 127.0.0.1 -uroot -p$$MYSQL_ROOT_PASSWORD -N -e \"SELECT 1 FROM dual\" || exit 1" ]
interval: 5s
timeout: 3s
retries: 30
clickhouse:
image: clickhouse/clickhouse-server:24.8
depends_on:
- jdbc-bridge
env_file: [.env]
environment:
- CLICKHOUSE_USER=${CLICKHOUSE_USERNAME:-ftacs}
ports:
- "${CH_HTTP_PORT:-8123}:8123" # HTTP
- "${CH_TCP_PORT:-9000}:9000" # Native
volumes:
- ${DATA_FOLDER:-.}/ft-data/clickhouse/data:/var/lib/clickhouse
- ${DATA_FOLDER:-.}/ft-data/clickhouse/logs:/var/log/clickhouse-server
- ${DATA_FOLDER:-.}/clickhouse/config.d/jdbc_bridge_${DB}.xml:/etc/clickhouse-server/config.d/jdbc_bridge.xml:ro
- ${DATA_FOLDER:-.}/clickhouse/initdb.d:/docker-entrypoint-initdb.d:ro
- ${DATA_FOLDER:-.}/clickhouse/config.d/config_new.xml:/etc/clickhouse-server/config.xml:ro
- ${DATA_FOLDER:-.}/clickhouse/config.d/users_new.xml:/etc/clickhouse-server/users.xml:ro
healthcheck:
test: [ "CMD", "bash", "-lc", "clickhouse-client --user=$$CLICKHOUSE_USER --password=$$CLICKHOUSE_PASSWORD --query='SELECT 1'" ]
interval: 5s
timeout: 3s
retries: 60
jdbc-bridge:
image: clickhouse/jdbc-bridge:2.1.0
expose: [ "9019" ]
depends_on:
mysql:
condition: service_healthy
hazelcast:
condition: service_healthy
volumes:
- ${DATA_FOLDER:-.}/clickhouse/jdbc-bridge/config/datasource_mysql.json:/app/config/datasources/datasource.json
- ${DATA_FOLDER:-.}/clickhouse/jdbc-bridge/drivers:/app/drivers
- ${DATA_FOLDER:-.}/clickhouse-jdbc-bridge/logs:/var/log/clickhouse-jdbc-bridge/
hazelcast:
image: hub.friendly-tech.com/components/hazelcast:ft.5.5.0
volumes:
- ${DATA_FOLDER:-.}/hazelcast/hazelcast.xml:/opt/hazelcast/hazelcast.xml:ro
- ${DATA_FOLDER:-.}/hazelcast/log4j2.properties:/opt/hazelcast/config/log4j2.properties:ro
- ${DATA_FOLDER:-.}/ft-data/hazelcast/logs:/opt/hazelcast/logs
command: [ "start","-c","/opt/hazelcast/hazelcast.xml" ]
environment:
JAVA_OPTS: >-
-Duser.timezone=${TZ}
-Dhazelcast.local.publicAddress=${HZ_PUBLIC_ADDRESS:-hazelcast}
-Dcom.sun.management.jmxremote
-Djava.rmi.server.hostname=hazelcast
-Dcom.sun.management.jmxremote.rmi.port=${HZ_JMX_INTERNAL_PORT:-9110}
-Dcom.sun.management.jmxremote.port=${HZ_JMX_INTERNAL_PORT:-9110}
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.local.only=false
-Dhazelcast.jmx=true
healthcheck:
test: [ "CMD", "curl", "-f", "http://127.0.0.1:8090/hazelcast/health" ]
interval: 10s
timeout: 5s
retries: 50
ports:
- "${HZ_PORT:-5701}:5701"
- "${HZ_SERVER_PORT:-5711}:5711"
- "${HZ_JMX_PORT:-9110}:${HZ_JMX_INTERNAL_PORT:-9110}"
ftacs:
depends_on:
mysql:
condition: service_healthy
hazelcast:
condition: service_healthy
clickhouse:
condition: service_healthy
image: hub.friendly-tech.com/ftacs/ftacs:latest
ports:
- "${ACS_WEB_SERVICE_PORT:-8080}:8080"
- "${ACS_MQTT:-1883}:1883"
- "${ACS_USP_WS:-8025}:8025"
- "${ACS_HTTP_ADDITIONAL:-8181}:8181"
- "${ACS_USP_MQTT:-18881}:18881"
- "${ACS_USP_BULK:-18891}:18891"
- "${ACS_USP_STOMP:-61617}:61617"
- "${ACS_USP_CoAP:-5783}:5783"
- "${ACS_UST_WSS:-4430}:4430"
- "${ACS_HTTPS:-8443}:8443"
- "${ACS_MQTT_TLS:-8883}:8883"
- "${ACS_USP_MQTT_TLS:-18882}:18882"
- "${ACS_USP_DTLS:-5784}:5784"
env_file: [ .env ]
environment:
USE_NOHUP: 0
APP_HOME: "/opt/FTACS"
JAVA_OPTS: "${FT_ACS_JAVA_RAM:--Xms1g -Xmx4g} -Duser.timezone=${TZ}"
healthcheck:
test: [ "CMD", "curl", "-f", "http://127.0.0.1:8080/acsstats" ]
interval: 10s
timeout: 5s
retries: 100
volumes:
- ${DATA_FOLDER:-.}/ftacs-conf:/opt/FTACS/conf
- ${DATA_FOLDER:-.}/ft-data/ftacs/logs:/opt/FTACS/logs
stop_grace_period: 45s
5.3. Deploy the Stack
cd ${DATA_FOLDER}
docker compose up -d
Monitor startup progress:
docker compose logs -f
Stop all services:
docker compose down
Stop and remove all data volumes (destroys data):
docker compose down -v
|
|
5.4. Docker Run (Standalone)
To run FTACS as a single container (without Compose), use the following command:
export DATA_FOLDER=/usr/local/ftacs
cd ${DATA_FOLDER}
docker run -d \
--name ftacs \
--env-file .env --env-file .env.mysql \
-p 8080:8080 \
-p 8443:8443 \
-v ${DATA_FOLDER:-.}/ftacs-conf:/opt/FTACS/conf \
-v ${DATA_FOLDER:-.}/ft-data/ftacs/logs:/opt/FTACS/logs \
hub.friendly-tech.com/ftacs/ftacs:latest
|
Ensure |
6. Non-Docker Deployment
6.1. Step 1: Install Java Development Kit
6.1.1. Linux
# Download JDK 25
wget https://download.oracle.com/java/25/latest/jdk-25_linux-x64_bin.tar.gz
# Extract
tar -xzf jdk-25_linux-x64_bin.tar.gz
# Move to installation directory
sudo mv jdk-25 /opt/jdk-25
# Set JAVA_HOME (add to ~/.bashrc or /etc/profile)
export JAVA_HOME=/opt/jdk-25
export PATH=$JAVA_HOME/bin:$PATH
# Verify installation
java -version
6.1.2. Windows
-
Download JDK 25 installer from Oracle website.
-
Run installer (e.g.,
jdk-25_windows-x64_bin.exe). -
Set
JAVA_HOMEenvironment variable:-
Right-click "This PC" → Properties → Advanced system settings
-
Environment Variables → New System Variable
-
Variable name:
JAVA_HOME -
Variable value:
C:\Program Files\Java\jdk-25
-
-
Add
%JAVA_HOME%\bintoPATHvariable. -
Verify: Open Command Prompt and run
java -version.
6.2. Step 2: Extract Distribution Package
# Linux/Unix
tar -xzf ftacs-dist-<version>.tar.gz
cd dist/
# Windows -- extract ftacs-dist-<version>.zip using Windows Explorer or:
unzip ftacs-dist-<version>.zip
cd dist\
6.3. Step 3: Configure app.env
Edit bin/app.env with your environment-specific settings.
See Manual Deployment (app.env) for the full reference.
6.5. Step 5: Verify Installation
Monitor the log file for successful startup:
# Linux
tail -f ../logs/server.log
# Windows
type ..\logs\server.log
Look for these indicators:
INFO: Tomcat started on ports 8080 (http), 8181 (http), 8443 (https)
INFO: Starting Quartz Scheduler now
INFO: Scheduler quartzScheduler started
INFO: TR069 Device URLs:
NOAUTH: /ftacs/ACS
BASIC: /ftacs-basic/ACS
DIGEST: /ftacs-digest/ACS
INFO: WebServices:
/ACSServer-ACS/ACSWebService
/ACSServer-ACS/ACSWebServiceAdditional
/ACSServer-ACS/ACSWebServiceConfiguration
/ACSServer-ACS/ACSWebServiceEventSubscription
INFO: Swagger UI: /rest/swagger-ui
INFO: Friendly IOT Management Server V6.x.x started
INFO: Started FtAcsApp in XX.XXX seconds
|
You may see messages about "ClusterManager: detected failed or restarted instances" during startup — this is normal for Quartz scheduler recovery and can be ignored. Liquibase migration messages appear in the |
7. Verify Installation
7.1. Check Startup Logs
Wait 30-60 seconds after starting the container, then check the logs:
# Docker Compose
docker compose logs ftacs | tail -20
# Docker standalone
docker logs ftacs | tail -20
A successful startup produces the following output:
INFO: Tomcat started on ports 8080 (http), 8181 (http), 8443 (https)
INFO: Starting Quartz Scheduler now
INFO: Scheduler quartzScheduler started
INFO: TR069 Device URLs:
NOAUTH: /ftacs/ACS
BASIC: /ftacs-basic/ACS
DIGEST: /ftacs-digest/ACS
INFO: WebServices:
/ACSServer-ACS/ACSWebService
/ACSServer-ACS/ACSWebServiceAdditional
/ACSServer-ACS/ACSWebServiceConfiguration
/ACSServer-ACS/ACSWebServiceEventSubscription
INFO: Swagger UI: /rest/swagger-ui
INFO: Friendly IOT Management Server V6.x.x started
INFO: Started FtAcsApp in XX.XXX seconds
|
The startup banner is generated by |
7.2. Check Endpoints
# Application statistics
curl http://localhost:8080/acsstats
# TR-069 ACS endpoint
curl -I http://localhost:8080/ftacs/ACS
# SOAP WSDL
curl http://localhost:8080/ACSServer-ACS/ACSWebService?wsdl
# Swagger UI
curl -I http://localhost:8080/rest/swagger-ui
Expected: HTTP 200 responses for all endpoints.
7.3. Access Web Interface
-
HTTP:
http://localhost:8080 -
HTTPS:
https://localhost:8443
8. Port Reference
8.1. HTTP/HTTPS Services
| Service | Port | Protocol |
|---|---|---|
Main web interface (SOAP, REST, TR-069, statistics, bulk data) |
8080 |
HTTP |
Secondary HTTP port (same services as 8080) |
8181 |
HTTP |
Secure web interface (SOAP, REST, TR-069, statistics, bulk data) |
8443 |
HTTPS |
8.3. USP Protocol (TR-369)
| Service | Port | Security |
|---|---|---|
USP WebSocket |
8025 |
Plain |
USP WebSocket Secure |
4430 |
WSS |
USP MQTT |
18881 |
Plain |
USP MQTT |
18882 |
TLS |
USP Bulk Data Receiver |
18891 |
Plain |
USP STOMP |
61617 |
Plain |
USP CoAP (UDP) |
5783 |
Plain |
USP CoAP (UDP) |
5784 |
DTLS |
8.4. Infrastructure Services
| Service | Port | Protocol |
|---|---|---|
MySQL database |
3306 |
TCP |
ClickHouse HTTP interface |
8123 |
HTTP |
ClickHouse native protocol |
9000 |
TCP |
Hazelcast cluster |
5701 |
TCP |
Hazelcast server |
5711 |
TCP |
Hazelcast JMX |
9110 |
TCP |
JDBC Bridge (internal) |
9019 |
TCP |
8.5. HTTP Endpoints
| Endpoint | Description |
|---|---|
|
TR-069 protocol statistics |
|
TR-069 endpoint (no authentication) |
|
TR-069 endpoint (HTTP Basic authentication) |
|
TR-069 endpoint (HTTP Digest authentication) |
|
Primary SOAP web service WSDL |
|
Additional SOAP web service WSDL |
|
Swagger UI documentation interface |
|
TR-069 endpoints can be changed, added, or removed via environment variables ( |
8.6. Endpoint URL Examples
# No Authentication http://<your-server>:8080/ftacs/ACS # Basic Authentication http://<your-server>:8080/ftacs-basic/ACS # Digest Authentication (HTTPS) https://<your-server>:8443/ftacs-digest/ACS # SOAP Web Service http://<your-server>:8080/ACSServer-ACS/ACSWebService?wsdl # Swagger UI http://<your-server>:8080/rest/swagger-ui
8.7. Security Considerations
Plain-text ports (no encryption): 1883, 8025, 8080, 8181, 18881, 18891, 61617, 5783
Encrypted ports: 4430 (WSS), 8443 (HTTPS), 8883 (MQTT TLS), 18882 (USP MQTT TLS), 5784 (CoAP DTLS)
|
In production, disable or firewall plain-text ports and route all traffic through encrypted endpoints. |
9. Container Management
9.1. Check Container Status
# List running containers
docker ps
# View container logs
docker logs ftacs
# Follow logs in real-time
docker logs -f ftacs
# View last 100 lines
docker logs --tail 100 ftacs
9.2. Stop, Start, and Restart
# Stop container
docker stop ftacs
# Start container
docker start ftacs
# Restart container
docker restart ftacs
9.3. Remove Container
# Stop and remove container
docker stop ftacs
docker rm ftacs
# Force remove running container
docker rm -f ftacs
9.4. Shell Access
# Execute bash in running container
docker exec -it ftacs bash
# Run single command
docker exec ftacs ls -la /opt/FTACS/logs
9.5. Update FTACS Image
See Docker Image Management Guide for the full image lifecycle.
# 1. Backup before update
tar -czf ftacs-backup-$(date +%Y%m%d).tar.gz ${DATA_FOLDER}/ft-data
docker exec mysql mysqldump -uftacs -pftacs ftacs > ftacs-db-backup.sql
# 2. Pull new image
docker pull hub.friendly-tech.com/ftacs/ftacs:<new-version> # <-- replace
# 3. Stop and remove current container
docker stop ftacs
docker rm ftacs
# 4. Run with new image
docker run -d \
--name ftacs \
--env-file .env --env-file .env.mysql \
-p 8080:8080 \
-p 8443:8443 \
-v ${DATA_FOLDER:-.}/ftacs-conf:/opt/FTACS/conf \
-v ${DATA_FOLDER:-.}/ft-data/ftacs/logs:/opt/FTACS/logs \
hub.friendly-tech.com/ftacs/ftacs:<new-version> # <-- replace
|
For Docker Compose, update the image tag in
|
10. Production Checklist
-
Change all default passwords in
.env/app.env(DB_PASSWORD,SSL_KEYSTORE_PASSWORD,CLICKHOUSE_PASSWORD) -
Use a valid SSL certificate — replace the self-signed
ftacs.keystorewith a CA-issued certificate -
Configure firewall rules — allow only required ports; restrict database access to ACS hosts only
-
Review TR-069 authentication — disable the no-auth endpoint (
/ftacs/ACS) if not required -
Secure configuration files — restrict permissions:
chmod 600 bin/app.env -
Enable auto-restart — use
--restart unless-stoppedindocker runorrestart: unless-stoppedincompose.yml -
Configure health checks — compose.yml includes health checks; for standalone
docker run, add--health-cmd -
Set up monitoring — deploy Grafana with ClickHouse data sources and import ACS dashboard templates
-
Configure backups — regular database backups, configuration directory backup, ClickHouse backup strategy, log rotation
-
Deploy multiple ACS instances for high availability — same configuration, external Hazelcast cluster with 2+ nodes, load balancer in front
-
Tune JVM settings — match the JVM Sizing table to your deployment size
10.1. Log Files Reference
| Log File | Purpose |
|---|---|
|
Main application log |
|
Web service calls and responses |
|
Database migration logs |
|
SQL query execution logs |
|
Bulk operation processing |
|
System monitoring events |
|
Database session management |
|
External system integration traces |
|
Data cleanup operations |
|
Connection pool diagnostics |
11. Troubleshooting
11.1. Symptom: Container fails to start or exits immediately
- Cause
-
Application configuration error, missing environment file, or dependency not ready.
- Fix
-
# Check container logs for the error message docker logs ftacs # Check docker events docker events --filter container=ftacs # Inspect container configuration docker inspect ftacs # Verify environment variables are loaded docker exec ftacs env | grep DB_
11.2. Symptom: Database connection failure on startup
- Cause
-
Database is not running, wrong hostname/port, or incorrect credentials.
- Fix
-
# Test MySQL connectivity from the container docker exec ftacs nc -zv mysql 3306 # Check database logs docker logs mysql # Verify database credentials match between .env and MySQL container docker exec ftacs env | grep DB_Check that
DB_HOST,DB_PASSWORD,MYSQL_PORT, andMYSQL_USERmatch the database configuration.
11.3. Symptom: "Port already in use" error
- Cause
-
Another process is already bound to the requested port.
- Fix
-
# Find process using port 8080 sudo lsof -i :8080 # Or use netstat netstat -tulpn | grep 8080 # Option A: Kill the process sudo kill <PID> # Option B: Change the host port mapping in compose.yml or docker run docker run -p 9080:8080 ...
11.4. Symptom: Permission denied on mounted volumes
- Cause
-
Host directory permissions do not allow the container user to read/write.
- Fix
-
# Fix volume permissions sudo chown -R $(whoami):$(whoami) ${DATA_FOLDER} chmod -R 755 ${DATA_FOLDER} # Or run container as root (not recommended for production) docker run --user root ...
11.5. Symptom: java.lang.OutOfMemoryError or container killed by OOM
- Cause
-
JVM heap size exceeds available memory, or Docker memory limit is too low.
- Fix
-
-
Increase Docker memory limit (Docker Desktop: Settings → Resources → Memory: 4 GB+).
-
Adjust JVM settings in
.envorapp.env:JAVA_OPTS='-Xms1g -Xmx4g' -
Analyze heap dump if the issue persists to identify memory leaks.
-
11.6. Symptom: Hazelcast connection warnings on startup
- Cause
-
Hazelcast cluster is not running or not reachable from the ACS host.
- Fix
-
-
Verify Hazelcast cluster is running:
docker logs hazelcast -
Check
HZ_MEMBERSaddresses in.env/app.env. -
Verify network connectivity:
telnet <hazelcast-host> 5701 -
Check firewall rules allow port 5701.
-
11.7. Symptom: "ClusterManager: detected failed or restarted instances"
- Cause
-
This is normal behavior when the application restarts or a previous instance was not shut down cleanly.
- Fix
-
No action needed. Quartz automatically recovers jobs from failed instances.
11.8. Symptom: Application fails to start (manual deployment)
- Cause
-
Incorrect
JAVA_HOME, wrong JDK version, missing database, or Liquibase migration failure. - Fix
-
-
Verify Java:
java -versionmust show JDK 25. -
Check
JAVA_HOMEinapp.env. -
Verify database is running:
telnet <DB_HOST> <DB_PORT>. -
Check credentials in
app.env. -
Review
logs/liquibase.logfor SQL errors. -
On Windows, ensure
APP_HOMEuses forward slashes:D:/ftacs/dist/
-
11.9. Symptom: Docker containers not reachable from host (bridge networking)
- Cause
-
The host firewall blocks traffic on Docker bridge interfaces (
br-*) in the host INPUT/OUTPUT path for IPv4 and/or IPv6. This is not a Docker Compose or application issue.
Signs:
-
Container is healthy and responds on
localhostinside the container. -
Published ports appear correct (
0.0.0.0:PORT→PORT). -
Requests from the host hang / time out (no
ECONNREFUSED, only timeouts).- Fix
-
Allow host-to-container traffic on Docker bridges:
# IPv4 (generic -- all Docker bridges) iptables -I INPUT 1 -i br+ -j ACCEPT iptables -I OUTPUT 1 -o br+ -j ACCEPT # IPv6 (separate rules required) ip6tables -I INPUT 1 -i br+ -j ACCEPT ip6tables -I OUTPUT 1 -o br+ -j ACCEPT # Persist rules (Debian/Ubuntu) apt-get install -y iptables-persistent netfilter-persistent save
Diagnosis steps:
# 1. Confirm container works internally
docker exec <container> curl -s -o /dev/null -w '%{http_code}\n' http://localhost:8080
# 2. Get container IPv4 address
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' <container>
# 3. Test from host to container IP
nc -vz <container_ipv4> 8080
# 4. Identify Docker bridge
ip -4 addr | grep '^.*br-'
# 5. Check firewall
iptables -S INPUT
iptables -S OUTPUT
|
IPv4 working does not imply IPv6 works. IPv4 and IPv6 are separate firewall stacks. Docker programs NAT and FORWARD rules but does not override host INPUT/OUTPUT firewall policies. |
11.10. Symptom: Slow performance or high response times
- Cause
-
Undersized JVM, database query performance issues, or network latency.
- Fix
-
-
Check database query performance.
-
Verify Hazelcast cache hit ratios.
-
Review connection pool settings.
-
Monitor with Grafana dashboards.
-
Check network latency to database/Hazelcast.
-
Increase JVM heap if needed (see JVM Sizing table).
-
11.11. Getting Support
If issues persist, collect the following information and contact Friendly Tech support:
-
app.env/.envconfiguration (mask passwords) -
logs/server.log(last 1000 lines) -
logs/liquibase.log(if database issues) -
Java version:
java -version -
Operating system version
-
Database type and version
-
Docker version:
docker version(if applicable)
11.12. Upgrade Procedure (Manual Deployment)
-
Backup current installation — database backup, configuration files, log files.
-
Stop application:
ps aux | grep ftacs kill <PID> -
Extract new version to a new directory.
-
Migrate configuration — copy and adapt
app.envfrom the old version; review new configuration options. -
Start new version — Liquibase automatically migrates the database schema.
-
Verify functionality — test device connections, web services, monitoring dashboards.
-
Rollback (if needed) — stop new version, restore database backup, start old version.