How to Self-Host ERPNext: Open Source ERP Alternative 2026
How to Self-Host ERPNext: Open Source ERP Alternative in 2026
TL;DR
SAP starts at $99/user/month with a 4-9 month implementation costing $100,000-$500,000. Odoo charges $24.90/user/month for its commercial modules. ERPNext is the open source alternative — GPL v3 license, no "Enterprise Edition" paywall, and the exact same version used by enterprise clients available for free on GitHub. Version 16 (released December 2025) brings 2x faster performance and a redesigned workspace UI. For 50 users, ERPNext on a self-hosted VPS costs ~$50/month in infrastructure vs $1,245/month for Odoo Enterprise or $5,000+/month for SAP. This guide walks you through a production-ready ERPNext v16 deployment with Docker Compose.
Key Takeaways
- No Enterprise Edition paywall: ERPNext has zero closed-source modules — the GitHub version is the enterprise version
- 22,000+ GitHub stars: The most-starred open source ERP project ever built
- Version 16 (December 2025): 2x performance improvements, redesigned workspaces, enhanced analytics
- Full module suite: Accounting, HR/Payroll, Inventory, Manufacturing, CRM, Projects, and Website — all included
- GPL v3 license: Full source access; Frappe Cloud offers managed hosting from $5/month if you don't want to self-host
- Odoo comparison: ERPNext is fully open source with no module paywalls; Odoo's most useful modules are closed-source Community Edition
- SAP comparison: ERPNext costs 99% less to implement and 95% less per user — with comparable coverage for SMB use cases
Why Teams Choose ERPNext Over Commercial ERPs
ERP is where the enterprise software pricing trap is most extreme. SAP and Oracle NetSuite treat implementation cost as a feature — a $200,000 deployment creates switching costs that lock customers in for decades.
ERPNext breaks this model deliberately. Frappe (the company behind ERPNext) explicitly rejects "Open Core" pricing — there are no features behind a commercial license, no modules that only enterprise clients get, no artificial tiers. The version you download from GitHub is identical to what paying Frappe Cloud customers use.
The trade-offs are real. SAP has 50+ years of industry-specific vertical functionality, a massive partner ecosystem, and certifiable compliance certifications for every major jurisdiction. ERPNext covers the 80% of ERP use cases that most SMBs actually need — accounting, HR, inventory, manufacturing, and CRM — without the implementation overhead or the annual license cost that grows with your headcount.
For a 50-person company choosing their first ERP, ERPNext self-hosted saves roughly $1,200/month vs Odoo Enterprise and $5,000+/month vs SAP Business One.
| ERPNext (Self-Hosted) | Odoo Enterprise | SAP Business One | |
|---|---|---|---|
| License | GPL v3 (free) | Proprietary (SaaS) | Proprietary |
| 10 users/month | ~$12 (VPS) | $249/mo | $990/mo |
| 50 users/month | ~$50 (VPS) | $1,245/mo | ~$4,950/mo |
| 100 users/month | ~$100 (VPS) | $2,490/mo | ~$9,900/mo |
| Implementation cost | $0–$30K | $10K–$80K | $100K–$500K |
| Open source | ✅ Full | ❌ Core only | ❌ |
| Multi-company | ✅ | ✅ (paid) | ✅ |
| Manufacturing/MRP | ✅ | ✅ (paid add-on) | ✅ |
| Payroll | ✅ | ✅ (paid add-on) | ✅ |
| eCommerce | ✅ Built-in | ✅ (paid add-on) | ❌ |
System Requirements
ERPNext v16 runs a full Frappe stack — Python app server, Node.js frontend builder, Redis queues, and MariaDB. It's not lightweight:
- CPU: 2 vCPU minimum (4 vCPU recommended for 10+ concurrent users)
- RAM: 4GB minimum (8GB recommended for production)
- Storage: 40GB SSD minimum (100GB recommended — attachments and logs grow)
- OS: Ubuntu 22.04+ or Debian 12+ (Docker-compatible Linux)
- Docker: v24.0+
- Docker Compose: v2.x plugin
- Ports: 80 and 443 for web UI
- Domain: Required for production HTTPS
Frappe stack components:
- Python 3.11+ (app framework)
- Node.js 18+ (frontend compilation)
- Redis 5+ (queue, cache, socketio)
- MariaDB 10.6+ or PostgreSQL 13+
- wkhtmltopdf (PDF generation for invoices, reports)
Recommended servers (2026 pricing):
- Hetzner CX32: 4 vCPU, 8GB RAM, €8.70/month — up to 25 users
- Hetzner CX42: 8 vCPU, 16GB RAM, €19.60/month — 25-100 users
Architecture Overview
ERPNext has more moving parts than most self-hosted apps. Understanding the components prevents confusion when something goes wrong:
┌──────────────────────────────────────────────────────┐
│ ERPNext Stack │
│ │
│ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │
│ │ Nginx │───▶│ Backend │───▶│ MariaDB │ │
│ │ Frontend │ │ (Python/ │ │ (database) │ │
│ │ │ │ Frappe) │ └───────────────┘ │
│ └──────────┘ └────┬─────┘ │
│ │ ┌───────────────┐ │
│ ├────────▶│ Redis Queue │ │
│ │ │ (background │ │
│ │ │ jobs) │ │
│ ┌──────────┐ │ └───────────────┘ │
│ │ Workers │◀────────┤ │
│ │ (queue │ │ ┌───────────────┐ │
│ │ workers) │ └────────▶│ Redis Cache │ │
│ └──────────┘ └───────────────┘ │
│ │
│ ┌──────────┐ ┌───────────────┐ │
│ │Scheduler │ │ SocketIO │ │
│ │(cron) │ │ (real-time │ │
│ └──────────┘ │ updates) │ │
│ └───────────────┘ │
└──────────────────────────────────────────────────────┘
Self-Hosting with Docker Compose
Frappe maintains the official frappe_docker repository. The recommended production setup uses their compose files with a few customizations.
Step 1: Clone frappe_docker
git clone https://github.com/frappe/frappe_docker.git ~/erpnext
cd ~/erpnext
Step 2: Create Your Environment File
# .env — do not commit this file
DB_PASSWORD=changeme-strong-db-password
ERPNEXT_VERSION=v16
FRAPPE_VERSION=v16
Step 3: Create docker-compose.yml
The official frappe_docker repo ships example compose files. Here's a production-ready setup for ERPNext v16:
# docker-compose.yml
version: "3.8"
x-erpnext: &erpnext
image: frappe/erpnext:${ERPNEXT_VERSION:-v16}
restart: unless-stopped
volumes:
- sites:/home/frappe/frappe-bench/sites
- logs:/home/frappe/frappe-bench/logs
services:
configurator:
<<: *erpnext
command: >
bash -c "bench set-config -g db_host db
&& bench set-config -gp db_port 3306
&& bench set-config -g redis_cache redis://redis-cache:6379
&& bench set-config -g redis_queue redis://redis-queue:6379
&& bench set-config -g redis_socketio redis://redis-socketio:6379
&& bench set-config -gp socketio_port 9000"
depends_on:
db:
condition: service_healthy
redis-cache:
condition: service_started
redis-queue:
condition: service_started
redis-socketio:
condition: service_started
restart: "no"
create-site:
<<: *erpnext
volumes:
- sites:/home/frappe/frappe-bench/sites
- logs:/home/frappe/frappe-bench/logs
environment:
DB_ROOT_USER: root
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
SITE_NAME: erp.yourdomain.com
INSTALL_APPS: erpnext
command: >
bash -c "wait-for-it -t 120 db:3306
&& wait-for-it -t 120 redis-cache:6379
&& wait-for-it -t 120 redis-queue:6379
&& wait-for-it -t 120 redis-socketio:6379
&& export start=`date +%s`
&& until [[ -n `grep -hs ^ sites/common_site_config.json | python -c \"import sys; import json; config = json.load(sys.stdin); print(config.get('db_host', ''))\"` ]]; do
&& echo \"Waiting for Frappe configurator...\";
&& sleep 1; now=`date +%s`; elapsed=$((now-start));
&& if [[ $elapsed -gt 120 ]]; then exit 1; fi; done
&& echo sites/assets >/etc/rsyslog.d/ignore.conf
&& bench new-site --no-mariadb-socket --admin-password=changeme --db-root-username=root --db-root-password=${DB_PASSWORD} --install-app erpnext --set-default erp.yourdomain.com"
depends_on:
configurator:
condition: service_completed_successfully
restart: "no"
backend:
<<: *erpnext
depends_on:
create-site:
condition: service_completed_successfully
frontend:
<<: *erpnext
command: nginx-entrypoint.sh
environment:
BACKEND: backend:8000
SOCKETIO: websocket:9000
UPSTREAM_REAL_IP_ADDRESS: "127.0.0.1"
FRAPPE_SITE_NAME_HEADER: erp.yourdomain.com
ports:
- "80:8080"
depends_on:
backend:
condition: service_started
websocket:
<<: *erpnext
command: ["node", "/home/frappe/frappe-bench/apps/frappe/socketio.js"]
depends_on:
backend:
condition: service_started
queue-short:
<<: *erpnext
command: bench worker --queue short
depends_on:
backend:
condition: service_started
queue-long:
<<: *erpnext
command: bench worker --queue long
depends_on:
backend:
condition: service_started
scheduler:
<<: *erpnext
command: bench schedule
depends_on:
backend:
condition: service_started
db:
image: mariadb:10.6
healthcheck:
test: mysqladmin ping -h localhost --password=${DB_PASSWORD}
interval: 10s
timeout: 5s
retries: 10
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
volumes:
- db-data:/var/lib/mysql
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
- --skip-character-set-client-handshake
- --skip-innodb-read-only-compressed
restart: unless-stopped
redis-cache:
image: redis:6.2-alpine
restart: unless-stopped
redis-queue:
image: redis:6.2-alpine
restart: unless-stopped
redis-socketio:
image: redis:6.2-alpine
restart: unless-stopped
volumes:
db-data:
sites:
logs:
Step 4: Launch ERPNext
# First run — this creates the site and installs ERPNext
# Takes 10-15 minutes on first boot
docker compose up -d
# Monitor progress
docker compose logs -f create-site
Look for Site erp.yourdomain.com installed successfully in the logs.
Step 5: Access ERPNext
Open http://your-server-ip and log in with:
- Username:
Administrator - Password:
changeme(from thecreate-sitecommand — change immediately)
The setup wizard walks you through company creation, currency, fiscal year, and chart of accounts selection.
ERPNext Setup Wizard: First Configuration
Company and Chart of Accounts
Setup Wizard Step 1:
Company Name: Acme Corp
Abbreviation: ACME
Default Currency: USD
Country: United States
Timezone: America/New_York
Step 2 — Chart of Accounts:
Standard: US GAAP (or select your country's standard)
→ ERPNext imports ~200 standard accounts automatically
Fiscal Year
Accounting → Setup → Fiscal Year → New
Year Name: 2026
Year Start Date: 01-01-2026
Year End Date: 12-31-2026
Core Modules Overview
Accounts (Financial Accounting)
ERPNext's Accounts module covers the full double-entry bookkeeping stack:
- General Ledger: Chart of accounts, journal entries, ledger reports
- Accounts Receivable: Customer invoices, payment tracking, aging reports
- Accounts Payable: Supplier invoices, purchase orders, payment runs
- Bank Reconciliation: Import bank statements, auto-match transactions
- Tax Management: GST, VAT, US sales tax — configurable per jurisdiction
- Multi-currency: Live exchange rates, realized/unrealized gain/loss tracking
- Financial Statements: P&L, balance sheet, cash flow — generated in real time
Accounts → Reports → Profit and Loss Statement
From Date: 01-01-2026
To Date: 03-31-2026
→ Exports to PDF or Excel with one click
HR and Payroll
HR → Employee → New
Full Name: Jane Smith
Department: Engineering
Designation: Software Engineer
Date of Joining: 2026-01-15
Salary Mode: Bank Transfer
Payroll → Salary Structure → New
Structure: "Senior Engineer - US"
Components:
Earning:
- Basic: formula = base * 0.40
- HRA: formula = base * 0.20
- Performance Bonus: amount = 5000
Deduction:
- Federal Tax: formula = (base + performance_bonus) * 0.22
- 401k: formula = base * 0.05
Running payroll:
Payroll → Payroll Entry → New
Company: Acme Corp
Period: March 2026
Payment Account: Payroll Bank Account
→ Process Payroll → Creates salary slips for all active employees
Inventory and Purchasing
Stock → Item → New
Item Code: WIDGET-001
Item Name: Acme Widget
Item Group: Products
Unit of Measure: Nos
Valuation Method: FIFO
Reorder Settings:
Reorder Level: 100
Reorder Qty: 500
ERPNext tracks inventory across multiple warehouses with real-time valuation. The stock ledger maintains a full audit trail of every movement.
Stock → Stock Entry → New
Type: Material Receipt
Items:
- WIDGET-001: 500 units → Warehouse: Main → $2.50/unit
→ Submit → Updates inventory value and GL simultaneously
Manufacturing and MRP
Manufacturing → Bill of Materials → New
Item: ASSEMBLED-WIDGET-001
BOM Components:
- WIDGET-BODY-01: 1 pc
- WIDGET-SPRING-02: 2 pcs
- WIDGET-FASTENER-03: 4 pcs
Operations:
- Assembly: 15 minutes @ $45/hr
- QC Check: 5 minutes @ $35/hr
Material Requirements Planning (MRP) calculates what to buy and when:
Manufacturing → Production Planning → Run MRP
Items: all items with pending Sales Orders
→ Creates Purchase Orders for raw materials
→ Creates Work Orders for production
→ Schedules by machine capacity and lead times
CRM and Sales
CRM → Lead → New
Lead Name: John Doe
Company: Prospect Corp
Status: Open
Lead Source: Website
CRM → Opportunity → Convert from Lead
Opportunity Amount: $45,000
Expected Close: 2026-04-30
Items:
- WIDGET-001: 1,000 units @ $45
The pipeline view shows all opportunities by stage, with close probability and expected revenue per rep.
Custom Domain and TLS
Step 1: Update DNS
# Add A record in your DNS provider:
erp.yourdomain.com → your.server.ip.address
Step 2: Add a Reverse Proxy with TLS
Add Caddy or Nginx Proxy Manager to your compose stack. With Caddy:
caddy:
image: caddy:2-alpine
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy-data:/data
depends_on:
- frontend
# Caddyfile
erp.yourdomain.com {
reverse_proxy frontend:8080
encode gzip
}
Remove the ports: "80:8080" from the frontend service and add it to the same network as Caddy.
Step 3: Update ERPNext Site URL
docker exec -it erpnext-backend-1 bash
bench set-config -g hostname erp.yourdomain.com
bench setup nginx # regenerates nginx config
Production Hardening
Automated Backups
#!/bin/bash
# backup-erpnext.sh
DATE=$(date +%Y%m%d_%H%M)
BACKUP_DIR="/backups/erpnext"
mkdir -p $BACKUP_DIR
# ERPNext built-in backup (includes DB + files)
docker exec erpnext-backend-1 \
bench backup --with-files --site erp.yourdomain.com
# Copy backup to host
docker cp erpnext-backend-1:/home/frappe/frappe-bench/sites/erp.yourdomain.com/private/backups/. \
$BACKUP_DIR/
# Upload to S3
rclone copy $BACKUP_DIR/ s3remote:backups/erpnext/
# Remove local backups older than 7 days
find $BACKUP_DIR -mtime +7 -delete
echo "ERPNext backup complete: $DATE"
Updates
cd ~/erpnext
# Pull new images
docker compose pull
# Stop, update, and restart
docker compose down
docker compose up -d
# Run migrations
docker exec erpnext-backend-1 bench migrate
Check the ERPNext releases page before major upgrades — v14→v15→v16 upgrades require running the migration command.
Performance Tuning
For large datasets (100k+ transactions), add these MariaDB settings:
db:
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
- --skip-character-set-client-handshake
- --skip-innodb-read-only-compressed
- --innodb-buffer-pool-size=2G # Set to 50-75% of available RAM
- --max-connections=500
- --query-cache-type=0 # Disable query cache (MariaDB 10.4+)
ERPNext vs Odoo: The Open Source ERP Comparison
Both ERPNext and Odoo are widely used open source ERPs. The key difference is in the license model:
| ERPNext | Odoo Community | Odoo Enterprise | |
|---|---|---|---|
| License | GPL v3 (all modules) | LGPL (core only) | Proprietary |
| Accounting | ✅ Full (free) | Limited | Full (paid) |
| Manufacturing | ✅ Full (free) | Limited | Full (paid) |
| Payroll | ✅ Full (free) | ❌ | ✅ (paid) |
| eCommerce | ✅ Full (free) | Limited | Full (paid) |
| Monthly cost (50 users) | ~$50 (VPS) | Free + VPS | $1,245/mo |
| UI/UX | Modern (v16) | Modern | Modern |
| Implementation support | Community + partners | Community + partners | Odoo partners |
| Best for | SMBs wanting full open source | Dev teams extending core | Companies buying SaaS ERP |
ERPNext's GPL v3 means every module is fully open source. Odoo Community is missing the modules most businesses actually need — Accounting, Manufacturing, and Payroll are behind the Enterprise paywall. This makes Odoo's "open source" framing misleading for most ERP use cases.
Frappe Cloud: Managed ERPNext Hosting
If you want ERPNext without the infrastructure management, Frappe (the company) offers managed cloud hosting:
frappe.cloud pricing (2026):
Shared: $5/month — 1 site, up to 50 users, 5GB storage
Dedicated: $25-100/month — dedicated VPS, more resources
Enterprise: Custom pricing — dedicated infrastructure + SLA
Frappe Cloud runs the same open source ERPNext — no proprietary features, full data portability. Useful for teams that want the software without the ops overhead.
Methodology
- GitHub stats from github.com/frappe/erpnext, March 2026
- ERPNext v16 release notes from github.com/frappe/erpnext/releases, December 2025
- Docker setup from github.com/frappe/frappe_docker, March 2026
- Pricing: Odoo from odoo.com/pricing, March 2026
- Pricing: SAP from sap.com/products/erp.html, March 2026
- Pricing: Frappe Cloud from frappe.cloud, March 2026
- ERPNext vs Odoo analysis: erpresearch.com/compare/erpnext-vs-odoo
- Cost comparison: dexciss.io/blog
Find more open source SAP and Odoo alternatives on OSSAlt — self-hosting guides, community ratings, and feature comparisons.
Related: Best Open Source Alternatives to Salesforce 2026 · Twenty vs EspoCRM 2026 · Self-Hosting vs Cloud: The Real Cost Comparison 2026