Air-Gapped Installation
This section describes the installation procedure for a server on an air-gapped network (with no internet access) that is blocked from the internet. The process consists of three stages.
① 인터넷 되는 PC ② USB 등 이동 매체 ③ 폐쇄망 서버
번들 내려받기 → 반출 → 로드 → 설정 → 기동
무결성·서명 검증 (검증 자동 재확인)
The server specifications, ports, and firewall requirements are the same as those in the "Prerequisites" section of the Installation document. Please review that section first.
0. Preparing the Air-Gapped Server
The one-line installation script downloads Docker from the internet if it is not present — this path will not work in an air-gapped network. Please ensure Docker is installed beforehand.
docker --version
docker compose version # v2.22 이상
You can install it from the distribution's offline repository or using RPM/DEB packages. If you want to also perform signature verification, please bring in the cosign binary as well (optional — if it's not present, only the verification step will be skipped).
1. Downloading on an Internet-Connected Machine
There are four files to download.
| File | Description |
|---|---|
plantpulse-studio-images-<version>.tar.gz | Bundle of 5 container images (approx. 2.8 GB) |
…tar.gz.sha256 | Checksum for integrity verification |
…tar.gz.sig | Cosign signature for origin (signature) verification |
plantpulse-studio-docker.tar.gz | Operational package — bin/ script · compose · .env.example · cosign.pub |
BASE=https://product.kopens.io/plantpulse-studio
VER=2026.08 # 또는: VER=$(curl -fsSL $BASE/latest.txt)
# 번들은 수 GB — 전송이 끊기면 -C - 가 이어받습니다
curl -fLO -C - --retry 5 $BASE/plantpulse-studio-images-$VER.tar.gz
curl -fLO $BASE/plantpulse-studio-images-$VER.tar.gz.sha256
curl -fLO $BASE/plantpulse-studio-images-$VER.tar.gz.sig
curl -fLO $BASE/plantpulse-studio-docker.tar.gz
latest.txtlatest.txt is a one-line file containing only the name of the latest version (e.g., 2026.08). It is not a copy of the bundle, so the file you download will not change even if a new version is released.
Once a version is published, it is never deleted. Even if 2026.09 is released, plantpulse-studio-images-2026.08.tar.gz
remains available, so you can always use that address to re-download a version you were using or to roll back. If you have scripted your installation procedure, it is safer to specify the version directly instead of using latest.txt.
It contains six images — Studio server · web · session runtime · builder sidecar · Docker socket proxy, and PostgreSQL. There are no additional images you need to download for an air-gapped network.
The stack itself does not launch a PostgreSQL container (it uses an external PG). Since there may not be a suitable PG available in an air-gapped network, the image is included in the bundle so you can set up PG on-site if needed.
Integrity and Origin Verification (Before Transfer)
First, extract the operational package to retrieve the public key (cosign.pub).
mkdir -p pkg && tar xzf plantpulse-studio-docker.tar.gz -C pkg --strip-components=1
# ① 무결성 — 전송 중 파일이 깨지지 않았는가
sha256sum -c plantpulse-studio-images-$VER.tar.gz.sha256
# ② 출처 — KOPENS 가 서명한 번들이 맞는가
cosign verify-blob --key pkg/cosign.pub --insecure-ignore-tlog=true \
--signature plantpulse-studio-images-$VER.tar.gz.sig \
plantpulse-studio-images-$VER.tar.gz
--insecure-ignore-tlog is neededPer company registry policy, we do not use a public transparency log (Rekor). This option only skips the querying of the public log; the signature itself is still cryptographically verified.
It might be a CDN cache. Append ?v=$(date +%s) to the URL and download it again.
2. Transferring via Removable Media
Copy the four files below as-is to a USB drive, etc. Do not forget .sha256 and .sig —
the import-side script will automatically re-verify using these files.
plantpulse-studio-images-2026.08.tar.gz
plantpulse-studio-images-2026.08.tar.gz.sha256
plantpulse-studio-images-2026.08.tar.gz.sig
plantpulse-studio-docker.tar.gz
3. Importing on the Air-Gapped Server
3-1. Deploying the Operational Package
sudo mkdir -p /opt/kopens/plantpulse-studio-docker
sudo tar xzf /media/usb/plantpulse-studio-docker.tar.gz \
-C /opt/kopens/plantpulse-studio-docker --strip-components=1
cd /opt/kopens/plantpulse-studio-docker
mkdir -p dist
sudo cp /media/usb/plantpulse-studio-images-2026.08.tar.gz* dist/
3-2. Loading Images
sudo bash bin/load.sh dist/plantpulse-studio-images-2026.08.tar.gz
If load.sh is in the same folder as .sha256 and .sig, it will automatically verify them, and stop the import if they don't match.
✅ 서명 검증 통과
▶ 로드 중: dist/plantpulse-studio-images-2026.08.tar.gz
✅ 로드 완료 — cp .env.example .env 설정 후 bin/up.sh
If you see ⚠ 서명 검증 생략(.sig/cosign.pub/cosign 중 부재), it means one of the three is missing.
Please decide whether to proceed without verification according to your security policy — at the very least, it is recommended to pass the .sha256
integrity check.
3-3. Creating the Configuration File
cp .env.example .env
vi .env
chmod 600 .env
These are the items that must be adjusted for an air-gapped network.
| Item | Value | Reason |
|---|---|---|
REGISTRY | Leave empty (REGISTRY=) | If a value is set, it will attempt a registry pull on every startup, causing delays and warnings |
PP_IMAGE_TAG | Version of the imported bundle (2026.07) | Must match the loaded image tag |
DATABASE_URL | postgres://ppstudio:<password>@<호스트>:5432/ppstudio | External PG connection — the password is embedded in this URL |
PLATFORM_API_TARGET | On-site platform address | Target for real data and authentication delegation |
STUDIO_LOCAL_USERS | admin:<password> | First login account |
PP_LANG / PP_TZ | ko / Asia/Seoul | Korean on-site |
For AI and platform keys, refer to Secret Management and enter them in .env .
The DB and roles must be created beforehand — follow the "Database Preparation" section of Installation and bin/provision-platform-db.sh exactly.
3-4. Startup
bash bin/up.sh
ℹ️ REGISTRY 비어있음(로컬/에어갭) — pull 생략, 로컬 이미지 사용
⏳ 헬스 대기...
✅ PlantPulse Studio 시작됨 → http://192.168.x.x/
4. Installation Verification
bash bin/status.sh
bash bin/smoke-install.sh
smoke-install.sh checks the health, web response, actual login, session runtime image, and container status all at once. If all of them pass, the system is actually usable.
Access http://<server-ip>/ from a browser and log in with the STUDIO_LOCAL_USERS account.
The subsequent steps are the same as the "First Login" section of the Installation document.
5. Updating an Air-Gapped Environment
You can bring in a new version bundle using the same method, load it, and then restart.
cd /opt/kopens/plantpulse-studio-docker
bash bin/backup.sh # ① 먼저 백업
sudo cp /media/usb/plantpulse-studio-images-2026.08.tar.gz* dist/
sudo bash bin/load.sh dist/plantpulse-studio-images-2026.08.tar.gz # ② 새 이미지 로드
sed -i 's/^TAG=.*/TAG=2026.08/' .env # ③ 태그 변경
bash bin/restart.sh # ④ 재기동
To also update the operational script (bin/), extract the new plantpulse-studio-docker.tar.gz into a temporary folder and overwrite files, excluding .env and dist/ .
.env and dist/.env contains the platform address, account, and API keys, and dist/ contains local backups.
Overwriting them entirely will prevent the stack from starting or will result in loss of backups.
6. Backup and Restore in an Air-Gapped Network
The backup and restore scripts operate without internet access — this is because the postgres:18-alpine image required when using an external PostgreSQL is included in the import bundle.
bash bin/backup.sh # 백업
DRYRUN=1 bash bin/restore.sh # 복구 리허설(비파괴)
For more information, see Backup and Restore.
Next Steps
- Secret Management — Principle of keeping keys only in
.env - Domain and Reverse Proxy — Serving services with an internal domain and HTTPS
- Backup and Restore
- Troubleshooting