NEXXVU Update center

update2.nexxvu.com

Install NEXXVU Portal

Recommended release 0.3.0-alpha.23, released , for Ubuntu Server 26.04 LTS (x86_64). Follow the tabs in order.

Beta Installation is demonstrated for the tested configuration below. Other configurations have not been tested.

1. Overview

The NEXXVU Portal is a web application that runs on your own server. It keeps an inventory of your infrastructure and shows its monitoring data. After enrollment it reports its status to the update centers named on this page and receives signed releases from them.

Recommended release

Version
0.3.0-alpha.23
Released
Release notes
Release notes for 0.3.0-alpha.23
Status
Beta

Supported platform

System
Ubuntu Server 26.04 LTS
Architecture
amd64 (x86_64)
Python
exactly 3.14.4 (the Ubuntu python3.14 package)

The installer stops on any other system, architecture or Python version.

Server size

Tested configuration
ResourceTested configuration
CPU4 vCPU
Memory8 GB RAM
Disk64 GB

This is the configuration the installation was tested on. A smaller minimum has not been tested.

Network

  • Outbound HTTPS (TCP 443) to update2.nexxvu.com and to the enrollment center your NEXXVU operator names.
  • Inbound TCP 80 and 443 to this server: the Portal's public HTTPS address (Let's Encrypt validation, then HTTPS). Nothing else needs to be reachable from outside.
  • A DNS name for the Portal (<PORTAL_NAME>.<YOUR_DOMAIN>) that resolves to this server.

Downloads

Download from update2.nexxvu.com. The primary update center, update1.nexxvu.com, is not in service yet; this page will list it here once it is.

FileDownload
Package nexxvu-portal-0.3.0-alpha.23-f5e9f839-generic-TEST-KEY-NOT-FOR-PRODUCTION.tar.gz update2.nexxvu.com
Release public key TEST-release-public.key update2.nexxvu.com
Package SHA-256
6aa055aa9cc447603eab3be59b1785d2b6397d2cd04d8d947cf09651f80da0ab
Release key SHA-256
950e04d0629c465998681f4c092f4e6a84f1948ef906bd6dcd4d6441562a47e7
Where is the signature?

There is no separate signature file. Inside the package, package/manifest.sig (Ed25519, Base64) signs package/manifest.json, which names the SHA-256 of the Portal release it carries. Tab 3 checks both with the release public key.

The steps

  1. Prepare Ubuntu: check the server, install the required packages.
  2. Install NEXXVU: download, verify, install and activate.
  3. First setup and enrollment: create the administrator password, enroll, enable reporting and updates.
  4. Updates and recovery: what happens afterwards, and what to do when something fails.

Prefer guided help? Install with Claude gives you one complete set of instructions to paste into Claude.

2. Prepare Ubuntu

Run these commands on the new server as a user that can use sudo.

Check the server

Read-only checks. Expect ubuntu 26.04 x86_64, at least the tested size, the update center resolving, and 200.

. /etc/os-release; echo "$ID $VERSION_ID $(uname -m)"
nproc; free -h; df -h /
getent hosts update2.nexxvu.com
curl --fail --proto =https -sS -o /dev/null -w '%{http_code}\n' https://update2.nexxvu.com/downloads/installers.json

Install the required packages

The installer itself downloads nothing. python3.14-venv is in the universe component. Answer Y when apt asks.

sudo apt update
sudo apt install python3.14-venv acl nftables openssl curl caddy

Check Python (expect 3.14.4), then hold the Python packages so apt upgrade does not replace them:

python3 -c 'import sys; print(sys.version.split()[0])'
sudo apt-mark hold python3.14 python3.14-venv python3.14-minimal libpython3.14-stdlib libpython3.14-minimal
Why Python is held

This release needs Python 3.14.4 exactly. Release the hold (sudo apt-mark unhold with the same package names) only when a release names a newer Python.

3. Install NEXXVU

On the server, create an empty working directory and change into it (for example mkdir nexxvu-download && cd nexxvu-download). Stop at the first mismatch or error and do not install. Report it to the update-center operator.

Download and verify

  1. Download the package and the release public key from update2.nexxvu.com:

    curl --fail --proto =https --remote-name https://update2.nexxvu.com/downloads/nexxvu-portal-0.3.0-alpha.23-f5e9f839-generic-TEST-KEY-NOT-FOR-PRODUCTION.tar.gz
    curl --fail --proto =https --remote-name https://update2.nexxvu.com/downloads/TEST-release-public.key
  2. Check the package checksum. Expect nexxvu-portal-0.3.0-alpha.23-f5e9f839-generic-TEST-KEY-NOT-FOR-PRODUCTION.tar.gz: OK.

    echo '6aa055aa9cc447603eab3be59b1785d2b6397d2cd04d8d947cf09651f80da0ab  nexxvu-portal-0.3.0-alpha.23-f5e9f839-generic-TEST-KEY-NOT-FOR-PRODUCTION.tar.gz' | sha256sum --check --strict
  3. Check the release public key. The printed value must equal the release key SHA-256 (950e04d0629c465998681f4c092f4e6a84f1948ef906bd6dcd4d6441562a47e7), and the key must decode to exactly 32 bytes.

    sha256sum TEST-release-public.key
    base64 --decode TEST-release-public.key | wc -c
  4. Unpack a copy for checking and confirm the package carries the same key (cmp prints nothing when the files are identical):

    mkdir check
    tar --extract --gzip --file nexxvu-portal-0.3.0-alpha.23-f5e9f839-generic-TEST-KEY-NOT-FOR-PRODUCTION.tar.gz --directory check
    cmp TEST-release-public.key check/package/update-signing-public-key
  5. Verify the signed manifest. Expect Signature Verified Successfully.

    { printf '\060\052\060\005\006\003\053\145\160\003\041\000'; base64 --decode TEST-release-public.key; } > release-public.der
    base64 --decode check/package/manifest.sig > manifest.sig.raw
    openssl pkeyutl -verify -pubin -keyform DER -inkey release-public.der -rawin -in check/package/manifest.json -sigfile manifest.sig.raw
    What this does

    The first line wraps the 32-byte key in its standard DER header so OpenSSL can read it. This is the same method the installer's own package check uses.

  6. Check the Portal release against the signed manifest. The output must end in : OK.

    python3 -c 'import json; m = json.load(open("check/package/manifest.json")); print(m["artifact_sha256"] + "  check/package/" + m["artifact_locator"])' | sha256sum --check --strict

    Then remove the checking copy: rm -r check. The installer checks the package again below.

Install and activate

Each command prints a result line. Continue only after the expected result.

  1. Unpack the verified package into a new directory that only root can read (no output):

    sudo install -d -o root -g root -m 0700 /root/nexxvu-install
    sudo tar --extract --gzip --file nexxvu-portal-0.3.0-alpha.23-f5e9f839-generic-TEST-KEY-NOT-FOR-PRODUCTION.tar.gz --directory /root/nexxvu-install
  2. Check the unpacked package. Expect GROUP-1=PASS.

    sudo /root/nexxvu-install/package/GROUP-1-VERIFY.sh /root/nexxvu-install/package
  3. Check the server, then rehearse without changes. Expect PREFLIGHT=PASS, then DRY-RUN=PASS.

    sudo /root/nexxvu-install/package/installer/INSTALL.sh --preflight /root/nexxvu-install/package
    sudo /root/nexxvu-install/package/installer/INSTALL.sh --dry-run /root/nexxvu-install/package
  4. Install, then verify. Expect INSTALL=PASS, then VERIFY=PASS. Nothing is started yet.

    sudo /root/nexxvu-install/package/installer/INSTALL.sh --install /root/nexxvu-install/package
    sudo /root/nexxvu-install/package/installer/INSTALL.sh --verify /root/nexxvu-install/package
  5. Activate: start the Portal on this server, then verify again. Expect LOCAL_RUNTIME_ACTIVATED_HEALTH_VERIFIED, then VERIFY-PROFILE=activated and VERIFY=PASS.

    sudo python3 -B /opt/nexxvu-runtime/runtime-lifecycle.py activate
    sudo /root/nexxvu-install/package/installer/INSTALL.sh --verify /root/nexxvu-install/package

Keep /root/nexxvu-install/package: verification and recovery use it.

4. First setup and enrollment

Public HTTPS address

The Portal itself answers only on this server. Caddy, installed with the packages above, gives it its public address with a Let's Encrypt certificate that renews itself. Before this step the DNS name must resolve to this server and inbound TCP 80 and 443 must reach it. Expect PORTAL-FRONT-VERIFY=PASS, then PORTAL-FRONT=PASS.

sudo /root/nexxvu-install/package/installer/PORTAL-FRONT.sh --enable --hostname <PORTAL_NAME>.<YOUR_DOMAIN> --tls acme
What this changes

It writes the Caddy configuration for that one name, lets the Portal accept the visitor's address from Caddy on this server only, and pins the Portal's local certificate for Caddy (re-pinned automatically after each renewal). It changes no firewall, DNS or Portal data. Caddy renews the certificate by itself; no e-mail address is needed.

First administrator

The administrator account is admin. There is no default password. The first sign-in needs a one-time setup code. The Portal creates it when it starts, and activation then prints the command that shows it:

sudo nexxvu-portal setup-code

Open https://<PORTAL_NAME>.<YOUR_DOMAIN>/ in your browser. Type the setup code, then choose a new password for admin. The code then stops working.

The code gives access to the administrator account. Do not send it by e-mail or chat, and do not paste it into tickets or logs.

Enrollment

Enrollment connects this Portal to the update centers. You need a one-time enrollment code from your NEXXVU operator, issued for this Portal's name.

  • The code looks like NXV1- followed by 32 letters and digits. It works once, only for that Portal name, and it expires. Do not share it.
  • Run the command in an interactive terminal and type the code at the hidden prompt NEXXVU enrollment code:. It is never a command-line argument.
  • Replace <PORTAL_NAME> and <YOUR_DOMAIN> with this Portal's name and your domain.
sudo python3 -B /opt/nexxvu-runtime/runtime-lifecycle.py enroll --center https://<ENROLLMENT_CENTER> --portal-name <PORTAL_NAME> --endpoint https://<PORTAL_NAME>.<YOUR_DOMAIN>

Expect PORTAL_ENROLLED. Enrollment contacts the primary update center only. Its public address, update1.nexxvu.com, is not in service yet: your NEXXVU operator gives you the enrollment center host name (<ENROLLMENT_CENTER>) together with the enrollment code.

Enrolling a reinstalled Portal

A Portal that is already enrolled is refused. To enroll a reinstalled Portal again, ask for a new code and add --reinstall-identity to the command.

Reporting and updates

The order matters: enable reporting first, then schedule it, then enable updates. Expect SERVICE_ENABLED three times.

sudo python3 -B /opt/nexxvu-runtime/runtime-lifecycle.py enable-reporting
sudo python3 -B /opt/nexxvu-runtime/runtime-lifecycle.py enable-reporting --schedule
sudo python3 -B /opt/nexxvu-runtime/runtime-lifecycle.py enable-updates

Check the result. Expect RUNTIME_ACTIVATION_VERIFIED.

sudo python3 -B /opt/nexxvu-runtime/runtime-lifecycle.py verify-activated

After the first scheduled report, the update-center operator sees the Portal in the fleet as online, with its name and installed version. Ask the operator to confirm this.

5. Updates and recovery

How updates arrive

  • A new release is offered to this Portal only after the update-center operator approves it for this Portal. It then appears on the Portal's Updates page, where an administrator reviews it, requests authorization and starts the signed update.
  • Every release is signed. The Portal checks each release against the release public key it received at enrollment (SHA-256 950e04d0629c465998681f4c092f4e6a84f1948ef906bd6dcd4d6441562a47e7) and refuses anything else.
  • Either update center can deliver reports and releases. Enrollment uses the primary only.

Reboot

The Portal, its local certificate renewal and its enabled reporting and update services start again by themselves after a reboot. To check this:

sudo reboot

Reconnect after a few minutes. Expect RUNTIME_ACTIVATION_VERIFIED, then VERIFY-PROFILE=activated and VERIFY=PASS.

sudo python3 -B /opt/nexxvu-runtime/runtime-lifecycle.py verify-activated
sudo /root/nexxvu-install/package/installer/INSTALL.sh --verify /root/nexxvu-install/package

Local certificate renewal

A daily timer renews the Portal's local certificate before it expires. To check it now: expect enabled, then TLS_NOT_DUE (nothing due yet) or TLS_RENEWED_HEALTH_VERIFIED.

systemctl is-enabled nexxvu-local-tls-renew.timer
sudo python3 -B /opt/nexxvu-runtime/runtime-lifecycle.py renew
sudo /root/nexxvu-install/package/installer/PORTAL-FRONT.sh --verify

Caddy renews the public certificate by itself; the last line checks the public address end to end (expect PORTAL-FRONT-VERIFY=PASS).

Recovery

Lost administrator password. This suspends admin sign-in, ends its sessions and prints a new one-time setup code. Then set a new password at https://<PORTAL_NAME>.<YOUR_DOMAIN>/setup.

sudo nexxvu-portal recovery reset-admin

Locked out by the sign-in IP allowlist. This empties the list, so every address may reach the sign-in page again.

sudo nexxvu-portal recovery clear-allowlist

When something fails

A refused step prints a fixed reason, for example GREENFIELD-INSTALL=STOP reason=… or RUNTIME_LIFECYCLE_REFUSED_EVIDENCE_RETAINED … with a hint. Nothing is deleted on a refusal. Send the reason line to the update-center operator. These read-only commands show the installed release and the state of the NEXXVU services:

sudo cat /opt/nexxvu-updater/state/current-release.json
systemctl --no-pager list-units 'nexxvu-*'
sudo journalctl -u nexxvu-portal.service -n 50 --no-pager

6. Install with Claude

Claude can guide you through the whole installation. Copy the scope of work below and paste it into Claude on a computer that can reach your server (for example Claude Code, or the Claude extension in your editor). Claude asks for your server details, runs the published commands with you and stops on any failed check.

  • You keep every secret to yourself: passwords, the setup code and the enrollment code are typed by you, never pasted into the chat.
  • Some steps are yours alone, for example DNS records, firewall ports and the hosting console.
SCOPE OF WORK: install NEXXVU Portal 0.3.0-alpha.23 on my Ubuntu server

You are my installation assistant. I am a beginner. Install NEXXVU Portal 0.3.0-alpha.23 on my own server by following this scope of work, one step at a time. It comes from the official install page https://update2.nexxvu.com/ (the primary update center update1.nexxvu.com is not in service yet). Before each step, tell me in one or two plain sentences what it does. After each command, compare its output with the "Expect" line and tell me the result.

PLACEHOLDERS - ask me for these values first, repeat them back to me, and use them everywhere below:
  <SERVER_ADDRESS>  the IP address or DNS name of my server
  <SSH_USER>        the account you use on the server (it must be allowed to use sudo)
  <PORTAL_NAME>     the Portal name my NEXXVU operator registered for this server
  <YOUR_DOMAIN>     my domain; the Portal address becomes https://<PORTAL_NAME>.<YOUR_DOMAIN>/
  <ENROLLMENT_CENTER> the enrollment center host name my NEXXVU operator gives me with the enrollment code

SAFETY RULES - these always apply
1. Never ask me for a password, setup code, enrollment code, private key or token, and never put one in a command, a file, a log or this chat. I type secrets myself: passwords in my browser, codes in my own terminal. If I paste a secret here by mistake, tell me, do not use it, and remind me to replace it.
2. Use only the commands in this scope of work, exactly as written (only the placeholders change). If another command is needed, first explain what it does and why, and wait for my OK.
3. Never disable, skip or work around a checksum or signature check, and never use a file that failed one.
4. If a check fails, a command reports an error, or the output differs from "Expect": STOP. Show me the exact result line and ask me what to do. Do not retry with other options on your own.
5. Do not change firewall, DNS, SSH or user settings yourself. Tell me what is needed; I do it.
6. Steps marked "I DO" are done by me. Give me clear instructions and wait until I confirm.

RELEASE FACTS (every download is checked against these)
  Version:             0.3.0-alpha.23, released 2026-10-09
  Package:             nexxvu-portal-0.3.0-alpha.23-f5e9f839-generic-TEST-KEY-NOT-FOR-PRODUCTION.tar.gz
  Package SHA-256:     6aa055aa9cc447603eab3be59b1785d2b6397d2cd04d8d947cf09651f80da0ab
  Release public key:  TEST-release-public.key
  Release key SHA-256: 950e04d0629c465998681f4c092f4e6a84f1948ef906bd6dcd4d6441562a47e7
  Download from:       https://update2.nexxvu.com/downloads/
  Platform:            Ubuntu Server 26.04 LTS, x86_64 (amd64), Python exactly 3.14.4
  Server size:         4 vCPU, 8 GB RAM, 64 GB disk (the tested configuration; no smaller size has been tested)

STEP 1 - Collect the details (ask me)
- <SERVER_ADDRESS> and how you reach the server: (a) SSH with a key: I give you <SSH_USER> and confirm that "ssh <SSH_USER>@<SERVER_ADDRESS>" works from this computer without a password prompt; or (b) my hosting provider's web console: then I run each command there and paste the output back to you.
- <PORTAL_NAME> and <YOUR_DOMAIN>.
- Whether I have asked my NEXXVU operator for a one-time enrollment code for <PORTAL_NAME>. If not, remind me to ask now; I need it in step 10 and keep it to myself.

STEP 2 - Prepare the server (I DO - give me this checklist and wait until I confirm every item)
- In my hosting console: a server with Ubuntu Server 26.04 LTS, x86_64, at least the server size above.
- DNS: a record for <PORTAL_NAME>.<YOUR_DOMAIN> that points to the server's address.
- Firewall: outbound HTTPS (TCP 443) to update2.nexxvu.com and the enrollment center; inbound TCP 80 and 443 to the server (its public HTTPS address); nothing else inbound.
- The account <SSH_USER> can use sudo and is reachable by SSH key (or I use the hosting console).

STEP 3 - Check the server (read-only)
    . /etc/os-release; echo "$ID $VERSION_ID $(uname -m)"
    nproc; free -h; df -h /
    getent hosts update2.nexxvu.com
    curl --fail --proto =https -sS -o /dev/null -w '%{http_code}\n' https://update2.nexxvu.com/downloads/installers.json
  Expect: "ubuntu 26.04 x86_64"; at least 4 CPUs, 8 GB memory and 64 GB disk on /; the update center resolves; "200". Anything else: STOP (rule 4).

STEP 4 - Prepare Ubuntu (apt asks to confirm the install: answer Y)
    sudo apt update
    sudo apt install python3.14-venv acl nftables openssl curl caddy
    python3 -c 'import sys; print(sys.version.split()[0])'
    sudo apt-mark hold python3.14 python3.14-venv python3.14-minimal libpython3.14-stdlib libpython3.14-minimal
  Expect: the python3 line prints 3.14.4; the packages are then held.

STEP 5 - Download, on the server, in a new empty directory (mkdir nexxvu-download && cd nexxvu-download)
    curl --fail --proto =https --remote-name https://update2.nexxvu.com/downloads/nexxvu-portal-0.3.0-alpha.23-f5e9f839-generic-TEST-KEY-NOT-FOR-PRODUCTION.tar.gz
    curl --fail --proto =https --remote-name https://update2.nexxvu.com/downloads/TEST-release-public.key

STEP 6 - Verify the download, in the same directory (every check must pass; never continue after a mismatch)
    echo '6aa055aa9cc447603eab3be59b1785d2b6397d2cd04d8d947cf09651f80da0ab  nexxvu-portal-0.3.0-alpha.23-f5e9f839-generic-TEST-KEY-NOT-FOR-PRODUCTION.tar.gz' | sha256sum --check --strict
  Expect: "nexxvu-portal-0.3.0-alpha.23-f5e9f839-generic-TEST-KEY-NOT-FOR-PRODUCTION.tar.gz: OK"
    sha256sum TEST-release-public.key
    base64 --decode TEST-release-public.key | wc -c
  Expect: the SHA-256 printed equals 950e04d0629c465998681f4c092f4e6a84f1948ef906bd6dcd4d6441562a47e7, then "32".
    mkdir check
    tar --extract --gzip --file nexxvu-portal-0.3.0-alpha.23-f5e9f839-generic-TEST-KEY-NOT-FOR-PRODUCTION.tar.gz --directory check
    cmp TEST-release-public.key check/package/update-signing-public-key
  Expect: no output.
    { printf '\060\052\060\005\006\003\053\145\160\003\041\000'; base64 --decode TEST-release-public.key; } > release-public.der
    base64 --decode check/package/manifest.sig > manifest.sig.raw
    openssl pkeyutl -verify -pubin -keyform DER -inkey release-public.der -rawin -in check/package/manifest.json -sigfile manifest.sig.raw
  Expect: "Signature Verified Successfully".
    python3 -c 'import json; m = json.load(open("check/package/manifest.json")); print(m["artifact_sha256"] + "  check/package/" + m["artifact_locator"])' | sha256sum --check --strict
  Expect: the line ends in ": OK".
  Then remove the checking copy: rm -r check

STEP 7 - Install and activate, in the same directory (keep /root/nexxvu-install/package afterwards)
    sudo install -d -o root -g root -m 0700 /root/nexxvu-install
    sudo tar --extract --gzip --file nexxvu-portal-0.3.0-alpha.23-f5e9f839-generic-TEST-KEY-NOT-FOR-PRODUCTION.tar.gz --directory /root/nexxvu-install
  Expect: no output.
    sudo /root/nexxvu-install/package/GROUP-1-VERIFY.sh /root/nexxvu-install/package
  Expect: GROUP-1=PASS
    sudo /root/nexxvu-install/package/installer/INSTALL.sh --preflight /root/nexxvu-install/package
    sudo /root/nexxvu-install/package/installer/INSTALL.sh --dry-run /root/nexxvu-install/package
  Expect: PREFLIGHT=PASS, then DRY-RUN=PASS
    sudo /root/nexxvu-install/package/installer/INSTALL.sh --install /root/nexxvu-install/package
    sudo /root/nexxvu-install/package/installer/INSTALL.sh --verify /root/nexxvu-install/package
  Expect: INSTALL=PASS, then VERIFY=PASS
    sudo python3 -B /opt/nexxvu-runtime/runtime-lifecycle.py activate
    sudo /root/nexxvu-install/package/installer/INSTALL.sh --verify /root/nexxvu-install/package
  Expect: LOCAL_RUNTIME_ACTIVATED_HEALTH_VERIFIED, then VERIFY-PROFILE=activated and VERIFY=PASS

STEP 8 - Public HTTPS address (the DNS record from step 2 must already point to the server)
    sudo /root/nexxvu-install/package/installer/PORTAL-FRONT.sh --enable --hostname <PORTAL_NAME>.<YOUR_DOMAIN> --tls acme
  Expect: PORTAL-FRONT-VERIFY=PASS, then PORTAL-FRONT=PASS. If it stops with a reason line about the certificate or health: STOP (rule 4); DNS or inbound TCP 80/443 is usually not in place yet.

STEP 9 - First administrator (I DO - you do not run this command: its output is a secret)
  I run this in my own SSH session or the hosting console:
    sudo nexxvu-portal setup-code
  It shows a one-time setup code. I open https://<PORTAL_NAME>.<YOUR_DOMAIN>/ in my browser, type the code, and choose a new password for the account "admin" (there is no default password). Ask me only whether it worked.

STEP 10 - Enrollment (I DO - the code prompt needs my own interactive terminal)
  Give me this command with my placeholders filled in; I run it in my SSH session or the hosting console:
    sudo python3 -B /opt/nexxvu-runtime/runtime-lifecycle.py enroll --center https://<ENROLLMENT_CENTER> --portal-name <PORTAL_NAME> --endpoint https://<PORTAL_NAME>.<YOUR_DOMAIN>
  I type the one-time enrollment code from my NEXXVU operator (NXV1- followed by 32 letters and digits) at the hidden prompt "NEXXVU enrollment code:". It is never a command-line argument. I tell you only the result line.
  Expect: PORTAL_ENROLLED. If it is refused: STOP; a code works only once.
  <ENROLLMENT_CENTER> is the host name my NEXXVU operator gave me with the code (the primary update center update1.nexxvu.com is not in service yet). If I do not have it: STOP and ask my operator.

STEP 11 - Reporting and updates (the order matters: plain enable-reporting first, then --schedule, then updates)
    sudo python3 -B /opt/nexxvu-runtime/runtime-lifecycle.py enable-reporting
    sudo python3 -B /opt/nexxvu-runtime/runtime-lifecycle.py enable-reporting --schedule
    sudo python3 -B /opt/nexxvu-runtime/runtime-lifecycle.py enable-updates
  Expect: SERVICE_ENABLED three times.
    sudo python3 -B /opt/nexxvu-runtime/runtime-lifecycle.py verify-activated
  Expect: RUNTIME_ACTIVATION_VERIFIED

STEP 12 - Final checks
a) HTTPS (I DO): I open https://<PORTAL_NAME>.<YOUR_DOMAIN>/ and sign in as admin. Ask me whether the dashboard opens.
b) Reporting (I DO): I ask my NEXXVU operator to confirm that <PORTAL_NAME> appears online in the fleet with version 0.3.0-alpha.23 after its first scheduled report.
c) Reboot (ask me before you reboot):
    sudo reboot
  Wait a few minutes, reconnect, then:
    sudo python3 -B /opt/nexxvu-runtime/runtime-lifecycle.py verify-activated
    sudo /root/nexxvu-install/package/installer/INSTALL.sh --verify /root/nexxvu-install/package
  Expect: RUNTIME_ACTIVATION_VERIFIED, then VERIFY-PROFILE=activated and VERIFY=PASS
d) Local certificate renewal:
    systemctl is-enabled nexxvu-local-tls-renew.timer
    sudo python3 -B /opt/nexxvu-runtime/runtime-lifecycle.py renew
    sudo /root/nexxvu-install/package/installer/PORTAL-FRONT.sh --verify
  Expect: "enabled", then TLS_NOT_DUE (nothing due yet) or TLS_RENEWED_HEALTH_VERIFIED, then PORTAL-FRONT-VERIFY=PASS

STEP 13 - Report back to me
- the Portal address: https://<PORTAL_NAME>.<YOUR_DOMAIN>/
- the installed version, from:
    sudo cat /opt/nexxvu-updater/state/current-release.json
  Expect: "semver" is 0.3.0-alpha.23
- every step that is not finished or did not pass, with its exact result line.

IF SOMETHING FAILS
- A refused step prints a fixed reason line, for example GREENFIELD-INSTALL=STOP reason=... or RUNTIME_LIFECYCLE_REFUSED_EVIDENCE_RETAINED. Nothing is deleted on a refusal. Show me the line; I send it to my NEXXVU operator. These read-only commands show the state of the NEXXVU services:
    systemctl --no-pager list-units 'nexxvu-*'
    sudo journalctl -u nexxvu-portal.service -n 50 --no-pager
- Lost administrator password (I DO; it prints a new one-time setup code, then I set a new password at https://<PORTAL_NAME>.<YOUR_DOMAIN>/setup):
    sudo nexxvu-portal recovery reset-admin