Core ZPR components
We are currently working towards Milestone 6.
- See the current iteration and backlog.
- See the roadmap.
Pre-Release / Beta Notice
This repository is in active, early-stage development.
- Breaking changes may occur at any time without prior notice or deprecation periods.
- The full suite of end to end security features are not yet implemented.
- Do not rely on these binaries for production systems until a stable release is announced.
Feedback and contributions are welcome.
Tools and libraries are pulled in from multiple repositories. You need to do a little configuration in order for the build system to access them.
Developers will have to either run git config --global url.git@github.com:.insteadOf https://github.com/
(which ends up in ~/.gitconfig), (or configure a PAT and use git askpass like
the runners now do). Also, anyone developing Golang will have to set go env -w GOPRIVATE="github.com/org-zpr/*"
(which ends up in ~/.config/go/env). Again, once we're public this requirement
goes away.
To run the ZPRnet you need at least:
- The packet handler (called
ph) which can run as either a node or an adapter.- Find that in this repo under
adapter/ph.
- Find that in this repo under
- The Visa Service (called
vs)- In the zpr-visaservice repo
- If you do not have a compiled policy you need the ZPL compiler (called
zplc)- In the zpr-compiler repo
A minimal ZPRnet has a node and a visa service. You will probably also want a service or two that run on the net, plus some client adapters that connect in and access the services.
In order to connect to the initial ZPRnet each adapter needs to share an RSA key with the visa service. This is done via policy. Since we are going to need a node and a visa service we need two keys.
openssl genrsa -out node-private-key.pem
openssl genrsa -out vs-private-key.pemThe private keys stay with the visa service adapter and node, but we need to put the public keys in the policy, so first extract them:
openssl rsa -in node-private-key.pem -pubout -out node-public-key.pem
openssl rsa -in vs-private-key.pem -pubout -out vs-public-key.pemThen in the policy zplc file, add a bootstrap section that looks like
this:
[bootstrap]
"node.zpr.org" = "/path/to/node-public-key.pem"
"vs.zpr" = "/path/to/vs-public-key.pem"Note: The visa service key is not yet required (as of 3/18/2026) -- but soon will be.
In addition to the visa service authentication, there is a separate authentication check when the link is first brought up between an adapter and a node. This uses certificates holding noise keys and signed by a certificate authority (CA). Adapters verify the certs they get from a node. So we need a certificate authority:
We'll put the authority related file into a directory named authority.
You will be prompted for a pass phrase. You'll need to use that whenever
you sign a certificate using the authority key.
# A place to put the files
mkdir authority
cd authority
# New key for the CA
openssl genrsa -aes256 -out auth-ca.key 4096
# New self-signed cert
openssl req -x509 -new -nodes -key auth-ca.key -sha256 -days 1826 -out auth-ca.crtUsing the handy zpr-pki script:
./integration-test/lib/zpr-pki genkey >node-noise.key
# First extract a public key from the private one
./integration-test/lib/zpr-pki pubkey <node-noise.key >node-noise-pub.pem
# Then sign the public key
./integration-test/zpr-pki gensignedcert authority/auth-ca.crt authority/auth-ca.key \
/CN=node.zpr.org 365 < node-noise-pub.pem >node-noise.crtThese are used over the HTTPS admin interface. By default the visa service will look for two files:
admin-tls-cert.pemadmin-tls-key.pem
Create them like so:
openssl req -new -newkey rsa:4096 -x509 -sha256 -days 365 -nodes -out admin-tls-cert.pem -keyout admin-tls-key.pemAssuming:
- Node substrate (dock) address is
129.6.7.1 - Node ZPR address is
fd5a:5052:90de::1
Sample configuration, place in a file named node-conf.toml.
[global]
# ca_file is needed for the node to verify adapter certificates and recognize
# the visa-service adapter as special. Without it, VS routing will not work.
ca_file = "authority/auth-ca.crt"
certificate_file = "node-noise.crt"
private_key_file = "node-noise.key"
self_addr = "129.6.7.1:5000"
zpr_addr = [ "fd5a:5052:90de::1" ]
tun_if = "tun9"
[authentication]
auth_private_key = "node-private-key.pem"The visa service adapter must present a CA-signed certificate so the node can
recognize it as the special visa-service peer. The certificate CN must be
vs.zpr — that is the hard-coded visa-service distinguished name the node
matches against. Generate and sign one:
./integration-test/lib/zpr-pki genkey >vs-noise.key
./integration-test/lib/zpr-pki pubkey <vs-noise.key >vs-noise-pub.pem
./integration-test/lib/zpr-pki gensignedcert authority/auth-ca.crt authority/auth-ca.key \
/CN=vs.zpr 365 < vs-noise-pub.pem >vs-noise.crtSample configuration, place in a file named adapter-vs-conf.toml.
[global]
# ca_file is optional for link establishment, but the VS adapter must present
# a CA-signed certificate_file so the node can recognize it as the visa service.
ca_file = "authority/auth-ca.crt"
certificate_file = "vs-noise.crt" # CN must be "vs.zpr"
private_key_file = "vs-noise.key"
zpr_addr = [ "fd5a:5052::1" ]
tun_if = "tun9"
[adapter]
node_addr = "129.6.7.1:5000"
node_public_key_file = "node-noise-pub.pem"
bootstrap_key = "vs-private-key.pem"name is not set here because certificate_file is present — the CN is read
from the certificate, not from name. name is only required for adapters
that have no certificate_file (self-signed cert path).
The visa service does not require custom configuration. However if you want
to customize it you can get it to spit out a configuration file. The default
name for it is vs.toml, so:
./vs --gen-config >vs.tomlValkey is required by the visa serivce.
On linux systems it may be installed as a service:
# check status
systemctl status valkey-server
# and if not running:
systemctl start valkey-serverOr you can just start it in the foreground in a termina;
valkey-serverHere is a simple policy to let any connected "user" access a "WebService".
We assume:
- WebService is connected using an adapter with
CN=web.zpr.org. - WebService has a bootstrap public RSA key in
web-public-key.pem. - WebService is accessed using HTTP port 80.
Create a file called zpr-full-access.zpl with these contents:
Define WebService as a service with device.zpr.adapter.cn:'web.zpr.org'.
Allow user to access WebService.
Then write a configuration file.
Create a file called zpr-full-access.zplc with these contents.
[nodes."node"]
provider = [ ["device.zpr.adapter.cn", "node.zpr.org"]]
zpr_address = "fd5a:5052:90de::1"
[trusted_services.default]
[visa_service]
dock_node = "node"
admin_attrs = [ [ "device.zpr.adapter.cn", "admin.zpr.org" ] ]
[bootstrap]
"node.zpr.org" = "node-public-key.pem"
"web.zpr.org" = "web-public-key.pem"
[protocols.http]
l4protocol = "iana.TCP"
port = 80
[services.WebService]
protocol = "http"To compile, use the compiler:
zplc zpr-full-access.zpl
# This will create the binary policy file, "zpr-full-access.bin2"Assuming you have three separate hosts for this. The node should be run on a Linux host but other platforms may work. This assumes Linux. Note that for any node or adapter where the ZPR address is specified in the config file, and you are running on Linux, you must manually configure the network TUN interface to work around a known bug in the Linux TUN library we are using.
So to prepare the Linux host to run the node, first set up the tun.
In the config file above we set the name to tun9 so we set that up
here:
# IP configuration for the node.
sudo ip tuntap add name tun9 mode tun multi_queue
sudo ip link set tun9 mtu 1400
sudo ip addr add fd5a:5052:90de::1/32 dev tun9
sudo ip link set tun9 upThe binary also expects to be able to access directory /var/run/zpr, so:
sudo mkdir /var/run/zpr
Then you can start the node:
./ph node -c /path/to/node-conf.toml
If the visa service is also running on linux as this guide assumes, then we need to configure its TUN interface similar to what we did for the node.
# IP configuration for the visa service adapter.
sudo ip tuntap add name tun9 mode tun multi_queue
sudo ip link set tun9 mtu 1400
sudo ip addr add fd5a:5052::1/32 dev tun9
sudo ip link set tun9 upNow start the visa service:
./vs /path/to/zpr-full-access.bin2
On the visa service host, in another terminal start the adapter:
./ph adapter -c /path/to/adapter-vs-conf.toml
Now you can attach additional adapters and start up the "WebService".
| Role | certificate_file |
name |
Behavior |
|---|---|---|---|
| node | required | ignored | Provided cert is used; node name comes from the cert CN |
| adapter | present | optional | Provided cert is used; CN comes from the cert where needed |
| adapter | absent | required | Self-signed cert is generated with CN from name |
| adapter | absent | absent | Config validation fails |
For adapters, CLI --name overrides [adapter].name in the config file.
ca_file |
Behavior |
|---|---|
| present | Peer cert signatures are verified against the CA; unverified peers are handled by link-type rules (see below) |
| absent | Peer cert signatures are not CA-verified; a warning is logged at startup and unverified peers are accepted |
Link-type rules when ca_file is configured:
| Link direction | Unverified peer cert | Action |
|---|---|---|
| Adapter → Node | Node cert unverified | Link rejected |
| Node → Node | Peer node cert unverified | Link rejected |
| Node → Adapter | Adapter cert unverified | Link accepted with a warning |
The visa service adapter is recognized as "special" by the node only when the adapter presents a CA-verified certificate claiming the visa-service DN. This means:
- The node must configure
ca_file(to verify the VS adapter's cert). - The VS adapter must present a CA-signed
certificate_file(not a self-signed cert).
Without both conditions, the VS adapter connects as an ordinary adapter and visa-service traffic is not routed to it.
- July 21, 2026
- Breaking: the ZPL
endpointclass and itsendpoint.*attribute domain were renamed todevice/device.*(e.g.endpoint.zpr.adapter.cn→device.zpr.adapter.cn). Requireszpr-commonv0.20.0; device-era compiled policy is not wire-compatible with endpoint-era runtimes.
- Breaking: the ZPL
- June 11, 2026
ca_fileis now optional for adapters (was previously required at startup).- Adapter
certificate_fileis optional; a self-signed cert is generated fromnamewhen absent. - Special-peer names (visa service) are now only assigned from CA-verified certs — both the node and the VS adapter must use a CA for VS routing to work.
- Fixed
--nameCLI ordering bug: the CN embedded in bootstrap/BAS auth objects now correctly reflects the CLI--namevalue. - Removed the silently-ignored
namekey from the node config example. - Added "Certificate and peer verification reference" section.
- March 13, 2026
- Rewrote the setup steps for latest code.
- Aug 20, 2025
deviceclass renamed toendpoint.
- July 31, 2025
- Removed reference to the runners.
- Add details about setting up TUN interface.
- June 18, 2025
- No longer need to set
self_addrin an adapter.
- No longer need to set
- June 12, 2025
- New bootstrap requirement and associated RSA key creation.
- Domain (eg,
endpoint,user, orservice) now required for attribute keys. - New
l4protocolrequired in the configuration.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in ZPR by you, shall be licensed as Apache 2.0, without any additional terms or conditions.