Skip to main content

Port Configuration Information

PlantPulse operates as a Docker Compose stack, and each container has its own ports. The same port design is followed for both single servers and clusters.

«Firewall is open» is different from «Actually open on the host»

The ports bound to the host are determined by ports: of compose/docker-compose.yml. The firewall list opened by install.sh is broader than that. The fact that it is in the firewall does not mean a response will come through that port.

The first table on this page contains all ports that are actually open on the host. Other ports only communicate within the containers.

Which Container Opens What​

ContainerPorts opened on host
plantpulse-proxy80 · 443 · 1883 · 1884 — The sole entry point for users and equipment
plantpulse-plugin-opcua11004 · 11005
plantpulse-ha10210
plantpulse-datalakeAll infrastructure series (Table below)
plantpulse-batch-web9500 · 9501 (PP_BATCH_HTTP_PORT · PP_BATCH_TLS_PORT)
plantpulse-warehouse-web9600 · 9601 (PP_WAREHOUSE_HTTP_PORT · PP_WAREHOUSE_TLS_PORT)
plantpulse-server-web · plantpulse-plugin-aasxNone — Operates only behind the proxy
plantpulse-certsNone (Does not open ports)

Port Topology​

PortContainerProtocolPurposeRecommendation
80proxyHTTPOperation Console / REST APIReverse Proxy Recommended
443proxyHTTPSOperation Console / REST API (TLS)✓
4950datalakeHTTPSMonitor UI + /api/healthMonitoring System
1883proxyTCPMQTT Plaintext — Edge Device / Sensor collectionPrivate Network Recommended
1884proxyTCP+TLSMQTT over TLS (Proxy is passthrough, Broker terminates)TLS Recommended
11004 / 11005opcua-serverOPC-UAEndpoint for external equipmentTLS Recommended
10210haHTTPHA Daemon /api/health · /api/cluster — Peers connect in 2-cluster configPeer IP only
9094datalakeTCP+TLSKafka External ClientTLS Required
5500 / 5501datalakeHTTP / HTTPSExternal system data inquiryAPI Key

Operational Advice: It is recommended to expose only 80/443 externally and keep the rest within a private network.

Do not expose 9500 · 9501 · 9600 · 9601 externally, even if they are «open» on the host

The batch and warehouse containers bind these four to the host (first table above). This is intended to allow operators to query those containers directly, not to expose them externally. Block them at the upper firewall and perform checks within the host.

curl -fsS http://127.0.0.1:9500/api/health | jq # 배치
curl -fsS http://127.0.0.1:9600/api/health | jq # 웨어하우스

To change ports, modify PP_BATCH_HTTP_PORT · PP_BATCH_TLS_PORT · PP_WAREHOUSE_HTTP_PORT · PP_WAREHOUSE_TLS_PORT of .env.

No separate port is required for real-time push to the web console

Real-time push is sent through the proxy (443). No separate WebSocket port is opened on the host.

Messaging​

PortContainerProtocolPurpose
1883 / 1884proxyTCP / TLSMQTT (HiveMQ). Published by proxy
18883 / 18884datalakeTCP / TLSReserved. No current listener opening these ports
9092datalakeTCPKafka PLAINTEXT (Private network only)
9093datalakeTCPKafka KRaft Controller
9094datalakeTCP+TLSKafka SASL_SSL
Kafka does not go through the proxy

After bootstrapping, Kafka clients reconnect to the address provided by advertised.listeners. Placing a proxy in front would require changing that address as well; otherwise, only the bootstrap succeeds, followed by a silent failure. Therefore, Kafka ports are published directly by the datalake.

STOMP(ActiveMQ) has been retired

As browser real-time push switched to SSE, the STOMP broker was removed from the datalake image. 61000 / 61004 are no longer serviced. Please clean up any remaining old firewall rules.

Storage (Private network only)​

PortProtocolPurpose
9042CQLAster TSDB
7000 / 7001TCPAster TSDB Gossip / SSL
5432TCPPostgreSQL
6379TCPValkey (Redis compatible)
6380TCP+TLSValkey TLS listener
9000HTTPRustFS API
9001HTTPRustFS Console

Analytics / SQL (Private network only)​

PortProtocolPurpose
7077TCPSpark Master RPC
4440HTTPSpark Master UI — Not 8080
8081HTTPSpark Worker UI
10000ThriftKyuubi SQL Gateway
10099HTTPKyuubi REST API
19001HTTPGravitino Integrated Catalog
9083ThriftHive Metastore
3500 / 3600HTTPLab Analysis Environment
4000 / 4001HTTP / HTTPSSQL Query Service

Processing / Time Series (Private network only)​

PortProtocolPurpose
7400 / 7401HTTP / HTTPSCEP (Aster CEP)
7800 / 7801HTTP / HTTPSTime Series Engine (TSE)
3000HTTPPlantPulse Dashboard
5500 / 5501HTTP / HTTPSData Gateway

Workflow (Private network only)​

PortProtocolPurpose
7233gRPCTemporal Frontend
8233HTTPTemporal Web UI
8380HTTPKestra (UI + API)
8381HTTPKestra management port

Other Datalake Ports​

PortPurpose
7003Diagnostic Console (Private network only)
60000 / 60001OPC Agent collection (Private network only)
6199 / 6299 / 6399 / 6499 / 7099JMX agent — Please allow Control Node IP only
9500 · 9501 · 9600 · 9601 are opened by «App Containers» — not the datalake

These four ports belong to the app tier — 9500 · 9501 are two Tomcat connectors for plantpulse-batch-web, and 9600 · 9601 are for plantpulse-warehouse-web. Both are HTTP and HTTPS connectors, and 9501 · 9601 are full connectors with their own SSLHostConfig, not just for redirection.

Definitions from when batch/warehouse were in the same container as the datalake remained on the datalake side, and at that time, they held host ports with nothing behind them, causing connection resets (discovered 2026-09-02). Those definitions have been cleaned up.

And on 2026-09-07, app containers began opening them themselves (User decision). Thus, the statement «App containers do not publish anything» is no longer true. It is therefore more important to remove these ports from the datalake list — if both try to grab the same port, the container that starts later will fail to boot with an error stating «only the port name».

Container Internal Only (Not disclosed to host)​

The following are ports that communicate only inside the container. There is no response when querying curl from the host.

PortTargetAlternative Verification Method
8090 · 4800 / 4801AAS(BaSyx) V3 API · V2 Registry/AASConsider a separate reverse proxy if external access is required
7199 · 7279Aster TSDB · HiveMQ JMXEnter datalake via bin/shell.sh then verify
App ports of plantpulse-server-webInside that containerbin/status.sh / bin/logs.sh <컨테이너>
4949 is plaintext

The console and health API are serviced on both ports — 4950(HTTPS) and 4949(plaintext HTTP). They are the same console and same API, differing only in scheme. 4949 no longer redirects to 4950.

4949 is plaintext — login passwords and session cookies flow in the clear. Use 4950 on untrusted networks. 4949 is an option for environments where self-signed certificate warnings actually block the operator.

# 호스트 / 외부에서
curl -kfsS https://<server-ip>:4950/api/health | jq

# 컨테이너 안에서 (어떤 구성에서도 동작합니다)
docker exec plantpulse-datalake curl -kfsS https://127.0.0.1:4950/api/health | jq

Pre-installation Port Conflict Check​

# 핵심 포트 점유 확인
ss -tlnp | grep -E ':(80|443|1883|1884|3000|4000|4950|5432|5500|6379|7077|7233|7400|7800|8233|8380|9000|9042|9092|10000|10210|11004|19001)\s'

If there is no output, there is no conflict. If there is output:

# 점유 프로세스 확인
sudo lsof -i :<port>
sudo ss -tlnp | grep ":<port>"

Commonly conflicting ports: 80 (Apache/Nginx), 5432 (External PostgreSQL), 3000 (Grafana/Node.js), 9092 (External Kafka), 6379 (External Redis). If using external services, it is simpler to move the port of that service.

bin/preflight.sh non-destructively checks major ports (80 · 443 · 4949 · 4950) before installation.

9500 · 9501 · 9600 · 9601 are missing from the single line of ss above. Since batch/warehouse use those ports, please include them in the regular expression to see if those four are also empty.

Firewall Configuration Examples​

install.sh automatically configures the host firewall (firewalld / ufw). Below are examples for when you must manually allow ports in the upper firewall (corporate network, cloud security group, router).

firewalld (RHEL/Rocky/Oracle)​

# 외부 노출 (모든 IP)
for port in 80 443 4950; do
firewall-cmd --permanent --add-port=${port}/tcp
done

# 외부 노출 (TLS 메시징 / 설비)
for port in 1884 9094 11004 11005; do
firewall-cmd --permanent --add-port=${port}/tcp
done

# 사설망 only (RFC 1918 + Tailscale CGN 허용)
for src in 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 100.64.0.0/10; do
for port in 1883 5432 6379 7077 7233 7800 8233 8380 9000 9001 9042 9092 10000 10210 19001; do
firewall-cmd --permanent --add-rich-rule="rule family=ipv4 source address=${src} port port=${port} protocol=tcp accept"
done
done

firewall-cmd --reload

ufw (Ubuntu)​

# 외부 노출
for port in 80 443 4950 1884 9094 11004 11005; do
ufw allow ${port}/tcp
done

# 사설망 only
for port in 1883 5432 6379 7077 7233 7800 8233 8380 9000 9042 9092 10000 10210 19001; do
for src in 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 100.64.0.0/10; do
ufw allow from $src to any port $port
done
done

ufw enable

Verify Automatic Configuration​

# RHEL/Rocky/Oracle
sudo firewall-cmd --list-ports
sudo firewall-cmd --list-rich-rules

# Ubuntu
sudo ufw status numbered

Cloud Security Groups (e.g., AWS / GCP / Azure)​

In addition to the host firewall, cloud security groups must be configured identically.

Inbound RuleSourcePort
Operation Console0.0.0.0/0 (or Corp IP)80, 443
Health CheckMonitoring Node4950
MQTTDevice1883, 1884
OPC-UAEquipment11004, 11005
Kafka TLSExternal Client9094
Private NetworkVPC CIDR1883, 5432, 6379, 7077, 9042, 9092, 10000, 10210, …