Skip to content

Installation

Condensa ships as a single self-contained binary: the web UI is embedded, the database is SQLite, and configuration is done through environment variables. Kubernetes is not required — it is only involved when the migration target is Awanio CEP.

Requirements

  • Linux x86_64 server (a VM is fine)
  • Network access from the Condensa server to:
    • VMware vCenter/ESXi (port 443)
    • the migration target — Awanio Cockpit or Vapor API (see Integration)
  • Disk space for staged transfers (only used by the staged fallback and OVA/VHD uploads): size the staging directory for the largest disk you plan to migrate

Data path dependencies

Condensa moves disk data one of two ways, and each has its own prerequisite. The engine is chosen automatically per migration, so it is worth knowing which one your setup will get before you start a large transfer.

Data pathHow data flowsWarm migrationPrerequisite
Direct VDDK (preferred)ESXi → target hostSupportedOn the target Vapor host: nbdkit with the VDDK plugin, VMware's VDDK library, plus qemu-nbd and nbdfuse
Staged (fallback, Cockpit targets only)ESXi → Condensa → targetNot supportedOn the Condensa host: qemu-img (package qemu-utils)

On the target host (Vapor): VDDK

Without it, warm migration is impossible and every migration falls back to the staged path. Install it through the Vapor UI (System → Third-party libraries) or the Ansible role, then confirm the badge reads installed. The migration log states which engine was chosen:

Target host supports VDDK; using direct VDDK pull

If instead you see Target host has no VDDK (nbdkit not found), the staged path is in use.

On the Condensa host: qemu-img

The staged path converts each exported disk to qcow2 inside Condensa, so qemu-img must be present there:

bash
sudo apt-get install -y qemu-utils     # Debian/Ubuntu
sudo dnf install -y qemu-img           # RHEL/Rocky

Condensa refuses to start a staged migration without it rather than failing part-way through an export. The virtual appliance ships with it installed.

Prefer VDDK on the target

The staged path copies every byte twice (source → Condensa → target) and needs staging space for the largest disk. Installing VDDK on the target removes both costs and unlocks warm migration — worth doing before migrating anything large.

Reachability for the staged path

When the staged path is used, the target downloads the prepared disk from Condensa over CONDENSA_PUBLIC_URL. That URL must be reachable from the target host, not just from your browser: an address on a private or NAT'd network the target cannot route to will fail at the download step.

Injecting CONDENSA_PUBLIC_URL at install time

Both installers accept the value directly, so you never have to hand-edit the environment file on a fresh host. Pass --public-url (or export CONDENSA_PUBLIC_URL before running); precedence is --public-url > $CONDENSA_PUBLIC_URL > the host's auto-detected primary address.

bash
# Self-installing binary
sudo ./condensa install --public-url http://condensa.example.com:8080

# Shell installer
sudo ./install.sh --public-url http://condensa.example.com:8080 ./condensa
# or via the environment:
sudo CONDENSA_PUBLIC_URL=http://203.0.113.10:8080 ./install.sh ./condensa

The auto-detected fallback is a best-effort guess from hostname -I; it is wrong on a NAT'd or multi-homed host, so set it explicitly at a customer site. Passing --public-url on an upgrade rewrites just that one line and keeps every secret in place — the fix when a first install guessed wrong.

Write the value so the target can use it verbatim: include the port unless it is the scheme default (443 for https, 80 for http), use https:// whenever CONDENSA_TLS is not off, and append the base-path prefix if you changed CONDENSA_BASE_PATH from /condensa.

SituationCONDENSA_PUBLIC_URL
DNS name, default HTTP porthttp://condensa.example.com:8080
Public IPhttp://203.0.113.10:8080
TLS enabled (CONDENSA_TLS≠off)https://condensa.example.com
Behind a base-path prefixhttp://10.20.0.5:8080/condensa

1. Install the binary

bash
sudo install -m 0755 condensa-server /usr/local/bin/condensa-server
sudo mkdir -p /var/lib/condensa/staging /var/log/condensa /etc/condensa

2. Generate the encryption key

Provider credentials (vCenter passwords, API tokens) are stored AES-256-GCM encrypted. The key is generated once and held by you — a leaked database does not leak infrastructure credentials.

bash
condensa-server -generate-key

You also need a JWT signing secret for authentication tokens. The server refuses to start without it (no insecure default), and changing it later invalidates existing sessions:

bash
openssl rand -base64 48

Store both in /etc/condensa/condensa.env:

bash
sudo tee /etc/condensa/condensa.env <<'EOF'
CONDENSA_ENCRYPTION_KEY=<generated-encryption-key>
JWT_SECRET=<generated-jwt-secret>
EOF
sudo chmod 600 /etc/condensa/condensa.env

Keep the key safe

Losing CONDENSA_ENCRYPTION_KEY means every provider credential must be re-entered. Back the file up alongside your other secrets.

3. Create the systemd unit

/etc/systemd/system/condensa.service:

ini
[Unit]
Description=Condensa VM migration server
After=network-online.target
Wants=network-online.target

[Service]
ExecStart=/usr/local/bin/condensa-server
Environment=PORT=8080
Environment=DB_PATH=/var/lib/condensa/condensa.db
Environment=CONDENSA_UPLOAD_DIR=/var/lib/condensa/staging
Environment=CONDENSA_LOG_FILE=/var/log/condensa/condensa.log
Environment=CONDENSA_PUBLIC_URL=http://condensa.example.com:8080
# condensa.env holds CONDENSA_ENCRYPTION_KEY and JWT_SECRET (chmod 600)
EnvironmentFile=/etc/condensa/condensa.env
Restart=on-failure

[Install]
WantedBy=multi-user.target
bash
sudo systemctl daemon-reload
sudo systemctl enable --now condensa

Environment variables

VariableRequiredPurpose
CONDENSA_ENCRYPTION_KEYYesAES-256 key for provider credentials at rest (-generate-key)
JWT_SECRETYesSigning key for auth tokens (≥32 bytes, e.g. openssl rand -base64 48); the server refuses to start without it
PORTNo (default 8080)HTTP listen port
DB_PATHNoSQLite database file path
CONDENSA_PUBLIC_URLFor staged transfers / OVAURL targets use to reach Condensa's disk-stream endpoint
CONDENSA_UPLOAD_DIRFor staged transfers / OVAStaging directory — size it for the largest staged disk
CONDENSA_LOG_FILERecommendedEnables the UI's Logs page
CONDENSA_ADMIN_USERNAME / CONDENSA_ADMIN_PASSWORDNoProvision the first admin non-interactively (automation)
CONDENSA_TLSRecommendedoff, self-signed, or on — see HTTPS
CONDENSA_TLS_CERT / CONDENSA_TLS_KEYWith CONDENSA_TLS=onPEM certificate chain and private key
CONDENSA_TLS_HOSTSNoExtra names/addresses a self-signed certificate should cover
CONDENSA_UPDATE_URLFor in-place updatesSigned update feed — see Updating
CONDENSA_UPDATE_PUBLIC_KEYWith CONDENSA_UPDATE_URLEd25519 key the feed is verified against

HTTPS

The login form posts a password and every later request carries a session token, so serve the dashboard over TLS. Condensa offers three modes:

CONDENSA_TLSBehaviour
off (default)Plain HTTP. Use only when a reverse proxy in front terminates TLS.
self-signedCondensa issues its own certificate and renews it automatically.
onUses CONDENSA_TLS_CERT and CONDENSA_TLS_KEY.

A value that is neither recognised nor empty is a startup error rather than a silent fall back to plaintext.

Self-signed certificates

Most installations are reached by IP address on a private network, where no certificate authority will issue anything. self-signed covers that case:

bash
CONDENSA_TLS=self-signed

The certificate is stored next to the database, covers loopback, the hostname and every interface address, and is re-issued automatically when it nears expiry or when the host gains an address it does not name. Browsers warn on first visit until you trust it — a one-time click, against sending credentials in the clear on every request.

Add names that are not derived from the interfaces:

bash
CONDENSA_TLS_HOSTS=condensa.internal.example.com,10.20.0.5

Certificates you supply

bash
CONDENSA_TLS=on
CONDENSA_TLS_CERT=/etc/condensa/tls/fullchain.pem
CONDENSA_TLS_KEY=/etc/condensa/tls/privkey.pem

The service user must be able to read both files.

Transfers that pull from Condensa

Two migration paths have the target download disk images from Condensa over CONDENSA_PUBLIC_URL: the staged fallback to Cockpit, and Awanio CEP (CDI). Those downloaders verify certificates, so a self-signed certificate will be refused unless the target trusts it. Use a CA-signed pair for those paths.

Direct VDDK migrations — the default for Cockpit and Vapor targets — pull from VMware rather than from Condensa and are unaffected.

Remember to set CONDENSA_PUBLIC_URL to an https:// URL when TLS is on.

4. First run

Open http://<server>:8080. On a fresh database Condensa shows a setup wizard that creates the first administrator account and logs you in. For scripted deployments, set CONDENSA_ADMIN_USERNAME and CONDENSA_ADMIN_PASSWORD instead — the admin is created at startup.

After setup:

  • create additional accounts under Users (admin-only). The member role is an operator role: it can view providers and create, start, and cancel migrations, while provider management, deletions, user administration, and the audit log stay admin-only.
  • every security-relevant action (logins and failures, user and provider changes, migration lifecycle) is recorded in the Audit Log tab.

5. Connect providers

Continue with Integration to register your VMware source and an Awanio Cockpit or Vapor target.

Updating

Updating never touches /var/lib/condensa or /etc/condensa, so your providers, their encrypted credentials, migration history, users and both secrets carry over. You do not reconfigure anything.

From the dashboard

When a newer release is published, administrators see a notice with an Install update button. Condensa downloads the release, verifies it, installs it and restarts — a few seconds of downtime. The button refuses while a migration is running, because a restart would abandon it.

Installations set up with Condensa 1.1.8 or later are preconfigured to check the enterprise portal — there are no keys and nothing to set up. The source is one line in /etc/condensa/condensa.env; blank it to disable update checks entirely:

bash
CONDENSA_UPDATE_URL=https://enterprise.awan.io/api/v1/products/condensa/releases/latest

Installations set up before 1.1.8 gain the same behaviour after their next manual upgrade; the line above can also be added by hand.

From the command line

bash
sudo condensa update --check    # report what is available, change nothing
sudo condensa update            # install the newest release and restart
sudo condensa update --to 1.1.7 # install a specific release

Add --force to update while a migration is running — it will be interrupted and fail.

What the updater checks

Before anything replaces the binary that currently works:

  1. the release must come from a trusted source — TLS to the configured portal, or, for air-gapped feeds, an Ed25519 signature that verifies against your configured keys;
  2. the downloaded file's SHA-256 must match the one the feed publishes;
  3. the downloaded binary must run and report the version it promised — this catches a truncated or wrong-architecture download that would otherwise leave the service unable to start;
  4. no migration may be running, unless forced.

The binary it replaces is kept alongside as condensa.previous, so a rollback is a copy and a restart.

Replacing the binary by hand

Still supported, and unchanged — database migrations run at startup:

bash
sudo install -m 0755 condensa /usr/local/bin/condensa
sudo systemctl restart condensa

Air-gapped installations

Hosts that cannot reach the enterprise portal still update in place, two ways.

Manual (simplest): bring the release tarball in through your controlled transfer channel, verify its SHA-256 against the value shown on the portal's release page, then:

bash
tar -xzf condensa-<version>-linux-amd64.tar.gz
sudo ./condensa install

The upgrade keeps the database, providers, credentials and settings.

Automatic, from an internal mirror: Awanio supplies, as part of the delivery, a signed feed (updates.signed.json) and the public keys that verify it. Host the feed and the release tarballs on an internal https server, then configure each installation:

bash
CONDENSA_UPDATE_URL=https://releases.internal.example.com/condensa/updates.signed.json
CONDENSA_UPDATE_PUBLIC_KEY=<key A>,<key B>

If the mirror's certificate comes from an internal CA, add that CA to the OS trust store of each Condensa host. The feed is Ed25519-signed, so a compromised mirror cannot alter what installations will accept; every other check the updater performs applies unchanged.