When you move Odoo or ERPNext from a test install to a real production system, your VPS suddenly stops being “just a server” and turns into the backbone of your finance, inventory, sales and HR data. At dchost.com we regularly see the same pattern: the first pilot runs fine, then usage grows, and the application starts feeling slow or unstable. In almost every case, the root cause is not the software itself, but how CPU, RAM, workers and the reverse proxy are sized and tuned.
This guide focuses exactly on those knobs. We will stay practical and opinionated: how many vCPUs and how much RAM per user segment, how to calculate Odoo worker counts, how to think about ERPNext/Frappe background workers, and how to place Nginx (or another reverse proxy) in front of your stack without breaking long‑polling or file uploads. If you already understand why you want Odoo or ERPNext on a VPS and now need production‑grade settings, this article is written for you.
İçindekiler
- 1 Why Proper VPS Tuning Matters for Odoo and ERPNext
- 2 Choosing the Right VPS Specs for Odoo and ERPNext
- 3 Configuring Odoo Workers on a VPS
- 4 ERPNext / Frappe: Web, Workers and Scheduler
- 5 Reverse Proxy Architecture for Odoo and ERPNext
- 6 Memory, Swap and Stability Under Load
- 7 Concrete Sizing Scenarios
- 8 Operations: Monitoring, Alerts and Load Testing
- 9 Security and Access Basics for ERP VPS Setups
- 10 Summary: Turning Your Odoo / ERPNext VPS into a Reliable Platform
Why Proper VPS Tuning Matters for Odoo and ERPNext
Odoo and ERPNext are not simple brochure websites. They are full‑stack business applications that combine:
- A Python web application (Odoo or Frappe framework)
- A relational database (PostgreSQL for both Odoo and ERPNext)
- Background workers for emails, reports, scheduled jobs and integrations
- Long‑polling / WebSocket‑style connections for notifications and chats
- Static files and attachments (documents, images, exports)
All of these share the same VPS CPU, RAM, disk and network. When you underestimate just one layer (for example worker memory or disk IOPS), it will usually surface as generic “Odoo is slow” or “ERPNext keeps timing out”. A well‑sized VPS with correctly tuned workers and a properly configured reverse proxy can often double perceived performance without changing a single line of code.
If you want a broader overview of platform choices and architecture options, we already covered that in our earlier guide on VPS hosting for Odoo, ERPNext and other self‑hosted CRM/ERP applications. Here we’ll go deeper into concrete CPU, RAM, worker and reverse proxy settings.
Choosing the Right VPS Specs for Odoo and ERPNext
You cannot tune what you don’t have. Before editing configuration files, you need a realistic baseline for vCPU, RAM, disk and network. These recommendations assume modern Linux (Ubuntu, Debian or similar) and PostgreSQL on the same VPS as the application server.
CPU Sizing: vCPUs vs Concurrent Users
For Odoo and ERPNext, CPU is primarily consumed by:
- Web workers handling HTTP requests
- Background job workers (emails, reports, integrations)
- Database queries and indexing
A rough but practical mapping we see in real projects:
- Small pilot (5–15 active users): 2 vCPU
- Growing team (15–50 active users): 4 vCPU
- Busy multi‑department setup (50–150 active users): 8 vCPU
- Heavier usage (150+ active users): 8+ vCPU and usually separate DB and app nodes
This assumes “active users” are really clicking around at the same time, not just having a tab open. It also assumes standard usage (sales, inventory, accounting) and not extremely heavy custom reports or huge batch imports.
If you want a more generic methodology that you can apply beyond ERPs, we recommend reading our article on how many vCPUs and how much RAM you really need on a VPS; the same thinking applies here, only the numbers shift slightly higher because ERPs are heavier than typical CMS workloads.
RAM Sizing: Don’t Forget PostgreSQL and Workers
CPU makes things fast, RAM keeps them stable. Odoo and ERPNext processes are relatively memory‑hungry, and PostgreSQL also needs a decent share. As a practical starting point:
- Small pilot (5–15 active users): 4 GB RAM minimum (2 GB is possible for pure testing, not recommended for production)
- Growing team (15–50 active users): 8 GB RAM
- Busy multi‑department setup (50–150 active users): 16 GB RAM
Empirically, you can think in terms of memory budget (numbers are rough but useful):
- Odoo/ERPNext web + background workers: ~150–300 MB per worker process
- PostgreSQL: 1–3 GB for small/medium databases, more for large datasets
- Redis (often used by ERPNext): 256–512 MB
- OS + monitoring + other daemons: 512 MB–1 GB
We’ll use these numbers later when calculating worker counts. For a deeper dive into how the kernel behaves under memory pressure, including swap and out‑of‑memory kills, see our guide on managing RAM, swap and the Linux OOM killer on VPS servers.
Disk and I/O: NVMe Really Helps
ERPs write lots of small database rows and attachments (PDF invoices, bills, product images). Slow disk means slow everything – PostgreSQL, background jobs, even login times. For production Odoo/ERPNext we strongly advise:
- NVMe SSD‑backed VPS (as provided in dchost.com VPS plans) rather than HDD or very old SATA SSD
- At least 50–100 GB of disk to leave headroom for logs and backups
- Regular external backups to object storage or another server
If you are comparing different disk options for a larger deployment, our general comparison of NVMe vs SATA vs HDD for hosting can help frame your choices.
Network: Latency and Bandwidth
Odoo and ERPNext are mostly low‑bandwidth (database‑driven) applications, but latency matters a lot. Place your VPS in a region close to your main office(s), and make sure you have enough outbound bandwidth for backups and potential integrations. At dchost.com we can help align VPS or dedicated server locations with your user base to keep round‑trip times under control.
Configuring Odoo Workers on a VPS
Odoo uses a multi‑process model in production. The two key concepts are:
- Workers: Processes that handle normal HTTP requests (CRUD screens, forms, reports)
- Long‑polling workers: Processes dedicated to “live” features such as chat and notifications
By default, a fresh Odoo install may run in single‑threaded “dev style” mode, which is fine for testing but not for production. Let’s walk through realistic worker sizing.
Baseline Formula for Odoo Workers
Odoo’s own rule of thumb is:
- workers ≈ (vCPU * 2) + 1
This assumes:
- You are running only Odoo on that VPS
- PostgreSQL is on another host (which is often not true for small setups)
- Sufficient RAM for the resulting worker count
In real‑world single‑VPS setups we usually go more conservative, because PostgreSQL and other services also need CPU and memory.
Memory‑Aware Worker Calculation
Let’s say you have a 4 vCPU / 8 GB RAM VPS running Odoo + PostgreSQL. We estimate:
- Reserve 2 GB for the OS, monitoring, Nginx and safety margin
- Reserve 2–3 GB for PostgreSQL
- Leave ~3 GB for Odoo workers
If each Odoo worker typically uses 200–250 MB under load, you can safely run:
- 3 GB / 0.25 GB ≈ 12 workers (theoretical max)
But we also care about CPU. With 4 vCPU, running 12 workers would be excessive. A more balanced configuration would be:
- workers = 6 (normal HTTP workers)
- longpolling_workers = 1 (for live notifications)
This uses roughly 7 workers total, which an 8 GB VPS can handle comfortably under typical usage while leaving headroom.
Example odoo.conf for a 4 vCPU / 8 GB VPS
[options]
; basic
db_host = False
db_port = False
db_user = odoo
db_password = STRONG_PASSWORD
; networking
xmlrpc_port = 8069
longpolling_port = 8072
proxy_mode = True
; workers
workers = 6
max_cron_threads = 2
limit_memory_soft = 2147483648 ; 2 GB per worker
limit_memory_hard = 2684354560 ; 2.5 GB per worker
limit_request = 8192
limit_time_cpu = 60
limit_time_real = 120
; logging
logfile = /var/log/odoo/odoo.log
logrotate = True
Notes:
- proxy_mode = True tells Odoo it is behind a reverse proxy (Nginx), so it trusts X‑Forwarded headers.
- limit_memory_soft/hard should be below total RAM; they protect you from runaway modules consuming all memory.
- max_cron_threads controls concurrent scheduled jobs; 1–2 is enough for most SMEs.
Mapping Odoo Workers to Concurrent Users
A very approximate but handy mapping:
- 1 worker can serve ~6–10 simultaneous active users comfortably
So with 6 workers you can often support 40–60 active users doing a mix of operations (sales, inventory, accounting) as long as database and disk are healthy. If you see CPU pinned at 100% and requests queuing during busy periods, you may:
- Increase workers slightly (if RAM allows)
- Optimize heavy reports or scheduled jobs
- Move PostgreSQL to a separate VPS or dedicated server
ERPNext / Frappe: Web, Workers and Scheduler
ERPNext runs on the Frappe framework and uses a slightly different process model, usually managed via bench and Supervisor or systemd. In production you typically see these process types:
- web: Gunicorn or similar WSGI workers handling HTTP requests
- worker: Background job workers for queued tasks
- worker-short / worker-long: Separate queues (short‑ and long‑running jobs)
- schedule: Scheduler for cron‑like tasks
Web Workers for ERPNext
A common Gunicorn rule of thumb is:
- workers ≈ (vCPU * 2) + 1
As with Odoo, on smaller single‑VPS setups we go more conservative to leave capacity for PostgreSQL and background workers. For example, on a 4 vCPU / 8 GB VPS:
- web: 4 workers (Gunicorn)
- timeout: 120 seconds (for heavy reports; adjust if needed)
Configured via Procfile or bench configuration, then managed by Supervisor or systemd.
Background Workers and Queues
ERPNext relies heavily on background jobs for sending emails, running reports, integrations and scheduled tasks. A simple but effective layout on a 4 vCPU / 8 GB VPS might be:
- worker: 2 processes
- worker-short: 1 process
- worker-long: 1 process
- schedule: 1 process
This gives you concurrency for normal jobs, keeps long‑running tasks from blocking everything, and leaves enough CPU for web workers and PostgreSQL. If email sending or integrations build up a queue, you can scale worker and worker-short up – always watching CPU and RAM usage.
Memory Planning for ERPNext Workers
Frappe workers are Python processes similar in size to Odoo workers. As a rough estimate:
- Web worker: 150–250 MB
- Background worker: 150–250 MB
- Redis: 256–512 MB
So in the example above (4 web workers + 4 background workers + 1 scheduler), you might allocate:
- ~8 workers × 250 MB ≈ 2 GB
- Redis: 512 MB
- PostgreSQL: 2–3 GB
- OS + Nginx + margin: 1.5–2 GB
That fits well into an 8 GB VPS as long as you avoid excessive additional daemons. If you consistently run close to the RAM limit, enable swap carefully (see our article on RAM, swap and OOM killer management) and plan a RAM upgrade or process tuning.
Reverse Proxy Architecture for Odoo and ERPNext
Running Odoo or ERPNext directly on port 8069 or 8000 is fine for internal tests, but production should always place a reverse proxy (commonly Nginx) in front. The reverse proxy handles:
- HTTPS termination (SSL/TLS)
- HTTP/2 or HTTP/3 support
- Request buffering and limits (file uploads, timeouts)
- Static assets caching (CSS, JS, images)
- Path‑ or host‑based routing for multiple apps
We have a general, hands‑on tutorial on reverse proxies in our article on step‑by‑step Nginx reverse proxy setup. Below we’ll tailor the configuration specifically for Odoo and ERPNext.
Key Nginx Settings for Odoo
Typical Odoo ports:
- Application (XML‑RPC/HTTP): 8069
- Long‑polling: 8072
A minimal but production‑friendly Nginx configuration might look like this:
upstream odoo {
server 127.0.0.1:8069 max_fails=3 fail_timeout=30s;
}
upstream odoo_longpolling {
server 127.0.0.1:8072 max_fails=3 fail_timeout=30s;
}
server {
listen 80;
server_name erp.example.com;
# Redirect HTTP to HTTPS
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name erp.example.com;
# SSL configuration (certs, protocols, ciphers)
ssl_certificate /etc/letsencrypt/live/erp.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/erp.example.com/privkey.pem;
# Recommended headers
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
# Increase upload limits for attachments
client_max_body_size 64m;
proxy_read_timeout 720s;
proxy_connect_timeout 60s;
proxy_send_timeout 720s;
# Static files (optional, if you serve them via Odoo)
location /web/static/ {
proxy_cache_valid 200 90m;
proxy_buffering on;
expires 864000;
proxy_pass http://odoo;
}
location /longpolling {
proxy_pass http://odoo_longpolling;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 720s;
proxy_buffering off;
}
location / {
proxy_pass http://odoo;
proxy_redirect off;
proxy_buffering on;
proxy_read_timeout 720s;
}
}
Key points:
- proxy_set_header lines are essential so Odoo can generate correct URLs and log client IPs.
- client_max_body_size must be large enough for your biggest attachment uploads.
- proxy_read_timeout is extended to avoid timeouts during large exports or reports.
- /longpolling is mapped to the long‑polling port to keep live notifications responsive.
Nginx Settings for ERPNext
ERPNext has an official Nginx template generated by bench setup nginx, which you should use as a base and then tune. Most of the concepts are similar:
- Upstream to Gunicorn web workers
- Proper proxy headers
- Increased timeouts for long reports
- client_max_body_size for attachment uploads
One extra consideration is static assets and caching. ERPNext’s Nginx template usually sets strong caching on assets (hashed filenames), which is good. Just make sure you reload Nginx after bench updates if the template changes.
Running Multiple Sites on One Reverse Proxy
It’s common to run several instances on the same VPS, for example:
erp.company.com→ production Odootest.company.com→ staging Odoo or ERPNext
Each gets its own server block with its own SSL certificate and upstream definition. If you also host a public website (WordPress, Laravel, etc.) on the same VPS, consider isolating workloads carefully and watching your resource usage; we have a dedicated article on monitoring VPS resource usage with htop, iotop, Netdata and Prometheus that shows how to catch contention early.
Memory, Swap and Stability Under Load
Even with correct CPU and worker counts, memory pressure can cause random slowness or crashes. Typical symptoms include:
- Odoo/ERPNext workers being killed and restarted
- PostgreSQL errors about out‑of‑memory
- The whole VPS becoming unresponsive during large imports
Practical Memory Rules of Thumb
- Keep at least 15–25% of RAM free during normal load.
- Don’t run more workers than your RAM budget realistically allows (see earlier calculations).
- Enable a moderate swap (e.g. 1–2× RAM for small VPS) to absorb spikes, but do not rely on swap for normal operation.
- Lower Odoo/ERPNext worker memory limits (
limit_memory_soft/hardin Odoo; fewer workers in ERPNext) if you see frequent OOM kills.
Our detailed article on RAM, swap and OOM killer management on VPS servers walks through real commands (free -h, dmesg, journalctl) to see whether the kernel is killing your processes.
For small and medium Odoo/ERPNext databases on the same VPS, simple PostgreSQL tuning goes a long way:
- shared_buffers: 20–25% of RAM (but not more than a few GB)
- work_mem: 8–32 MB per connection for small setups
Be cautious: both values multiply with concurrent connections. Over‑tuning PostgreSQL can starve your application workers.
Concrete Sizing Scenarios
Let’s translate all the above into three realistic scenarios we often implement for clients at dchost.com.
Scenario 1: Small Team Pilot (10–15 Active Users)
- Use case: Single company, basic CRM + sales + invoicing, light inventory.
- Recommended VPS: 2 vCPU, 4 GB RAM, 80 GB NVMe disk.
Odoo example:
- workers = 3
- longpolling_workers = 1
- max_cron_threads = 1
ERPNext example:
- Gunicorn web workers: 2
- worker: 1
- worker-short: 1
- schedule: 1
This fits comfortably in 4 GB RAM if you keep PostgreSQL and Redis settings modest. For pilots, this is usually enough, and you can scale vertically as usage grows.
Scenario 2: Growing Company (30–60 Active Users)
- Use case: Several departments on Odoo/ERPNext (Sales, Purchase, Inventory, Accounting), daily imports/exports.
- Recommended VPS: 4 vCPU, 8–12 GB RAM, 160+ GB NVMe disk.
Odoo example (4 vCPU / 8 GB):
- workers = 6
- longpolling_workers = 1
- max_cron_threads = 2
ERPNext example (4 vCPU / 8 GB):
- Gunicorn web workers: 4
- worker: 2
- worker-short: 1
- worker-long: 1
- schedule: 1
At this stage you should also invest in proper monitoring. Our guide on monitoring VPS resource usage with htop, iotop, Netdata and Prometheus shows how to build dashboards and alerts before users start complaining.
Scenario 3: Multi‑Department / Multi‑Company (80–200+ Active Users)
- Use case: Many concurrent users, heavy accounting and reporting, integrations (e‑commerce, external WMS, etc.).
- Recommended architecture: Separate database and application layers.
A common layout:
- Application VPS: 8 vCPU, 16–32 GB RAM, running Odoo/ERPNext web + workers + Nginx.
- Database VPS or dedicated server: 8+ vCPU, 32–64 GB RAM, tuned PostgreSQL and fast NVMe storage.
At this scale, per‑project tuning becomes highly specific: index optimization, caching, connection pooling, sometimes even read replicas for reporting. dchost.com can provide both powerful VPS instances and bare‑metal dedicated servers or colocation if you want to bring your own hardware and run PostgreSQL on a fully isolated node.
Operations: Monitoring, Alerts and Load Testing
Capacity planning is not a one‑time task. Odoo and ERPNext usage patterns change as more departments adopt the system, new customizations are deployed, or reporting usage grows. You need continuous feedback from the server side.
Key Metrics to Watch
- CPU: sustained usage above 70–80% during business hours suggests you may need more vCPUs or worker tuning.
- RAM: avoid constant use above 80–85%; leave breathing room for spikes.
- Disk I/O: high IOwait means your disk is saturated; NVMe or better IOPS limits help.
- Database connections: track the number of active connections to PostgreSQL.
Our monitoring guide with htop, iotop, Netdata and Prometheus (linked earlier) shows how to surface all of this in dashboards instead of guessing when users complain.
Load Testing Before Big Go‑Lives
If you are about to onboard a new department or migrate a lot of users at once, doing a small load test is worth it. Simulate realistic user flows (login, search, create order, validate invoice) and slowly ramp up concurrency. Watch CPU, RAM, PostgreSQL and worker queue lengths. Adjust worker counts and, if necessary, VPS size before the real go‑live instead of mid‑project.
Security and Access Basics for ERP VPS Setups
Performance is only half the story; these systems hold your core business data. At minimum:
- Restrict SSH and database access to trusted IPs or VPN users.
- Use strong TLS settings and keep certificates renewed automatically.
- Apply regular OS and application security updates.
- Take automatic, off‑site backups of databases and application files.
We maintain a detailed checklist in our article on VPS security hardening with sshd_config, Fail2ban and disabling direct root SSH, and for panel access we describe secure remote patterns (VPN, bastion hosts, zero‑trust) in our post on secure remote access to hosting panels with VPN and bastion hosts. The same principles apply to ERP servers.
Summary: Turning Your Odoo / ERPNext VPS into a Reliable Platform
Running Odoo or ERPNext on a VPS is not just about installing the software; it’s about turning that VPS into a predictable, well‑tuned platform. Start by picking realistic CPU and RAM for your current and near‑future user counts, then derive worker counts from those resources rather than from defaults alone. Keep an eye on how much memory each worker type consumes, and ensure PostgreSQL has enough headroom without starving the application.
Put a reverse proxy like Nginx in front to handle HTTPS, timeouts and routing cleanly, and monitor CPU, RAM, disk and queue lengths so you can adjust before users feel pain. When you outgrow a single VPS, move to a split app/database layout on larger VPS or dedicated servers – something we design frequently for dchost.com clients who scale from pilot projects to mission‑critical ERP deployments.
If you’re unsure where your current setup stands, our team can review your existing Odoo or ERPNext instance, look at real resource usage, and propose a concrete VPS, dedicated server or colocation plan on dchost.com with matching worker and reverse proxy settings. The goal is simple: you focus on running your business in your ERP, and we make sure the infrastructure quietly does its job in the background.
