Corrected in README.md, CLAUDE.md, 02-environment/README.md and 03-plc/VERSIONS.md. The @VERSION 1.03.00 header inside the .qli files is the quickload FILE FORMAT version, not the CI Server release. Left alone. This also sharpens a caveat that was previously stated wrongly. The EQP-E-DUP_ITEM rejection - an item import fails if two items share an IO_ADDRESS - was observed on 2026-08-14 on the DEVELOPMENT machine, which ran R1.03. Production runs R1.05, where it has never been tested. The design still works around it by publishing level and speed in % only, and that workaround costs nothing; but anyone wanting a second unit for a measurement should try it on R1.05 before assuming they need a second PLC register to carry it.
144 lines
6.5 KiB
Markdown
144 lines
6.5 KiB
Markdown
# 02-environment — where this runs and how to reach it
|
||
|
||
Two machines. One runs the PLC, the other runs the SCADA. Both sit on the
|
||
`10.0.0.0/24` PoC network.
|
||
|
||
| Role | Hostname | LAN | Notes |
|
||
|---|---|---|---|
|
||
| **SCADA** — Yokogawa CI Server R1.05 | `yau-poc-cicore1` | `10.0.0.21` | Windows. Polls the PLC over Modbus TCP. |
|
||
| **PLC** — OpenPLC Runtime v4 in Docker | `yau-sls-poc-lin001` | `10.0.0.17` | Ubuntu 22.04 on Azure, public IP `20.211.144.151`. **Shared, live host** — see below. |
|
||
|
||
Also on the network: an Active Directory domain controller at `10.0.0.5`
|
||
(`yau.poc`), and roughly a dozen other Windows hosts.
|
||
|
||
## ⚠️ The Linux host is shared, live, and not ours
|
||
|
||
`yau-sls-poc-lin001` is the YAU Innovation Team's general-purpose Docker host and
|
||
VPN gateway. It runs **~28 containers** for several unrelated projects — Grafana,
|
||
InfluxDB, Node-RED, Forgejo, Authelia, Portainer and more — behind a Caddy reverse
|
||
proxy with AD + Duo MFA. It serves customer-facing demos.
|
||
|
||
**`openplc-runtime` is one container among many, and this project owns only that
|
||
one.** Rules that follow from it:
|
||
|
||
- **Never restart Caddy or Authelia** — they interrupt every other service.
|
||
- **Never put growing data on the root disk** (`/` is 62 GB). Use `/datadisk`.
|
||
- **Never publish a container port on `0.0.0.0`.** The host has a public IP.
|
||
- Everyone shares the `azureuser` login, so there is no per-person audit trail —
|
||
**announce disruptive work.**
|
||
|
||
`YAU_Linux_Host_Onboarding.md` is the host's own brief, written by its owner
|
||
(Daniel Watson) and current as of 2026-09-01. **Read it before changing anything
|
||
on that machine.** Its §10 is a list of rules, each of which exists because
|
||
breaking it already caused an outage.
|
||
|
||
## Access
|
||
|
||
### The Linux host — SSH
|
||
|
||
```bash
|
||
ssh -i ~/.ssh/yau-sls-poc-lin001_key.pem azureuser@20.211.144.151
|
||
```
|
||
|
||
An SSH config alias makes this shorter. The working copy used during the audit:
|
||
|
||
```
|
||
Host lin001
|
||
HostName 20.211.144.151
|
||
User azureuser
|
||
IdentityFile ~/.ssh/yau-sls-poc-lin001_key.pem
|
||
IdentitiesOnly yes
|
||
```
|
||
|
||
`10.0.0.17` is **only routable from inside the VNet or over the WireGuard VPN** —
|
||
from outside, use the public IP.
|
||
|
||
### The CI Server host
|
||
|
||
No remote access route is recorded. It was reached interactively during
|
||
development. If you need one, ask.
|
||
|
||
### What you need from the host owner
|
||
|
||
| Item | What it is |
|
||
|---|---|
|
||
| `yau-sls-poc-lin001_key.pem` | SSH private key — `chmod 600` it or SSH refuses to use it |
|
||
| AD account in `HTTPS_UserAccess` | required for every web UI on the host |
|
||
| Duo enrolment | second factor for those UIs |
|
||
| A WireGuard peer | optional, but it is what makes `10.0.0.x` reachable directly |
|
||
|
||
## Ports
|
||
|
||
| Service | Host | Port | Bound to | Notes |
|
||
|---|---|---|---|---|
|
||
| OpenPLC **Modbus TCP server** | `10.0.0.17` | 502 | **`10.0.0.17` only** | The PLC is the Modbus *slave*. CI Server polls it. |
|
||
| OpenPLC **REST API** (HTTPS) | `10.0.0.17` | 8443 | **`10.0.0.17` only** | Control channel — upload, start/stop. JWT auth. No browser UI. |
|
||
| CI Server Modbus **client** | `10.0.0.21` | — | outbound | |
|
||
|
||
> [!IMPORTANT]
|
||
> **The bind address is the security control.** Modbus has no authentication or
|
||
> encryption, and 8443 is the control channel with only JWT in front of it. The
|
||
> host has a public IP, so binding these to `10.0.0.17` rather than `0.0.0.0` is
|
||
> the only thing keeping them off the internet. **Never widen it.**
|
||
|
||
**There is no host firewall.** `ufw` is inactive on `yau-sls-poc-lin001`; inbound
|
||
filtering is entirely the **Azure Network Security Group**. Opening a port means
|
||
editing the NSG in the Azure portal, not the host.
|
||
|
||
## Secrets
|
||
|
||
Live in **`secrets.local.md`**, which is git-ignored and must never be committed.
|
||
`secrets.local.md.template` shows the shape — copy it, fill it in, keep it local.
|
||
|
||
It holds the OpenPLC runtime `admin` password and CI Server credentials. The SSH
|
||
key is a file, not a line in that document, and is likewise never committed.
|
||
|
||
Host-level credentials (service admin passwords, API tokens for Grafana, Influx,
|
||
Authelia and so on) are **not this project's** — they live in the host owner's
|
||
`Linux Machine Config.txt`. Ask; do not copy them here.
|
||
|
||
## Files here
|
||
|
||
| File | What |
|
||
|---|---|
|
||
| `YAU_Linux_Host_Onboarding.md` | The Linux host's own brief — the stack, the auth model, the deployment pattern, and the rules. **Written and owned by the host owner, not by this project.** Current 2026-09-01. |
|
||
| `openplc-container.md` | How the PLC container is configured, as read from the running host |
|
||
| `openplc-compose.yml` | Verbatim copy of the live `~/openplc-compose.yml` |
|
||
| `MIGRATION.md` | Moving the PLC container to another host — the as-built record of the 2026-08-19 move, kept as a repeatable runbook |
|
||
| `secrets.local.md.template` | The shape of the git-ignored secrets file |
|
||
|
||
**Not kept here:** the host's full operations manual (`Host_Documentation.md`,
|
||
~400 lines covering ChirpStack, Forgejo, EQP licensing, the Telegraf fleet and the
|
||
rest of the platform). None of it is WRPS, it is owned elsewhere, and a stale copy
|
||
in this repo would be worse than a pointer. Ask the host owner for the current
|
||
version.
|
||
|
||
## Checking the environment is healthy
|
||
|
||
```bash
|
||
ssh lin001 "docker ps --filter name=openplc-runtime"
|
||
ssh lin001 "docker logs --tail 30 openplc-runtime"
|
||
ssh lin001 "df -h / /datadisk" # both disks - / is only 62 GB
|
||
```
|
||
|
||
From a machine that can route to `10.0.0.17` (VNet or VPN):
|
||
|
||
```bash
|
||
python ../05-tests/verify_modbus.py --host 10.0.0.17 --port 502 --unit 1
|
||
```
|
||
|
||
From anywhere else, poll from a throwaway container on the host's own network:
|
||
|
||
```bash
|
||
ssh lin001 "docker run --rm --network openplc-net python:3.12-alpine \
|
||
sh -c 'pip install -q pymodbus && python -c \"...\"'"
|
||
```
|
||
|
||
## Known issues
|
||
|
||
| Issue | Detail |
|
||
|---|---|
|
||
| **PLC scan overruns** | The 100 ms task overran ~100 times between 2026-08-19 and 2026-08-28 — roughly one per 4–5 days. Logged as a warning; the task runs at a reduced rate and the demo continues. Not investigated; the host is shared, so contention is a candidate. |
|
||
| **Migration artefacts left on the host** | `~/openplc-migration/` still holds `openplc-image.tar.gz` (354 MB) and `openplc-vol.tar.gz`. `MIGRATION.md` Part G says to delete them, and **the volume tarball contains the runtime's JWT secret.** |
|
||
| **The runtime image cannot be re-pulled** | It was produced by `docker commit` and exists in no registry. Deleting it loses the compiled PLC program. See `03-plc/as-built/`. |
|
||
| **No deployment toolchain** | The OpenPLC Editor lived only on the retired `dev-ubuntu` host. See `03-plc/DEPLOY.md` §0. |
|