Bu makale şu anda yalnızca İngilizce olarak mevcuttur. Çeviri yakında eklenecektir.
By the end of this recipe, you will have a production-ready Odoo 19 instance running on AWS EC2 with PostgreSQL 17, Nginx reverse proxy, Let's Encrypt SSL, scheduled backups to S3, and a systemd service that survives reboots. Skill required: comfortable Linux administrator who has run a public-facing service before. Time required: 4 to 5 hours start to finish on a fresh AWS account. ECOSIRE runs this exact stack to serve 5M+ monthly requests for ecosire.com and 200+ client production deployments — every line below is from our actual playbook.
The reason most Odoo deployments break in production is not Odoo itself, it is the surrounding stack. Default PostgreSQL on Ubuntu uses 128 MB of shared memory. Default Nginx times out at 60 seconds, which kills long Odoo reports. Default Ubuntu has no swap, so the first OOM kills the postmaster and corrupts the database. The recipe below fixes all of those before you ever boot Odoo.
What you will need
- AWS account with billing enabled and an IAM user that has EC2 + Route53 + S3 permissions.
- Domain name in Route53 or any DNS provider where you can create A records.
- SSH keypair generated and downloaded as
.pem(or.ppkfor PuTTY users). - Odoo source: 19.0 Community from
github.com/odoo/odooor Enterprise tarball from your customer portal. - Time: 4 to 5 hours active work, no downtime needed because the system does not exist yet.
- Budget: $77 to $130 per month for a t3.large with 100 GB gp3 EBS, plus ~$5 for backups in S3 standard. Reserve instances knock 40 percent off if you commit to 1 to 3 years.
Step-by-step
1. Launch the EC2 instance
In the AWS console, launch a t3.large (2 vCPU, 8 GB RAM) running Ubuntu 24.04 LTS, with 100 GB gp3 EBS root volume. Configure the security group to allow ports 22 (SSH from your IP only), 80 (HTTP from anywhere), and 443 (HTTPS from anywhere). Do NOT open 8069 publicly. Use Elastic IP and associate it with the instance so the IP survives reboots.
# After SSH'ing in
sudo apt update && sudo apt upgrade -y
sudo timedatectl set-timezone UTC
hostnamectl set-hostname odoo-prod
Verification: uname -a returns Ubuntu 24.04 and df -h / shows around 100 GB.
2. Add 4 GB of swap
This is the single most-skipped step in self-hosted Odoo deployments. PostgreSQL workers + Odoo gevent processes spike memory under load; without swap the OOM killer takes down random processes and the next user-facing error is a corrupted database.
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
sudo sysctl vm.swappiness=10
echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf
free -h
Verification: free -h shows a Swap line with 4.0Gi total.
3. Install PostgreSQL 17
Ubuntu 24.04 ships with PG16; we want PG17 for the JSON improvements and partition performance. Add the official PG repo:
sudo apt install -y curl ca-certificates
sudo install -d /usr/share/postgresql-common/pgdg
sudo curl -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc \
--fail https://www.postgresql.org/media/keys/ACCC4CF8.asc
echo "deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] \
https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" | \
sudo tee /etc/apt/sources.list.d/pgdg.list
sudo apt update
sudo apt install -y postgresql-17 postgresql-client-17
Verification: psql --version returns 17.x and sudo systemctl status postgresql is active.
4. Tune PostgreSQL for an 8 GB box
Edit /etc/postgresql/17/main/postgresql.conf with these values. They are calibrated for a t3.large running Odoo where roughly 50 percent of RAM is given to PG and the rest to Odoo workers + OS cache.
# Memory
shared_buffers = 2GB
effective_cache_size = 4GB
work_mem = 16MB
maintenance_work_mem = 512MB
# WAL
wal_buffers = 16MB
min_wal_size = 1GB
max_wal_size = 4GB
checkpoint_completion_target = 0.9
# Planner
random_page_cost = 1.1 # for SSD/gp3
default_statistics_target = 100
# Connections
max_connections = 100
# Logging
log_min_duration_statement = 500ms
log_checkpoints = on
log_lock_waits = on
Restart PG: sudo systemctl restart postgresql. Verification: sudo -u postgres psql -c "SHOW shared_buffers" returns 2GB.
5. Create the Odoo database user
sudo -u postgres createuser --pwprompt --createdb odoo
# Set a strong password, save it to your password manager
Edit /etc/postgresql/17/main/pg_hba.conf and ensure local connections use scram-sha-256, NOT peer:
local all odoo scram-sha-256
host all all 127.0.0.1/32 scram-sha-256
Restart PG. Verification: psql -U odoo -h 127.0.0.1 -d postgres -c "SELECT 1" connects with the password you set.
6. Install Odoo dependencies
sudo apt install -y python3 python3-pip python3-dev python3-venv \
build-essential libxslt1-dev libzip-dev libldap2-dev libsasl2-dev \
libpq-dev libjpeg-dev wkhtmltopdf nodejs npm git
sudo npm install -g rtlcss
Verification: wkhtmltopdf --version returns 0.12.6 (qt-patched). The patched version is critical — the standard Ubuntu wkhtmltopdf build does not render Odoo PDFs correctly.
7. Install Odoo
sudo useradd -m -d /opt/odoo -U -r -s /bin/bash odoo
sudo -u odoo git clone --depth 1 --branch 19.0 https://github.com/odoo/odoo /opt/odoo/odoo
sudo -u odoo python3 -m venv /opt/odoo/venv
sudo -u odoo /opt/odoo/venv/bin/pip install --upgrade pip wheel
sudo -u odoo /opt/odoo/venv/bin/pip install -r /opt/odoo/odoo/requirements.txt
sudo mkdir -p /var/log/odoo /var/lib/odoo
sudo chown -R odoo:odoo /var/log/odoo /var/lib/odoo
Verification: /opt/odoo/venv/bin/python -c "import odoo" runs without errors when invoked from /opt/odoo/odoo/.
8. Write the Odoo config and systemd unit
Create /etc/odoo/odoo.conf:
[options]
admin_passwd = $pbkdf2-sha512$25000$... ; generate via odoo-bin --gen-admin-passwd
db_host = 127.0.0.1
db_port = 5432
db_user = odoo
db_password = <the password you set in step 5>
addons_path = /opt/odoo/odoo/addons,/opt/custom-addons
data_dir = /var/lib/odoo
logfile = /var/log/odoo/odoo.log
log_level = info
workers = 4
limit_memory_hard = 2684354560
limit_memory_soft = 2147483648
limit_request = 8192
limit_time_cpu = 600
limit_time_real = 1200
proxy_mode = True
list_db = False
Create /etc/systemd/system/odoo.service:
[Unit]
Description=Odoo
After=network.target postgresql.service
Requires=postgresql.service
[Service]
Type=simple
User=odoo
Group=odoo
ExecStart=/opt/odoo/venv/bin/python /opt/odoo/odoo/odoo-bin -c /etc/odoo/odoo.conf
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
Reload and start: sudo systemctl daemon-reload && sudo systemctl enable --now odoo. Verification: sudo systemctl status odoo is active and curl -I http://127.0.0.1:8069 returns 200.
9. Configure Nginx as reverse proxy
sudo apt install -y nginx
Create /etc/nginx/sites-available/odoo with proxy timeouts long enough for Odoo reports:
upstream odoo { server 127.0.0.1:8069; }
upstream odoochat { server 127.0.0.1:8072; }
server {
listen 80;
server_name odoo.example.com;
proxy_read_timeout 720s;
proxy_connect_timeout 720s;
proxy_send_timeout 720s;
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;
client_max_body_size 100M;
location /websocket { proxy_pass http://odoochat; proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; }
location / { proxy_redirect off; proxy_pass http://odoo; }
gzip on;
gzip_types text/css application/javascript application/json text/plain text/xml;
}
sudo ln -s /etc/nginx/sites-available/odoo /etc/nginx/sites-enabled/ and reload Nginx. Verification: curl -I http://odoo.example.com returns 200.
10. Add Let's Encrypt SSL
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d odoo.example.com --redirect --hsts --staple-ocsp --email [email protected] --agree-tos --non-interactive
Verification: https://odoo.example.com loads with a valid certificate and a redirect from HTTP.
11. Schedule daily backups to S3
Install AWS CLI and configure with an IAM user that can write to your S3 bucket. Add /usr/local/bin/odoo-backup.sh:
#!/bin/bash
set -e
DATE=$(date +%F)
DUMP=/tmp/odoo-$DATE.dump
sudo -u postgres pg_dump -Fc production > $DUMP
sudo tar -czf /tmp/filestore-$DATE.tar.gz /var/lib/odoo/filestore/production
aws s3 cp $DUMP s3://your-bucket/odoo-backups/
aws s3 cp /tmp/filestore-$DATE.tar.gz s3://your-bucket/odoo-backups/
rm $DUMP /tmp/filestore-$DATE.tar.gz
chmod +x /usr/local/bin/odoo-backup.sh and add to root crontab: 15 2 * * * /usr/local/bin/odoo-backup.sh. Verification: run the script manually and confirm both files appear in S3.
Common mistakes
- Skipping swap. The OOM killer takes down PostgreSQL the first time a heavy report runs. We have seen this corrupt databases.
- Default PG memory settings. With 128 MB shared_buffers, Odoo report performance is ~10x slower than tuned.
- Opening port 8069 publicly. Always proxy through Nginx so you get rate limits, gzip, and proper TLS termination.
- Forgetting
proxy_mode = True. Without it, Odoo generates HTTP redirects to its internal IP, breaking SSL. - Storing filestore on EFS. Use EBS gp3 — EFS adds 5 to 10 ms per file read, which makes attachment-heavy workflows feel sluggish.
Going further
Read replicas: add a streaming replica on a second EC2 for reporting workloads. Configure Odoo to use the replica via the db_host parameter on a dedicated reporting instance.
RDS Aurora migration: once you exceed 500 GB, migrate the database from local PG to Aurora PostgreSQL for managed backups and read scaling. Aurora gives you point-in-time recovery for free.
ALB + multiple Odoo instances: for high availability, run two t3.large instances behind an Application Load Balancer with sticky sessions on the websocket endpoint. Filestore must move to S3-backed storage at this point.
CloudFront in front of Nginx: cache static assets at edge, knock 200 ms off TTFB for global users.
For full managed Odoo hosting on AWS, ECOSIRE.IO runs this exact stack with 99.9 percent SLA. Or read our companion piece on how to back up and restore an Odoo database with zero downtime.
Frequently Asked Questions
Why t3.large and not t3.xlarge?
t3.large (2 vCPU, 8 GB) handles up to 50 concurrent active users comfortably. Once you have 80+ concurrent or run heavy nightly imports, jump to t3.xlarge (4 vCPU, 16 GB). ECOSIRE itself runs on t3.xlarge with PG17 + Redis + Node.js + 5 PM2 processes — different stack, similar tuning principles.
Can I use RDS instead of self-managed PG?
Yes, and we recommend it for production with more than 1 TB of data. Set db_host in odoo.conf to the RDS endpoint, allow the EC2 security group on port 5432, and you save 4 hours of PG admin per month at the cost of about $0.05 per GB-month on Aurora.
How do I scale to multiple servers?
Run Odoo workers across 2 to 4 EC2 instances behind an ALB. Filestore must be shared (move to S3 with ir_attachment.location = s3://bucket). Sessions must be shared (Odoo handles this via DB session storage by default). Long-polling/websocket needs sticky sessions on the ALB.
What about Docker?
Docker simplifies development but adds complexity in production: filestore mounts, log forwarding, signal handling. Most ECOSIRE clients run Odoo bare-metal on EC2 with Docker only for local dev. Kubernetes makes sense above 10 servers and is overkill below it.
If running infrastructure is not your team's strength, ECOSIRE managed Odoo hosting handles the full stack including 24/7 monitoring and security patching.
Yazan
ECOSIRE TeamTechnical Writing
The ECOSIRE technical writing team covers Odoo ERP, Shopify eCommerce, AI agents, Power BI analytics, GoHighLevel automation, and enterprise software best practices. Our guides help businesses make informed technology decisions.
ECOSIRE
Odoo ERP ile İşinizi Dönüştürün
Operasyonlarınızı kolaylaştırmak için uzman Odoo uygulaması, özelleştirme ve destek.
İlgili Makaleler
Odoo Form Görünümüne Özel Düğme Nasıl Eklenir (2026)
Odoo 19 form görünümlerine özel eylem düğmeleri ekleyin: Python eylem yöntemi, görünüm devralma, koşullu görünürlük, onay diyalogları. Üretimde test edilmiştir.
Odoo'da Studio Olmadan Özel Alan Nasıl Eklenir (2026)
Odoo 19'daki özel modül aracılığıyla özel alanlar ekleyin: model mirası, görünüm uzantısı, hesaplanan alanlar, mağaza/depo dışı kararlar. Kod öncelikli, sürüm kontrollü.
Odoo'da Harici Düzeni Kullanarak Özel Rapor Nasıl Eklenir?
Web.external_layout'u kullanarak Odoo 19'da markalı bir PDF raporu oluşturun: QWeb şablonu, paperformat, action bağlama. Baskı logosu + altbilgi geçersiz kılmalarıyla.