Skip to main content

Environment Variable Configuration

Default passwords must be changed during customer deployment

Passwords appearing in this document (such as CERT_PASS) are defaults for internal dev boxes and are not secret. Do not use them as-is in customer or mass production deployments:

  • install.sh generates a random 14-character string if CERT_PASS is not specified (bin/install.sh:298). The generated value is recorded in /etc/kopens/credentials.txt (0600, root) and the factory label.
  • The box OS access password is also changed during installation.
  • Therefore, the default values in this document are only valid for a single internal dev box.

PlantPulse Edge configuration is divided into two layers.

LayerWhatWhere
Environment Variables (env) ← This pageLanguage/timezone, JDK path, TLS password, data path, site values during installationenv.sh / /etc/kopens/*.env / systemd / docker -e
Application Settings (properties)edge.id / cassandra.* / mqtt.* / OPC-UA runtime keys, etc.app.properties → app.properties Reference

Once the env layer determines the language, timezone, JVM options, passwords, and configuration directory locations, app.properties operates on top of it. These are values that are set once per box and rarely change.


Value Determination Order​

env.sh is the single source that all installation, upgrade, and startup scripts source. If the same variable exists in multiple locations, the first one defined wins — because the shell's ${VAR:-기본값} only triggers «when the variable is missing».

OrderWhereWhat
1/etc/kopens/env.sh.generatedSidecar created once by install.sh. API_KEY · ADMIN_PASS · MQTT_PASS · OPCUA_PASS · CERT_PASS. 0600 root
2${VAR:-기본값} within env.shDefault values declared in the file
3Operator export lines at the end of env.shThe last one written wins
The sidecar is between the default value and the operator

Secrets created during installation are preserved even if you run install.sh again (because step 1 is determined first). If an operator wants to force a value, they can add a line of export at the end of env.sh.

Deleting the sidecar and reinstalling will generate new credentials

If you run install.sh again after deleting /etc/kopens/env.sh.generated, passwords and API keys are regenerated. This will cause a mismatch with the API keys registered on the upper Platform, stopping collection — check /etc/kopens/credentials.txt before deleting.


1. Core env Variables at a Glance​

VariableMeaningDefault
PP_LANGUI/OS/JVM Language (BCP 47) — Single language per boxen
PP_TZTimezone (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 (Common for Tomcat/HiveMQ/OPC-UA)Randomly generated during installation
CLEAN_ON_STARTUPWhether to clear work/temp upon bootingfalse
JAVA_TOOL_OPTIONSCommon options for all JVMs (entrypoint/setenv.sh injects language/timezone)(Auto-configured)
Do not leave secrets in argv/logs/history

CERT_PASS / SERVER_API_KEY / various passwords must not be exposed in shell history, ps argv, or logs. Run installation after injecting via *_FILE (e.g., EDGE_ADMIN_PASSWORD_HASH_FILE, CASSANDRA_PASSWORD_FILE) or sourcing a root 0600 file using source. Random credentials generated by install.sh are stored once in /etc/kopens/credentials.txt (chmod 0600 root).


2. Language / Timezone — PP_LANG / PP_TZ​

PlantPulse enforces a single language/timezone per box. User-specific cookies / Accept-Language are ignored, and the webapp + host OS + container OS + JVM all use the same value.

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 layer)​

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 the container​

container-entrypoint.sh maps PP_LANG to POSIX locale and configures 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"

These are also recorded in /etc/locale.conf, /etc/environment, and /etc/timezone to be maintained during re-login or tool calls.

PpFixedLocaleResolver is boot-once — no runtime changes

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

2.3 LOCALE in native mode (setenv.sh)​

In native mode, the LOCALE of server/bin/setenv.sh must be dynamic — there were cases where the old hardcoded -Duser.language=ko -Duser.country=KR took precedence over JAVA_TOOL_OPTIONS, causing ko to win.

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

And in conf/env.sh: export PP_LANG / export PP_TZ / export JAVA_HOME=/usr/lib/jvm/java-21-openjdk.


3. native conf/env.sh​

This is the environment file for the 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 (Path based on script)
PE_DATA_DIRData Separation Directory (Usually separate partition /data1)
JAVA_HOMEJDK 21 (If unspecified, defaults to UnsupportedClassVersionError)
PP_LANG / PP_TZLanguage / Timezone (See Chapter 2 above)
CLEAN_ON_STARTUPClear work/temp upon booting

For the overall native installation structure, refer to the installation guide.


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

In container boxes, the systemd unit reads the following files as EnvironmentFile and injects them as docker -e. If a file exists, it overrides the default values embedded in the unit.

FileKeyCreatorPurpose
/etc/kopens/version.envPE_VERSION=<tag>OTA upgrade.shFixes image tag — OTA/rollback changes only this line
/etc/kopens/i18n.envPP_LANG / PP_TZinstall.shLanguage / Timezone
/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 Locations — -Dpe.conf.dir​

These are core env/system properties that determine where to read app.properties and log4j2.xml. In WAR mode (2026-06-13~), configurations are read directly from the host /etc/kopens — no image/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: Host /etc/kopens/conf/app.properties is the actual file and source-of-truth. /etc/kopens/app.properties is a 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 upon each boot (changes are reflected by changing only the log level and restarting; no image rebuild needed).

For the configuration keys themselves (what to write), see the app.properties Reference and Web UI System Configuration. This page covers where and how those files are read.


6. env override during install.sh installation​

Box site values, networks, and credentials are injected as env variables at the time of installation (install.sh is reflected in 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_IDUnique Box ID (^EDGE_[A-Z0-9_]{1,60}$)Auto-generated based on MAC
SITE_IDSite ID (Required for Platform registration)SITE_00001
DEV_MODEEDGE (Connected to Platform) / STANDALONE (Not connected)EDGE
SERVER_HOST / SERVER_API_KEYPlatform API Integration (Required for EDGE mode)—
PP_LANG / PP_TZLanguage / Timezoneen / Asia/Seoul
ADMIN_PASS / API_KEY / MQTT_PASS / OPCUA_PASSInitial credential overrideRandom per box
CERT_PASSTLS keystore passwordRandomly generated during installation
CERT_DOMAIN / CERT_SAN_DNS / CERT_SAN_IPCertificate CN / SANplantpulse.io / Auto
NET1_IFACE / NET2_IFACE …, NET2_IP / NET2_GATEWAY / NET2_DNSNIC Mapping / static IPAuto-detect / DHCP
IMAGE_TAGFix docker image taglatest
SKIP_PULL=1Skip docker pull (airgap/re-run)0
SKIP_COSIGN_VERIFY=1Skip image signature verification during installation. This does not apply to OTA upgrades0 (staging/standalone 1)

dev.mode supports both EDGE and STANDALONE, and only rejects PLATFORM. During STANDALONE, the SERVER_HOST / SERVER_API_KEY prompts are skipped (server.host blank → DiagnosticSender init skip).


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

Drop-in overrides for 8GB boxes (override.conf) are located in Container Mode Resource Limits.


8. Applying Changes​

Changed ItemHow to Apply
PP_LANG / PP_TZ (i18n.env / env.sh)Restart Container/Tomcat (locale is boot-once)
CERT_PASS (cert.env)Restart Container (entrypoint re-patches 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.properties → bin/restart-app.sh (App only, 30~90s)
env layer ≠ app.properties

Writing PP_LANG in app.properties will not apply it — language is determined by the env layer (env.sh / i18n.env). Conversely, runtime keys like cassandra.host should be written in app.properties, not env.


9. Common Pitfalls​

SymptomCause / Solution
UI language does not changeWritten in app.properties or no restart. Restart after modifying i18n.env (container)/env.sh (native)
ko continues to win in nativesetenv.sh LOCALE is hardcoded. Make it dynamic (${PP_LANG}, see 2.3 above)
UnsupportedClassVersionErrorJAVA_HOME is not JDK 21
OPC-UA keystore password errorMismatch between CERT_PASS and opc.ua.server.keystore.password=${ENV:CERT_PASS:} mirror in cert.env
Password exposed in ps/logsSource root 0600 env file or use *_FILE instead of argv
Configuration changes not reflectedDid not fix the canonical file pointed to by -Dpe.conf.dir (Container=/etc/kopens, native=$PE_HOME/conf)

10. Next Documents​