Set up Odoo with PostgreSQL on AWS using Terraform

blog-banner

Introduction: 

At Surekha Technologies, we've been helping businesses streamline their ERP deployments, and one challenge we consistently encounter is the complexity of setting up Odoo with PostgreSQL on AWS. After working with various clients on their Odoo implementations, we decided to develop a standardized approach for Odoo infrastructure automation using Terraform AWS deployment that eliminates the common mistakes we’ve seen in manual setups. 

Why We Chose This Approach 

Working with Odoo deployments has been a big part of our business for several years now. We've helped everyone from companies getting their first ERP system running to large enterprises migrating from legacy solutions. The manual setup process,  especially when configuring Postgres setup on AWS, has often led to inconsistencies between development and production environments. We kept running into the same issues where a client's development environment would work perfectly, but then production would have differences that caused issues later.

That’s why we shifted to deploy Odoo using Terraform because this approach has changed how we make Odoo deployments for our clients, reducing setup time while ensuring consistency across all environments.

This blog covers the important insights our team has gained through years of deploying Odoo for clients. It serves as a guide, covering the strategies we use in our client projects.

In this blog, we will cover:

  1. Configuring AWS infrastructure so that Odoo application has optimal performance.

  2. PostgreSQL configuration best practices, balancing security with performance.

  3. The Terraform modules we have developed and optimized across numerous deployments.

  4. Common mistakes we’ve encountered and the effective solutions we’ve implemented to streamline processes.

Overview of each tool used in this blog:

Amazon Web Services (AWS)

AWS (Amazon Web Services) is a platform where we would create server for hosting the odoo and postgres application docker containers. For our Odoo setup, we'll mainly use EC2 (virtual machines) and VPC. Think of it as renting a data center without worrying about maintaining the actual hardware.

Terraform

Terraform is what we call "Infrastructure as Code" – basically, you write configuration files that describe what you want your infrastructure to look like and Terraform makes it happen. Instead of clicking around in the AWS console, you write everything as code to set up and manage your cloud resources.

PostgreSQL

PostgreSQL is the open-source database that runs behind Odoo .Odoo stores everything here – your customer data, inventory, financial records, the works.

Odoo

Odoo is a tool that can be used by businesses for various purposes such as employee management, inventory management, CRM. It's modular, so you can begin with the basics and expand as your needs grow.

Pre-requisites:

The following prerequisites are required for the odoo setup :

  1. Terraform installed on your local machine. Follow the below mentioned steps for setup.

  2. AWS CLI installed

IAM User Permissions: The IAM user configured through AWS CLI needs to have below permissions for creating EC2 instances, VPCs, security groups, and managing key pairs.

  1. AmazonEC2FullAccess

  2. ec2:DescribeVpcs

  3. ec2:DescribeAvailabilityZones

  4. ec2:DescribeSubnets

  5. ec2:DescribeNetworkInterfaces

1. Install Terraform and AWS CLI 

First, we’ll need to install Terraform and the AWS CLI on your local system. 

Install Terraform on Ubuntu 

sudo apt-get update && sudo apt-get install -y gnupg software-properties-common

wget -O- https://apt.releases.hashicorp.com/gpg | \ 

gpg --dearmor | \ 

sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg > /dev/null 

gpg --no-default-keyring \ 

    --keyring /usr/share/keyrings/hashicorp-archive-keyring.gpg \ 

    --fingerprint 

echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(grep -oP '(?<=UBUNTU_CODENAME=).*' /etc/os-release || lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list 

sudo apt update 

sudo apt-get install terraform

Install AWS CLI so that terraform has permission to provision resources in AWS by making API calls:

curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" 

unzip awscliv2.zip 

sudo ./aws/install 

2. Create Terraform Directory Structure 

Move to the desired directory where you want to create terraform files.

Let’s begin by creating a folder structure to organize your Terraform files and configuration:

  1. mkdir SSH-keys

  2. mkdir odoo-conf-files

  3. mkdir -p modules/ec2-instance

  4. mkdir -p modules/key-pair

  5. mkdir -p modules/security-groups

Create Terraform Directory Structure

3. Create SSH Key Pair 

We need a key pair to access the EC2 instance after it's created: 

  • ssh-keygen -t rsa -b 4096 -f SSH-keys/odoo_key -N ""

Create SSH Key Pair

4. Odoo Configuration and Docker Compose Files 

Let’s configure the Odoo application using the odoo.conf and docker-compose.yml files. 

Create odoo.conf File 

This file will define the Odoo configuration:

nano odoo-conf-files/odoo.conf

[options]  

addons_path = /mnt/extra-addons/enterprise-addons, /mnt/extra-addons/custom-addons, /usr/lib/python3/dist-packages/  

data_dir = /var/lib/odoo  

admin_passwd = admin_password  

csv_internal_sep = ,  

db_maxconn = 64  

db_name =  

db_port = 5432  

db_template = template1  

dbfilter = .*  

debug_mode = False  

email_from = False  

limit_memory_hard = 1677721600  

limit_memory_soft = 6291456000  

limit_request = 8192  

limit_time_cpu = 600  

limit_time_real = 1200  

list_db = True  

log_db = False  

log_handler = [':INFO']  

log_level = info  

logfile = /var/log/odoo/odoo.log  

longpolling_port = 8072  

max_cron_threads = 2  

osv_memory_age_limit = 1.0  

osv_memory_count_limit = False  

smtp_password = False  

smtp_port = 25  

smtp_server = localhost  

smtp_ssl = False  

smtp_user = False  

workers = 0  

xmlrpc = True  

xmlrpc_interface =  

;xmlrpc_port = 8069  

;xmlrpcs = True  

; xmlrpcs_interface =  

; xmlrpcs_port = 8071 

Create docker-compose.yml File

This file will set up the Docker containers for Odoo and PostgreSQL.

  • nano odoo-conf-files/docker-compose.yml

version: '3' 

services: 

  postgres: 

    image: postgres:13 

    container_name: postgres-db 

    ports: 

      - "5432:5432" 

    environment: 

      POSTGRES_DB: postgres 

      POSTGRES_USER: odoo 

      POSTGRES_PASSWORD: postgres 

    volumes: 

      - ./postgres/data:/var/lib/postgresql/data 

      - ./postgres/logs:/var/log/postgresql 

    healthcheck: 

      test: ["CMD-SHELL", "pg_isready -U odoo"] 

      interval: 30s 

      timeout: 10s 

      retries: 5 

    restart: always 

    labels: 

      - "autoheal=true" 

    networks: 

      - default 

  odoo: 

    image: odoo:17 

    container_name: odoo17-web 

    depends_on: 

      - postgres 

    ports: 

      - "8069:8069" 

      - "8072:8072" 

    environment: 

      - HOST=postgres 

      - USER=odoo 

      - PASSWORD=postgres 

    volumes: 

      - ./extra-addons/enterprise-addons:/mnt/extra-addons/enterprise-addons 

      - ./extra-addons/custom-addons:/mnt/extra-addons/custom-addons 

      - ./conf/odoo.conf:/etc/odoo/odoo.conf 

      - ./logs:/var/log/odoo 

      - odoo17_web_data:/var/lib/odoo 

    healthcheck: 

      test: ["CMD", "curl", "--insecure", "--fail", "http://localhost:8069"] 

      interval: 30s 

      timeout: 10s 

      retries: 3 

      start_period: 15s 

    restart: always 

    stdin_open: true 

    tty: true 

    labels: 

      - "autoheal=true" 

    networks: 

      - default 

volumes: 

  odoo17_web_data: 

networks: 

  default: 

    external: 

      name: odoo-docker-network 

Talk to our Odoo website experts

5. Create User Data Script for EC2 Setup

Create a user-data.sh script to install Docker, Docker Compose, and other dependencies on the EC2 instance.

  • nano user-data.sh

#!/bin/bash  

 

# Update and install required packages  

sudo apt-get update -y  

sudo apt-get upgrade -y  

 

DEBIAN_FRONTEND=noninteractive apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release software-properties-common 

 

mkdir -p /etc/apt/keyrings 

 

# Set up the Docker GPG key and repo  

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg 

  

chmod a+r /etc/apt/keyrings/docker.gpg  

  

# Add the repository to Apt sources:  

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list 

 
sudo apt-get update -y 

sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin 

# Start and enable Docker service  

sudo systemctl start docker  

sudo systemctl enable docker  

while ! sudo systemctl is-active --quiet docker; do 

echo "Waiting for Docker service to start..." 

sleep 5 

done 

#Adding the ubuntu user to docker group  

sudo usermod -aG docker ubuntu  

#Creating folder structure for odoo  

sudo mkdir -p /home/ubuntu/odoo  

sudo chown -R ubuntu:root /home/ubuntu/odoo  

sudo chmod -R 700 /home/ubuntu/odoo  

sudo mkdir -p /home/ubuntu/odoo/logs  

sudo chmod 777 -R /home/ubuntu/odoo/logs  

sudo mkdir -p /home/ubuntu/odoo/conf  

sudo mkdir -p /home/ubuntu/odoo/extra-addons  

sudo mkdir -p /home/ubuntu/odoo/extraaddons/custom-addons  

sudo mkdir -p /home/ubuntu/odoo/extra-addons/enterprise-addons  

sudo chmod 775 -R /home/ubuntu/odoo/extra-addons 

sudo mkdir -p /home/ubuntu/odoo/postgres/data  

sudo mkdir -p /home/ubuntu/odoo/postgres/logs  

sudo chown -R ubuntu:root /home/ubuntu/odoo  

 

docker network create odoo-docker-network  

 

# Create a completion marker file 

touch /home/ubuntu/odoo/.setup-complete 

6. Create Terraform Configuration Files

Now, let’s set up the Terraform files to define the infrastructure. 

Main.tf : This file defines the resources we’ll be creating, such as EC2 instances and modules: 

  • nano main.tf  

terraform { 

required_providers { 

aws = { 

source = "hashicorp/aws" 

version = "6.6.0" 

 

provider "aws" { 

region = "ap-south-1" 

 

module "key_pair" {  

source = "./modules/key-pair" 

public_key_path = var.public_key_path 

key_name = var.key_name 

 

module "security_groups" { 

source = "./modules/security-groups" 

 

module "ec2_instance" { 

source = "./modules/ec2-instance" 

ami = var.ami 

instance_type = var.instance_type 

key_name = module.key_pair.key_name 

security_group_id = module.security_groups.security_group_id 

user_data_file = var.user_data_file 

private_key_path = var.private_key_path 

compose_file_path = var.compose_file_path 

odoo_conf_path = var.odoo_conf_path 

volume_size = var.volume_size 

volume_type = var.volume_type 

Note: 

  • Don't worry about the indentation, as it would be fixed by a terraform command later on in this blog. 

Variables.tf : Define all variables for EC2 instance, SSH keys, and other configurations: 

  • nano variables.tf

variable "key_name" {} 

variable "public_key_path" {} 

variable "ami" {} 

variable "instance_type" {} 

variable "private_key_path" {} 

variable "compose_file_path" {} 

variable "odoo_conf_path" {} 

variable "volume_size" {} 

variable "user_data_file" {} 

variable "volume_type" {}   

Outputs.tf : Define outputs to capture information like the EC2 instance public IP and DNS: 

  • nano outputs.tf

 

output "odoo_instance_public_ip" { 

value = module.ec2_instance.instance_public_ip 

description = "Odoo instance public ip" 

 

output "odoo_instance_public_dns" { 

value = module.ec2_instance.instance_public_dns 

 

output "odoo_instance_private_IP" { 

value = module.ec2_instance.instance_private_ip 

7. Create Modules for EC2, Key-pair, and Security Groups

Each module represents a specific part of the infrastructure setup. These include the EC2 instance, key pair, and security groups.

EC2 Instance Module

The EC2 instance module will create the instance, configure SSH access, and upload the necessary files.

main.tf file for module of EC2-instance:

  • nano modules/ec2-instance/main.tf

 

resource "aws_instance" "Odoo-server" { 

ami = var.ami 

instance_type = var.instance_type 

key_name = var.key_name 

vpc_security_group_ids = [var.security_group_id] 

 

user_data = file(var.user_data_file) 

root_block_device { 

volume_size = var.volume_size 

volume_type = var.volume_type 

encrypted = true 

tags = { 

Name = var.instance_name 

 

resource "null_resource" "upload_config" { 

depends_on = [aws_instance.Odoo-server] 

connection { 

type = "ssh" 

user = "ubuntu" 

private_key = file(var.private_key_path) 

host = aws_instance.Odoo-server.public_ip 

timeout = "10m" 

provisioner "remote-exec" { 

inline = [ 

"echo 'Waiting for setup to complete...'", 

"while [ ! -f /home/ubuntu/odoo/.setup-complete ]; do echo 'Still waiting...'; sleep 10; done", 

"echo 'Setup completed. Proceeding...'" 

provisioner "file" { 

source = var.compose_file_path 

destination = "/home/ubuntu/odoo/docker-compose.yml" 

provisioner "file" { 

source = var.odoo_conf_path 

destination = "/home/ubuntu/odoo/conf/odoo.conf" 

provisioner "remote-exec" { 

inline = [ 

"echo 'Starting Docker Compose...'", 

"cd /home/ubuntu/odoo", 

# Try without sudo first, then with sudo if needed 

"docker compose up -d || sudo docker compose up -d", 

"echo 'Docker Compose started successfully'" 

outputs.tf file for EC2-instance module: 

  • nano modules/ec2-instance/outputs.tf   

output "instance_public_ip"{ 

value = aws_instance.Odoo-server.public_ip 

output "instance_public_dns"{ 

value = aws_instance.Odoo-server.public_dns 

output "instance_private_ip"{ 

value = aws_instance.Odoo-server.private_ip 

variables.tf file for EC2-instance module: 

  • nano modules/ec2-instance/variables.tf

variable "ami" {} 

variable "instance_type" {} 

variable "key_name" {} 

variable "security_group_id"{} 

variable "user_data_file" {} 

variable "volume_size" { 

default = 30 

variable "volume_type" {} 

variable "instance_name" { 

default = "Odoo-instance" 

variable "private_key_path" {} 

variable "compose_file_path"{} 

variable "odoo_conf_path"{} 

Key-pair Module

The key-pair module generates the SSH key for accessing the EC2 instance.

main.tf file for module of Key-pair:

  • nano modules/key-pair/main.tf

resource "aws_key_pair" "instance_key_pair" { 

key_name = var.key_name 

public_key = file(var.public_key_path) 

outputs.tf file for key-pair module : 

  • nano modules/key-pair/outputs.tf 

output "key_name"{ 

value = aws_key_pair.instance_key_pair.key_name 

variables.tf file for key-pair module : 

  • nano modules/key-pair/variables.tf 

variable "public_key_path"{} 

variable "key_name"{} 

Security Groups Module 

The security group module will create the required security group rules for accessing Odoo and PostgreSQL. 

main.tf file for module of security-groups: 

  • nano modules/security-groups/main.tf 

resource "aws_default_vpc" "instance_default_vpc" { 

tags = { 

Name = "default_VPC" 

resource "aws_security_group" "Odoo-SG" { 

name = "Odoo-SG" 

description = "Odoo Postgres Security Group" 

vpc_id = aws_default_vpc.instance_default_vpc.id 

 

tags = { 

Name = "Odoo-SG" 

ingress { 

from_port = 22 

to_port = 22 

protocol = "tcp" 

cidr_blocks = ["0.0.0.0/0"] 

ingress { 

from_port = 80 

to_port = 80 

protocol = "tcp" 

cidr_blocks = ["0.0.0.0/0"] 

ingress { 

from_port = 8069 

to_port = 8069 

protocol = "tcp" 

cidr_blocks = ["0.0.0.0/0"] 

egress { 

from_port = 0 

to_port = 0 

protocol = "-1" 

cidr_blocks = ["0.0.0.0/0"] 

outputs.tf file for security-groups module : 

  • nano modules/security-groups/outputs.tf 

output "vpc_id" { 

value = aws_default_vpc.instance_default_vpc.id 

 

output "security_group_id"{ 

value = aws_security_group.Odoo-SG.id 

Finally create terraform.tfvars file to pass environment variables to all modules: 

You can even customise the file, based on your requirements of usage. 

  • nano terraform.tfvars 

key_name = "odoo_key" 

public_key_path = "./SSH-keys/odoo_key.pub" 

private_key_path = "./SSH-keys/odoo_key" 

 

ami = "ami-0f918f7e67a3323f0" 

instance_type = "t3.large" 

user_data_file = "./user-data.sh" 

compose_file_path = "./odoo-conf-files/docker-compose.yml" 

odoo_conf_path = "./odoo-conf-files/odoo.conf" 

volume_size = 30 

volume_type = "gp3" 

8. Apply the Terraform Configuration 

Once you’ve set up all the configuration files, you can proceed with applying the Terraform configuration. 

Firstly, initialize Terraform to create all the providers mentioned: 

  • terraform init

Apply the Terraform Configuration

Format the Terraform code to correct the indentation of Terraform files: 

  • terraform fmt --recursive 

indentation of Terraform files

Validate the syntax of terraform code as: 

  • terraform validate

syntax of terraform code

To see what resources would be created after applying the terraform code:

  • terraform plan

applying the terraform code

To apply and provision the infrastructure:

  • terraform apply

  • Enter “yes” when prompted

terraform apply code terraform apply code value

9. Accessing the Odoo Instance

After successful deployment, Terraform will output the public IP of your EC2 instance:

Accessing the Odoo Instance

You can access Odoo by navigating to the Public IP as:

http://13.200.40.168:8069

Create Database

You can also find the created ec2-instance in AWS console with all other resources

AWS console with all other resources

Conclusion

Through this guide, we've shared the automated deployment approach that our team has developed and refined. This approach works whether you're a startup launching your first ERP system or an enterprise standardizing across multiple environments, as it eliminates the inconsistencies in manual Odoo deployments.

At Surekha Technologies, we believe that robust infrastructure shouldn't be a barrier to business growth. We’ve helped businesses at every stage of their Odoo journey with multi-environment deployments.

If you're considering an Odoo implementation or looking to modernize your existing deployment process, we'd love to discuss how our expertise can help streamline your project.

Contact us

For Your Business Requirements

Contact us