Docker Compose
Both layouts assume the same directory layout on the host:
- Your Aether
dockerfile - A
certs/folder - A twin Python file mounted as
./boiler.py→/aether/main.pyinside the container (change the volume if your filename differs)
A license JWT is always required in the container, the same as on bare metal. Provide it with VEILNET_AETHER_TOKEN (for example under environment: or env_file: in Compose), unless your entrypoint passes token= into Nexus(...) only. Nexus validates the JWT offline (signature and expiry); outbound internet is not required for validation.
Aether only
Use this on a trusted network or when you bring your own security (firewall, VPN, reverse proxy).
- HTTP on host port 8000
- OPC UA on 4840
Point external tools at opc.tcp://<docker-host>:4840. Set Nexus(opc_ua_url=...) in your twin to listen on all interfaces in the container (for example opc.tcp://0.0.0.0:4840) so the published port works.
Save as docker-compose.aether.yml:
services:
aether:
build:
context: .
dockerfile: dockerfile
container_name: aether
image: veilnet/aether:dev
restart: unless-stopped
ports:
- "8000:8000"
- "4840:4840"
volumes:
- ./certs:/aether/certs
- ./boiler.py:/aether/main.py
docker compose -f docker-compose.aether.yml up -d
Aether with VeilNet Conflux (recommended for secure remote access)
VeilNet Conflux provides the tunnel path for secure remote connectivity. Aether shares Conflux’s network namespace so OPC UA and HTTP reach your twin over VeilNet instead of exposing raw plant ports on the public internet.
Learn more about this pattern—network_mode: container:veilnet-conflux, one Conflux per host, .env (registration token, guardian, VeilNet IP, taints for mesh routing), depends_on + service_healthy, and reaching services across hosts by VeilNet IP—in the VeilNet guide: Docker – namespace sharing.
You also need a .env next to the compose file for Conflux, per your VeilNet deployment. The Conflux image must define a Docker healthcheck so depends_on: service_healthy works (the official Conflux image exposes a healthcheck on the VeilNet interface, as described in that guide).
On-site docs for the same topic: Docker – namespace sharing (Conflux).
Save as docker-compose.veilnet.yml:
services:
veilnet-conflux:
container_name: veilnet-conflux
image: veilnet/conflux:Beta-v1.0.8
restart: unless-stopped
env_file: [ .env ]
cap_add: [ NET_ADMIN ]
devices:
- /dev/net/tun:/dev/net/tun
veilnet-aether:
build:
context: .
dockerfile: dockerfile
container_name: veilnet-aether
image: veilnet/aether:dev
restart: unless-stopped
volumes:
- ./certs:/aether/certs
- ./boiler.py:/aether/main.py
network_mode: "container:veilnet-conflux"
depends_on:
veilnet-conflux:
condition: service_healthy
docker compose -f docker-compose.veilnet.yml up -d
Service roles
veilnet-conflux— Conflux image,.env,NET_ADMIN,/dev/net/tun.veilnet-aether— Builds fromdockerfile, mountscertsand the twin script,network_mode: container:veilnet-conflux.
Edit the mounted twin script on the host to change logic or the OPC UA endpoint; inside the container it runs as main.py.