Skip to content

Distribution & reachability

Under Admin → Agents & Collectors → Agent connection you configure which address your machines use to reach the server (the server address — including the base for the optional agent gateway) and migrate an existing fleet to a new address.

Where do installers and binaries come from?

From the Vesana server itself — at https://<your-server>/agent/install.sh, /collector/install.sh and so on. The installer and auto-update fetch everything straight from the server (or from the agent gateway port if you use it). There is no separate "distribution source" any more: the former external mode (separate distribution server) and the signing-pubkey field were removed in 09/2026 — no distribution server existed to point at, and no installer ever verified the signature.

Without network access to the target machine use the offline bundle: the "Offline bundle" tab when adding an agent/collector produces a tar.gz/zip with binary, installer and pre-filled configuration (USB, file share). A bundle-installed agent later updates normally via the server once it can reach it. If the server uses a self-signed certificate, the bundle carries its fingerprint (file vesana-cert-pin.env, read by the installer), like the online commands.

The server address

Field Who uses it? When to set it?
Server address Agents, collectors, install scripts, the pre-filled Windows installer When machines should reach the server at a different address than the BASE_URL in .env — especially with the agent gateway enabled (then including the port, e.g. https://server.example.com:8443). If nothing is saved, BASE_URL applies. Saved with "Save address".

The server address ends up everywhere a machine gets provisioned: in the Linux/Windows install commands, in the downloaded setup.exe (the URL is patched into the binary server-side) and in offline bundles. Existing machines keep their address until you switch them further down the page.

Precheck from the server

While you type the address, the server calls it itself (GET /health) and shows "Precheck: reachable from the server" or the reason (port closed, timeout, DNS, TLS). This exposes typos and wrong ports before you switch an agent. Behind Cloudflare or NAT the precheck can fail even though the address works from outside — what counts is the test run with one device (see below).

Agent gateway: locking down the web UI

Since v1.9.93. When agents and collectors report in from customer networks over the internet, your server must be publicly reachable. Without further measures that also exposes the entire web UI: login page, management API, everything.

The agent gateway solves this: a separate port that serves machine endpoints only — agent configuration, heartbeats, result ingestion, installers and binary downloads. No login page, no frontend, no management or admin API. In your firewall you only open the gateway port and restrict the UI port to internal networks or VPN. Customer machines still need outbound HTTPS only — nothing changes there.

Enabling it — right in the UI

On the same page (Admin → Agents & Collectors → Agent connection) you will find the "Agent gateway" card: flip the switch — Vesana starts the gateway on port 8443 and fills in the server address https://<host>:8443 for you (can be overridden for proxy setups). You set a different port afterwards via "Change port" → "Apply (restart)". Vesana persists the setting (it survives updates and restarts). If the start fails — e.g. because the port is already taken on the host — the setting is rolled back and the error is shown right in the card; the card also has an expandable firewall hint. Disabling works via the same switch. Your running machines stay on their current address until you deliberately switch them. The switch needs the updater service.

Alternative: manually via .env (headless/automation or without the updater)

Add two lines to your installation's .env and restart the stack:

COMPOSE_PROFILES=agent-gateway     # combine profiles: "ai,agent-gateway"
AGENT_GATEWAY_PORT=8443            # host port, freely choosable (default 8443)

docker compose -f docker-compose.prod.yml up -d

The gateway container uses the same image and the same TLS certificates as the main web server. Smoke test:

curl -k https://<server>:8443/health              # → {"status":"ok", ...}
curl -k https://<server>:8443/                    # → 404 — no frontend
curl -k https://<server>:8443/api/v1/auth/login   # → 404 — no login

Both ports are freely choosable

Only one public IP, and agents should use standard port 443? Just swap:

HTTPS_PORT=8443           # web UI moves to 8443 (internal only)
AGENT_GATEWAY_PORT=443    # agents use the standard port

Migrating an existing installation — order matters!

The UI port keeps serving everything (including the agent endpoints). Your agents only break if you migrate them and then close the firewall. So strictly in this order:

  1. Enable the gateway (see above) and verify with the three curl probes.
  2. Check the server address (see The server address): switching on set it to the gateway URL, e.g. https://server.example.com:8443; the precheck should show "reachable". From now on new agents automatically get the right URL.
  3. Switch the existing fleet — further down the same page: "1. test" → choose a test device → "Test with one device". Only once the test device reports back on the new address (≤ 1 min) does "2. switch" → "Switch all" become clickable. Every machine picks up the new address on its next heartbeat, checks it itself first and rewrites its configuration; if it cannot reach the address, it stays connected on the old one.
  4. Control phase: watch the list (filters "on target" / "pending" / "error") or the diagnostics log (category "Connection") until all machines come in via the new path. Do not proceed earlier.
  5. Only now: firewall — UI port (HTTPS_PORT) internal/VPN only, gateway port public.

Don't lock yourself out

If you close the firewall before the fleet is migrated, all agents lose their connection (status "No data"). This is always reversible — reopening the firewall is enough — but it costs monitoring gaps. Stick to the order.

Rollback

At any time, without an update or restart: reopen the firewall, or set the server address back on the same page and switch the machines again.

What deliberately does NOT go through the gateway

Area Why Consequence
Public status pages human endpoint, needs the frontend With a locked-down UI port they are not publicly reachable — if needed, open the UI port selectively for the required sources
Installed web app on the phone is the regular web UI Technicians use it via VPN / the internal URL

The Windows installer (setup.exe) and the install scripts, however, are deliberately available on the gateway — that is provisioning of customer machines, which is exactly what the port is for. You can hand the download link directly to a customer.

Troubleshooting

Symptom Cause / fix
curl https://server:8443/health → timeout Firewall/NAT: gateway port not open, or container not running (docker compose ps)
Precheck in the admin UI fails, curl from the customer network works The server itself cannot reach its own public URL (hairpin NAT). The precheck is an indicator; the test run with one device is what counts
Test device cannot reach the new address The device stays connected on the old address (no outage); the reason is shown in its row. Fix address/port, "Reset test run", test again
Agent stays on "No data" after migration Check agent.log on the machine (C:\ProgramData\Vesana\Agent\agent.log or journalctl -u vesana-agent): does it show the new URL? Timeout → firewall; 401 → token; TLS error → certificate (check the fingerprint in the agent config server_cert_sha256)
Login page visible on the gateway port Must never happen — check the role: the container needs VESANA_NGINX_ROLE=gateway (set automatically with the standard compose)

Self-signed certificate?

The gateway uses the certificates of the Vesana stack (the same ssl volume as the stack web server). If you terminate TLS with your own reverse proxy in front (a second nginx, Caddy, Traefik with Let's Encrypt), the gateway port still presents the self-signed stack certificate — your proxy does not sit in front of the gateway port. That is fine: Vesana detects this itself. The install commands and the pre-filled Windows installer then carry the fingerprint of the stack certificate, and when migrating an existing fleet it travels along in the heartbeat. Agent and collector accept exactly this certificate in addition to the regular check — without disabling the check. The install command itself also checks the fingerprint while downloading the installer — on Windows via a built-in certificate check (PowerShell 5.1 and 7), on Linux via curl --pinnedpubkey (curl must be present on the target machine). A command generated with an older stack certificate fails after the certificate changes: generate the command in Vesana again.

The option "Server has a self-signed certificate (skip TLS verification)" when adding an agent/collector disables verification entirely — only needed if you deliberately do not want the pin. For publicly reachable servers, a real certificate (e.g. Let's Encrypt) remains the better choice.

Certificate from Vesana (Let's Encrypt) and pins

If Vesana issues the certificate itself (Admin → System → Certificate, TLS / certificate), the web UI AND the gateway port serve the same publicly trusted certificate — agents and collectors then no longer need a pin, including those that were connected to the self-signed one with a pin (they check “chain OR pin”). Vesana never pins an ACME certificate: it changes with every renewal. If a device reaches Vesana at an address the certificate does not cover (e.g. an IP), the pre-check names it BEFORE installing — then move the device to a covered name via Agent connection.

Do not delete the ssl volume while agents run through the gateway

A newly generated stack certificate has a different fingerprint. Agents that can no longer reach the UI port because of the firewall cannot learn the new pin. Changing the certificate means: move the fleet back to the UI port via Agent connection first, or distribute the new pin via an address migration.