Docker Compose

Run Aether in a container with published HTTP and OPC UA ports, or share VeilNet Conflux’s network namespace for secure remote access.

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.py inside 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

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 from dockerfile, mounts certs and 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.