Aakvatech Limited - Installing Frappe Pilot Cleanly on Ubuntu: Avoid Redis, Python, MariaDB and Node.js Dependency Failures
Installing Frappe Pilot on a fresh Ubuntu server can fail surprisingly late if host dependencies are incomplete. This guide shows how to validate the server first and avoid repeated bench initializati
Frappe Pilot is designed around a sensible operating model: prepare the server once with privileged access, then allow the dedicated bench user to manage normal Pilot operations without requiring unrestricted root access.
In practice, however, a partially prepared Ubuntu server can reach the Pilot bench initialization wizard before every required dependency has been validated.
The result can be a frustrating sequence:
Start Pilot bench initialization
↓
Redis missing
↓
Retry
↓
Build libraries missing
↓
Retry
↓
Python.h missing
↓
Retry
↓
Node.js missing
↓
Retry
↓
Node.js 22 installed, but Frappe requires >=24
↓
Retry again
The better approach is simple:
Validate and provision the complete host before creating the first Pilot bench.
This article documents a clean installation procedure based on real installation failures encountered while deploying current Frappe v16 workloads through Pilot.
Why this matters
A failed Pilot initialization is generally recoverable. Pilot rolls back the partially created bench directories and preserves bench.toml.
That is useful, but repeatedly discovering dependencies halfway through setup wastes time and can obscure the real problem.
The important distinction is between:
- host provisioning, which may require root;
- Pilot installation, which should run under the dedicated Pilot/bench user;
- bench initialization, which should not suddenly require unrestricted privileged package installation.
Pilot's installer itself follows a two-stage model: the privileged installation prepares the host and bench user, after which Pilot is intended to operate without general root access.
The installation failures we encountered
Several separate failures exposed the same broader requirement: a fresh server should pass a complete prerequisite check before bench initialization starts.
1. Redis was missing
Pilot initialization stopped with:
Required: redis-server. No passwordless sudo available;
install manually with your system package manager,
then re-run this command.
Redis is a host-level dependency.
Pilot should find either:
redis-server
or, on distributions using Valkey:
valkey-server
before the first bench is initialized.
2. Required build packages were missing
The next failure reported:
Missing system packages:
build-essential,
pkg-config,
libmariadb-dev
These are required because several Python dependencies used by Frappe contain native extensions that must be compiled.
A working Python interpreter alone is therefore not enough.
3. Python existed, but Python.h did not
The most instructive failure occurred while building:
mysqlclient==2.2.7
The compiler failed with:
fatal error: Python.h: No such file or directory
The selected interpreter was Python 3.14, but:
ls -l /usr/include/python3.14/Python.h
returned:
No such file or directory
This highlights an important rule:
The development headers must match the actual Python interpreter selected for the bench.
Installing generic:
apt install python3-dev
does not necessarily guarantee that the headers for Python 3.14 are installed.
For Python 3.14, verify:
ls -l /usr/include/python3.14/Python.h
and install:
apt install -y python3.14-dev
when required.
4. Node.js was completely missing
Pilot later stopped with:
Node.js is not installed.
Re-run install.sh as root to install it,
or install it yourself.
That is another host-level prerequisite that should be validated before the bench setup starts.
5. Node.js existed, but was too old
After Node.js was installed, Yarn produced:
error frappe-framework@:
The engine "node" is incompatible with this module.
Expected version ">=24". Got "22.22.1"
This is an important distinction.
Checking:
which node
is not enough.
The installer must also validate:
node --version
For the Frappe version involved in this deployment, Node.js needed to satisfy:
>=24
A host with Node.js 22 therefore passes a simple executable check but still cannot build the Frappe frontend.
Another hidden source of problems: broken APT repositories
While upgrading Node.js, the NodeSource setup script failed during:
apt update
because an unrelated MariaDB MaxScale repository returned:
404 Not Found
The active repository was:
https://dlm.mariadb.com/repo/maxscale/latest/apt
This demonstrates an important operational rule:
apt updatemust be completely healthy before starting a Pilot installation.
A broken third-party repository can prevent the installation of an entirely unrelated component.
For example, NodeSource may be configured correctly, but its installer cannot complete because MariaDB MaxScale has an invalid repository entry.
Recommended clean installation process
The following process is recommended for a new Ubuntu Pilot server.
Step 1: Prefer Ubuntu LTS
For production installations, prefer a stable long-term-support release such as:
Ubuntu 24.04 LTS
Very recent interim Ubuntu releases may not yet be supported by every third-party repository used by the stack.
Check:
cat /etc/os-release
Pay particular attention to:
PRETTY_NAME
VERSION_CODENAME
Step 2: Validate APT first
Before installing Pilot:
apt update
Do not proceed if you see:
404 Not Found
does not have a Release file
Malformed stanza
repository is not signed
Inspect third-party repositories:
ls -la /etc/apt/sources.list.d/
For MariaDB-related entries:
grep -R -n "mariadb\|maxscale" \
/etc/apt/sources.list \
/etc/apt/sources.list.d/ 2>/dev/null
Disabling an unused MaxScale repository
Ubuntu now commonly uses deb822 .sources files.
A stanza may look like:
# MariaDB MaxScale
X-Repolib-Name: MariaDB MaxScale
Enabled: yes
Types: deb
URIs: https://dlm.mariadb.com/repo/maxscale/latest/apt
Suites: <ubuntu-codename>
Components: main
Signed-By: /etc/apt/keyrings/mariadb-keyring.gpg
If MaxScale is not required and its repository is unsupported, keep the complete stanza but change:
Enabled: yes
to:
Enabled: no
Do not leave an incomplete deb822 stanza.
Then run:
apt update
again.
Step 3: Install the base build dependencies
Install:
apt install -y \
git \
curl \
bash \
sudo \
ca-certificates \
build-essential \
pkg-config \
tzdata \
python3 \
python3-dev
Verify:
git --version
gcc --version
pkg-config --version
python3 --version
Step 4: Install MariaDB client development libraries
Frappe's Python dependency stack may need to compile mysqlclient.
Install:
apt install -y \
libmariadb-dev \
libmariadb-dev-compat
Verify:
pkg-config --exists libmariadb \
&& echo "MariaDB development libraries: OK"
Check the actual compiler flags:
pkg-config --cflags libmariadb
pkg-config --libs libmariadb
Step 5: Validate the selected Python version
Determine which version the planned bench will use.
For Python 3.14:
python3.14 --version
Then verify the compiler headers:
test -f /usr/include/python3.14/Python.h \
&& echo "Python 3.14 headers: OK" \
|| echo "Python 3.14 headers: MISSING"
If missing:
apt install -y python3.14-dev
Then verify again:
ls -l /usr/include/python3.14/Python.h
The rule is:
Python 3.14 runtime
+
Python 3.14 development headers
not merely:
Python runtime
+
some version of python3-dev
Step 6: Install Redis
Install:
apt install -y redis-server
Verify:
which redis-server
redis-server --version
Pilot runs bench-specific Redis instances, so the distribution-provided service can be disabled while retaining the binary:
systemctl disable --now redis-server
Verify again:
redis-server --version
Step 7: Install Node.js 24 explicitly
Do not rely on the Ubuntu package version without checking it.
First:
node --version
If it reports Node 22 while Frappe requires Node 24, upgrade it before Pilot bench initialization.
Make sure:
apt update
works cleanly.
Then configure NodeSource for Node 24:
curl -fsSL \
https://deb.nodesource.com/setup_24.x \
-o /tmp/nodesource_setup.sh
bash /tmp/nodesource_setup.sh
Install:
apt install -y nodejs
Verify:
node --version
npm --version
Expected:
v24.x.x
If it still reports Node 22, inspect:
apt-cache policy nodejs
before proceeding.
Step 8: Perform a full preflight
Before Pilot installation or bench creation, run:
echo "=== Operating System ==="
grep -E '^(PRETTY_NAME|VERSION_CODENAME)=' /etc/os-release
echo
echo "=== APT ==="
apt update
echo
echo "=== Git ==="
git --version
echo
echo "=== Compiler ==="
gcc --version | head -1
echo
echo "=== pkg-config ==="
pkg-config --version
echo
echo "=== MariaDB development headers ==="
pkg-config --exists libmariadb \
&& echo "libmariadb: OK" \
|| echo "libmariadb: MISSING"
echo
echo "=== Redis ==="
redis-server --version
echo
echo "=== Node.js ==="
node --version
echo
echo "=== npm ==="
npm --version
echo
echo "=== Python ==="
python3 --version
For a Python 3.14 bench:
echo
echo "=== Python 3.14 ==="
python3.14 --version
test -f /usr/include/python3.14/Python.h \
&& echo "Python 3.14 development headers: OK" \
|| echo "Python 3.14 development headers: MISSING"
Do not proceed until every dependency required by the intended bench passes.
Step 9: Run the Pilot installer as root
For upstream Pilot:
curl -fsSL \
https://raw.githubusercontent.com/frappe/pilot/develop/install.sh \
-o /tmp/pilot-install.sh
bash /tmp/pilot-install.sh
Pilot's installer is intentionally structured around two phases.
The root phase handles system-level preparation such as:
- system packages;
- database engines;
- Redis;
- Node.js;
- nginx;
- certbot;
- process-management dependencies;
- bench-user creation;
- systemd lingering;
- restricted sudo rules.
After this phase, it instructs the administrator to switch to the bench user.
Step 10: Switch to the bench user
For the standard user:
su - frappe
If you deliberately configured another user, use that user instead.
Check:
whoami
Step 11: Run the Pilot installer as the bench user
Run:
curl -fsSL \
https://raw.githubusercontent.com/frappe/pilot/develop/install.sh \
-o /tmp/pilot-install.sh
bash /tmp/pilot-install.sh
Pilot itself should not normally be installed and operated as root.
Step 12: Verify the environment from the bench user's shell
This catches PATH differences between root and the Pilot user.
Run:
which pilot
which python3
which node
which npm
which redis-server
which git
which gcc
which pkg-config
Then:
node --version
npm --version
redis-server --version
python3 --version
Node must still satisfy the Frappe requirement.
Also check systemd lingering:
loginctl show-user "$(whoami)" -p Linger
Expected:
Linger=yes
Step 13: Only now initialize the first bench
At this point the host should already satisfy:
APT repository health OK
Git OK
Compiler/build-essential OK
pkg-config OK
MariaDB development libraries OK
Selected Python headers OK
Redis or Valkey OK
Node.js >= required version OK
npm OK
systemd user lingering OK
Pilot bench user OK
Only then create the first bench through Pilot.
What Pilot itself could improve
The installation experience also suggests a useful architectural improvement for Pilot.
Instead of discovering each dependency during different initialization stages, Pilot could perform one complete host preflight before doing any destructive or time-consuming work.
For example:
Checking host requirements...
[OK] Git
[OK] GCC
[OK] pkg-config
[OK] MariaDB development libraries
[OK] Redis 7.x
[OK] Python 3.14.4
[MISSING] Python 3.14 development headers
[INVALID] Node.js 22.22.1 — requires >=24
Host is not ready for bench initialization.
This would be significantly better than:
Initialize
→ fail
→ install dependency
→ retry
→ fail later
→ install another dependency
→ retry
Node.js should be version-validated
A check such as:
if not which("node"):
raise BenchError("Node.js is missing")
is insufficient.
Pilot should also inspect:
node --version
and compare it with the Frappe version's required Node engine.
Python headers should match the interpreter
Checking only whether:
python3-dev
is installed is likewise insufficient.
Pilot should verify the actual header path belonging to the Python executable selected for the bench.
For Python 3.14, that means validating something equivalent to:
/usr/include/python3.14/Python.h
APT health should be checked before repository installers
Before invoking NodeSource, MariaDB repositories, or other package provisioning, the installer should confirm that the package manager itself can successfully refresh repositories.
This makes failures from unrelated third-party repositories visible at the correct stage.
A practical preflight checklist
Before clicking Initialize Bench, confirm:
- [ ]
apt updatecompletes without errors. - [ ] No unsupported third-party repository is enabled.
- [ ]
git --versionworks. - [ ]
gcc --versionworks. - [ ]
pkg-config --versionworks. - [ ]
pkg-config --exists libmariadbsucceeds. - [ ] The selected Python interpreter exists.
- [ ] The matching
Python.hexists. - [ ]
redis-server --versionor the equivalent Valkey command works. - [ ]
node --versionmeets Frappe's required version. - [ ]
npm --versionworks. - [ ] Pilot is running under the intended bench user.
- [ ] systemd lingering is enabled.
Final recommendation
Treat Pilot installation as host provisioning first, bench creation second.
Do not start the first bench merely because the Pilot web interface is available.
A server can have Pilot installed while still lacking the compiler headers, Redis binary, correct Node.js version, or Python development files needed by Frappe.
The preferred sequence is:
Fresh supported Ubuntu server
↓
Validate APT
↓
Install host dependencies
↓
Install matching Python headers
↓
Install Redis
↓
Install Node.js 24
↓
Run complete preflight
↓
Run Pilot host installer as root
↓
Switch to Pilot user
↓
Install/operate Pilot as that user
↓
Verify environment again
↓
Initialize first bench
Doing this once at the start is considerably easier than troubleshooting dependencies one failure at a time during bench initialization.
Reference articles and discussions
- Frappe Pilot GitHub repository
- Frappe Pilot
install.sh - Frappe Framework GitHub repository
- NodeSource Node.js 24 Debian/Ubuntu setup
- MariaDB Repository Configuration Tool
- Installation logs and troubleshooting observations from a fresh Pilot deployment were used to develop and validate the installation sequence described in this article.
Aakvatech Limited is a Frappe Gold Partner and ERPNext implementation company headquartered in Dar es Salaam, Tanzania, operating across East Africa and the UAE.
This article was co-created using AI to accelerate drafting, with final insights curated and validated by the author. Any customer, personal, or sensitive data referenced during drafting has been anonymized or masked where applicable. All contributors, reference URLs, tools, and materials used to assist this content curation are credited in the Reference section.
No comments yet. Login to start a new discussion Start a new discussion