Recommended Free Tools
The reliable pattern is a two-container Docker Compose stack: an Odoo container connected to a PostgreSQL container, with separate persistent volumes for the Odoo filestore and PostgreSQL database. This guide uses the explicit odoo:19.0 image tag and publishes Odoo on port 8069. Image tags and PostgreSQL compatibility can change, so confirm the available tags immediately before deployment.
Need a server to try this on? Antihost offers Linux VPS plans with NVMe storage, full root access and a 14-day free trial.
Install Docker Engine and the Docker Compose plugin on Ubuntu first, using Docker’s current Ubuntu instructions at Docker’s official Ubuntu installation guide. The commands on that page change over time; do not substitute an old tutorial. Odoo’s Ubuntu package documentation is a separate installation route and does not define which Ubuntu releases can host the Docker image.
As an Amazon Associate I earn from qualifying purchases.
What you are building
Odoo’s official image documentation states that “This image requires a running PostgreSQL server.” Compose gives the two services a private network and lets the Odoo container reach PostgreSQL by its service name. The resulting layout is:
- web: the Odoo application, listening on container port 8069.
- db: PostgreSQL, with its own persistent data volume.
- odoo-data: the Odoo filestore volume mounted at
/var/lib/odoo. - addons: an optional host directory mounted at
/mnt/extra-addonsfor custom modules.
A container is disposable. The database and filestore are not. If you remove an Odoo container without a persistent volume, attachments and other filestore content are lost even if the application container can be recreated.
#1 Best Overall
Requirements on the Ubuntu host
Install Docker Engine and Compose
Follow the current instructions at docs.docker.com/engine/install/ubuntu/ for your Ubuntu release. The official Odoo material reviewed for this setup does not establish the current host-install command sequence, so use Docker’s own documentation rather than copying commands from an older article.
After installation, verify both components from a shell:
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →docker --version
docker compose version
If your Linux account is not permitted to access the Docker socket, run commands with the access method configured by Docker’s installation instructions (often sudo) or correct the host’s Docker-group policy before continuing. Treat Docker socket access as administrative access.
Check storage, networking and DNS
- Reserve enough disk space for PostgreSQL, the Odoo filestore, logs and future backups.
- Ensure the host can pull images from the registry and that clients allowed to use Odoo can reach the chosen host port.
- Choose a stable server name or IP address. You will use it in the browser and, if applicable, in a reverse proxy.
Do not infer host support from the .deb page
Odoo’s Odoo 19 package page currently documents Ubuntu Noble (24.04 LTS) for the .deb route. That statement describes the package, not a Docker-host support matrix. A Docker image runs through the host’s Docker Engine and kernel; select an Ubuntu release supported by Docker’s current documentation and your own operational policy.
How do I run Odoo with Docker Compose?
1. Create a project directory
mkdir -p ~/odoo-docker/addons
cd ~/odoo-docker
Keep the Compose file, the environment file and the addons directory together. Restrict access to this directory if other users share the server.
2. Create a password file
Create .env in the project directory:
POSTGRES_PASSWORD=replace-with-a-long-random-secret
Use a unique, high-entropy password rather than the demonstration credentials shown in simple examples. Restrict the file and exclude it from source control:
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallRank #2
chmod 600 .env
Do not commit .env to a public repository, paste it into support tickets, or put the secret directly in a published Compose file. The official image documentation also describes Docker secrets and password-file patterns; use those when your deployment’s secret-management policy requires them.
3. Write the Compose file
Create compose.yml with this starting configuration:
services:
web:
image: odoo:19.0
depends_on:
- db
ports:
- "8069:8069"
environment:
HOST: db
USER: odoo
PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- odoo-data:/var/lib/odoo
- ./addons:/mnt/extra-addons
db:
image: postgres:15
environment:
POSTGRES_DB: postgres
POSTGRES_USER: odoo
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- db-data:/var/lib/postgresql/data
volumes:
odoo-data:
db-data:
This follows the topology and environment-variable pattern in Odoo’s official image example. It is a deployment starting point, not a complete production-hardening design. Confirm that the selected PostgreSQL major version is compatible with your selected Odoo major release, and check the registry immediately before deployment for current image tags and rebuilds. Docker tags are mutable release artifacts.
4. Understand each setting before starting
| Setting | Purpose | Important qualification |
|---|---|---|
image: odoo:19.0 |
Selects an Odoo 19 image by major/minor tag. | Tags and their underlying builds can change. Pin and record a digest if your change-control process requires immutable deployments. |
HOST: db |
Tells Odoo to use the Compose service named db as PostgreSQL’s hostname. |
If you rename the database service, change this value to the new service name. |
USER and PASSWORD |
Credentials Odoo uses to log in to PostgreSQL. | They must match the database container’s initialization values. |
8069:8069 |
Maps host port 8069 to Odoo’s container port 8069. | Only the host side needs to change when another host port is required. |
odoo-data:/var/lib/odoo |
Persists Odoo’s filestore and related data outside the container lifecycle. | Removing this volume removes the filestore. |
db-data:/var/lib/postgresql/data |
Persists PostgreSQL’s database files. | Database persistence is separate from filestore persistence; back up both. |
./addons:/mnt/extra-addons |
Makes host-side custom addons available to Odoo. | Place only code you trust in this directory and manage it like application source. |
Start the stack and open Odoo
Launch from the Compose directory
From the directory containing compose.yml and .env, run:
Free tools Windows power users keep installed
One-click scans. No signup required.
docker compose up -d
The -d option leaves the services running in the background. Check whether both containers are running:
docker compose ps
Then inspect startup output:
docker compose logs --tail=100 web
docker compose logs --tail=100 db
When Odoo has started and the database is accepting connections, browse to http://<server-address>:8069 from a network allowed to reach that port. Replace <server-address> with the server’s DNS name or IP address; do not include the angle brackets in the real URL.
Rank #3
First-run checks
- The Odoo page loads without a database-connection error.
- The database-management screen can create or select a database using the PostgreSQL service.
- You can create a test record and upload a small attachment, then restart the stack and confirm both remain.
docker compose psstill shows both services after the restart.
A first run can take longer while images are pulled and the database initializes. Logs are the authoritative place to distinguish a slow startup from a configuration failure.
What PostgreSQL settings does Odoo need?
In this Compose network, the critical values are the service hostname, database user and password:
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
- Hostname:
db, matching the database service key. - Port: PostgreSQL’s default internal port is used when no separate Odoo
PORTvalue is supplied. If you configure a non-default port, setPORTon the Odoo service to match. - User:
odoo, matchingPOSTGRES_USER. - Password: the same value supplied through
POSTGRES_PASSWORDin both services. - Database initialization:
POSTGRES_DB: postgresin this example. Change it only when you understand how your Odoo provisioning process selects the target database.
The database environment variables initialize a new PostgreSQL data directory. Changing them after the volume already contains a database does not rewrite existing users or passwords automatically. If credentials appear correct but authentication fails, determine whether the volume was initialized with older values before changing containers.
Keep addons and configuration separate from the image
Custom addons
Put custom modules under the project’s addons directory. The mount at /mnt/extra-addons makes them visible inside the Odoo container. After adding or updating a module, use Odoo’s normal module-update procedure and review the application logs for Python or manifest errors. Keep the addon source in version control, but keep passwords and other secrets out of that repository.
Custom Odoo configuration
The official image permits mounting a custom configuration file at /etc/odoo. If you use that option, start from the image’s configuration template rather than writing a file from memory. The image supplies some runtime arguments, so an override can accidentally remove or conflict with values the image expects. Test the resulting container command and logs after every configuration change.
Enterprise modules and licensing
The Docker instructions describe mounting Enterprise modules, but there is no official Odoo Enterprise Docker image. Obtain the modules through Odoo’s authorized channels and verify edition availability, licensing and deployment terms before relying on them. Do not treat a community image as an official Enterprise distribution.
Change the public port safely
You can expose a different host port while leaving Odoo’s internal listener on 8069. For example:
ports:
- "8070:8069"
Clients would then use http://<server-address>:8070. Odoo’s image guidance warns that web.base.url may need adjustment when the externally visible address or port differs, particularly for generated links, mail and reports. Set the canonical URL to the address users actually reach, and retest links and report downloads after changing it.
How do I keep my Odoo data when I update a container?
Updating within the same Odoo major version
An image refresh within Odoo 19 is different from an upgrade to Odoo 20. Before an in-major update:
- Schedule a maintenance window and stop writes to the application.
- Back up the PostgreSQL database and the Odoo filestore.
- Test that the backups can be read or restored in an isolated environment.
- Pull the selected image and recreate only after the backup is verified.
docker compose pull web
docker compose up -d web
docker compose ps
docker compose logs --tail=100 web
The named volumes are reused by Compose, so recreating the container does not remove data unless you explicitly remove the volumes. Record the image tag or digest used so you can roll back to the prior build if application checks fail.
Moving to a new Odoo major version
A major-version move requires a database migration and compatibility work. It is not a matter of changing odoo:19.0 to another tag and pulling. Preserve both the database and filestore, review the migration procedure for the target release, test the process on a copy, and schedule downtime appropriate to the database size and module set.
Back up both data stores
PostgreSQL data and Odoo attachments are separate. A logical database dump without the filestore is incomplete, and copying only the filestore cannot restore Odoo’s records. Use your approved backup system to capture:
Best Value
- A consistent PostgreSQL backup of the Odoo databases.
- The complete contents of the named
odoo-datavolume. - The Compose file, addon source and any custom configuration needed to reproduce the deployment.
- The exact image tags or digests and the password-secret handling required to restore them.
Practice a restore on a disposable host. A backup that has never been restored is an assumption, not a recovery plan.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Troubleshooting common failures
“Could not connect to the database”
- Confirm
HOSTis exactlydb, including case and spelling. - Confirm
USERandPASSWORDmatch the values used to initialize PostgreSQL. - Read both service logs:
docker compose logs webanddocker compose logs db. - Check that the database container is running with
docker compose ps. - If the database volume was initialized previously, remember that changing
.envdoes not automatically change the existing PostgreSQL password.
Databases or attachments disappeared
Check mounts before creating anything else:
docker compose ps
docker volume ls
docker inspect <container-name>
Verify that odoo-data is mounted at /var/lib/odoo and db-data at /var/lib/postgresql/data. Do not run docker compose down -v unless you intentionally want to delete the named volumes. Reattach the original volumes and restore from backup if a volume was removed.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →The browser cannot reach port 8069
- Confirm the web service is running and listening in its logs.
- Confirm the host mapping is present in
docker compose ps. - Check the Ubuntu host firewall and any upstream security-group rule for the chosen port.
- Test locally on the server first, then test from the permitted client network.
Custom addons are not visible
Confirm the host directory is the same directory referenced by ./addons, that the mount appears in the container, and that each module has a valid manifest. Review Odoo logs after updating the apps list. A module that imports unavailable Python dependencies can fail even when the mount itself is correct.
Mail links or reports contain the wrong address
When the public host name or port differs from the container’s defaults, review Odoo’s web.base.url and test generated links, outbound mail templates and PDF reports. The internal port remains 8069; the externally advertised URL must match what users can resolve and reach.
Production decisions you still need to make
The Compose example gets Odoo running; it is not a complete public-service security design. Before exposing it to the Internet, make separate, documented decisions about:
- Firewall policy: allow only the administration and application traffic your users need. Do not publish PostgreSQL directly to the Internet.
- HTTPS and reverse proxy: terminate TLS with a maintained reverse proxy and configure Odoo’s public URL consistently.
- Secrets: use Docker secrets or an equivalent protected secret store instead of distributing plaintext passwords.
- Backups: automate database and filestore backups, retain multiple generations and perform restore drills.
- Updates: define maintenance windows, record image versions, review release notes and keep a tested rollback path.
- Observability: monitor disk usage, container health, PostgreSQL errors, failed logins and backup jobs.
The exact firewall, TLS and backup implementation depends on your Ubuntu release, network boundary and organizational controls; consult current authoritative Docker, Ubuntu and security documentation for those details.
Docker image or Ubuntu .deb package?
Both are valid installation routes, but they solve different operational problems. Odoo’s Ubuntu Noble (24.04 LTS) statement applies to its Odoo 19 .deb package route, not to Docker hosts.
| Decision area | Docker image deployment | Ubuntu .deb deployment |
|---|---|---|
| Isolation and repeatability | Application and PostgreSQL are described as services with explicit images and mounts; recreating the stack is straightforward. | Packages integrate with the host operating system and its service manager. |
| Host dependency management | Requires Docker Engine and Compose on Ubuntu; application dependencies are delivered in images. | Requires the package’s supported host libraries and package-management workflow. |
| Data operations | Named volumes clearly separate the filestore and PostgreSQL data, but both need independent backups. | Data and service paths follow the package installation’s host conventions. |
| Custom code | Mount addons at /mnt/extra-addons and optionally configuration at /etc/odoo. |
Install and manage custom modules in the package-based filesystem layout. |
| Documented Ubuntu version in the supplied material | No Docker-host matrix is established by Odoo’s package page. | Odoo 19’s package page currently lists Ubuntu Noble (24.04 LTS). |
Choose Docker when you want a Compose-described application/database pair and image-based lifecycle. Choose the package route when host-native service management better fits your operations. Do not use the package compatibility statement as evidence that every Ubuntu release can run the Docker deployment.
The Bottom Line
Install Docker Engine and Compose from Docker’s current Ubuntu documentation, deploy Odoo and PostgreSQL as separate Compose services, persist both named volumes, and verify backups before changing images. The example starts Odoo 19 on port 8069; check current Odoo and PostgreSQL tags and test the restore and upgrade procedure before treating the stack as production-ready.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minute




