Installing Xen Orchestra from Sources - The Easy Way

If you run XCP-ng in your homelab, you’ve probably already heard of Xen Orchestra. It’s the web-based management interface for your XCP-ng hosts — think VM consoles, backup scheduling, storage management, live migration, and more, all in a browser. The only catch: the fully-featured version requires a paid subscription from Vates.

The good news is that Xen Orchestra is open source, and you can build it from source yourself for free. The not-so-good news is that the build process involves Node.js, Yarn, a handful of config files, and enough steps to make it easy to get wrong — especially when you want to keep it updated over time.

That’s exactly why I built install_xen_orchestra — a Bash script that handles the full lifecycle: fresh install, updates, backups, restores, rebuilds, and even XO Proxy deployment, all from a single script.


What It Does

At its core, the script automates what the official Xen Orchestra source installation docs walk you through manually. But it goes well beyond a one-time install — it’s designed to be the tool you run every time you need to touch your XO instance.

Function CLI Flag Description
Install --install Fresh install of Xen Orchestra from source
Update --update Pull latest source, rebuild, and restart (with backup)
Restore --restore Restore from a previous backup
Rebuild --rebuild Fresh clone + clean build, preserves your settings
Reconfigure --reconfigure Apply config changes without a full rebuild
XO Proxy --proxy Deploy XO Proxy to a Xen pool master

Running the script with no arguments drops you into an interactive menu instead.


The Interactive Menu

Like my other tools, this one has a keyboard-navigable menu for those who prefer not to memorize flags. It also shows you at a glance whether your local script and XO installation are up to date vs. the upstream master branch:

╔══════════════════════════════════════════════════════════════════════════════════╗
║              Install Xen Orchestra from Sources Setup and Update                 ║
╚══════════════════════════════════════════════════════════════════════════════════╝

                    Current Script Commit : 693f4 (Branch: main)
                    Master Script Commit  : 693f4 (Branch: main)
                    Current XO Commit     : a1b2c (Branch: master)
                    Master XO Commit      : d4e5f (Branch: master)
                    Current Node          : v24.15.0

────────────────────────────────────────────────────────────────────────────────

▸ [✓] Install Xen Orchestra                   [ ] Reconfigure Xen Orchestra
  [ ] Update Xen Orchestra                    [ ] Rebuild Xen Orchestra
  [ ] Rename Sample-xo-config.cfg             [ ] Edit xo-config.cfg
  [ ] Install XO Proxy

────────────────────────────────────────────────────────────────────────────────

Selected: 1

↑↓←→ Navigate   SPACE Select/Deselect   ENTER Confirm   Q Quit

Use arrow keys to navigate, Space to select, and Enter to run. You can queue multiple actions at once.


Quick Start

bash

git clone https://github.com/acebmxer/install_xen_orchestra.git
cd install_xen_orchestra
cp sample-xo-config.cfg xo-config.cfg
nano xo-config.cfg   # configure to your liking
./install-xen-orchestra.sh

Do not run with sudo. The script handles privilege escalation internally — run it as a normal user with sudo access.

If xo-config.cfg doesn’t exist when the script runs, it’s automatically created from the sample config — so the first-time setup is forgiving.


Configuration

Everything is controlled through xo-config.cfg. Here are the key options:

Setting Default Description
HTTP_PORT 80 HTTP port XO listens on
HTTPS_PORT 443 HTTPS port
INSTALL_DIR /opt/xen-orchestra Where XO is installed
GIT_BRANCH master Git branch or tag to build from
NODE_VERSION 24.15.0 Node.js version to use
SERVICE_USER xo-service User the XO service runs as
BACKUP_KEEP 5 Number of backups to retain
BIND_ADDRESS 0.0.0.0 Network bind address
REVERSE_PROXY_TRUST false Trust X-Forwarded headers (for reverse proxy setups)

One thing worth noting on BACKUP_KEEP: the rotation logic only applies to backups created by the current version of the script. If you’re upgrading from an older version, old backups with a different naming convention won’t be pruned automatically — worth a manual check of your backup directory after upgrading.


Smart Update Safety — Running Task Detection

This is one of my favorite features. Before applying an update, the script queries the Xen Orchestra REST API to check for any active tasks — things like running backups or VM exports. If any are found, the update is aborted automatically to prevent data loss or mid-operation corruption.

Authentication for the task check supports three methods, resolved in priority order:

Priority Method
1 Auth token (XO_TASK_CHECK_TOKEN in config)
2 Credentials (XO_TASK_CHECK_USER / XO_TASK_CHECK_PASS in config)
3 Interactive prompt at runtime

The recommended approach is to create a dedicated admin account in the XO web UI (e.g. task-checker@local.net) and generate an auth token for it. Tokens can be revoked independently and are more secure than storing a password in a config file. Here’s how to generate one:

bash

curl -X POST -u 'task-checker@local.net:yourpassword' \
  https://localhost/rest/v0/users/me/authentication_tokens -k

Copy the id from the response and drop it into your config:

XO_TASK_CHECK_TOKEN=UlTBEnFeL12XocK-7Qx-DKvOYbPn0eG7Z2oMvOniNjg

If you’d rather not deal with tokens, plain credentials work too — and if neither is configured, the script will just prompt you interactively each time you update.


Backup and Restore

Every update and rebuild automatically takes a backup first. The BACKUP_KEEP setting controls how many are retained (default: 5). If something goes sideways after an update, restoring is a single command:

bash

./install-xen-orchestra.sh --restore

The restore function presents a list of available backups to choose from — no digging through directories manually.


XO Proxy Support

The script also handles XO Proxy deployment (--proxy), which is needed when you have Xen pools that aren’t directly reachable from your XO server — common in multi-site homelab setups or when pools are on isolated VLANs.


Supported Distributions

The script works across all major server distributions:

  • Debian 10, 11, 12, 13
  • Ubuntu (all supported releases)
  • RHEL / CentOS / AlmaLinux / Rocky Linux
  • Fedora

A Few Gotchas Worth Knowing

Low RAM hosts: The Yarn build is memory-intensive. On hosts with less than 2 GB RAM, the OOM killer can take out the Node process mid-build. If that happens, add a swapfile before retrying:

bash

sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

Air-gapped hosts: If your server can’t reach the NodeSource repo, set NODE_VERSION to a specific patch version (e.g. 24.15.0) in the config — the script will download a pre-built binary from nodejs.org instead.

SELinux on RHEL/Rocky/Alma: If xo-server fails to bind ports, check for AVC denials with ausearch -m avc -ts recent | grep xo-server and generate a local policy with audit2allow if needed.

Git “dubious ownership” errors: This happens when the install directory is owned by a different user than the one running the script. Fix it with:

bash

sudo chown -R xo-service:xo-service /opt/xen-orchestra

Getting Started

If you’re running XCP-ng and want a fully-featured Xen Orchestra instance without the subscription, this script gets you there without having to piece together the process from the docs every time.

bash

git clone https://github.com/acebmxer/install_xen_orchestra.git
cd install_xen_orchestra
./install-xen-orchestra.sh

The full source is on GitHub. If you run into an issue on your distro or have a feature request, feel free to open an issue.

1 Answer

1

For anyone using my script prior to 5/15/26. Please see note

:warning: Upgrading from an earlier version of this script? Read this first.

This version bumps the config schema to v2 (adds PUBLIC_URL and ENCRYPT_REDIS_CREDENTIALS) and corrects two config.toml generation bugs. Your xo-config.cfg is migrated automatically and non-destructively, but the corrected /etc/xo-server/config.toml is only written by --reconfigure.

Run --reconfigure once before resuming normal updates:

./install-xen-orchestra.sh --reconfigure

This regenerates config.toml with the fixes (your old file is backed up first; data in /var/lib/xo-server is untouched). It is strongly recommended if you set both REDIRECT_TO_HTTPS=true and REVERSE_PROXY_TRUST — that combination previously produced a duplicate [http] section and silently dropped one of the settings.

Afterwards, run --update as normal for routine XO updates — --update does not need to be preceded by --reconfigure again.