- 리슨 포트: **9090** (유닛의 `Environment=PORT=` 로 변경 가능)
- 앱은 기본적으로 `:9090`에서 직접 서비스됩니다. nginx `:80` reverse proxy는 optional이며, `deploy/nginx.conf`는 BSP가 필요할 때 쓰는 sample 설정입니다.
- 영속 상태 — **패키지에 없음**(런타임/다른 컴포넌트가 생성):
- DB: `/home/root/db/dynamic_data.db` (`DB_PATH`)
- 로그: `/opt/log/dpworldapp` (`LOG_DIR`)
> **nginx optional**: `scripts/deploy.ps1`는 nginx 설정을 설치하거나 수정하지 않습니다. BSP에서 `deploy/nginx.conf`를 사용할 때만 이미지 레이아웃에 맞게 설치하고, Python 앱 단독 프록시라면 `proxy_pass`를 `http://127.0.0.1:9090/` 로 맞추세요.
- 네트워크 apply 사용 시 (**권장 = 직접 교체**): `deploy/dpworld-network-apply-hardened.sh` 의 내용을 **`/usr/bin/dpworld-network-apply.sh` 원본 이름으로 설치**(펌웨어 base 스크립트 교체). firmware-native base 유닛(`dpworld-network-apply.service`/`dpworld-network-seed.service`)이 그 경로를 호출하므로 자동 적용됨. **이 방식에서는 `20-hardened.conf` ExecStart override 드롭인은 설치하지 않습니다** (`scripts/deploy.ps1` 라이브 후적용 fallback 전용 — §7, `docs/firmware-boot-hardening.md`). 단, 온디맨드 apply 는 웹이 `systemctl start dpworld-network-apply.service` 로 호출하는데, boot-seed `Requires=` 가 seed(boot-only oneshot)를 `--boot` 모드로 재트리거합니다. seed 도 하드닝본이라 드롭인이 없어도 안전 통과하여 `systemctl start` 는 성공하지만(필수 아님), 그 불필요한 `seed --boot` 재실행을 회피하려면 **`10-ondemand.conf` 드롭인 베이킹을 권장**합니다(완화 overlay) — `deploy/dpworld-network-apply-ondemand.conf` 를 `/lib/systemd/system/dpworld-network-apply.service.d/10-ondemand.conf` 로 설치(§7, 아래 참고).
- Wi-Fi AP 사용 시: `deploy/dpworld-ap-apply.service`, `deploy/dpworld-ap-seed.service`, `deploy/dpworld-hostapd-ap0.service`, `deploy/dpworld-udhcpd-ap0.service`, `deploy/dpworld-ap-apply.sh`를 함께 설치
- 복구 유닛 사용 시: `deploy/dpworld-net-recover.service` 설치
`dpworld-ap-apply.service`와 `dpworld-net-recover.service`는 웹 설정기/watchdog이 on-demand로 `systemctl start` 하므로 `[Install]` 없이 설치만 하면 됩니다. `dpworld-network-apply.service`/`dpworld-network-seed.service`는 firmware-native base 유닛이며 `/usr/bin/dpworld-network-apply.sh` 를 호출합니다 — 본 패키지는 **그 base 스크립트를 하드닝본으로 교체**합니다(권장, §7). (펌웨어 원본을 교체할 수 없는 라이브 디바이스에서는 `.service.d` override 드롭인이 fallback.)
| | ① 직접 교체 (BSP 베이킹, **권장**) | ② override (라이브 후적용, fallback) |
|---|---|---|
| 대상 | 펌웨어 이미지를 빌드하는 협력사 | 이미 구워진 디바이스(우리 `deploy.ps1`) |
| 방법 | 하드닝본 내용을 **`/usr/bin/dpworld-network-apply.sh` 원본 이름**으로 설치(원본 교체) | 하드닝본을 `…-hardened.sh` 로 두고 `.service.d/20-hardened.conf` 드롭인 2개로 ExecStart 교체 |
> **온디맨드 드롭인 `10-ondemand.conf` (권장 bake — OPTIONAL 완화, 필수 아님)**: web-configurator/watchdog 는 온디맨드 네트워크 적용을 `systemctl start dpworld-network-apply.service` 로 호출합니다. 이 base 유닛은 `Requires=dpworld-network-seed.service`(boot-only oneshot)를 걸어 온디맨드 start 시 seed 를 `--boot` 로 재트리거하지만, seed 도 하드닝본이라 드롭인이 없어도 안전 통과합니다(systemctl start 성공, 'Dependency failed' 0). 이 드롭인은 `Requires=` 를 비워 그 불필요한 `seed --boot` 재실행만 회피하는 완화 overlay 입니다. `deploy/dpworld-network-apply-ondemand.conf` → `/lib/systemd/system/dpworld-network-apply.service.d/10-ondemand.conf` 로 설치(①·② 양쪽 모두 권장).
>
> **참고 (2026-07-01 .56 실측)**: 이 드롭인은 현재 .56 이미지에 미baked. 없어도 `systemctl start dpworld-network-apply.service` 는 성공함(Requires=seed 로 seed --boot 가 재트리거되나 seed 도 하드닝본이라 안전 통과). 다만 매 런타임 apply 마다 seed --boot 가 재실행되는 부수효과가 있어, 이 드롭인(또는 seed RemainAfterExit=yes) baking 이 권장됨.
> fallback(②) 사용 시에는 `…-hardened.sh` 이름으로 설치하고 `.service.d` 드롭인 2개(`deploy/dpworld-network-apply.service.d/`, `deploy/dpworld-network-seed.service.d/`)를 함께 둡니다.