04 — Confluxconflux 1.0.0-pre

Put a machine on the overlay, then get on with the work

Conflux is one binary that carries the anchor daemon and its control tool. On VeilNet's public network it enrols the machine itself; on a network of your own it installs the file your root node minted. Either way it starts an anchor and registers a boot service. Joining takes one command, and coming back after a reboot takes none.

On this page

Install

Download the build for the platform from the pre-release page, check it against SHA256SUMS, and install it somewhere that survives a reboot.

$ sha256sum -c SHA256SUMS --ignore-missing
conflux-linux-amd64: OK
$ sudo install -m 0755 conflux-linux-amd64 /usr/local/bin/conflux
$ conflux version

Per-platform notes

PlatformWhat else is needed
LinuxNothing. TUN is in the kernel, and the service gets it through CAP_NET_ADMIN. Where SELinux refuses to run the extracted binaries, conflux detects it and prints the commands that fix it.
macOSApple silicon only; there is no Intel build. utun is in the kernel, so there is no driver to install. Releases are not notarised: if macOS refuses a downloaded binary, clear the quarantine attribute with xattr -d com.apple.quarantine conflux-darwin-arm64.
WindowsRun PowerShell as Administrator. TUN mode also needs wintun.dll, which conflux fetches and checks; conflux proxy needs no driver. See Windows.
FreeBSD, OpenBSDAs on Linux, except forwarding: for --subnet or --serve-exit with an interface, anchor prints the commands for the host rather than running them, as it does on macOS and Windows. The boot service is an rc script: enabled with sysrc and run under daemon(8) on FreeBSD, enabled with rcctl on OpenBSD.

Windows

  • Every command that changes the machine needs Administrator, and the service runs as LocalSystem.
  • A TUN interface needs Wintun, which conflux does not ship: it is GPLv2, and a driver extracted from a program's own resources is the shape of a DLL hijack. The first time a TUN machine needs it, conflux fetches wintun 0.14.1 over HTTPS, checks the archive against a pinned SHA-256, and places wintun.dll beside the extracted anchor. A start that finds it missing, as after an upgrade, fetches it again. If the download fails, conflux prints where to put the file by hand.
  • Each release carries a build-provenance attestation, and conflux version prints the digests of what it extracts.
  • --uplink is refused: anchor has no way to open a link on Windows.

Running as a service

The service manager runs one process, conflux serve, the supervisor. At every boot it reads conflux.json, starts anchord, waits until it answers, renews the credential if it is past two thirds of its window, and starts the anchor. A start that fails is retried with a backoff up to thirty seconds. One that no retry changes, such as a configuration conflux refuses, taints the credential does not grant or an expired credential with nowhere to renew it, stops the supervisor after three attempts with exit 70; nothing to start at all is exit 78. While it runs, the supervisor asks every thirty seconds whether the anchor is still there and rebuilds it if not. A blocked anchor is left as it is: it is still running, outside its realm.

PlatformRegistered asOn exit 70 or 78
Linuxsystemd unit conflux.service, Type=notify, with ExecStart=/var/lib/conflux/conflux serve and Restart=on-failurestays down: RestartPreventExitStatus=78 70, and the unit shows as failed
macOSlaunchd job org.veilnet.conflux, in /Library/LaunchDaemonsstarted again after launchd's throttle interval, since launchd cannot exempt an exit code
FreeBSD, OpenBSDrc script conflux, run under daemon(8) on FreeBSD and by rc.subr on OpenBSDstays down: nothing restarts the supervisor, which restarts anchord itself
Windowsservice conflux, displayed as VeilNet Conflux, as LocalSystem, automatic at boot, recovery after 5, 10 and 30 secondsstays down: the service reports itself stopped, which the recovery actions do not count as a failure

Two pairs of verbs look alike and are not. start and down act on the running anchor now, and a reboot behaves the same either way. install and uninstall act on the boot registration, and uninstall takes the identity with it.

What survives what
downstartinstalluninstall
Running anchorstopped(re)started(re)startedstopped
Boot servicekeptkeptregisteredremoved
conflux.jsonkeptkeptkeptdeleted
manifest.b64keptkeptkeptdeleted, permanently
Extracted binarieskeptkeptkeptdeleted

Upgrading to a newer build

New builds of a pre-release are published under the same tag, so the version number alone does not tell two of them apart. conflux version also prints the commit a binary was built from, and that is the part to compare. To move a machine onto a newer build, replace the binary and run conflux start.

$ conflux version
conflux 1.0.0-pre (f47de0fac83d24489664ca15fc6a317ac9c9f683) linux/amd64
$ sudo install -m 0755 conflux-linux-amd64 /usr/local/bin/conflux
$ sudo conflux start

The new build's anchor extracts into a directory of its own rather than over the one the running daemon has open, and start copies the new conflux to where the service runs it from, then restarts the service onto it. Nothing is re-enrolled and the identity is untouched. Until the restart, conflux status reports the binaries as stale.

Removing

$ sudo conflux uninstall
$ sudo rm /usr/local/bin/conflux

uninstall removes the boot service, the configuration and the identity. There is no other copy of the identity anywhere, so it asks first.

Quick start

Run conflux up on one machine, then run it on every other machine with the taint it printed. There is no account to create and no key to manage.

1 — the first machine
$ sudo conflux up
An IPv4 lets the other machines on this network reach this one by a v4 address.
A private address is advertised to them; give each machine that should be
reachable on its own a different one. The IPv6 address is derived from this
machine's identity and needs no answer.

  IPv4 [e.g. 10.128.0.7/24, blank for none]: 10.128.0.1/24

Minted a taint for this network:

    brhk-2mq9-tzva-6pjs-k4xe-nw7d-qf

This machine's credential is issued in it, for the life of its identity. Share it:
any machine that runs

    conflux up --taint brhk-2mq9-tzva-6pjs-k4xe-nw7d-qf

is issued a credential in it too, and joins this network and nothing else.

Starting.

  anchor       anchor6btpa3gn6w4stipba4hekzho7caw6srfyy5puvbz7mfanaiept5a
  overlay      fd80:c4b9:99ae:4411:c531:fd4f:754f:f08a/48
  ipv4         10.128.0.1/24
  interface    anchor0
  taint        brhk-2mq9-tzva-6pjs-k4xe-nw7d-qf
  credential   valid until 2026-10-06T06:35:43Z (29d 23h)
  service      active (systemd: conflux.service, enabled at boot)

Reachable from any machine that runs:  conflux up --taint brhk-2mq9-tzva-6pjs-k4xe-nw7d-qf
2 — every other machine
$ sudo conflux up --taint brhk-2mq9-tzva-6pjs-k4xe-nw7d-qf --ipv4 10.128.0.2/24

Passing --taint and --ipv4 answers the prompt in advance, so this is safe to run from a provisioning script. The taint is what the machine's enrolment asks for, so it counts the first time: once a machine holds a credential its taints are fixed, and a later --taint may only repeat them. The IPv4 question is asked once in a machine's life. The answer is kept, blank included, and running up again without the flag leaves the address alone. With nobody at a terminal to answer and neither --ipv4 nor --no-ipv4 given, conflux exits rather than wait.

3 — check that it worked
$ ping 10.128.0.1
$ sudo conflux status
$ sudo conflux peers

Give it a minute: peers find each other by gossip, which takes anywhere from fifteen to sixty seconds. A reboot needs nothing typed. The service is registered and enabled, the credential renews itself, and the machine comes back at the same overlay address.

Next, expose a service: a database, a dashboard or a self-hosted app, reachable from every machine that shares the taint and from nowhere else.

Concepts

Conflux runs an anchor, and the anchor protocol's model is covered in full in its own documentation. Three parts of it explain most of what conflux does.

An anchor is an identity

An anchor's name is its public key. The AnchorID conflux prints is derived from a 32-byte seed, and so is the overlay IPv6 address beside it. Nothing assigns either. The address stays the same for as long as the seed survives, which is why conflux enrols exactly once. It also cannot be changed, which is why losing the seed loses the machine's place on the network.

A realm is admission control

A realm is a root key and a credential per member. An anchor presents a chain proving it descends from the root, and the chain is checked during the handshake, before any data flows. Membership is a signature, not a list on a server. The public network's machines join ghost realm alpha; an organisation's machines join a tree of its own, with its own root node at the root. The architecture shows both.

Overlay addresses are derived, not assigned

Every anchor has an IPv6 address computed from its identity and its realm. It needs no coordination and cannot collide.

IPv4 is different, which is why up asks for one. Thirty-two bits is too few to derive without collisions, so a machine's IPv4 is chosen by its operator. It never crosses the overlay as IPv4: anchor translates traffic sent from it into IPv6 from the derived address. So nothing has to arbitrate it, and two machines may share one, though a machine that should be reachable at its IPv4 needs an address of its own. Any unicast address will do except one inside 198.18.0.0/15, where anchor answers the IPv4 peers it translates for, and which it will not send from.

A private address is advertised, and peers reach the machine at it. A public one is sent from and not advertised. A length, as in 10.128.0.7/24, routes the rest of that range to the peers answering there. Blank is a valid answer, and a common one: the machine still reaches IPv4 peers, and is reached at its IPv6 address.

Taints

A taint is a compartment label. Inside a realm, taints decide which members can exchange data. The rule is containment, not overlap: two anchors may exchange data only if one of them carries every taint the other does. Try it in the playground.

Containment, not overlap
A carriesB carriesExchange data?Why
{x}{x}yeseach set contains the other
{x}{x, y}yesA's set is contained in B's
{x, y}{x, z}noneither contains the other, despite sharing x
{x}{y}noneither contains the other
none{x}noan anchor with none carries the default compartment, which {x} does not contain

Everything else still works across a taint boundary: separated anchors still connect, bootstrap from each other and relay for each other. They just cannot exchange data.

  • Three machines with three generated taints are three disconnected machines. A taint has to be shared deliberately; nothing propagates it. And since a credential's taints are fixed when it is issued, putting them together afterwards means drawing new identities for all but one.
  • A hub with {a} and spokes with {a,b} and {a,c} works as a hub. The hub reaches both spokes, and the spokes cannot reach each other. That is the arrangement containment exists to express.
  • Two machines with {office,laptop} and {office,desktop} cannot talk, which surprises people. Give them the same set.
  • Pass --taint once per label. A comma-separated list is refused rather than read as one label. A label is 1 to 64 bytes of UTF-8 with no space of any kind, no character that does not print, and no @ or +, which bind a forwarded network to compartments. A machine carries at most 32.

conflux status prints the set in conflux.json, which mirrors what the credential grants, or none: the realm's default compartment for an issued credential that grants none. A Taints order may have moved the running anchor since, and that does not show there. conflux peers has a DATA column that says yes or no for each peer. When two machines are up and cannot see each other, that column is the first thing to check.

Granted by the credential

An anchor does not claim its taints; its issuer grants them. The enrolment asks for a set, the credential that comes back commits to it, anchor starts the identity under no other, and a renewal restates it. So a machine's taints are fixed for the life of its identity, and on a machine that already holds a credential a later --taint may only repeat them.

  • Changing them is a new identity, with a new AnchorID and a new overlay address: sudo conflux uninstall --yes, then sudo conflux up --taint NEW.
  • The taints in conflux.json are checked against the credential at every start, and a set it does not grant is refused for good rather than retried.
  • A member whose credential grants the taint power can move a running machine to other compartments with a Taints order, which anchor keeps and reapplies at every start. An alpha credential grants that power to nobody.

The two modes

The mode is what this machine gets out of the realm. up and proxy are exclusive, because one daemon holds one anchor. The medium is what the anchor reaches the realm over, and either mode works over either medium.

Fig. 01 — Publishing a service, two ways01 / 02
CLIENTlaptopCONFLUX UPanchor0OVERLAYSERVER · CONFLUX PROXYdb-1ANCHOR · NO INTERFACE[fd80:…]:543210.128.0.5:5432SERVICEpostgres · 127.0.0.1:5432NO HOST SOCKET · SEES 127.0.0.1

conflux proxy keeps the overlay inside the daemon. Nothing appears on the host. The way in is the ports you publish, each connection handed to a backend you name, and if it routes, the way out is a subnet or an exit served from the anchor's own process.

The service stays on loopback, unchanged, and sees every connection arrive from there.

conflux up gives the host a real interface. Anything on the machine can use the overlay, and publishing a service is an ordinary bind.

A client is always a machine running up: a proxy machine has no interface to connect out from.

conflux upconflux proxy
What the host getsa TUN interface: ping, ssh, everythingnothing on the host
What the realm getsthis machine, at an overlay addressthe named services, at overlay ports, and any subnet or exit it routes
Privilege to runroot / CAP_NET_ADMIN / Administratorroot, only to register the boot service
An IPv4yes, owned by the host's kernelyes, held by the anchor's own stack
Needs wintun.dll on Windowsyesno
Can forward a subnetyes, --subnet: the host forwardsyes, --subnet: the anchor forwards from its own process
Can serve or use an internet exityes, --serve-exit, --use-exityes; --use-exit covers only the anchor's own traffic
Can run over an uplinkyes, --uplinkyes, --uplink
Boot serviceyesyes

Switching modes keeps the identity, and every setting either mode can use: the subnets and both exits, the IPv4, the taints, the uplink, the peers, the port and low latency. Only switching to up clears something, the proxy specs, which only userspace serves. --no-subnet, --no-serve-exit and --no-use-exit are the way back from routing on either verb.

Reverse proxy

On a machine where CAP_NET_ADMIN is out of reach, skip the interface and publish only the ports that need to be reachable. A peer that connects to this machine's overlay port 8080 gets a fresh connection to 127.0.0.1:3000. Nothing appears on the host, and the anchor itself needs no privilege. sudo is only for registering the boot service.

$ sudo conflux proxy 8080=127.0.0.1:3000 53/udp=127.0.0.1:53
Each spec is OVERLAYPORT[/NETWORK]=BACKEND
SpecMeans
8080=127.0.0.1:3000TCP on overlay port 8080 → 127.0.0.1:3000
53/udp=127.0.0.1:53UDP on overlay port 53 → 127.0.0.1:53
5432=[::1]:5432an IPv6 backend, bracketed
80=nas.lan:8080a backend on another host the machine can reach, by name
  • The network defaults to tcp and can be tcp or udp. The same port on both is two specs, 53=… and 53/udp=…; a port repeated on one network is refused.
  • The backend is host:port, dialled fresh for each connection rather than resolved up front, so a name that does not resolve yet is fine, and so is a named port. It can be loopback or any host this machine can already reach.
  • The overlay port and the backend port are independent, and nothing is bound on the host, so 80=127.0.0.1:3000 clashes with nothing.
  • With a private IPv4, peers reach these ports at it as well as at the IPv6 address.

A userspace router

A proxy can also forward for the realm. With --subnet or --serve-exit, every connection a peer sends through it ends inside the anchor's own process, which dials the destination from an ordinary socket of its own, TCP and UDP, so the far end sees this host's address, as it would behind a translating router. Nothing on the host is set up, and no privilege is needed for that either. With either flag the port specs may be left out, and a proxy given no port, no subnet and no exit is refused, since it would have nothing to offer.

$ sudo conflux proxy --subnet 192.168.1.0/24 --serve-exit

To change a running anchor without touching its configuration, use anchorctl's own proxy command. Its changes last until the anchor restarts, when conflux starts it again from the configured list.

$ sudo conflux anchorctl proxy                             # what it is serving
$ sudo conflux anchorctl proxy -add 9000=127.0.0.1:9000    # one more, until restart
$ sudo conflux anchorctl proxy -rm 9000                    # and gone again

Publishing a service in TUN mode

On a machine running conflux up, the kernel owns the overlay addresses, so a service published on the overlay is an ordinary bind. There is no proxy to configure.

  • Bind to 0.0.0.0 or ::, or to the overlay address itself so the service is reachable only over the overlay. A service bound to 127.0.0.1 is not reachable from peers.
  • A service that binds the overlay address at boot should start after conflux. Under systemd, After=conflux.service waits until the anchor is up.
  • A peer arriving over IPv6 appears from its own derived address. A peer arriving over IPv4 appears from the 198.18.0.0/15 range. Write allow-lists against the IPv6 address, which is bound to the peer's identity.
  • Broadcast and multicast do not cross the overlay, so discovery by mDNS or SSDP does not either. Connect to services by address.
  • There are no names for peers, only addresses. conflux peers lists every peer's, and an entry in /etc/hosts gives one a name of your own.

Subnets, exits and other settings

Forwarding a subnet

conflux up --subnet 192.168.1.0/24, or the same on conflux proxy, offers that network to the rest of the realm, so machines on it with no conflux at all become reachable. An entry is a private prefix with no host bits set, an interface name, which follows whatever private networks are on it, or '*', every private network on every interface, quoted so the shell leaves it alone. Private means RFC 1918, 100.64.0.0/10 and unique local IPv6; reaching the public internet is what an exit is for.

An entry can be bound to some of this machine's own taints, as SPEC@a+b. 192.168.1.0/24@office is offered only to peers whose taints also pass the containment rule against {office}, and eth1@office+lab binds an interface to {office, lab}. A binding names only taints this machine is in. A list holds at most 64 entries, each at most 255 bytes, with at most 16 distinct compartments bound across it.

$ sudo conflux up --subnet 192.168.1.0/24 --subnet eth1@office
$ sudo conflux proxy --subnet '*'

The last list set wins. A member whose credential grants the subnets power can replace the list while the anchor runs, with a Subnets order, and anchor serves that list from every start, a reboot included, until an up or proxy with --subnet or --no-subnet sets it again. While it does, conflux status says whose it is:

  forwarding   10.9.0.0/24@lab — set by an order from anchor… at 2026-10-06T09:00:00Z, in place of conflux.json's; --subnet or --no-subnet sets it again

Exits

$ sudo conflux up --serve-exit      # be a way out to the public internet for the realm
$ sudo conflux up --use-exit        # send this machine's own internet over the overlay

The two are alternatives, both are off unless asked for, and both work on up and on proxy. On a proxy, --use-exit covers only the anchor's own traffic, since nothing else on the host sees the overlay. Conflux never takes either from an enrolment file: an anchor that became an internet exit because a document said so is the worst kind of surprise. --no-serve-exit and --no-use-exit are the way back.

Other settings

FlagWhat it does
--low-latencyCarry frames as datagrams: no head-of-line blocking between flows, and a lost frame stays lost. For voice, video and games. --no-low-latency goes back to streams.
--lan-discovery yes|no|autoProbe the local network for members of the same tree. Turning it off is a privacy choice, not a connectivity one: it announces that an anchor is here. auto, the default, leaves it to enrolment. An explicit yes is refused beside --uplink.
--port NThe UDP port to listen on, for a firewall rule or a port forward. Omit it and the system picks one; --no-port goes back to that. Refused beside --uplink, which binds no socket.
--interface NAMEThe interface name on Linux and Windows. macOS and the BSDs number their own.
--peers HOST:PORTWhere to start looking for the realm; ANCHORID@host:port also names the anchor expected there. Enrolment supplies this; name one only to override it. --no-peers forgets the override.
--no-subnetForward nothing for the realm: the way back from --subnet, and from a member's Subnets order.
--no-uplinkGo back to the host's network on a machine configured for a link.
--api URLThe enrolment API base. The default is https://api.veilnet.com.au.

Configuration

Conflux keeps one configuration per machine, root-owned, with no home directory anywhere in it. Every directory is 0700 and every file 0600.

ConfigurationState, identity and binariesSocket and token
Linux/etc/conflux//var/lib/conflux//run/conflux/
macOS/Library/Application Support/conflux//Library/Application Support/conflux//var/run/conflux/
Windows%ProgramData%\conflux\%ProgramData%\conflux\%ProgramData%\conflux\run\
FreeBSD, OpenBSD/usr/local/etc/conflux//var/db/conflux//var/run/conflux/
What is in them
FileWhat it holds
conflux.jsonWhat you asked for, in the configuration directory. The rest are in the state directory.
manifest.b64The identity: the seed, the credential chain, the taints it grants and the bootstrap list, in one line as the issuer wrote it; a renewal rewrites the chain and the list inside it. Recoverable from nowhere.
state.jsonWhat conflux worked out: the AnchorID, the credential's window, the last clock skew and the uplink reopen tally. Delete it and the next start learns it again.
anchord.jsonThe daemon's own configuration, rendered from conflux.json on every start. Editing it does nothing lasting.
bin/The extracted anchor pair, one directory per build, and wintun.dll on Windows.
confluxThe copy of conflux the boot service runs (conflux.exe on Windows).

conflux.json is what you asked for, and the whole of what a reboot needs. Every up and proxy rewrites it.

conflux.json
{
  "version": 1,
  "mode": "proxy",
  "taints": ["brhk-2mq9-tzva-6pjs-k4xe-nw7d-qf"],
  "ipv4": "10.128.0.5/24",
  "proxies": ["5432=127.0.0.1:5432", "80=127.0.0.1:3000"],
  "lowLatency": false
}

Editing it by hand is supported. sudo conflux start restarts from whatever it says, and anything anchor would refuse on the file's face is refused by conflux first, naming the field, and not retried. What depends on the host is anchor's to find at start: a subnet whose interface is not up yet, which is retried, and TLS material under export that will not load. An export block names where telemetry goes; without one, the machine exports nothing.

taints is the one field an edit cannot change once the machine has enrolled. It mirrors what the credential grants, and a set the credential does not grant is refused at every start.

Commands

Conflux keeps a small, fixed set of command names for itself. Everything else is passed to anchorctl unchanged: peers, routes, events, metrics, send, inspect and the rest, and the realm's controls over its members, block, unblock, blocks, taints, subnets and telemetry. Run them with sudo: the commands that change the machine need root, and the rest talk to the running anchor through a token only root can read.

CommandWhat it does
conflux upenrol if needed, start in TUN mode, register the boot service
conflux proxyenrol if needed, start in userspace mode serving those backends
conflux enrolinstall a credential minted for this machine on a network of your own, instead of drawing one; --manifest - reads it from stdin. It refuses to replace a manifest already there
conflux downstop the anchor now; the boot service and configuration stay
conflux startstart it again now, from the configuration already on disk, after copying this conflux to where the service runs it from
conflux renewfetch a fresh credential and install it on the running anchor, without a restart; exits 69 on a fixed-term credential, which has nowhere to renew
conflux statusconflux's state, with anchorctl status beneath it; exits 78 with no configuration
conflux installregister the boot service, and start it if a configuration exists
conflux uninstallremove the boot service, the configuration and the identity; --yes skips the question
conflux versionconflux's version and commit, and the anchor build it carries
conflux help [COMMAND]conflux's usage with anchorctl's beneath it, or one command's own usage
conflux anchorctl …run the embedded anchorctl, uninterpreted

Four names exist on both sides: start, proxy, renew and status. Each collision is resolved rather than guessed. Bare conflux status is conflux's and prints anchorctl's beneath it, while conflux status -watch 5s goes to anchorctl because it was given arguments. stop and restart are refused, with a pointer to down and start. Passing them through would leave conflux's configuration describing an anchor that is not the one running.

Realm controls

Six of the passed-through commands are the realm's control over its members. None of them is a conflux verb, and every one but blocks acts on another member of the same realm, never on this machine.

CommandWhat it doesNeeds the power
block -target ID [-days N] [-reason TEXT]shuts another member out of the realm, on every member, until the block ends or is lifted; without -days it lasts until a member unblocks itblock
unblock -target IDlifts a block, whoever issued itblock
blockslists the blocks in forcenone
taints -peer ID [-set A,B]reads another member's compartments, or moves it to otherstaint
subnets -peer ID [-set A,B | -clear]reads what another member forwards for the realm, or replaces its listsubnets
telemetry -from IDasks another member how it istelemetry
  • Each needs its power in this machine's credential, granted by its issuer as taints are: anchorctl issue -caps block, and so on. An alpha credential grants none, so on the public network these orders are refused with anchor's explanation. On a network of your own the root node holds them, and they reach the machines in its own realm.
  • They take the full 58-character AnchorID, anchor…, as conflux status prints it, not the ten-character short form in the tables peers and blocks print. For every private network on a member, write subnets -set '*'; anchorctl's help says all, which anchor does not accept.
  • A block does not stop anything. The blocked anchor keeps running, an outsider to its realm until the block ends or is lifted, and shows DATA no on every peer. To stop the anchor on this machine, use conflux down. Why the power needs guarding is covered under security.

Exit codes

CodeMeaning
0success
1failure
2usage
13needs root or Administrator
69nothing is running here, or nothing to act on: down and start where conflux is not installed, renew with no manifest or on a fixed-term credential
70a configuration conflux or anchor refuses for good; the systemd unit does not restart on it
78no configuration; the systemd unit does not restart on that either
otherfor a passed-through command, anchorctl's own code, verbatim

Environment

VariableEffect
CONFLUX_DIRroots a whole separate installation in one directory, configuration, identity, socket and a boot service named after the root, so it cannot replace the machine's own
CONFLUX_DEBUG=1passes -v to anchord
CONFLUX_ALLOW_INSECURE_API=1permits a plain-http API base, for tests only
ANCHOR_SOCKET, ANCHORD_TOKENif already set, conflux leaves them alone and a passed-through command uses yours

Credentials and renewal

On VeilNet's public network, enrolment is one unauthenticated call that needs no account: POST /ghosts/alpha with the taints to put the anchor in, {"taints": ["brhk-2mq9-tzva-6pjs-k4xe-nw7d-qf"]}, at most 32 of them and never none. The API mints an identity inline, signs a credential for it in those taints, returns both, and forgets them. There is no sign-up, no session and no record. The free tier is free of us, not merely free of charge.

A credential lasts thirty days, and conflux renews it at two thirds of the window, day twenty. That leaves ten days of retry budget for a machine having a bad week, and a failed renewal is retried every minute. Renewal runs on every start, before the anchor is built, and on a timer while it runs. It is hot: the running anchor takes the new credential without dropping a session. The request restates the taints the manifest names, which a renewal cannot change, and the answer's bootstrap list, when it carries a usable one, replaces the stored one for the next start.

Fig. 02 — Thirty days, renewed at day twenty
RETRY BUDGET · 10 DAYSDAY 0DAY 10DAY 20DAY 30RENEWED · NO SESSION DROPSISSUEDWOULD LAPSEEACH RENEWAL STARTS A FRESH THIRTY DAYS

A machine that was switched off past its expiry renews on its next start and keeps its AnchorID and its overlay address. There is no window to miss.

  • A failed renewal never falls back to enrolling. That fallback would silently change the machine's overlay address and orphan every peer that knew it.
  • Re-running conflux up does not enrol; it reads the identity that is already there.
  • Switching modes does not enrol: up after proxy keeps the identity.

On a network of your own

A private sovereign network works the other way round. There is no enrolment route. Each machine's credential is minted in advance by the network's root node, its operator is handed one file, and conflux enrol installs it. conflux up then starts from that file without enrolling.

$ sudo conflux enrol --manifest gateway-3.b64
$ sudo conflux up

Where the network runs a guardian, the machine renews itself through it, authenticating with a secret minted for that one machine. Without one, the credential the root node mints with its CLI carries no renewal fields at all, so it is fixed-term: it runs to its expiry, and a replacement is minted and installed before then. A credential that does not renew says what that means for the machine.

Revocation exists: the machine's credential can go unrenewed and lapse. There is also a block order, which needs the block power, shuts the machine out now and can be lifted. Whoever mints the credential also chooses how long it lasts and the taints it grants, and may allocate the machine's IPv4. Enrol copies the IPv4 and any export block into the configuration once, where they can be changed like any other setting. The taints are not copied to be edited: they are the credential's, and every start checks conflux.json against them. See commissioning a node.

A credential that does not renew

A document with no renewal fields, no renewalUrl and no renewalAuth, is fixed-term rather than broken. It runs to its expiry and is then replaced, not renewed.

$ sudo conflux enrol --manifest gateway-3.b64
credential installed
  from         gateway-3.b64
  renewal      none: it runs to its expiry and is then replaced
  expires      2026-11-07 09:00 UTC
  taint        site-a
  bootstrap    genesis-1.example.net:4700, genesis-2.example.net:4700

Next: sudo conflux up
Fig. 03 — Thirty days, and nothing renews it
DAY 0DAY 10DAY 20DAY 30ISSUEDLAPSES · REPLACE IT BEFORENOTHING RENEWS IT: A REPLACEMENT IS INSTALLED

The root node's CLI mints for thirty days unless told otherwise. The replacement is installed before the last day: past it, the next start is refused for good.

  • conflux enrol installs it with no --api, since there is no renewal URL to read a base from.
  • Nothing asks to renew it. A start makes no call, the timer stops rather than retrying every minute, and conflux renew exits 69. None of this is reported as a failing renewal, because nothing failed.
  • An expired one is refused at enrol. Past its expiry on a machine already running, the next start is refused for good and the unit shows as failed until it is replaced.
  • enrol refuses to replace an existing manifest, so a replacement goes in as a fresh install, with whatever identity the new file carries: sudo conflux uninstall --yes, then sudo conflux enrol with the new file.
  • exit: true in the document is reported, not obeyed. The machine serves an exit only after conflux up --serve-exit, or the same on proxy.
  • A document that names a renewalAuth but no renewalUrl is not fixed-term. It says how to authenticate a renewal and not where to send one, so it is refused at enrol as a mistake by its issuer.

Security

Conflux adds exactly two things the protocol does not have: an executable written to disk, and a private key in a file. The protocol's own guarantees are in the anchor documentation.

Protect the manifest

The manifest holds the 32-byte identity seed, and anyone who has it is that anchor. One issued through a guardian also holds the machine's renewal secret, so whoever has it can keep that identity's credential current as well. Treat it as a private key: keep it off shared storage, out of backups that could leave the machine, and at exactly the permissions conflux sets.

How the file is held

  • 0600, with the mode set on the descriptor before any content is written. Writing first and chmod'ing after leaves a window at the umask's mode.
  • 0700 on the directory. A 0600 file in a traversable directory is one rename away from being replaced.
  • On Windows, where mode bits mean nothing, conflux gives %ProgramData%\conflux to SYSTEM and Administrators, with a protected DACL that everything beneath it inherits. It refuses a directory another account created.
  • Never in an argv. It travels on stdin, so it never appears in ps or /proc/*/cmdline. Never in a log either, because the types that carry it redact themselves.

What the boot service runs

The service runs as root, or SYSTEM on Windows, and starts whatever file it names at every boot. So it names the copy of conflux in the state directory, which only root can change and which up, proxy, install and start refresh, and never the file conflux was run from: a home directory or a download is a place another account could swap in a program of its own, to be run as root at the next start.

The commands that reach past this machine

Everything else conflux does stops at the machine it is typed on. Five passed-through orders do not: block, unblock, taints, subnets and telemetry act on another member of the realm, each gated by its own power in this machine's credential. blocks only reads. A credential granting block is therefore not one more copy of a machine's identity. It is the authority to shut any anchor of its realm out of it. Keep it somewhere that reflects the difference, issue it to as few machines as the work allows, and issue it short: its lifetime is the whole of how long a stolen one can act.

  • A block is not a revocation. It shuts a machine out on every member it reaches and leaves its credential untouched; removing a machine for good is still expiry. On the public network there is no revocation of either kind: an alpha credential grants no block, and renewal there is open to whoever holds the seed, so a leaked manifest is a permanent loss of that identity. How expiry and blocks work together.
  • It can be lifted. Any holder of block may unblock, whoever issued the block, and a block given -days N ends on every member at the instant it says. A mistyped AnchorID is one unblock away from being undone. Read the target back before running it all the same.
  • It spreads member to member, in a handful of hand-overs, and every member holds it and hands it to members that were away. The realm converges on it rather than switching at an instant, and a member it has not reached yet still admits the machine.
  • It is unrelated to conflux down, which stops the anchor on this machine and leaves the registration in place. A blocked anchor is not stopped at all: it goes on running, outside its realm.

What conflux does not defend against

  • A root-equivalent local attacker. They can read the manifest, and that is the end of it.
  • A compromised release channel, beyond what the digests printed by conflux version and the release attestation provide.
  • Traffic analysis, which belongs to the protocol and is covered in its own documentation.
  • Anything a taint appears to promise beyond its issuing. A taint is granted by the credential, so it is an authorisation boundary as strong as the issuing behind it. And a member whose credential grants the taint power can move a machine to other compartments while it runs.

Troubleshooting

Start with sudo conflux status. It prints conflux's own state and anchorctl's beneath it, and most of what follows is a way of reading that output. Conflux decides the mode, the taints, the IPv4, the subnets, the proxies, the exits, the medium, where the files live and when to renew. The anchor underneath decides everything else: every packet, every route, every credential check. Knowing which of the two is in play usually tells whether a problem is a setting or a network condition.

The five most common checks
SymptomWhere to look
Two machines are up and cannot reach each otherGive it a minute; peers take 15 to 60 seconds to find each other. Then the DATA column in conflux peers: it is almost always a taint set that is not contained. DATA no on every peer can also mean this machine is blocked; conflux blocks on another member lists the blocks in force.
conflux status says the credential is EXPIREDRenewal is failing, and the next line names the error. Renewal needs outbound HTTPS to the API. A restarted anchor does not start on an expired credential, so the supervisor keeps retrying, renewing first each time, and once a renewal gets through the machine keeps its address. A fixed-term credential that has expired is replaced, not renewed.
The service started but no anchor came up within 90sStop the service and run the supervisor in the foreground with sudo conflux serve --foreground. anchord's own lines are prefixed anchord:, so its reason for a refusal is printed in its own words.
conflux refuses to start, naming the clockThe clock is more than ten minutes from the API's. Fix NTP first; nothing connects until then.
Anything elseThe logs: journalctl -u conflux -n 50 on Linux, /var/log/conflux.log on macOS and FreeBSD, /var/log/daemon on OpenBSD, and %ProgramData%\conflux\logs\conflux.log on Windows.
Conflux · TroubleshootingEvery error conflux prints, what it means and what to do →Reading conflux status, the messages and their fixes, uplinks, Windows, the service and its logs, and clock skew.

Anything those pages do not answer is worth an email. We would rather hear it during a pre-release than after: sovereign@veilnet.net.