Skip to main content

env Environment Configuration — env.sh / PPLANG / CERTPASS / -Dpe.conf.dir

Default passwords must be changed for customer deployments

The passwords shown in this document (CERT_PASS and the like) are defaults for the in-house dev box and are not secrets. Do not use them as-is in customer or production deployments:

  • install.sh generates a 14-character random value when CERT_PASS is not specified (bin/install.sh:298). The generated value is written to /etc/kopens/credentials.txt (0600, root) and to the factory label.
  • Change the box OS login password at installation time as well.
  • The defaults in this document are therefore valid only for a single in-house dev box.

PlantPulse Edge configuration is split into two layers.

LayerWhatWhere
Environment variables (env) ← this pageLanguage/time zone, JDK path, TLS password, data paths, site values set at install timeenv.sh / /etc/kopens/*.env / systemd / docker -e
Application settings (properties)Runtime keys such as edge.id / cassandra.* / mqtt.* / OPC-UAapp.propertiesapp.properties guide

Once the env layer determines the language, time zone, JVM options, passwords, and configuration directory location, app.properties runs on top of it. These are values you set once per box and rarely change.


1. Key env variables at a glance

VariableMeaningDefault
PP_LANGUI/OS/JVM language (BCP 47) — one language per boxen
PP_TZTime zone (java.util.TimeZone ID)Asia/Seoul
JAVA_HOMEJDK path (class file 65 → JDK 21)/usr/lib/jvm/java-21-openjdk
PE_HOMEGateway root/opt/kopens/plantpulse-edge
PE_DATA_DIRData directory (Cassandra/Redis/HiveMQ/Node-RED)/data1
CERT_PASSTLS keystore password (shared by Tomcat/HiveMQ/OPC-UA)kopens123! (legacy) / random at install time
CLEAN_ON_STARTUPWhether to clean work/temp at bootfalse
JAVA_TOOL_OPTIONSOptions common to all JVMs (entrypoint/setenv.sh injects language/time zone)(auto-configured)
Never leave secrets in argv, logs, or shell history

CERT_PASS / SERVER_API_KEY and any password must not be exposed in shell history, ps argv, or logs. Use *_FILE injection (e.g. EDGE_ADMIN_PASSWORD_HASH_FILE, CASSANDRA_PASSWORD_FILE) or source a root 0600 file before running the installation. Random credentials generated by install.sh are stored once in /etc/kopens/credentials.txt (chmod 0600 root).


2. Language / time zone — PP_LANG / PP_TZ

PlantPulse enforces a single language and time zone per box. Per-user cookies and Accept-Language are ignored; the webapp, host OS, container OS, and JVM all use the same values.

PP_LANG=en PP_TZ=Asia/Seoul # 글로벌 default (영문 UI + 한국 시간)
PP_LANG=ko PP_TZ=Asia/Seoul # 완전 한국 박스
PP_LANG=en PP_TZ=UTC # 완전 영문 박스

2.1 Propagation chain (4 layers)

env.sh / i18n.env ─→ install.sh ─→ systemd EnvironmentFile + docker -e ─→ container-entrypoint.sh ─→ webapp PpFixedLocaleResolver
(값 정의) (host locale) (PP_LANG / PP_TZ 주입) (OS LANG/TZ + JAVA_TOOL_OPTIONS) (UI 언어 결정)

2.2 What the entrypoint does in a container

container-entrypoint.sh maps PP_LANG to a POSIX locale and builds the JVM options:

PP_LANG="${PP_LANG:-en}"; PP_TZ="${PP_TZ:-Asia/Seoul}"

case "$PP_LANG" in
ko|ko_*|ko-*) LANG=ko_KR.UTF-8 ; lang=ko country=KR ;;
en|en_*|en-*) LANG=en_US.UTF-8 ; lang=en country=US ;;
esac
export LANG TZ="$PP_TZ"
ln -sf "/usr/share/zoneinfo/$PP_TZ" /etc/localtime

# 모든 JVM 프로세스 통일
export JAVA_TOOL_OPTIONS="$JAVA_TOOL_OPTIONS -Duser.language=$lang -Duser.country=$country -Duser.timezone=$PP_TZ"

The values are also written to /etc/locale.conf, /etc/environment, and /etc/timezone, so they persist across re-logins and tool invocations.

PpFixedLocaleResolver resolves once at boot — no runtime change

The language is determined once at boot and cannot be changed via cookies or Accept-Language. Toggling ko↔en requires changing PP_LANG and restarting the container/Tomcat.

2.3 LOCALE in native mode (setenv.sh)

In native mode, LOCALE in server/bin/setenv.sh must be dynamic — there was a case where the old hardcoded -Duser.language=ko -Duser.country=KR took precedence over JAVA_TOOL_OPTIONS and ko won.

# server/bin/setenv.sh
LOCALE="-Duser.language=${PP_LANG:-en} -Duser.country=${PP_COUNTRY:-US} -Duser.timezone=${PP_TZ:-Asia/Seoul}"

Then add export PP_LANG / export PP_TZ / export JAVA_HOME=/usr/lib/jvm/java-21-openjdk to conf/env.sh.


3. native conf/env.sh

This is the environment file for a native box. bin/start.sh sources it before startup.

# $PE_HOME/conf/env.sh
export PE_HOME=/opt/kopens/plantpulse-edge
export PE_DATA_DIR=/data1
export JAVA_HOME=/usr/lib/jvm/java-21-openjdk # JDK 21 — class file 65 호환 (필수)
export PP_LANG="${PP_LANG:-en}"
export PP_TZ="${PP_TZ:-Asia/Seoul}"
export CLEAN_ON_STARTUP=false
KeyMeaning
PE_HOMEGateway root (base path for scripts)
PE_DATA_DIRSeparate data directory (usually a dedicated partition /data1)
JAVA_HOMEUnsupportedClassVersionError if JDK 21 is not specified
PP_LANG / PP_TZLanguage / time zone (see section 2)
CLEAN_ON_STARTUPClean work/temp at boot

For the full native installation layout, see Native installation.


4. Container /etc/kopens/*.env (systemd EnvironmentFile)

On a container box, the systemd unit reads the following files as EnvironmentFile and injects them as docker -e. If a file exists, it overrides the unit's built-in defaults.

FileKeyCreated byPurpose
/etc/kopens/version.envPE_VERSION=<tag>OTA upgrade.shPins the image tag — OTA/rollback changes only this one line
/etc/kopens/i18n.envPP_LANG / PP_TZinstall.shLanguage / time zone
/etc/kopens/cert.envCERT_PASSTLS issuance scriptKeystore password
# plantpulse-edge.service (발췌)
EnvironmentFile=-/etc/kopens/version.env
EnvironmentFile=-/etc/kopens/i18n.env
EnvironmentFile=-/etc/kopens/cert.env
Environment=PE_VERSION=latest
Environment=KOPENS_IMAGE=docker.kopens.io/pe/plantpulse-edge
Environment=PP_LANG=en
Environment=PP_TZ=Asia/Seoul
Environment=CERT_PASS=kopens123!

To change the language:

sudo tee /etc/kopens/i18n.env <<'EOF'
PP_LANG=ko
PP_TZ=Asia/Seoul
EOF
sudo systemctl restart plantpulse-edge.service

For a full breakdown of the systemd unit, see Docker installation §4.


5. Configuration directory location — -Dpe.conf.dir

This is the key env/system property that determines where app.properties and log4j2.xml are read from. In WAR mode (2026-06-13 onward), configuration is read directly from the host /etc/kopens — no image or batch rebuild is required.

Mode-Dpe.conf.dirCanonical file
Container/opt/kopens/plantpulse-edge/conf (= host /etc/kopens/conf bind-mount)/etc/kopens/app.properties
native$PE_HOME/conf$PE_HOME/conf/app.properties
  • Container: the host /etc/kopens/conf/app.properties is the real file and the source of truth. /etc/kopens/app.properties is a legacy-compatibility symlink pointing to it (ln -sfn /etc/kopens/conf/app.properties /etc/kopens/app.properties).
  • log4j2.xml is a code artifact — the entrypoint copies it from the webapp default at every boot (change the log level and restart to apply; no image rebuild needed).

For the configuration keys themselves (what to write), see the app.properties guide and the Environment configuration screen. This page covers where and how those files are read.


6. env overrides at install.sh time

At installation time, site values, network settings, and credentials for the box are injected as env vars (install.sh reflects them into app.properties).

sudo PROFILE=production \
EDGE_ID=EDGE_00303 \
SITE_ID=SITE_00001 \
SERVER_HOST=192.168.0.41 \
SERVER_API_KEY='<platform-api-key>' \
PP_LANG=en PP_TZ=Asia/Seoul \
CERT_PASS='<keystore-pass>' \
bash install.sh
VariableMeaningDefault
PROFILEproduction / staging / standalone / airgap preset
EDGE_IDBox-unique ID (^EDGE_[A-Z0-9_]{1,60}$)Auto-generated from MAC
SITE_IDSite ID (required for platform registration)SITE_00001
DEV_MODEEDGE (platform connected) / STANDALONE (not connected)EDGE
SERVER_HOST / SERVER_API_KEYPlatform API integration (required in EDGE mode)
PP_LANG / PP_TZLanguage / time zoneen / Asia/Seoul
ADMIN_PASS / API_KEY / MQTT_PASS / OPCUA_PASSInitial credential overridesRandom per box
CERT_PASSTLS keystore passwordkopens123! (legacy) / random
CERT_DOMAIN / CERT_SAN_DNS / CERT_SAN_IPCertificate CN / SANplantpulse.io / automatic
NET1_IFACE / NET2_IFACE …, NET2_IP / NET2_GATEWAY / NET2_DNSNIC mapping / static IPAuto-detected / DHCP
IMAGE_TAGPin the docker image taglatest
SKIP_PULL=1Skip docker pull (air-gapped/re-run)0
SKIP_COSIGN_VERIFY=1Skip image signature verification0 (staging/standalone 1)

dev.mode accepts both EDGE and STANDALONE; only PLATFORM is rejected. With STANDALONE, the SERVER_HOST / SERVER_API_KEY prompts are skipped (server.host blank → DiagnosticSender init skipped).


7. JVM heap env (container)

envComponentDefaultOverride example
HIVEMQ_HEAPHiveMQ-Xms2g -Xmx2g1g
CASSANDRA_HEAPCassandraauto based on host /proc/meminfo (~1/4)1g
TOMCAT_HEAPTomcat-Xms2g -Xmx2g1g

The drop-in override for an 8GB box (override.conf) is described in Container mode §Resource limits.


8. Applying changes

What you changedHow to apply
PP_LANG / PP_TZ (i18n.env / env.sh)Restart the container/Tomcat (locale is resolved once at boot)
CERT_PASS (cert.env)Restart the container (the entrypoint re-patches the keystore password)
PE_VERSION (version.env)systemctl restart plantpulse-edge.service
app.properties (container)config.sh --set … && config.sh --restart
app.properties (native)vi conf/app.propertiesbin/restart.sh (~6 s)
The env layer ≠ app.properties

Writing PP_LANG in app.properties has no effect — the language is determined by the env layer (env.sh / i18n.env). Conversely, runtime keys such as cassandra.host belong in app.properties, not in env.


9. Common pitfalls

SymptomCause / fix
UI language does not changeWritten in app.properties, or no restart. Edit i18n.env (container) / env.sh (native) and restart
ko keeps winning on nativeLOCALE in setenv.sh is hardcoded. Make ${PP_LANG} dynamic (see 2.3)
UnsupportedClassVersionErrorJAVA_HOME is not JDK 21
OPC-UA keystore password errorCERT_PASS in cert.env does not match the opc.ua.server.keystore.password=${ENV:CERT_PASS:} mirror
Password exposed in ps/logsUse *_FILE or source a root 0600 env file instead of argv
Configuration changes not appliedThe canonical file pointed to by -Dpe.conf.dir was not edited (container = /etc/kopens, native = $PE_HOME/conf)

10. Next documents