Professional CLI for Frappe deployment and management.
Project description
frappe-cli
A production-ready CLI that installs and operates Frappe / ERPNext on Ubuntu — from a bare VPS to a working HTTPS site in one command.
Built with Python + Click + Rich. Every step is independently runnable, self-healing, and idempotent — safe to re-run on partially-installed servers.
Highlights
- One-command bootstrap:
frappe install wizardprovisions a fresh Ubuntu VPS end-to-end (MariaDB → Redis → Node → bench → site → ERPNext → nginx → supervisor → SSL). - 17 individually runnable steps:
frappe step <name>lets you re-run, debug, or compose any wizard step on its own (same code path as the wizard). - Multi-bench friendly: works on fresh and non-fresh VPS — auto-detects existing bench installs and existing bench directories.
- Self-healing: automatically repairs the supervisor symlink that vanilla
bench setup productionsometimes misses on multi-bench hosts. - Hard verification: polls
supervisorctl statusfor RUNNING and pings bench Redis for PONG before declaring success. - Resumable: the wizard saves progress; if a step fails you can fix and
frappe install wizard --resume. - Operator-friendly utilities:
frappe ssl list/setup,frappe service status,frappe backup setup,frappe firewall setup, and more.
Installation
frappe-cli is published on PyPI: https://pypi.org/project/frappe-cli/.
With uv (recommended)
uv installs CLIs in isolated environments, similar to pipx, and is extremely fast.
# Install uv (if you don't have it yet)
curl -LsSf https://astral.sh/uv/install.sh | sh
# Install frappe-cli globally
uv tool install frappe-cli
# Verify
frappe --version
frappe --help
To upgrade later:
uv tool upgrade frappe-cli
With pip
# User install (no sudo required)
pip install --user frappe-cli
export PATH="$HOME/.local/bin:$PATH"
# Or system-wide
sudo pip install frappe-cli
frappe --help
With pipx
pipx install frappe-cli
frappe --help
Requirements
| Requirement | Version |
|---|---|
| Python | ≥ 3.10 |
| OS | Ubuntu 22.04 or 24.04 (other Debian variants work, others untested) |
| User | A non-root user with sudo access |
Note:
frappe-cliwill install Node.js, MariaDB, Redis, nginx, supervisor, wkhtmltopdf, certbot, anduvfor you. You do not need to pre-install them.
Quick start: bootstrap a fresh VPS
The fastest path from a clean Ubuntu server to a working HTTPS Frappe site:
sudo apt update && sudo apt install -y python3-pip curl
# 1. Install frappe-cli
curl -LsSf https://astral.sh/uv/install.sh | sh
uv tool install frappe-cli
# 2. Run the interactive wizard (≈30–60 min depending on the host)
frappe install wizard
You'll be prompted for:
| Prompt | Example |
|---|---|
| Bench directory | my-bench |
| Site (FQDN, must resolve to this host) | erp.example.com |
| Frappe branch | version-15 |
| App to install | erpnext |
| App branch | version-15 |
| MariaDB root password | (new password) |
| Site Administrator password | (new password) |
| Let's Encrypt email | you@example.com |
| Sudo password | (your user password) |
If a step fails, fix the issue and resume from where it stopped:
frappe install wizard --resume
When it's done:
curl -I https://erp.example.com # HTTP/2 200, served by nginx, valid Let's Encrypt cert
Command structure
frappe <group> <command> [options]
| Group | What it does |
|---|---|
install wizard |
End-to-end automated installer with state + resume |
step |
Run any individual wizard step on its own (recommended for debugging / partial setups) |
ssl |
Issue / list Let's Encrypt certificates for existing sites |
site |
Create, list, backup, restore sites |
app |
Get / install / update / remove Frappe apps |
service |
Restart, status, logs for bench + system services |
backup |
Manual + scheduled backups (optionally to an external HD) |
firewall |
UFW configuration with secure defaults |
maintenance |
Log rotation, etc. |
monitor |
Live logs and system health (stubs / growing) |
optimize |
Performance tuning (stubs / growing) |
rollback |
Restore from backup, uninstall site, etc. |
config |
YAML config get/set/validate |
Every command supports --help and many support --dry-run and --debug.
Everyday recipes
Add SSL to an existing site
# See all sites and which are still on HTTP
frappe ssl list
# Issue an HTTPS cert for one site (auto-detects the owning bench)
frappe ssl setup --site-name erp.example.com
# First time ever using Let's Encrypt on this host? Provide an email
frappe ssl setup --site-name new.example.com --email you@example.com
Re-run a single wizard step
Every step the wizard runs is also exposed as a standalone command. Same code, same self-healing, same verification.
# Show all steps in execution order
frappe step list
# Run just SSL for one site
frappe step ssl --bench-name my-bench --site-name erp.example.com
# Re-do the production setup (nginx + supervisor) for a bench
frappe step production --bench-name my-bench
# Try a step without executing anything
frappe step production --bench-name my-bench --dry-run
# Force a step even when check() says "already done"
frappe step ssl --bench-name my-bench --site-name erp.example.com --force
The full step catalogue:
| # | Command | Purpose |
|---|---|---|
| 1 | frappe step system-update |
apt-get update && upgrade |
| 2 | frappe step system-deps |
Frappe's required apt packages |
| 3 | frappe step uv-check |
Ensure uv is installed |
| 4 | frappe step nodejs |
Install Node.js + Yarn |
| 5 | frappe step mariadb-install |
Install MariaDB + utf8mb4 config |
| 6 | frappe step mariadb-secure |
Secure MariaDB root user |
| 7 | frappe step redis |
Install Redis server |
| 8 | frappe step wkhtmltopdf |
Install wkhtmltopdf + X11 fonts |
| 9 | frappe step bench-install |
uv tool install frappe-bench |
| 10 | frappe step bench-init |
bench init <name> --frappe-branch ... |
| 11 | frappe step site-create |
bench new-site <site> |
| 12 | frappe step app-get |
bench get-app <url> |
| 13 | frappe step dns-multitenant |
bench config dns_multitenant on |
| 14 | frappe step production |
bench setup production + supervisor self-heal + verify |
| 15 | frappe step app-install |
bench --site <s> install-app <app> |
| 16 | frappe step bench-restart |
supervisorctl reread/update + nginx reload |
| 17 | frappe step ssl |
bench setup lets-encrypt <site> |
Add another site to an existing bench
frappe step site-create --bench-name my-bench --site-name shop.example.com
frappe step dns-multitenant --bench-name my-bench
frappe step app-install --bench-name my-bench --site-name shop.example.com --app-url erpnext
frappe step bench-restart --bench-name my-bench
frappe step ssl --bench-name my-bench --site-name shop.example.com
Set up an automated backup
frappe backup setup \
--bench-name my-bench \
--site-name erp.example.com \
--admin-email you@example.com
Service health check
frappe service status --bench-name my-bench --site-name erp.example.com
frappe service restart
Firewall (UFW)
frappe firewall setup # opens 22, 80, 443 by default
Tips for non-fresh VPS
frappe-cli is designed to work on hosts that already have bench installed or already have other Frappe benches:
frappe step bench-install— checks ifbenchis onPATH(any of~/.local/bin,/usr/local/bin,/usr/bin) and skips if found.frappe step bench-init— skips if the target bench directory already hasapps/frappe/.frappe step production— explicitly creates the missingsupervisor.confsymlink that vanillabench setup productionsometimes forgets on multi-bench hosts.frappe step ssl— usessudo test -fso it can correctly detect existing certs in the root-owned/etc/letsencrypt/live/directory.
Why frappe-cli over raw bench?
| Pain point | bench alone |
frappe-cli |
|---|---|---|
| Fresh VPS bootstrap | 8+ manual steps, lots of doc-hopping | One command |
| Multi-bench supervisor symlink | Sometimes silently missing → "Redis connection refused" on install-app |
Auto-created and verified |
Redis health check before install-app |
None | TCP PING/PONG on queue/cache/socketio ports |
bench setup lets-encrypt prompts |
Two interactive [y/N] prompts |
Automated |
| State across reboots / partial failures | Manual | --resume from saved state |
| Re-running a single step | Find the command, get the args right | frappe step <name> |
| Listing sites without SSL | grep + sudo find | frappe ssl list |
Configuration file (optional)
For reproducible installs, pass a YAML config with --config:
# production.yaml
system:
timezone: "Africa/Nairobi"
locale: "en_US.UTF-8"
user: "frappe"
frappe:
branch: "version-15"
bench_name: "my-bench"
site_name: "erp.example.com"
admin_password: "changeme"
mariadb_root_password: "changeme"
services:
enable_ssl: true
enable_ufw: true
backup:
admin_email: "you@example.com"
retention_days: 7
See src/frappe_cli/data/example_config.yaml.
Logs and troubleshooting
- All commands log to
/var/log/frappe-installer.log(with local fallback if not writable). - Use
--debugon any command for verbose subprocess output. - Use
--dry-runonstep/installcommands to preview what would run. - For a known-working manual flow you can compare against, see
docs/superpowers/test3-bench-setup.md— a step-by-step runbook used to verify every wizard step.
Development
git clone https://github.com/okama12/frappe-cli.git
cd frappe-cli
# Install dependencies
poetry install
# Run all tests (133 passing)
PYTHONPATH=src poetry run pytest tests/
# Lint (ruff + black --check + isort --check + mypy)
poetry run bash scripts/lint.sh
# Try a local build
pip install --editable .
frappe --help
Project layout
src/frappe_cli/
├── cli.py # root Click group
├── install/
│ ├── wizard.py # `frappe install wizard`
│ ├── context.py # InstallContext dataclass
│ ├── state.py # ~/.frappe-cli-state.json (resume support)
│ └── steps/ # one InstallStep class per wizard step
├── step/ # `frappe step <name>` — thin wrappers around steps/
├── ssl/ # `frappe ssl setup`, `frappe ssl list`
├── site/, app/, service/, backup/, firewall/, ...
└── utils/ # shell, errors, logging, validators
Tests live under tests/ (one file per command group, plus test_install_steps.py for the wizard's step classes).
Contributing
- Fork → feature branch.
- Add or improve a command group / step.
- Add tests in
tests/(useclick.testing.CliRunner). - Run
poetry run bash scripts/lint.shandPYTHONPATH=src poetry run pytest. - Open a PR with a clear description.
About
Built by Rashidi Okama in Tanzania to make day-to-day Frappe work easier.
- Website: https://rashidiokama.com
- GitHub: https://github.com/okama12
Run frappe about for the in-CLI credits panel. If this project saves you time, please star the repo — it really helps.
License
MIT © Rashidi Okama
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file frappe_cli-0.1.31.tar.gz.
File metadata
- Download URL: frappe_cli-0.1.31.tar.gz
- Upload date:
- Size: 67.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
49884392e4c384f7ec0ce5180cdacfcd38153bfa2b8d284412df2206407ac299
|
|
| MD5 |
25cc061917368e73a31ee39db612994b
|
|
| BLAKE2b-256 |
54d4f9768c072ccccfb28291483ddc44709ad27f89713e7b2ecb235c77686d3d
|
File details
Details for the file frappe_cli-0.1.31-py3-none-any.whl.
File metadata
- Download URL: frappe_cli-0.1.31-py3-none-any.whl
- Upload date:
- Size: 96.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1cb0f06591bca82a484e3693f51fc206cb899b1acd062c86b05503e14ce77343
|
|
| MD5 |
a46f19fdac0087da2b8cf78b9a63ee48
|
|
| BLAKE2b-256 |
73a7f1909761cb16210ceb3bca2ba91e3075aa48ae36c9a0886b9eded353bf4e
|