Installation and First Configuration
This is the complete guide: a bare server at the start, a licensed node carrying real traffic at the end. Work through it in order. Nothing here assumes you have used Stratum before.
There are two halves. Install (steps 1–5) gets the agent running and licensed. Configure (steps 6–10) is the part people skip and then wonder why nothing responds — a freshly installed node deliberately starts with almost everything switched off.
Before you begin
| Requirement | Detail |
|---|---|
| Operating system | Debian 11+, Ubuntu 22.04+, RHEL 8+, Rocky Linux 8+, or AlmaLinux 8+ |
| Kernel | 5.8 or newer with kernel type information enabled (CONFIG_DEBUG_INFO_BTF=y) |
| Architecture | x86-64 (amd64) or arm64 |
| Privileges | root — the agent manages interfaces and loads the in-kernel data plane |
| Network | Outbound HTTPS to your panel |
| Interfaces | One is enough to start. Two (management + workload) is the recommended layout |
| Licence | A valid key. The download itself is gated on it |
A stock Debian 12 kernel is older than this and will not run the data plane. The installer checks before it changes anything — see step 2.
1. Get a licence key
You cannot download anything without one. The key gates the installer, the binaries, and every later update.
Register on the site, place an order for the plan and node count you want, follow the payment instructions, and submit your transaction reference and proof. Payment is verified by a person, and the licence is issued once it is — licences are never handed out automatically. It then appears in your account with its key.
See Licensing for the full model, and Your Account for where the key lives.
2. Check the kernel first
The data plane runs inside the kernel, so the kernel has to be new enough. The installer does not guess: it loads the real data plane as a dry run before touching your system, and stops if that fails.
If your kernel is too old, it tells you and offers three ways forward:
- Auto-upgrade — installs a newer kernel, reboots, and resumes the install by itself.
- Show commands and stop — prints exactly what to run, and changes nothing.
- Abort — nothing is touched.
A piped, non-interactive install never reboots you silently. It stops with the
manual instructions unless you explicitly ask otherwise with
CENVERO_KERNEL_UPGRADE=auto.
3. Run the installer
curl -sSL -H "X-License-Key: YOUR_LICENSE_KEY" \
https://stratum.cenvero.com/install | bash
Substitute your own key, and your own panel host if you self-host. The key can
also travel as ?key=YOUR_LICENSE_KEY in the URL or as an
Authorization: Bearer YOUR_LICENSE_KEY header — prefer the header, since URLs
end up in logs.
Every artifact is verified before it is written to disk: it must match the checksum the panel advertises over TLS, and carry a valid publisher signature. An artifact that fails either check is refused. The same verification runs on later self-updates.
The installer prompts for host IP, subnet, gateway, the interfaces to use, and
the address pool. It reads those prompts from the terminal directly, so it still
works under curl … | bash.
Unattended install
Supply every setting through the environment and it runs with no prompts:
CENVERO_LICENSE_KEY=... \
CENVERO_HOST_IP=203.0.113.10 \
CENVERO_SUBNET=203.0.113.0/24 \
CENVERO_GATEWAY=203.0.113.1 \
CENVERO_MGMT_NIC=eth0 \
CENVERO_VM_NIC=eth1 \
CENVERO_POOL_START=203.0.113.100 \
CENVERO_POOL_END=203.0.113.200 \
bash install.sh
| Variable | Purpose |
|---|---|
CENVERO_LICENSE_KEY | Your licence key |
CENVERO_HOST_IP | This node's management address |
CENVERO_SUBNET | The management subnet, in CIDR form |
CENVERO_GATEWAY | Default gateway |
CENVERO_MGMT_NIC | Interface for management traffic |
CENVERO_VM_NIC | Interface for workload traffic |
CENVERO_POOL_START / CENVERO_POOL_END | Address range handed out to workloads |
CENVERO_API_TOKEN | Off unless set. auto generates one, or supply your own. Can also be done later — see step 8 |
CENVERO_KERNEL_UPGRADE | auto, manual, or skip for the kernel check in step 2 |
CENVERO_REINSTALL | Set to 1 to re-run over an existing install, keeping config and data |
CENVERO_PANEL_URL | Your panel, if you self-host |
CENVERO_CHANNEL | Pins this node to one release channel |
CENVERO_API_DOMAIN | Extra hostname to include on the node's certificate |
The installer is idempotent. It detects a previous install and stops rather
than overwriting your configuration and state. Use CENVERO_REINSTALL=1 when
you genuinely mean to re-run.
4. Know what you just installed
Two names look alike and are not the same thing. This trips up nearly everyone once:
| Name | What it is |
|---|---|
cenvero-stratum | The service. This is what systemctl acts on |
cenvero-str-ctl | The command-line tool. It talks to the running service |
So restarting the node is:
systemctl restart cenvero-stratum
systemctl restart cenvero-str-ctl fails with "unit not found" — that is the
CLI, not a service. And cenvero-str-ctl restart is not a command either: the
CLI talks to the agent, it does not start or stop it.
Where things live:
| Path | Contents |
|---|---|
/etc/cenvero-str/ | Node configuration |
/var/lib/cenvero-str/ | State and local data |
/var/log/cenvero-str/ | Logs |
/run/cenvero-str/ | The local control socket |
5. Activate the node
Activation binds the licence to this specific machine and pulls down its signed licence.
sudo cenvero-str-ctl license activate CNVR-XXXX-XXXX-XXXX-XXXX
The key is positional — there is no --key flag. This raises an activation
request for this machine, which you then confirm in your account. Once you
confirm, the agent installs the signed licence on its own and begins enforcing
it.
To check where it has got to:
cenvero-str-ctl license status
cenvero-str-ctl hardware
hardware prints this machine's hardware id, which is what you match against
the pending request in the panel when you have several machines activating at
once.
If activation is refused with a node quota message, this licence's node slots are all in use. Each machine you approve takes one slot; a machine you reject or revoke gives its slot back.
At this point the node is installed and licensed. Everything below is configuration — and a fresh node starts with most services deliberately off, so this half is not optional.
6. See what is actually running
cenvero-str-ctl status
cenvero-str-ctl service
service is the one to read carefully. It looks like this:
SERVICE ENABLED ADDRESS STATE NOTE
REST API off 203.0.113.10:7070 down no api_token configured
gRPC API off 203.0.113.10:7071 down no api_token configured
WebSocket API off 203.0.113.10:7072 down no api_token configured
Metrics on 127.0.0.1:9090 listening -
DNS on 127.0.0.1:53 listening -
DHCP on :67 listening -
Read it as three independent columns:
- ENABLED is your switch — what you asked for. It takes effect at the next restart.
- STATE is a live check of whether something is actually listening right now.
- NOTE explains any gap between the two.
A service can be enabled and still down. That is not a contradiction: it means your switch was recorded but something else is stopping the service from starting, and NOTE tells you what. For the three management APIs, that something is almost always a missing API token — see step 8.
The local control socket is always up and is not a service you can toggle. That
is why cenvero-str-ctl keeps working even with every network API off.
Apply an enable/disable change with:
systemctl restart cenvero-stratum
7. Understand what is exposed
Default ports, and who can reach them:
| Port | Service | Bound to | Reachable from |
|---|---|---|---|
| 7070 | REST API | node address | the network — off until you configure a token |
| 7071 | gRPC API | node address | the network — off until you configure a token |
| 7072 | WebSocket API | node address | the network — off until you configure a token |
| 9090 | Metrics | 127.0.0.1 | this machine only |
| 53 | DNS | 127.0.0.1 | this machine only |
| 67 | DHCP | all interfaces | the local network |
Two things worth taking in.
The three management APIs are off by design, not broken. With no API token
configured the agent refuses to open a management API at all, rather than
opening one with no credential on it. If you never turn them on, you manage the
node from the panel and from cenvero-str-ctl locally, and nothing is listening
on those ports.
DHCP is the one service bound to every interface, because it has to answer broadcasts from clients that do not have an address yet. On a node with a public address, that means UDP/67 is reachable from outside unless your firewall drops it. Worth a rule if the node faces the internet.
8. Turn on the management API — only if you need it
You need this if something other than you at a terminal has to drive the node: your own automation, a script, an orchestrator. If the panel and the CLI are enough, skip this step and leave the surface closed.
The token is not created for you, and that is deliberate — a node that minted its own API credential would be granting access nobody asked for. You ask for one explicitly, at any time, on a node that is already running. You do not need to reinstall anything.
Generate one on the node
The usual way. The node mints a strong random token, stores it, and shows it to you:
sudo cenvero-str-ctl api-token generate
It prints the token once. Copy it then — it is not displayed again, and there is no command that will show it back to you. If you lose it, generate a new one; that replaces the old, and anything still using the old token starts getting 401 after the next restart.
Supply your own instead
If you need a specific value — one your automation already holds, or one from your secret manager — pipe it in. Piping keeps it out of your shell history, which is why there is no flag to pass it as an argument:
printf '%s' "$MY_TOKEN" | sudo cenvero-str-ctl api-token set
Anything under 16 characters is refused. A token short enough to guess is worse than no token at all, because you would believe the API was protected.
Check or remove it
cenvero-str-ctl api-token status # is one set? (never prints the value)
cenvero-str-ctl api-token clear # remove it — the APIs stop at the next restart
status deliberately reports only whether a token exists, never what it is.
At install time, if you prefer
CENVERO_API_TOKEN=auto mints one during the install, and
CENVERO_API_TOKEN=<value> sets yours — the same result, before the node first
starts. It is entirely optional: generating one later is fully supported and
changes nothing else about the node.
Whichever way you set it, the token is kept in your local overrides, so a later sync from the panel will not discard it.
Then enable the APIs you want
cenvero-str-ctl service on rest
systemctl restart cenvero-stratum
The API speaks HTTPS, never plaintext, so reach it as
https://<node>:7070/…. An http:// URL will fail even with everything
configured correctly. Your node's certificate is signed by your own account
authority, so a browser warns until you trust that root.
The name comes after on — service on rest, not service rest on. Valid
names are rest, grpc, websocket, metrics, dns and dhcp, and off
takes the same form.
The API binds only when all three hold: a token is configured, the service is
on, and the node has a TLS certificate (step 9 — the agent refuses to serve
plaintext). If any one is missing, the port stays closed and a browser gets
"connection refused". cenvero-str-ctl service status tells you which.
Every protected endpoint then requires that token as a bearer credential. API Reference has the details.
9. Get the node its certificate
The node serves its APIs over TLS. Ask the panel to sign a certificate for it:
sudo cenvero-str-ctl tls request
You then approve the request in your account, under TLS. Once approved:
sudo cenvero-str-ctl tls pull
cenvero-str-ctl tls info
tls info should report mode: ca-signed with an expiry. Note the commands
here are tls info and tls pending-status — there is no tls status.
Renewal is automatic. See TLS and Licence.
10. Configure the node's job
Now give the node something to do. There is no node type to pick — every node hosts workloads and routes. What it can do is limited only by how many interfaces it has free, which Nodes and Interfaces explains.
Define networks and addressing. Create the networks your workloads sit on and the pools they draw addresses from:
cenvero-str-ctl network list
cenvero-str-ctl ipam pools
cenvero-str-ctl ipam allocations
See Networking Overview.
Set up DNS and DHCP. Both are already listening. What they lack is your zones, scopes and reservations. See DHCP and DNS.
Write firewall rules. A new node has no rules of its own. See Firewall.
Add a path to the internet. Source-NAT lets a private tenant subnet reach the internet through one public address. See Gateway and NAT.
Set bandwidth and quotas. Your plan already caps the node's total speed. These divide it up between tenants. See Tenants.
Verify the install
Run through this list. Everything should be true before you put real traffic on the node.
| Check | Command | Expected |
|---|---|---|
| Service is up | systemctl status cenvero-stratum | active (running) |
| Agent responds | cenvero-str-ctl status | reports its state |
| Licence is live | cenvero-str-ctl license status | active, with an expiry |
| Certificate is signed | cenvero-str-ctl tls info | mode: ca-signed |
| Services match intent | cenvero-str-ctl service | what you enabled is listening |
| Node is healthy | cenvero-str-ctl heal | all checks pass |
| Metrics answer | curl 127.0.0.1:9090/metrics | a metrics response |
Troubleshooting
systemctl restart cenvero-str-ctl says unit not found. The service is
cenvero-stratum. cenvero-str-ctl is the CLI.
cenvero-str-ctl restart says unknown command. The CLI talks to the agent;
it does not control the service. Use systemctl restart cenvero-stratum.
The REST, gRPC and WebSocket APIs are all down. Expected on a fresh node
with no API token. This is fail-closed behaviour, not a fault. Fix it with
cenvero-str-ctl api-token generate, then service on rest, then restart.
The API port refuses the connection (ERR_CONNECTION_REFUSED, or curl
reporting connection refused). Nothing is listening there. Enabling the service
is only half of it — without a token the server does not start, so the port stays
closed. Check cenvero-str-ctl api-token status first, then
cenvero-str-ctl service status: the row should read enabled and listening.
service on rest said it was enabled, but ENABLED still shows off. Your
switch was saved — confirm with cenvero-str-ctl config show. On builds
before this behaviour was corrected, the ENABLED column also folded in whether
an API token exists, so a service you had genuinely enabled still displayed as
off when no token was configured. Set a token (step 8) and the row resolves.
ENABLED now reports only your switch.
curl 127.0.0.1:9090 returns 404. That port serves /metrics and nothing
else. The bare root is not a page. Use curl 127.0.0.1:9090/metrics.
Activation fails with a node quota message. Every slot on the licence is taken. Reject or revoke a machine you no longer run and its slot comes back, or raise the node count on the licence.
tls pull succeeds but the panel shows nothing to approve. The node needs
to be registered before it can raise a request. Check cenvero-str-ctl license
status first — if the node never registered, that is the thing to fix, and a
node quota message is the usual reason.
The install stopped over the kernel. Your kernel is older than the data plane needs. Step 2 covers your options.
Something else. cenvero-str-ctl heal runs the health checks, and the logs
are in /var/log/cenvero-str/.
Where to go next
- Quick Start — define a network and attach a workload
- Configuration — the node configuration in full
- Nodes and Interfaces — what a node does, and the interfaces it needs
- Networking Overview — how traffic moves
- Clustering Overview — join this node to others
- Operations — day-to-day running
- Upgrades — keeping the node current
Take this guide with you
Every page here is downloadable, so you can keep it alongside your runbooks or feed it to your own tooling:
- This page — installation.json
- The whole documentation set — docs.json
Both return the Markdown source, so they stay readable offline and are not tied
to this site. Add ?include=html to either for the rendered HTML as well.