Deploying a lab¶
Packages and extras¶
Python 3.11 or newer is required. One wheel serves every role; extras select the additional dependencies:
| Install | Adds | Used on |
|---|---|---|
pip install labnet |
Client library | Client computers |
pip install "labnet[lab-pc]" |
FastAPI, Uvicorn, gRPC health | Lab PCs |
pip install "labnet[central]" |
FastAPI, SQLAlchemy, Alembic, Uvicorn | Central |
pip install "labnet[central,postgres]" |
+ psycopg | Central with PostgreSQL |
pip install "labnet[certs]" |
cryptography | The computer that issues certificates |
pip install labnet-control-center |
FastAPI, Uvicorn, pypdf, the watchdog | The Control Center (on the Central computer) |
pip install "labnet[driver-dev]" |
grpcio-tools | Writing a driver package (labnet driver build) |
uv sync (repository root) |
Every package, editable, plus pytest and import-linter | Development |
Production hosts install a reviewed bundle, never an editable checkout. In
practice labnet update creates each role's virtual environment and
installs the wheels for you.
Production deployment¶
This walkthrough uses four Windows computers on one private LAN. All addresses are static and all connections use raw IP addresses; no DNS service is assumed.
| Computer | Static IP | Runs | Required inbound traffic |
|---|---|---|---|
development_pc |
192.168.50.40 |
repository clone, labnet-certs, labnet bundle |
only the chosen file-transfer method |
central_server_pc |
192.168.50.10 |
labnet-central behind Caddy |
TCP 443 from Lab PCs and clients |
lab_pc_1 |
192.168.50.20 |
labnet-lab-pc |
TCP 50051 from approved clients |
client |
192.168.50.30 |
experiment scripts | none |
Exclude each address from DHCP, or reserve it for that computer. The
certificates contain the server IPs, so changing a server's IP requires a new
certificate. Each runtime computer needs Python 3.11 (py -3.11 in
PowerShell).
1. Prepare development_pc¶
Clone the repository and create the development environment:
git clone https://github.com/mill0851/labnet && cd labnet
uv sync
The TLS model¶
TLS gives two things: encryption on the wire, and proof that a client reached the intended server. LabNet uses the minimum set of certificates for that:
- One private CA. Its private key
labnet-ca.keysigns certificates and never leaves the signing computer. Its public certificatelabnet-ca.pemis copied everywhere something must be verified. - One server certificate per server:
central.crtwithcentral.keyfor Central (read by Caddy), andlab-pc-01.crtwithlab-pc-01.keyfor each Lab PC (read bylabnet-lab-pc). Each lists, as its subject alternative name, the exact IP clients dial. - No client certificates. Users and Lab PCs prove who they are with API keys, and leases decide what they may do. TLS only secures and authenticates the connection.
| Computer | Files it holds | Why |
|---|---|---|
development_pc (or protected offline storage) |
labnet-ca.key, labnet-ca.pem |
Issues certificates |
| Central | central.crt, central.key |
Caddy presents Central's identity |
| Lab PC | lab-pc.crt, lab-pc.key, labnet-ca.pem |
Presents its identity; trusts Central |
| Client | labnet-ca.pem |
Trusts Central and every Lab PC |
.pem and .crt files are public. .key files are secret, and only the
server that uses a key should receive it. Never copy labnet-ca.key to
Central, a Lab PC, a client, a release share, or the repository.
Create the certificates¶
labnet-certs init-ca --dir C:\LabNet-CA # prompts for a passphrase for labnet-ca.key
labnet-certs issue central --ip 192.168.50.10 --dir C:\LabNet-CA
labnet-certs issue lab-pc-01 --ip 192.168.50.20 --dir C:\LabNet-CA
labnet-certs show C:\LabNet-CA\lab-pc-01.crt --ca C:\LabNet-CA\labnet-ca.pem
init-ca creates a ten-year CA. Store its passphrase in the lab's secret
manager: losing it makes the CA unusable, and leaking it together with the key
lets anyone issue trusted certificates. issue signs a one-year server
certificate (--days changes this; repeat --ip/--dns for more names) and
refuses to overwrite existing files. show prints the names and validity
dates and verifies the signature. Use it before copying anything.
Stage the server files on encrypted removable media or another approved
transfer location (for example E:\LabNet-TLS). Remove the server keys from
there once deployed. Afterwards, keep C:\LabNet-CA in encrypted offline
storage and restore it only to issue or renew a certificate.
On each server, restrict its .key file: open Properties → Security →
Advanced, disable inheritance, and leave only Administrators plus the
account that runs Caddy or the Lab PC, with read access.
Renewal: issue a replacement with labnet-certs issue <name> --ip … --force,
deploy it, and restart Caddy or the Lab PC. The CA stays unchanged.
Exposure: if a server key may have leaked, issue a replacement at once.
This minimal CA has no revocation list, so an organizational PKI is the better
choice when revocation or many identities are needed. If the CA key leaks,
create a new CA and redistribute labnet-ca.pem before reissuing every server
certificate.
Build the release¶
# set version = "x.y.z" in every packages/*/pyproject.toml and commit, then:
labnet bundle --site sites/pqt # --driver <folder> for each driver package; --no-dependencies to use PyPI
The bundle dist/labnet-x.y.z-pqt/ (git-ignored) holds the wheels (LabNet,
the Control Center, the drivers, and every dependency), site-pqt.zip (the
lab's configuration from sites/pqt/), and MANIFEST.json with the SHA-256
of each file. Copy it to a restricted, read-only share such as
\\192.168.50.40\LabNet-Releases\x.y.z. The hashes detect wrong or
damaged files; controlling who can write to the share is what keeps them
trustworthy.
A wheel is an installable package archive. It does not contain settings,
keys, certificates, or databases; labnet bundle refuses a site folder that
holds any.
Installing from the bundle¶
Every computer installs its role with the bundle's install.ps1, which
needs only Python 3.11 and its py launcher:
$install = '\\192.168.50.40\LabNet-Releases\x.y.z\install.ps1'
powershell -ExecutionPolicy Bypass -File $install -Role <central|control-center|lab-pc|client>
It checks the bundle, installs labnet from it into a temporary environment,
and runs labnet update from there, which refuses while the role runs, builds
C:\ProgramData\LabNet\venvs\<role>-x.y.z-<time>, checks it, and only then
points C:\ProgramData\LabNet\<role>-venv at it. -ExecutionPolicy Bypass
applies to that one run (Windows otherwise refuses unsigned scripts from a
share). The steps below use $install from this block.
2. Set up central_server_pc¶
- Certificates. Copy
central.crtandcentral.keytoC:\ProgramData\LabNet\certs\. - Settings. Create
C:\ProgramData\LabNet\central.envfromsites/pqt/central.env.example:
LABNET_DATABASE_URL=sqlite:///C:/ProgramData/LabNet/Central/labnet.db
LABNET_CENTRAL_BIND_HOST=127.0.0.1
LABNET_CENTRAL_BIND_PORT=8008
- Install. This verifies the bundle, creates
C:\ProgramData\LabNet\central-venv, and creates the database schema.
powershell -ExecutionPolicy Bypass -File $install -Role central
- Users and their settings files, in one command:
$admin = "C:\ProgramData\LabNet\central-venv\Scripts\labnet-central-admin.exe"
& $admin --env-file C:\ProgramData\LabNet\central.env setup `
--admin central-admin --user researcher --lab-pc lab-pc-01 `
--write-env C:\LabNet-Keys `
--server-url https://192.168.50.10 `
--ca-file C:/ProgramData/LabNet/certs/labnet-ca.pem
This writes C:\LabNet-Keys\lab-pc-01.env and researcher.env (and
central-admin.env), each with its new API key, Central's URL, and the CA
path. Central keeps only key hashes, so these files are the only copy:
- move lab-pc-01.env to lab_pc_1 and researcher.env to the client
over the secure transfer;
- keep central-admin.env for administration;
- then delete C:\LabNet-Keys.
Running setup again later only creates missing users.
- Start Central by hand in its own PowerShell window, and leave that window open (it listens on loopback only):
C:\ProgramData\LabNet\central-venv\Scripts\labnet-central.exe --env-file C:\ProgramData\LabNet\central.env
Invoke-RestMethod http://127.0.0.1:8008/health/ready
- HTTPS with Caddy. Install Caddy and save
C:\ProgramData\LabNet\Caddyfile:
https://192.168.50.10 {
tls C:/ProgramData/LabNet/certs/central.crt C:/ProgramData/LabNet/certs/central.key
reverse_proxy 127.0.0.1:8008
}
Validate it with caddy validate --config C:\ProgramData\LabNet\Caddyfile,
then start it by hand in a second window with
caddy run --config C:\ProgramData\LabNet\Caddyfile. Caddy loads the certificate and key with its
tls directive
and forwards to Central with
reverse_proxy.
Central's private key never touches the Python process.
sites/pqt/Caddyfile.example is the whole file,
with the Control Center's site and its logins added (see
Control Center).
- Firewall. Allow inbound TCP 443 from the Lab PCs and approved clients. Never open port 8008.
- Control Center. The web interface runs on this same computer; see Control Center for its setup.
- Safe-state watchdog. Applies an Automation grant's safe state if the
Control Center dies mid-grant; see
The safe-state watchdog for its user,
watchdog.envand how to start it.
3. Set up each Lab PC¶
- Certificates. Copy
lab-pc-01.crt→C:\ProgramData\LabNet\certs\lab-pc.crt,lab-pc-01.key→…\lab-pc.key, andlabnet-ca.pem→…\labnet-ca.pem. - Settings. Rename the transferred
lab-pc-01.envtoC:\ProgramData\LabNet\lab-pc.envand add the lines fromsites/pqt/lab-pc.env.example:
# from setup --write-env
LABNET_LAB_PC_ID=lab-pc-01
LABNET_SERVER_URL=https://192.168.50.10
LABNET_DEVICE_MANAGER_API_KEY=labnet_...
LABNET_CA_FILE=C:/ProgramData/LabNet/certs/labnet-ca.pem
# added for this computer
LABNET_ENVIRONMENT=production
LABNET_GRPC_ADVERTISED_TARGET=192.168.50.20:50051
LABNET_GRPC_CERT_FILE=C:/ProgramData/LabNet/certs/lab-pc.crt
LABNET_GRPC_KEY_FILE=C:/ProgramData/LabNet/certs/lab-pc.key
LABNET_DEVICE_INVENTORY=C:/ProgramData/LabNet/site/inventories/lab_pc_01.py:create_devices
The API key switches on Central registration and lease checks. The
certificate and key switch on TLS, with gRPC listening on all interfaces.
The advertised target must match the IP in the certificate.
3. Drivers. Install the vendor drivers or SDKs, and test each instrument
locally (for example with examples/05_local_hardware.py adapted to its
family). The inventory module comes from the repository's sites/pqt/ folder.
4. Install. This installs LabNet, the drivers and the site, then loads
lab-pc.env and builds the inventory's devices (without connecting), to
catch a mistake or a missing driver immediately.
powershell -ExecutionPolicy Bypass -File $install -Role lab-pc
- Start the Lab PC by hand in its own PowerShell window, and leave it open:
C:\ProgramData\LabNet\lab-pc-venv\Scripts\labnet-lab-pc.exe --env-file C:\ProgramData\LabNet\lab-pc.env
Invoke-RestMethod http://127.0.0.1:9001/health/ready
Readiness reports the gRPC listener, Central registration, and each device. 6. Firewall. Allow inbound TCP 50051 from approved clients only. Port 9001 stays on loopback.
4. Set up a client¶
- Copy
labnet-ca.pemtoC:\ProgramData\LabNet\certs\, and save the transferredresearcher.envasC:\ProgramData\LabNet\client.env. - Install the library and the drivers:
powershell -ExecutionPolicy Bypass -File $install -Role client
- Point clients at the settings file once (user environment variable), then
run the first example (copied from the repository's
examples/):
[Environment]::SetEnvironmentVariable("LABNET_ENV_FILE", "C:\ProgramData\LabNet\client.env", "User")
C:\ProgramData\LabNet\client-venv\Scripts\python.exe 01_hello_device.py
The script authenticates with Central at 192.168.50.10, leases a device,
and connects directly to lab_pc_1 at 192.168.50.20:50051. One CA file
verifies both connections.
Starting the lab by hand¶
Every process runs in its own PowerShell window that stays open. Start them in this order; to stop one, press Ctrl+C in its window.
| Order | Computer | Window | Command |
|---|---|---|---|
| 1 | central_server_pc |
Central | C:\ProgramData\LabNet\central-venv\Scripts\labnet-central.exe --env-file C:\ProgramData\LabNet\central.env |
| 2 | central_server_pc |
Caddy | caddy run --config C:\ProgramData\LabNet\Caddyfile |
| 3 | central_server_pc |
Control Center | C:\ProgramData\LabNet\control-center-venv\Scripts\labnet-control-center.exe --env-file C:\ProgramData\LabNet\control-center.env |
| 4 | central_server_pc |
Safe-state watchdog | C:\ProgramData\LabNet\control-center-venv\Scripts\labnet-watchdog.exe --env-file C:\ProgramData\LabNet\watchdog.env (or its Task Scheduler task) |
| 5 | each Lab PC | Lab PC | C:\ProgramData\LabNet\lab-pc-venv\Scripts\labnet-lab-pc.exe --env-file C:\ProgramData\LabNet\lab-pc.env |
| 6 | clients | experiments | your scripts, with LABNET_ENV_FILE set |
Only Central has to come first; everything else recovers if it starts early.
Lab PCs keep retrying their registration, and the Control Center shows a
banner until Central answers. Before an update, stop the affected windows;
labnet update refuses to run while that role is still running.
Network rules summary¶
- Central: allow TCP 443 from approved Lab PCs and client networks.
- Lab PC: allow TCP 50051 from approved client networks.
- Never expose Central's port 8008 or a Lab PC's port 9001.
- Clients need no inbound rule.
- Where practical, limit outbound traffic: Lab PCs need Central HTTPS; clients need Central HTTPS and the gRPC ports of authorized Lab PCs.
Deployment verification¶
Verify in this order:
- Central
/health/liveand/health/readyreturnstatus: okthrough HTTPS (curl.exe --cacert …\labnet-ca.pem https://192.168.50.10/health/ready). - Central lists the expected Lab PC devices.
- The Lab PC's loopback readiness reports gRPC serving and devices available.
- A client authenticates and lists the expected devices
(
02_choose_device.py). - The client leases a device and completes one harmless read.
- A second client cannot lease the same device at the same time.
- Closing the first client releases the lease and frees the device.