Skip to main content

Professional CLI for Frappe deployment and management.

Project description

frappe-cli

PyPI version Python License: MIT Tests

  ███████╗██████╗  █████╗ ██████╗ ██████╗ ███████╗     ██████╗██╗     ██╗
  ██╔════╝██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔════╝    ██╔════╝██║     ██║
  █████╗  ██████╔╝███████║██████╔╝██████╔╝█████╗      ██║     ██║     ██║
  ██╔══╝  ██╔══██╗██╔══██║██╔═══╝ ██╔═══╝ ██╔══╝      ██║     ██║     ██║
  ██║     ██║  ██║██║  ██║██║     ██║     ███████╗    ╚██████╗███████╗██║
  ╚═╝     ╚═╝  ╚═╝╚═╝  ╚═╝╚═╝     ╚═╝     ╚══════╝     ╚═════╝╚══════╝╚═╝

                     Frappe CLI  ·  fp  ·  v1.0.4
           Install · Operate · Develop — all in one command

A production-ready CLI that installs and operates Frappe / ERPNext — from a bare VPS to a working HTTPS site in one command. Also your daily bench shortcut.

Built with Python + Click + Rich. Every step is independently runnable, self-healing, and idempotent — safe to re-run on partially-installed servers.


Two tools in one

┌─────────────────────────────────────────────────────────────────────┐
│                          fp  (frappe-cli)                           │
├──────────────────────────────┬──────────────────────────────────────┤
│   🏗  INSTALLER / OPS        │   ⚡  DAILY DEV WORKFLOW             │
│                              │                                      │
│  fp install wizard           │  fp use <site>     ← set context     │
│  fp step <name>              │  fp migrate        ← auto --site     │
│  fp ssl setup/list           │  fp console                          │
│  fp service status           │  fp restart                          │
│  fp backup setup             │  fp build / watch                    │
│  fp firewall setup           │  fp get-app <url>                    │
│                              │  fp sites / fp context               │
└──────────────────────────────┴──────────────────────────────────────┘

Highlights

  • One-command bootstrap: fp install wizard provisions a fresh Ubuntu VPS end-to-end (MariaDB → Redis → Node → bench → site → ERPNext → nginx → supervisor → SSL).
  • 17 individually runnable steps: fp step <name> lets you re-run, debug, or compose any wizard step on its own (same code path as the wizard).
  • Context-aware dev workflow: fp use mysite.local remembers your active bench + site — then every bench command becomes one word.
  • Multi-bench friendly: works on fresh and non-fresh VPS — auto-detects existing bench installs and directories.
  • Self-healing: automatically repairs the supervisor symlink that vanilla bench setup production sometimes misses on multi-bench hosts.
  • Hard verification: polls supervisorctl status for RUNNING and pings bench Redis for PONG before declaring success.
  • Resumable: the wizard saves progress; if a step fails you can fix and fp install wizard --resume.
  • Operator-friendly utilities: fp ssl list/setup, fp service status, fp backup setup, fp firewall setup, and more.

Installation

frappe-cli is published on PyPI: https://pypi.org/project/frappe-cli/.

Note: Do not use fc as the command — bash reserves it for shell history. Use fp instead (short for Frappe Platform, matches .fp.yaml).

With uv (recommended)

# 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
fp --version
fp --help

To upgrade later:

uv tool upgrade frappe-cli

With pip

pip install --user frappe-cli
export PATH="$HOME/.local/bin:$PATH"
fp --help

With pipx

pipx install frappe-cli
fp --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-cli will install Node.js, MariaDB, Redis, nginx, supervisor, wkhtmltopdf, certbot, and uv for 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:

Fresh Ubuntu VPS
      │
      ▼
  apt install python3-pip curl
      │
      ▼
  uv tool install frappe-cli
      │
      ▼
  fp install wizard          ← interactive prompts, ~30-60 min
      │
      ├─ system-update
      ├─ system-deps
      ├─ nodejs
      ├─ mariadb-install + mariadb-secure
      ├─ redis
      ├─ wkhtmltopdf
      ├─ bench-install + bench-init
      ├─ site-create
      ├─ get-app + install-app
      ├─ production (nginx + supervisor)
      └─ ssl (Let's Encrypt)
            │
            ▼
  ✓ https://erp.example.com  ← live in one command
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)
fp 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:

fp install wizard --resume

When it's done:

curl -I https://erp.example.com   # HTTP/2 200, served by nginx, valid Let's Encrypt cert

⚡ Daily dev workflow

This is where fp really shines. Instead of typing bench --site <long.site.name> migrate every time, you set your context once and then use short commands.

  ~/my-bench/                    ← bench root
  ├── apps/
  │   ├── frappe/
  │   └── my_custom_app/         ← you are here, deep in code
  ├── sites/
  │   ├── dev.local/
  │   └── staging.example.com/
  └── .fp.yaml                   ← fp writes: site: dev.local

Step 1 — set your active site (once per session)

Works from any directory inside the bench — bench root, apps/, apps/my_app/, etc.

cd ~/my-bench
fp use dev.local
# ✓ Active site set to dev.local  (bench: my-bench)

Step 2 — run bench commands without the boilerplate

# Before fp:
bench --site dev.local migrate
bench --site dev.local console
bench --site dev.local clear-cache

# With fp:
fp migrate
fp console
fp clear-cache

Switching between sites

You never "lose" a site — just use a different one. The old site is still there.

fp sites
  ● dev.local          ← active (green dot)
    staging.example.com

fp use staging.example.com
# ✓ Active site set to staging.example.com

fp migrate            → bench --site staging.example.com migrate

All dev commands

  fp use <site>         Write active site to .fp.yaml
  fp context            Show current bench + active site
  fp sites              List all sites (active site marked with ●)

  ── site-scoped (auto-injects --site) ─────────────────────────────
  fp migrate            Sync schema, run patches, rebuild assets
  fp console            IPython console for the active site
  fp install-app <app>  Install app on active site
  fp uninstall-app <a>  Remove app from active site
  fp list-apps          Apps installed on active site
  fp clear-cache        Clear framework cache
  fp mariadb            MariaDB shell for active site

  ── bench-scoped (no --site needed) ───────────────────────────────
  fp restart            Restart supervisor / systemd processes
  fp build              Build JS + CSS assets
  fp start              Start dev server (Procfile)
  fp watch              Watch + recompile JS/CSS on change
  fp get-app <url>      Download app from git URL

How it works: fp detects the bench root by walking up from your current directory looking for both a sites/ and apps/ folder. The active site is stored in <bench_root>/.fp.yaml — a plain YAML file you can inspect or edit directly. The wizard's state (~/.frappe-cli-state.json) is completely separate and untouched.


Command structure

fp <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
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
optimize Performance tuning
rollback Restore from backup, uninstall site, etc.
config YAML config get/set/validate
use Set active bench + site context
context Show current bench + active site
sites List sites in the current bench

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
fp ssl list

# Issue an HTTPS cert for one site (auto-detects the owning bench)
fp ssl setup --site-name erp.example.com

# First time ever using Let's Encrypt on this host? Provide an email
fp 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
fp step list

# Run just SSL for one site
fp step ssl --bench-name my-bench --site-name erp.example.com

# Re-do the production setup (nginx + supervisor) for a bench
fp step production --bench-name my-bench

# Try a step without executing anything
fp step production --bench-name my-bench --dry-run

# Force a step even when check() says "already done"
fp step ssl --bench-name my-bench --site-name erp.example.com --force

The full step catalogue:

# Command Purpose
1 fp step system-update apt-get update && upgrade
2 fp step system-deps Frappe's required apt packages
3 fp step uv-check Ensure uv is installed
4 fp step nodejs Install Node.js + Yarn
5 fp step mariadb-install Install MariaDB + utf8mb4 config
6 fp step mariadb-secure Secure MariaDB root user
7 fp step redis Install Redis server
8 fp step wkhtmltopdf Install wkhtmltopdf + X11 fonts
9 fp step bench-install uv tool install frappe-bench
10 fp step bench-init bench init <name> --frappe-branch ...
11 fp step site-create bench new-site <site>
12 fp step app-get bench get-app <url>
13 fp step dns-multitenant bench config dns_multitenant on
14 fp step production bench setup production + supervisor self-heal + verify
15 fp step app-install bench --site <s> install-app <app>
16 fp step bench-restart supervisorctl reread/update + nginx reload
17 fp step ssl bench setup lets-encrypt <site>

Add another site to an existing bench

fp step site-create     --bench-name my-bench --site-name shop.example.com
fp step dns-multitenant --bench-name my-bench
fp step app-install     --bench-name my-bench --site-name shop.example.com --app-url erpnext
fp step bench-restart   --bench-name my-bench
fp step ssl             --bench-name my-bench --site-name shop.example.com

Set up an automated backup

fp backup setup \
  --bench-name my-bench \
  --site-name erp.example.com \
  --admin-email you@example.com

Service health check

fp service status --bench-name my-bench --site-name erp.example.com
fp service restart

Firewall (UFW)

fp 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:

  • fp step bench-install — checks if bench is on PATH (any of ~/.local/bin, /usr/local/bin, /usr/bin) and skips if found.
  • fp step bench-init — skips if the target bench directory already has apps/frappe/.
  • fp step production — explicitly creates the missing supervisor.conf symlink that vanilla bench setup production sometimes forgets on multi-bench hosts.
  • fp step ssl — uses sudo test -f so 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 fp install wizard
Daily migrate / console bench --site long.site.name migrate fp migrate
Multi-bench supervisor symlink Sometimes silently missing → errors 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 fp step <name>
Listing sites without SSL grep + sudo find fp 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 --debug on any command for verbose subprocess output.
  • Use --dry-run on step / install commands 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 (163 passing)
PYTHONPATH=src poetry run pytest tests/

# Lint (ruff + black --check + isort --check + mypy)
poetry run bash scripts/lint.sh

# Install locally and try it
poetry run fp --help

Project layout

src/frappe_cli/
├── cli.py                  # root Click group — registers all commands
├── dev/
│   ├── context.py          # bench detection + .fp.yaml read/write
│   └── commands.py         # use, context, sites + passthrough commands
├── install/
│   ├── wizard.py           # fp install wizard
│   ├── context.py          # InstallContext dataclass
│   ├── state.py            # ~/.frappe-cli-state.json (resume support)
│   └── steps/              # one InstallStep class per wizard step
├── step/                   # fp step <name> — thin wrappers around steps/
├── ssl/                    # fp ssl setup, fp 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 step classes and test_dev_commands.py for dev workflow).


Contributing

  1. Fork → feature branch.
  2. Add or improve a command group / step.
  3. Add tests in tests/ (use click.testing.CliRunner).
  4. Run poetry run bash scripts/lint.sh and PYTHONPATH=src poetry run pytest.
  5. Open a PR with a clear description.

About

Built by Rashidi Okama in Tanzania to make day-to-day Frappe work easier.

Run fp 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

frappe_cli-1.0.5.tar.gz (73.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

frappe_cli-1.0.5-py3-none-any.whl (102.1 kB view details)

Uploaded Python 3

File details

Details for the file frappe_cli-1.0.5.tar.gz.

File metadata

  • Download URL: frappe_cli-1.0.5.tar.gz
  • Upload date:
  • Size: 73.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for frappe_cli-1.0.5.tar.gz
Algorithm Hash digest
SHA256 dae821a54ec8c7057d4895fd5bad099a1ccaf8d7d225121a9a217f40d151d06f
MD5 b720e14865be2496b982a1d6b5715412
BLAKE2b-256 b6f1503650b3b7dcbca8325ee1292ed66bd782f11dbde034efa7c0e1ca5bf236

See more details on using hashes here.

File details

Details for the file frappe_cli-1.0.5-py3-none-any.whl.

File metadata

  • Download URL: frappe_cli-1.0.5-py3-none-any.whl
  • Upload date:
  • Size: 102.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for frappe_cli-1.0.5-py3-none-any.whl
Algorithm Hash digest
SHA256 f1479a327c607300ddda4c0704f157cad4f9d5332576c0e370328020109b2c97
MD5 6d650fcf9055879c0c6801f09cbdcc70
BLAKE2b-256 989c85b04bfb69053f03eb0425e0c35d18985bc58ef8b1b5ada5b1e68bc3ae75

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page