Installation & Deployment

This guide walks you through installing and running the Service API — a Spring Boot 3 application built with Java 25 and Gradle. Docker is the recommended deployment method for consistency and ease of use.

1. Prerequisites

1.1. System Requirements

Component Requirement

Java

JDK 25 (only for local Gradle builds; not needed for Docker deployment)

Database

MySQL 8.0+ or Oracle 21c XE / 19c (ACS schema must already exist)

Docker

Docker Engine 20.10+ and Docker Compose 2.0+

OS

Linux (recommended), macOS, or Windows with WSL2

RAM

2 GB minimum (4+ GB recommended)

Disk

1 GB free space for the image and logs

Before starting, make sure:

  • Docker Engine 20.10+ and Docker Compose 2.0+ installed. If Docker is not installed, follow the Docker Installation Guide.

  • You have network access to the ACS database (MySQL or Oracle).

  • You have network access to the Northbound API instance.

  • You have network access to the Hazelcast cluster (if caching is used).

1.2. Prepare Working Directory

Create the working directory on the host machine:

mkdir -p /usr/local/service-api/logs
cd /usr/local/service-api

Download the deployment files from the FT_DISK on SharePoint and place them on the server. Alternatively, copy the files from the source repository.

Expected layout after placing the files:

/usr/local/service-api/
+-- .env.mysql                    # Environment variables (MySQL profile)
+-- .env.oracle                   # Environment variables (Oracle profile)
+-- service-api.yml               # Main service configuration
+-- hazelcast-client.yaml         # Hazelcast cache cluster config
+-- logs/                         # Application logs (mounted volume)

You only need the env file that matches your database (.env.mysql or .env.oracle), not both.

Configuration files are also available in the source repository:

File Path in repository

.env.mysql, .env.oracle

docker/

service-api.yml

src/main/resources/yml/

hazelcast-client.yaml

src/main/resources/config/

2. Option A: Quick Start

For experienced users who already have Docker installed and configuration files ready. The example below uses MySQL; for Oracle replace .env.mysql with .env.oracle.

# 1. Go to the working directory (files should already be in place -- see "Prerequisites")
cd /usr/local/service-api

# 2. Get the Docker image (choose one):

#    Option A: Pull from Harbor registry (recommended)
docker login hub.friendly-tech.com
#    Note: "docker pull" is optional if you use docker compose --
#    "docker compose up" will pull the image automatically.
docker pull hub.friendly-tech.com/api/service-api:latest

#    Option B: Load from archive (for offline servers — see "Transfer Image to Offline Server" below)
#    gzip -dc service-api-<version>.tar.gz | docker load

# 3. Edit the environment file for your database
vi .env.mysql               # or .env.oracle for Oracle
                             # set MYSQL_HOST, MYSQL_PASSWORD, NORTHBOUND_API_URL, etc.

# 4. Make sure compose.yml references the correct env file
#    env_file: .env.mysql    (default) or .env.oracle

# 5. Start the application
docker compose up -d

# 6. Verify
curl -s http://localhost:8080/iot-webservice/actuator/health

To switch between MySQL and Oracle, change the env_file value in compose.yml:

env_file:
  - .env.oracle    # instead of .env.mysql

After startup the application is available at http://localhost:8080. For detailed step-by-step instructions, continue with Option B: Detailed Installation.

3. Option B: Detailed Installation

Step-by-step guide covering each stage of the installation process.

3.1. Step 1: Get the Docker Image

# Authenticate with the registry
docker login hub.friendly-tech.com

# Pull the latest image (optional if using docker compose --
# "docker compose up" will pull the image automatically)
docker pull hub.friendly-tech.com/api/service-api:latest

To pin to a specific release version:

docker pull hub.friendly-tech.com/api/service-api:v1.0.0-b0.0.13

The version v1.0.0-b0.0.13 is an example. Always use the version tag that corresponds to your deployment.

Optionally, retag the image for shorter references in docker run commands:

docker tag hub.friendly-tech.com/api/service-api:latest service-api:latest

If you skip retagging, use the full image name (hub.friendly-tech.com/api/service-api:latest) in all subsequent commands.

To request Harbor access, contact the DevOps team for a user account or robot token.

3.1.2. Option B: Transfer Image to Offline Server

Use this option when the target server has no internet access and cannot pull images from Harbor directly. The image is pulled on a machine that does have Harbor access, exported to a tar archive, transferred to the offline server, and loaded there.

  1. On a machine with Harbor access, log in and pull the image for the target server’s architecture:

    docker login hub.friendly-tech.com
    docker pull --platform linux/amd64 \
      hub.friendly-tech.com/api/service-api:<version>

    An explicit --platform matching the offline target server’s architecture is required. The image in Harbor is multi-arch (linux/amd64, linux/arm64); without --platform, docker pull selects the host architecture, which may not match the target. For example, on an Apple Silicon (arm64) Mac without --platform, the resulting archive will be arm64 and will fail with a platform does not match warning on amd64 servers. The example uses linux/amd64; replace it with the platform of your offline target server (linux/arm64, etc.).

  2. Save the pulled image to a tar archive and compress it:

    docker save hub.friendly-tech.com/api/service-api:<version> \
      -o service-api-<version>.tar
    gzip service-api-<version>.tar
  3. Transfer service-api-<version>.tar.gz to the offline server (e.g., via scp or removable media).

  4. On the offline server, load the image:

    gzip -dc service-api-<version>.tar.gz | docker load

3.1.3. Option C: Build from Source (developers only)

docker buildx build \
  --platform linux/amd64,linux/arm64 \
  --secret id=github_token,env=GITHUB_TOKEN \
  --secret id=github_user,src=<(printf '%s' "Friendly-Technologies") \
  -t service-api:latest \
  --load .

Building from source requires valid GitHub credentials with access to private dependencies. Loading a pre-built image is faster and avoids build-environment issues.

After loading or pulling, verify the image is available:

docker images | grep service-api

3.2. Step 2: Configure Environment

The Service API reads its configuration from:

  • .env.mysql or .env.oracle — environment variables loaded via Docker --env-file

  • service-api.yml — service configuration (mounted to /etc/app/service-api.yml)

  • hazelcast-client.yaml — cache configuration (mounted to /etc/app/hazelcast-client.yaml)

Edit the environment file that matches your database:

cd /usr/local/service-api
vi .env.mysql               # or .env.oracle for Oracle

For comprehensive details on every configuration option, see the Service API Configuration Guide.

If the database, Hazelcast cluster, or Northbound API runs on the host machine (not in Docker), use one of the following as the hostname in MYSQL_HOST / ORACLE_HOST, NORTHBOUND_API_URL, and in hazelcast-client.yaml:

  • host.docker.internal — works on Docker Desktop (macOS, Windows) and on Linux with --add-host=host.docker.internal:host-gateway (for docker run). The provided compose.yml already includes extra_hosts for this.

  • The host machine’s real IP address (e.g., 192.168.1.10)

localhost or 127.0.0.1 will not work — inside the container these point to the container itself, not the host.

3.2.1. .env.mysql

# ==========================================================
# Service API - Environment Configuration (MySQL)
# ==========================================================

# Active Spring profile: mysql or oracle
SPRING_PROFILES_ACTIVE=mysql

# Container connector ports
# PORT is the HTTP connector port inside the container.
PORT=8080

# HTTPS/TLS settings
# HTTP and HTTPS can run together when they use different container ports.
# SERVER_SSL_ENABLED=false -> HTTP only.
# SERVER_SSL_ENABLED=true  -> HTTPS on HTTPS_PORT (set it explicitly, e.g. 8443).
# In dual mode, keep PORT different from HTTPS_PORT (example: PORT=8080, HTTPS_PORT=8443).
# If these container ports are equal, only one connector can bind to that port.
# HTTPS_PORT=8443
# Legacy compatibility: SERVER_PORT is still supported as HTTPS fallback, but prefer HTTPS_PORT.
SERVER_SSL_ENABLED=false
SERVER_SSL_KEY_STORE=file:/etc/app/keystore.p12
SERVER_SSL_KEY_STORE_PASSWORD=<keystore-password>     # <-- replace when HTTPS enabled
SERVER_SSL_KEY_STORE_TYPE=PKCS12
SERVER_SSL_KEY_PASSWORD=<key-password>                # <-- replace when HTTPS enabled
SERVER_SSL_KEY_ALIAS=server
SERVER_SSL_TRUST_STORE=
SERVER_SSL_TRUST_STORE_PASSWORD=

# Container timezone
TZ=Europe/Kiev

# ==========================================================
# Database
# ==========================================================
# HikariCP connection pool settings
DB_MAX_POOL_SIZE=10
DB_MIN_IDLE=5
DB_CONNECTION_TIMEOUT_MS=30000

# MySQL connection
# For Docker networking: use container name or host.docker.internal
# For external database: use IP address or hostname
MYSQL_HOST=<your-mysql-host>            # <-- replace
MYSQL_PORT=3306
MYSQL_SCHEMA=ftacs
MYSQL_USER=ftacs
MYSQL_PASSWORD=<your-db-password>       # <-- replace
MYSQL_DRIVER_CLASS_NAME=com.mysql.cj.jdbc.Driver

# ==========================================================
# Northbound API
# ==========================================================
# URL of the Northbound API service
# If both services are in the same Docker network, use container name:
#   http://northbound-api:8080/iot-webservice
# If Northbound API runs on a separate host:
#   http://<host>:<port>/iot-webservice
NORTHBOUND_API_URL=http://<your-nbi-host>:8080/iot-webservice  # <-- replace

# ==========================================================
# Configuration Paths
# ==========================================================
# Path to service-api YAML configuration inside the container
CONFIG_PATH=file:/etc/app/

# Path to Hazelcast client configuration directory inside the container
CACHE_CONFIG_PATH=file:/etc/app/

# ==========================================================
# Logging
# ==========================================================
# Log level for the application package (com.friendly.apiservice).
# Values: ERROR, WARN, INFO, DEBUG. In DEBUG mode business errors include stack traces.
# Can also be changed at runtime via Actuator.
LOGGING_LEVEL_COM_FRIENDLY_APISERVICE=DEBUG

# ==========================================================
# Timeouts
# ==========================================================
# Default timeout for device operations (seconds)
TIMEOUT=60

3.2.2. .env.oracle

# ==========================================================
# Service API - Environment Configuration (Oracle)
# ==========================================================

# Active Spring profile: mysql or oracle
SPRING_PROFILES_ACTIVE=oracle

# Container connector ports
# PORT is the HTTP connector port inside the container.
PORT=8080

# HTTPS/TLS settings
# HTTP and HTTPS can run together when they use different container ports.
# SERVER_SSL_ENABLED=false -> HTTP only.
# SERVER_SSL_ENABLED=true  -> HTTPS on HTTPS_PORT (set it explicitly, e.g. 8443).
# In dual mode, keep PORT different from HTTPS_PORT (example: PORT=8080, HTTPS_PORT=8443).
# If these container ports are equal, only one connector can bind to that port.
# HTTPS_PORT=8443
# Legacy compatibility: SERVER_PORT is still supported as HTTPS fallback, but prefer HTTPS_PORT.
SERVER_SSL_ENABLED=false
SERVER_SSL_KEY_STORE=file:/etc/app/keystore.p12
SERVER_SSL_KEY_STORE_PASSWORD=<keystore-password>     # <-- replace when HTTPS enabled
SERVER_SSL_KEY_STORE_TYPE=PKCS12
SERVER_SSL_KEY_PASSWORD=<key-password>                # <-- replace when HTTPS enabled
SERVER_SSL_KEY_ALIAS=server
SERVER_SSL_TRUST_STORE=
SERVER_SSL_TRUST_STORE_PASSWORD=

# Container timezone
TZ=Europe/Kiev

# ==========================================================
# Database
# ==========================================================
# HikariCP connection pool settings
DB_MAX_POOL_SIZE=10
DB_MIN_IDLE=5
DB_CONNECTION_TIMEOUT_MS=30000

# Oracle connection
# For Docker networking: use container name or host.docker.internal
# For external database: use IP address or hostname
ORACLE_HOST=<your-oracle-host>          # <-- replace
ORACLE_PORT=1521
ORACLE_SERVICE=XEPDB1
ORACLE_USER=ftacs
ORACLE_PASSWORD=<your-db-password>      # <-- replace
ORACLE_DRIVER_CLASS_NAME=oracle.jdbc.OracleDriver

# ==========================================================
# Northbound API
# ==========================================================
# URL of the Northbound API service
# If both services are in the same Docker network, use container name:
#   http://northbound-api:8080/iot-webservice
# If Northbound API runs on a separate host:
#   http://<host>:<port>/iot-webservice
NORTHBOUND_API_URL=http://<your-nbi-host>:8080/iot-webservice  # <-- replace

# ==========================================================
# Configuration Paths
# ==========================================================
# Path to service-api YAML configuration inside the container
CONFIG_PATH=file:/etc/app/

# Path to Hazelcast client configuration directory inside the container
CACHE_CONFIG_PATH=file:/etc/app/

# ==========================================================
# Logging
# ==========================================================
# Log level for the application package (com.friendly.apiservice).
# Values: ERROR, WARN, INFO, DEBUG. In DEBUG mode business errors include stack traces.
# Can also be changed at runtime via Actuator.
LOGGING_LEVEL_COM_FRIENDLY_APISERVICE=DEBUG

# ==========================================================
# Timeouts
# ==========================================================
# Default timeout for device operations (seconds)
TIMEOUT=60

Pre-configured template files are available on FT_DISK and in the source repository.

Copy the file that matches your database to the working directory:

cp .env.mysql /usr/local/service-api/.env.mysql
# or
cp .env.oracle /usr/local/service-api/.env.oracle

3.2.3. TLS Keystore (HTTPS)

To enable HTTPS, provide a PKCS12 keystore file at /etc/app/keystore.p12 inside the container. With the recommended mount (-v $(pwd):/etc/app), place the file in your working directory as keystore.p12.

For local development, you can generate a self-signed keystore:

cd /usr/local/service-api

keytool -genkeypair \
  -alias server \
  -keyalg RSA \
  -keysize 2048 \
  -storetype PKCS12 \
  -keystore keystore.p12 \
  -validity 3650 \
  -storepass <keystore-password> \
  -keypass <key-password> \
  -dname "CN=localhost, OU=Dev, O=Friendly, L=Local, ST=Local, C=US" \
  -ext "SAN=dns:localhost,ip:127.0.0.1"

Then set these values in .env.mysql or .env.oracle: SERVER_SSL_ENABLED=true, HTTPS_PORT=8443, SERVER_SSL_KEY_STORE=file:/etc/app/keystore.p12, SERVER_SSL_KEY_STORE_PASSWORD=<keystore-password>, SERVER_SSL_KEY_PASSWORD=<key-password>.

For production, use a certificate issued by your CA/security team and export it to PKCS12 format (.p12).

3.2.4. service-api.yml

The main service configuration file controls email settings, speed tests, subscription parameters, service groups, and wireless configurations. Refer to the Service API Configuration Guide for detailed information about this file’s structure and options.

3.2.5. hazelcast-client.yaml

Basic structure:

hazelcast-client:
  cluster-name: <your-cluster-name>
  network:
    cluster-members:
      - <hazelcast-server-host>:<hazelcast-server-port>
  connection-strategy:
    async-start: false
    reconnect-mode: ON
cluster-name

Name of the Hazelcast cluster to connect to

cluster-members

List of Hazelcast server addresses (format: host:port)

async-start

Whether to start connection asynchronously (recommended: false for startup validation)

reconnect-mode

How to handle connection loss (ON = automatic reconnection)

3.3. Step 3: Deploy

Create a compose.yml file in your working directory:

version: "3.8"

services:
  service-api:
    image: hub.friendly-tech.com/api/service-api:latest
    container_name: service-api
    env_file:
      - .env.mysql          # or .env.oracle
    ports:
      - "8080:8080"         # <host-port>:<container-port> -- change the host port
                             # if 8080 is already used by another application (e.g. "9080:8080")
      - "8443:8443"         # Optional: publish this mapping only when HTTPS is enabled
    volumes:
      - .:/etc/app
      - ./logs:/app/logs
    extra_hosts:
      - "host.docker.internal:host-gateway"
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/iot-webservice/actuator/health"]
      interval: 30s
      timeout: 3s
      start_period: 60s
      retries: 3

To change external ports, edit only the left side of each mapping (<host-port>:<container-port>), for example 9080:8080 for HTTP and 9443:8443 for HTTPS.

Publishing both mappings at the same time is valid and does not conflict. Conflicts happen only if host ports overlap (left side) or if HTTP/HTTPS are configured to the same container port. For HTTP-only deployment, remove the 8443:8443 mapping.

# Prepare host log directory (used by /app/logs mount)
mkdir -p logs

# Start the application
docker compose up -d

# View logs
docker compose logs -f service-api

# Stop
docker compose down

3.3.2. Option 2: docker run

cd /usr/local/service-api

mkdir -p logs

docker run -d \
  --name service-api \
  --env-file .env.mysql \
  -v $(pwd):/etc/app \
  -v $(pwd)/logs:/app/logs \
  -p 8080:8080 \
  -p 8443:8443 \
  --restart unless-stopped \
  hub.friendly-tech.com/api/service-api:latest

If default host ports are busy, change only the left side: -p 9080:8080 -p 9443:8443. For HTTP-only deployment, omit -p 8443:8443.

Replace --env-file .env.mysql with --env-file .env.oracle for Oracle. If you retagged the image locally, use service-api:latest instead of the full Harbor path. To persist file logs on the host, keep -v $(pwd)/logs:/app/logs in the run command.

3.3.3. Docker Networking

If the Service API container must communicate with other containers (database, Hazelcast, Northbound API, etc.), create a shared Docker network:

docker network create app-network

Add --network app-network to your docker run command or add the network section to your compose.yml. Use container names (not raw IPs) in .env.mysql / .env.oracle to leverage Docker DNS resolution.

To deploy Service API alongside Northbound API and Provision Portal as a single stack, see the Java API Stack Deployment Guide.

3.4. Step 4: Verify Installation

After starting the container, run the following checks:

# 1. Check container status
docker ps -f name=service-api
# Expected: container with status "Up" and mapped ports (8080 and 8443 when published)

# 2. Health check
curl -s http://localhost:8080/iot-webservice/actuator/health
# Expected: {"status":"UP"}

# 2b. HTTPS health check (when SERVER_SSL_ENABLED=true)
curl -sk https://localhost:8443/iot-webservice/actuator/health
# Expected: {"status":"UP"}

# 3. Check application logs
docker logs service-api --tail 50
# Look for: "Started ServiceApiApplication in XX.XXX seconds"

# 4. Swagger UI (open in browser)
# http://localhost:8080/iot-webservice/swagger-ui/index.html
# https://localhost:8443/iot-webservice/swagger-ui/index.html

4. Container Management

Command Description

docker compose up -d

Start all services in the background

docker compose down

Stop and remove containers

docker compose logs -f service-api

Follow application logs

docker compose ps

Show container status

docker compose restart service-api

Restart the application

docker compose pull

Update images to latest versions

docker exec -it service-api sh

Enter the application container

docker exec service-api ls -la /etc/app

Check mounted configuration files

docker logs --tail 100 service-api

View last 100 log lines

docker stats service-api --no-stream

View resource usage

docker inspect service-api --format '{{json .Config.Env}}'

Check environment variables

5. Updating the Application

docker compose pull downloads the latest image from the registry, then docker compose up -d recreates the container with the new version. Configuration files are preserved.

# 1. Backup configuration
cd /usr/local/service-api
tar -czf service-api-backup-$(date +%Y%m%d).tar.gz .env.* service-api.yml hazelcast-client.yaml

# 2. Pull the latest image
docker compose pull service-api

# 3. Recreate the container with the new image
docker compose up -d service-api

# 4. Verify
curl -s http://localhost:8080/iot-webservice/actuator/health

5.2. Via docker load (offline servers)

When the upgrade target server has no access to the Harbor registry, the new image must be pulled on a machine that does have Harbor access, exported to a tar archive, transferred to the offline server, and loaded there.

  1. On a machine with Harbor access, log in and pull the new image for the target server’s architecture:

    docker login hub.friendly-tech.com
    docker pull --platform linux/amd64 \
      hub.friendly-tech.com/api/service-api:<new-version>

    An explicit --platform matching the offline target server’s architecture is required. The image in Harbor is multi-arch (linux/amd64, linux/arm64); without --platform, docker pull selects the host architecture, which may not match the target. For example, on an Apple Silicon (arm64) Mac without --platform, the resulting archive will be arm64 and will fail with a platform does not match warning on amd64 servers. The example uses linux/amd64; replace it with the platform of your offline target server (linux/arm64, etc.).

  2. Save the pulled image to a tar archive and compress it:

    docker save hub.friendly-tech.com/api/service-api:<new-version> \
      -o service-api-<new-version>.tar
    gzip service-api-<new-version>.tar
  3. Transfer service-api-<new-version>.tar.gz to the offline server (e.g., via scp or removable media).

  4. On the offline server, load the new image and replace the running container:

    # 1. Load the new image from archive
    gzip -dc service-api-<new-version>.tar.gz | docker load
    
    # 2. Replace the container
    docker stop service-api
    docker rm service-api
    
    docker run -d \
      --name service-api \
      --env-file .env.mysql \
      -v $(pwd):/etc/app \
      -v $(pwd)/logs:/app/logs \
      -p 8080:8080 \
      --restart unless-stopped \
      hub.friendly-tech.com/api/service-api:<new-version>
    
    # 3. Verify
    curl -s http://localhost:8080/iot-webservice/actuator/health

5.3. Rollback

docker stop service-api
docker rm service-api

# Re-run with the previous image tag
docker run -d --name service-api \
  --env-file .env.mysql \
  -v $(pwd):/etc/app \
  -v $(pwd)/logs:/app/logs \
  -p 8080:8080 \
  --restart unless-stopped \
  hub.friendly-tech.com/api/service-api:<previous-version-tag>

6. Production Checklist

# Item Notes

1

Restart policy

restart: unless-stopped is already configured in the examples

2

Health check

Configured for /iot-webservice/actuator/health with a 30s interval

3

Database credentials

Replace default values in the .env file (MYSQL_PASSWORD / ORACLE_PASSWORD)

4

Northbound API URL

Verify NORTHBOUND_API_URL points to the correct instance

5

File permissions

Restrict env files: chmod 600 .env.*

6

Log management

Configure Docker log rotation: --log-opt max-size=50m --log-opt max-file=5

7

Timezone

Set TZ in .env (defaults to Europe/Kiev)

8

Resource limits

Add --memory=2g or deploy.resources.limits in compose.yml for production

7. Troubleshooting

Start with quick diagnostics:

docker logs service-api --tail 100
docker inspect service-api --format '{{json .Config.Env}}'
docker exec service-api ls -la /etc/app
docker exec service-api ls -la /app/logs

7.1. Could not resolve placeholder 'CONFIG_PATH'

Symptom: PlaceholderResolutionException: Could not resolve placeholder 'CONFIG_PATH'

Solutions:

  1. Verify --env-file points to the correct .env.mysql or .env.oracle file. Use an absolute path if needed: --env-file /usr/local/service-api/.env.mysql.

  2. Confirm the env file contains CONFIG_PATH=file:/etc/app/.

  3. Validate inside the container: docker exec service-api env | grep CONFIG_PATH.

7.2. open .env.mysql: no such file or directory

Symptom: Docker fails to start with a "file not found" error.

Solutions:

  1. Run docker run from the directory containing the env file, or use an absolute path: --env-file /usr/local/service-api/.env.mysql.

  2. Check file permissions: chmod 640 .env.*.

7.3. FileNotFoundException: /etc/app/service-api.yml

Symptom: Application logs show the configuration file is missing.

Solutions:

  1. Confirm service-api.yml exists in /usr/local/service-api/: ls -la /usr/local/service-api/service-api.yml.

  2. Verify the volume mount: -v $(pwd):/etc/app.

  3. Check inside the container: docker exec service-api ls /etc/app.

7.4. Logs are not written to the host directory

Symptom: application.log exists in container, but /usr/local/service-api/logs on host is empty or missing.

Solutions:

  1. Add a bind mount for logs in docker run: -v $(pwd)/logs:/app/logs.

  2. Create the host directory before starting: mkdir -p /usr/local/service-api/logs.

  3. Verify mount configuration: docker inspect service-api --format '{{json .Mounts}}'.

7.5. Database Connection Failures

Symptom: MySQL Communications link failure or Oracle ORA-12514 in logs.

Solutions:

  1. Verify the database host is reachable from the container:

    docker exec service-api nc -zv <db-host> <db-port>
  2. Check MYSQL_HOST / ORACLE_HOST and credentials in your .env.* file.

  3. If using Docker networking, ensure both containers are on the same network:

    docker network inspect app-network

7.6. Northbound API Connection Failure

Symptom: Connection refused or timeout errors when calling Northbound API.

Solutions:

  1. Verify NORTHBOUND_API_URL in the env file is correct.

  2. Check that the Northbound API container is running: docker ps -f name=northbound-api.

  3. If using Docker networking, ensure both containers are on the same network and use container names instead of localhost.

7.7. Hazelcast Connection Failure

Symptom: Unable to connect to any address in logs.

Solutions:

  1. Verify Hazelcast members are running and on the same Docker network.

  2. Check that cluster-name and cluster-members in hazelcast-client.yaml match the server configuration.

  3. Confirm CACHE_CONFIG_PATH in the env file points to the mounted directory.

7.8. Port Conflict

Symptom: address already in use error.

Solutions:

  1. Find the process using the port:

    lsof -i :8080
    # or
    docker ps
  2. Stop the conflicting service, or expose a different host port: -p 9080:8080.

7.9. Build Fails: Permission denied: ./gradlew

Symptom: Docker build stage fails on ./gradlew.

Solutions:

  1. On the host: chmod +x gradlew.

  2. Ensure your source checkout preserves execute permissions.

7.10. Build Fails: Secret Errors

Symptom: Could not read script '/run/secrets/github_user' during build.

Solutions:

  1. Provide the required --secret flags when running docker build (see Step 1: Get the Docker Image).

  2. Verify GitHub credentials are valid and have access to private dependencies.

8. Port Reference

Port Protocol Description

8080

HTTP

HTTP connector port (always available when PORT is exposed)

8443

HTTPS

TLS connector port (used when SERVER_SSL_ENABLED=true)

By default the application runs on HTTP (PORT=8080). When HTTPS is enabled (SERVER_SSL_ENABLED=true and keystore settings provided), it can run with two connectors: HTTPS on HTTPS_PORT (typically 8443) and HTTP on PORT (typically 8080). Use different values for those container ports to keep both connectors active. Publishing both Docker mappings (-p 8080:8080 and -p 8443:8443) is safe.