If you want an ERP for a small business without paying per user, the two serious open-source choices are Odoo Community and Dolibarr, and both run well on your own VDS (a virtual server with its own resources and IP address). Pick Dolibarr if you mainly need customers, quotes, invoices, stock and simple accounting, and want something light that one person can look after. Pick Odoo Community if you expect to grow into manufacturing, a web shop, projects or many connected apps, and can give it a bigger server. In our lab both ran on 2 vCPU and 3 GB of RAM: Dolibarr used under 400 MB with 20 scripted users, Odoo about 820 MB in its recommended multi-worker mode. Neither licence charges per user.
Key facts, checked on 9 October 2026:
- The current official Odoo image is
odoo:20(build 20.0-20260926) on Docker Hub. Odoo Community is licensed under the LGPL version 3; Odoo Enterprise needs "a valid Odoo Enterprise Subscription for the correct number of users" (Odoo licences). - Odoo's pricing page shows Standard at EUR 18.60 and Custom at EUR 33.90 per user per month before discounts. Yearly billing and a 12-month discount for the initial users bring the price down. Only the Custom plan allows on-premise hosting, which means Enterprise on your own server.
- Dolibarr 24.0.0 was released on 20 August 2026 and supports PHP 7.2 to 8.5 (Dolibarr releases). It is free software under the GNU GPL v3 or later (Dolibarr on GitHub). The official Docker image gave us 24.0.1.
- Odoo's own sizing rule is (number of CPUs x 2) + 1 workers, and "1 worker ~= 6 concurrent users", with about 150 MB per light worker and about 1 GB per heavy one (Odoo deployment docs).
Odoo vs Dolibarr: which one is for you?
Ask yourself what a normal Tuesday in your business looks like. If it is "send three quotes, turn one into an invoice, check what is in the warehouse, see who has not paid", Dolibarr covers that and stays out of your way. Its screens look like a classic business program, it runs on PHP with MariaDB or MySQL, and a 2 GB server is plenty for a small team.
If your Tuesday also includes a production order, an online shop that must take stock off the same shelf, a helpdesk queue or a team planning projects, Odoo is the better base. It has more apps that share one database, a more modern interface and a large partner network. The price is weight: the image alone is 3.5 GB, and a properly configured Odoo uses two to three times the RAM of Dolibarr.
| Dolibarr 24 | Odoo Community 20 | |
|---|---|---|
| Licence | GPL v3 or later, every module free | LGPL v3; some apps exist only in paid Enterprise |
| Stack | PHP, Apache, MariaDB/MySQL or PostgreSQL | Python, PostgreSQL |
| RAM in our lab, 20 busy users | About 380 MB (app + database) | About 350 MB in single-process mode, about 820 MB with 5 workers |
| Disk for the Docker stack | 1.6 GB | 3.1 GB |
| Good at | Quotes, orders, invoices, stock, bank, simple accounting | CRM, sales, inventory, manufacturing, website, projects, many add-ons |
| Who can run it | One technical person, part time | Someone who is comfortable with Docker, PostgreSQL and config files |
What "no per-user fees" really means
An ERP (enterprise resource planning system) is one program that keeps sales, stock, invoices and staff in one database, so the same customer record feeds the quote, the delivery and the invoice. Hosted ERPs usually charge for every person who logs in. Self-hosting changes that: Dolibarr and Odoo Community cost nothing per user, so the bill is the server plus the time you spend on it.
Odoo is open core. Community is free, while some apps and services, such as Studio (the drag-and-drop customisation tool), the full Accounting app, Helpdesk and Sign, are sold as Enterprise. Odoo's pricing page also has a "One App Free" plan with unlimited users for a single app, hosted by Odoo. For contrast, here is what Odoo's paid plans add up to at list price:
| Users | Odoo Standard (Odoo Online) | Odoo Custom (needed for Enterprise on your own server) | Odoo Community or Dolibarr |
|---|---|---|---|
| 5 users | EUR 93.00 a month | EUR 169.50 a month | EUR 0 in licences |
| 20 users | EUR 372.00 a month | EUR 678.00 a month (EUR 8,136 a year) | EUR 0 in licences |
List prices from odoo.com/pricing-plan, checked on 9 October 2026, before VAT, before yearly-billing savings and before the first-year discount. Odoo.sh hosting is charged on top of the Custom plan. The honest comparison is not "free versus EUR 678": Enterprise includes Odoo's support, upgrades and hosting, and with Community or Dolibarr that work is yours or your IT partner's.
What we measured in our lab
We installed both on Debian 13 in two separate test machines with 2 vCPU and 3 GB of RAM each, using Docker 29.9 and Docker Compose 5.6. Each got 500 customers and 200 confirmed orders or invoices. Then a script logged in and clicked through lists for 60 seconds as 5 and then 20 parallel users, with no pause between clicks. A real person pauses for 10 to 30 seconds between clicks, so one of our "busy users" is heavier than several real ones. RAM figures come from docker stats and are app plus database. Two limits to keep in mind: the test script ran inside the same 2 vCPU machine and took CPU away from the apps, and each app clicked through its own pages, so read the response times as rough guides, not a head-to-head speed contest.
| Setup | Idle after login | 5 busy users | 20 busy users | Average response at 20 users |
|---|---|---|---|---|
| Dolibarr 24.0.1 + MariaDB 11.8 | 276 MB | 300 MB | 381 MB | 0.38 s |
| Odoo 20 + PostgreSQL 17, default single process | 261 MB | 306 MB | 349 MB | 0.34 s |
| Odoo 20 + PostgreSQL 17, 5 workers | 675 MB | 818 MB | 819 MB | 0.26 s |
Three things stood out. First, Odoo's default mode is a single Python process that runs out of CPU before RAM: it sat at 198% CPU (both cores) with 20 users. Switching to 5 workers handled 23% more requests in the same minute and cut the 95th-percentile response from 0.68 s to 0.38 s, at the cost of about 470 MB more RAM. Second, Dolibarr barely grows: Apache started more processes and the web container went from 76 MB to 169 MB. Third, the slow moments in real use are PDF reports, imports and month-end reports, which our list-clicking test did not cover. That is why Odoo's docs plan 1 GB for a heavy worker, far more than the roughly 100 MB per process we saw.
Setup times in the lab: pulling the Odoo and PostgreSQL images took 52 seconds, creating the database 17 seconds, and installing CRM, Sales, Invoicing, Inventory and Employees 67 seconds. Dolibarr's first boot, which creates all its tables, took 71 seconds.
How big a server for 5 and 20 users
Odoo's formula gives a 2 vCPU server at most 5 workers and a 4 vCPU server at most 9. At 6 users per worker, 20 people need about 4 workers plus one for scheduled jobs. The docs' memory estimate for 9 workers is 9 x (0.8 x 150 MB + 0.2 x 1,024 MB), roughly 3 GB for Odoo alone, before PostgreSQL and the system. Dolibarr has no such formula; our numbers and its PHP design say RAM is rarely the limit.
| Team size | Dolibarr | Odoo Community |
|---|---|---|
| 1 to 5 users | VPS Micro: 2 vCPU, 2 GB RAM, 40 GB NVMe | VPS Mini: 4 vCPU, 4 GB RAM, 80 GB NVMe, 5 workers |
| Up to 20 users | VPS Mini: 4 vCPU, 4 GB RAM, 80 GB NVMe | VDS Small: 4 vCPU, 8 GB RAM, 240 GB NVMe, 9 workers |
These are our recommendations from the lab and Odoo's formula, with room for backups, updates and reports. A solo user can run Dolibarr on a VPS Nano with 1 GB, but there is little headroom. If your company grows, you can move to a bigger plan from the client area with a short reboot, so starting small is not a trap. All RS Computers plans use KVM, NVMe disks and unmetered traffic, and come with their own IPv4 and IPv6 addresses.
Step 1: Docker and a normal user
Both apps run in Docker, which packs each program with everything it needs into a "container". Install it from Docker's own repository, as the official Debian guide describes, and create a user called erp to run the apps. Users in the docker group can control the whole server, so add only people you trust. If Docker is new to you, our Docker on a VPS guide explains the basics.
# as root
apt-get update
apt-get install -y ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian $(. /etc/os-release && echo "$VERSION_CODENAME") stable" > /etc/apt/sources.list.d/docker.list
apt-get update
apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
apt-get install -y cron
adduser --disabled-password --gecos "" erp
usermod -aG docker erp
docker --version
Expected: Docker version 29.9.0, build f415da8 or newer. The cron package runs the nightly backup later; the minimal Debian 13 image we used did not have it. Switch to the new user with su - erp for the next steps.
Step 2a: Odoo Community 20 with PostgreSQL
First the passwords and the Odoo config file. The admin_passwd line is the "master password" that protects creating and deleting databases.
# as the erp user
mkdir -p ~/odoo/config && cd ~/odoo
printf 'DB_PASSWORD=%s\n' "$(openssl rand -hex 16)" > .env
chmod 600 .env
cat > config/odoo.conf <<EOF
[options]
admin_passwd = $(openssl rand -hex 16)
proxy_mode = True
http_interface = 0.0.0.0
data_dir = /var/lib/odoo
addons_path = /mnt/extra-addons
list_db = True
EOF
grep admin_passwd config/odoo.conf
Write the master password down. Keep the http_interface = 0.0.0.0 line: in our first try we set only proxy_mode = True, and Odoo 20 then listened on 127.0.0.1 inside its container, so nothing could reach it. The log said HTTP service running on 127.0.0.1:8069 and every request failed.
# as the erp user, in ~/odoo
cat > compose.yaml <<'YML'
services:
db:
image: postgres:17
environment:
POSTGRES_DB: postgres
POSTGRES_USER: odoo
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- db-data:/var/lib/postgresql/data
restart: unless-stopped
web:
image: odoo:20
depends_on:
- db
ports:
- "127.0.0.1:8069:8069"
- "127.0.0.1:8072:8072"
environment:
HOST: db
USER: odoo
PASSWORD: ${DB_PASSWORD}
volumes:
- odoo-data:/var/lib/odoo
- ./config:/etc/odoo
restart: unless-stopped
volumes:
db-data:
odoo-data:
YML
docker compose up -d
docker compose logs web | grep "HTTP service"
Expected: HTTP service running on 0.0.0.0:8069. The ports are bound to 127.0.0.1 on purpose. Docker's published ports skip a normal firewall such as UFW, so binding to localhost is what keeps your ERP off the open internet until HTTPS is in place. Port 8072 carries Odoo's live updates (chat and notifications) once workers are on.
Open the database screen through an SSH tunnel (next section), fill in the master password, a database name such as company, your email, a password, language and country, and click Create. Then install apps from the Apps menu. You can also install them from the command line, which took 67 seconds in our lab:
# as the erp user, in ~/odoo
docker compose stop web
docker compose run --rm web odoo -d company -i crm,sale_management,account,stock,hr --stop-after-init
docker compose start web
Now turn on workers for your server size and switch off the public database manager. For a 2 vCPU server we used the values from Odoo's own sample; on 4 vCPU raise workers to 9.
# as the erp user, in ~/odoo
sed -i 's/^list_db = True/list_db = False/' config/odoo.conf
cat >> config/odoo.conf <<EOF
workers = 5
max_cron_threads = 1
limit_memory_soft = 629145600
limit_memory_hard = 1677721600
limit_time_cpu = 600
limit_time_real = 1200
EOF
docker compose restart web
docker compose logs web --since 1m | grep -E "Worker|WebSocket"
Expected: five lines with WorkerHTTP: Alive, one with WorkerCron: Alive and Evented/WebSocket service running on 0.0.0.0:8072. The address /web/database/manager now shows "The database manager has been disabled by the administrator".
Step 2b: Dolibarr 24 with MariaDB
# as the erp user
mkdir -p ~/dolibarr && cd ~/dolibarr
printf 'DB_PASSWORD=%s\nDB_ROOT_PASSWORD=%s\nADMIN_PASSWORD=%s\n' "$(openssl rand -hex 16)" "$(openssl rand -hex 16)" "$(openssl rand -hex 12)" > .env
chmod 600 .env
cat > compose.yaml <<'YML'
services:
mariadb:
image: mariadb:11.8
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
MYSQL_DATABASE: dolidb
MYSQL_USER: dolidbuser
MYSQL_PASSWORD: ${DB_PASSWORD}
volumes:
- db-data:/var/lib/mysql
restart: unless-stopped
web:
image: dolibarr/dolibarr:latest
depends_on:
- mariadb
ports:
- "127.0.0.1:8080:80"
environment:
DOLI_DB_HOST: mariadb
DOLI_DB_NAME: dolidb
DOLI_DB_USER: dolidbuser
DOLI_DB_PASSWORD: ${DB_PASSWORD}
DOLI_URL_ROOT: "http://localhost:8080"
DOLI_ADMIN_LOGIN: admin
DOLI_ADMIN_PASSWORD: ${ADMIN_PASSWORD}
DOLI_COMPANY_NAME: "My Company"
DOLI_INIT_DEMO: 0
volumes:
- documents:/var/www/documents
- custom:/var/www/html/custom
restart: unless-stopped
volumes:
db-data:
documents:
custom:
YML
docker compose up -d
docker compose logs web | tail -5
Repeat the last command every minute until you see Schema update is not required ... Enjoy ! and an Apache line ending in resuming normal operations. That took 71 seconds for us. Log in as admin with the ADMIN_PASSWORD from .env, then switch on the modules you need under Setup, Modules: Third parties, Products, Commercial proposals, Sales orders, Invoices, Stock and Banks.
One trap we fell into: the image documents a DOLI_CRON setting for scheduled jobs. Set it to 1 on the main container and that container runs only the cron service. Apache never starts and the database is never created. Our first attempt sat silent for three minutes before we read the start script. Leave it off the web container; the image's repository has a separate example for running scheduled jobs.
Reaching it safely: tunnel first, HTTPS later
Until you have a domain and a certificate, use an SSH tunnel. It forwards a port on your own computer to the server over the encrypted SSH connection:
# on your own computer
ssh -N -L 8069:127.0.0.1:8069 root@YOUR_SERVER_IP
Leave that window open and browse to http://localhost:8069 for Odoo. For Dolibarr, use 8080 in both places and open http://localhost:8080. We checked the tunnel in the lab and the Odoo login page came through it with HTTP status 200. When the team needs access, put a reverse proxy with a free Let's Encrypt certificate in front; our Caddy, Nginx and Traefik guide covers it. For Odoo, route /websocket to port 8072 and everything else to 8069. For Dolibarr, change DOLI_URL_ROOT to your https address. If staff only work from the office, a WireGuard VPN keeps the ERP off the public internet entirely.
Back up the database every night
Your ERP is your invoices, your stock and your tax records. Each app has two parts to save: the database, and a folder of uploaded files (Odoo calls it the filestore, Dolibarr the documents folder). This script for Odoo dumps both and keeps 14 days:
# as the erp user: save as ~/backup-odoo.sh
#!/bin/bash
set -e
cd ~/odoo
D=$(date +%F)
mkdir -p ~/backups
docker compose exec -T db pg_dump -U odoo -Fc company > ~/backups/company-$D.dump
docker compose exec -T web tar czf - -C /var/lib/odoo filestore/company > ~/backups/filestore-$D.tgz
find ~/backups -name '*.dump' -mtime +14 -delete
find ~/backups -name '*.tgz' -mtime +14 -delete
ls -lh ~/backups
The Dolibarr version uses mariadb-dump with --single-transaction, so the dump is consistent while people keep working:
# as the erp user: save as ~/backup-dolibarr.sh
#!/bin/bash
set -eo pipefail
cd ~/dolibarr
. ./.env
D=$(date +%F)
mkdir -p ~/backups
docker compose exec -T -e MYSQL_PWD="$DB_PASSWORD" mariadb \
mariadb-dump --single-transaction -u dolidbuser dolidb | gzip > ~/backups/dolidb-$D.sql.gz
docker compose exec -T web tar czf - -C /var/www documents > ~/backups/documents-$D.tgz
find ~/backups -name '*.gz' -mtime +14 -delete
find ~/backups -name '*.tgz' -mtime +14 -delete
ls -lh ~/backups
Make the script executable and run it every night at 02:30 (shown for Odoo; use the Dolibarr file name for Dolibarr):
# as the erp user
chmod 700 ~/backup-odoo.sh
~/backup-odoo.sh
(crontab -l 2>/dev/null; echo "30 2 * * * $HOME/backup-odoo.sh > $HOME/backups/last.log 2>&1") | crontab -
crontab -l
In our lab the Odoo dump was 5.6 MB and took 1.1 seconds; the Dolibarr backup was 129 KB plus 144 KB of documents in 1.5 seconds. A backup you have never restored is a hope, so we restored the Odoo dump into a test database:
# as the erp user, in ~/odoo
docker compose exec -T db createdb -U odoo company_test
docker compose exec -T db pg_restore -U odoo -d company_test --no-owner < ~/backups/company-2026-10-09.dump
docker compose exec -T db psql -U odoo -d company_test -tc "select count(*) from sale_order"
docker compose exec -T db dropdb -U odoo company_test
Expected: 200, the number of orders we created. The Dolibarr dump restored the same way into a test database and showed all 200 invoices. A copy on the same server does not survive the server, so send ~/backups somewhere else every night; our restic and MinIO guide shows how, and Uptime Kuma can warn you when the ERP stops answering.
Where your data lives: Amsterdam, Dublin or Prishtina
An ERP holds personal data about customers and staff, so where the server stands matters. RS Computers runs KVM servers in Amsterdam (Netherlands), Dublin (Ireland) and Prishtina (Kosovo); availability by city is on the plans page.
- Amsterdam and Dublin are inside the EU, where the GDPR applies and data can move between member states without extra transfer paperwork. Servers in both cities also get their own /48 of IPv6.
- Prishtina keeps a Kosovo company's data at home. Kosovo's Law No. 06/L-082 on Protection of Personal Data is enforced by the Information and Privacy Agency, and, according to DLA Piper's summary, transfers to countries on the agency's adequacy list, which includes the EU member states, need no prior approval. More reasons are in why buy a VPS in Kosovo.
This is general information, not legal advice. Your accountant or lawyer should confirm what your sector and your customers' countries require.
Frequently asked questions
Is Odoo Community really free for unlimited users?
Yes. Odoo Community is released under the LGPL version 3, which has no user limit and no licence fee. You pay only for the server and your time. Per-user fees apply to Odoo Enterprise, which Odoo listed at EUR 18.60 (Standard) and EUR 33.90 (Custom) per user per month before discounts on 9 October 2026.
Is Dolibarr or Odoo better for a small business?
Dolibarr is better for a small business that mainly needs quotes, orders, invoices, stock and simple accounting, and wants a light server that is easy to maintain. Odoo Community is better when you expect manufacturing, an online shop, projects or many connected apps. In our lab Dolibarr needed about 380 MB of RAM for 20 busy users; Odoo with workers needed about 820 MB.
How much RAM does Odoo need?
For 5 users, plan a server with 4 GB of RAM; for 20 users, 8 GB. In our lab Odoo 20 with PostgreSQL used about 820 MB under load with 5 workers, but Odoo's documentation budgets about 1 GB for each heavy worker, which covers PDF reports, imports and month-end work.
Can Dolibarr run on a 1 GB VPS?
Yes, for one or two users. Dolibarr 24 with MariaDB used 276 MB of RAM at idle and 381 MB with 20 scripted users in our lab. A 2 GB server gives more room for backups, updates and larger reports, so it is the safer choice for a team.
How do I back up Odoo or Dolibarr?
Back up two things: the database and the uploaded files. For Odoo, run pg_dump on the PostgreSQL container and archive the filestore folder. For Dolibarr, run mariadb-dump with --single-transaction and archive the documents folder. Schedule it with cron, copy the files to another server, and test a restore.
Can I move from Odoo Community to Enterprise later?
Yes. Odoo's editions page says you can switch versions at any time. Running Enterprise on your own server requires the Custom plan. Ask Odoo or a partner to plan the switch, because it adds the Enterprise modules to your existing database.
Pick one and try it for a week
Both apps install in minutes, so the cheapest way to decide is to run both side by side for a week with your real quotes and invoices, then keep the one your team actually opens. A VPS Mini or VDS Small fits Odoo; a VPS Micro is plenty for Dolibarr. If you would rather have us install and configure it, setup work is quoted per job: message us on Telegram or email us, and tell us which city your data should live in.