Getting Started
Deploy First Environment

Deploy Your First Environment


Overview

This guide walks you through deploying your first Odoo environment on PaaSPortal. You'll create an environment, configure resources, and deploy it to your server. By the end, you'll have a running Odoo instance accessible via HTTPS.

What you'll accomplish:

  • Create a new environment for your project
  • Allocate CPU, RAM, and disk resources
  • Configure database and domain settings
  • Deploy with automated container orchestration
  • Access your running Odoo instance

What happens during deployment:

  • Docker containers are created on your server (PostgreSQL + Odoo)
  • Git repositories are cloned for custom addons
  • Database is initialized with Odoo schema
  • Traefik routing is configured for HTTPS access
  • Health checks validate successful deployment

Total time: Deployment takes 3-5 minutes on first run (2-3 minutes for subsequent deploys when Docker images are cached).


What is an Environment?

An environment is an isolated Odoo instance running on your infrastructure. Each environment has:

  • Dedicated resources: CPU, RAM, and disk allocation
  • Own database: PostgreSQL container with isolated data
  • Unique domain: System-generated subdomain (e.g., myapp-dev.apps.paasportal.com)
  • Git branch: Specific code version from your repository
  • Container isolation: Completely independent from other environments

Environment Types

PaaSPortal supports three environment types:

Development

  • Purpose: Active development and feature testing
  • Recommended Resources: 1-2 CPU cores, 2-4 GB RAM, 10-20 GB disk
  • Auto-Deploy: Enable for automatic deployment on Git push
  • Use Case: Daily development work, trying new modules, debugging

Staging

  • Purpose: Pre-production validation and UAT
  • Recommended Resources: 2-4 CPU cores, 4-8 GB RAM, 20-50 GB disk
  • Auto-Deploy: Optional (useful for CI/CD testing)
  • Use Case: Client demos, acceptance testing, performance testing

Production

  • Purpose: Live operations with real users and data
  • Recommended Resources: 4-8+ CPU cores, 8-16+ GB RAM, 50-200+ GB disk
  • Auto-Deploy: Disable for manual control
  • Use Case: Live business operations, customer-facing application

Best Practice: Create Development first, test thoroughly, then clone to Staging, and finally to Production.


Prerequisites

Before creating your first environment, ensure you have:

Infrastructure Setup

  • Active server configured: See GST-003: Add Your First Server
    • Server status must be RUNNING (green indicator)
    • Server must have available capacity
  • Organization quota available: Check SettingsUsage
    • CPU quota available
    • RAM quota available
    • Disk quota available

Project Configuration

Permissions

  • Required Permission: project.environments.create (Project Admin or Org Owner)
  • Backend Access: PaaSPortal needs SSH access to your server (configured during server setup)

Step 1: Navigate to Environment Creation

  1. Go to DashboardProjects
  2. Click on your project from the project list
  3. Click the Environments tab in the project detail page
  4. Click Add Environment button (top-right corner, blue button)

You'll be redirected to /projects/{project-id}/environments/new


Step 2: Configure Basic Settings

Environment Name

Field: Environment Name (text input)

The environment name is auto-generated based on your project slug and environment type:

  • Pattern: {project-slug}-{env-type}-{sequence}
  • Example: acme-development, myapp-staging-2, erp-production
  • Validation:
    • Lowercase letters, numbers, and hyphens only
    • Must be unique within the project
    • Maximum 50 characters

Recommendation: Use the auto-generated name for consistency. You can customize it if needed.

Environment Type

Field: Type (dropdown)

Options:

  • Development - For active development and testing
  • Staging - For pre-production validation
  • Production - For live operations

Impact:

  • Type affects backup frequency (production gets more frequent backups)
  • Production environments have deletion protection
  • Billing differs by type (production is billed at full rate)

Recommendation: Start with Development for your first environment.


Step 3: Select Target Server

Server Selection

Field: Server (dropdown)

Display Format: Each server shows:

{server-name} | {ip-address} | Available: {cpu} cores, {ram} GB, {disk} GB

Example:

Production Server 1 | 203.0.113.100 | Available: 6 cores, 24 GB, 150 GB

Server Requirements:

  • Must belong to your organization
  • Status must be RUNNING (green indicator)
  • Must have sufficient capacity for requested resources
  • Environment count below server's limit (default: 8 environments per server)

Test Connection

Before proceeding, click Test Connection next to the server dropdown:

  • Success: Green checkmark, "Connection successful"
  • Failure: Red X, error message (check SSH credentials in SettingsServers)

If no servers available:

  1. Navigate to SettingsServers
  2. Click Add Server
  3. Follow GST-003: Add Your First Server guide
  4. Wait for server status to change to RUNNING
  5. Return to environment creation

Step 4: Allocate Resources

Configure CPU, RAM, and disk allocation for your environment. These resources are dedicated to this environment.

Resource Presets (Quick Start)

Click a preset to auto-fill resource values:

PresetCPU CoresRAMDiskBest For
Small1.02 GB10 GBDevelopment, small apps
Medium2.04 GB20 GBStaging, medium traffic
Large4.08 GB50 GBProduction, high traffic
X-Large8.016 GB100 GBEnterprise, heavy workloads

CPU Cores

Field: CPU Cores (number input)

  • Range: 0.25 - 32 cores
  • Default: 1.0 core
  • Increment: 0.25 core steps

How to Choose:

  • 0.5-1 cores: Testing, low traffic development
  • 1-2 cores: Active development, small production
  • 2-4 cores: Staging, medium production (10-50 users)
  • 4-8+ cores: Large production (50-200+ users)

Note: CPU is split between Odoo and PostgreSQL (see PostgreSQL section below)

RAM (Memory)

Field: RAM (MB) (number input)

  • Range: 256 MB - 131,072 MB (128 GB)
  • Default: 2048 MB (2 GB)
  • Increment: 256 MB steps

How to Choose:

  • 1-2 GB: Minimal testing
  • 2-4 GB: Development, small production
  • 4-8 GB: Staging, medium production
  • 8-16 GB: Large production
  • 16+ GB: Enterprise workloads with many users

Memory Considerations:

  • Odoo workers consume ~150-250 MB each
  • Default configuration uses 4 workers = ~1 GB for workers
  • PostgreSQL needs memory for caching
  • Leave headroom for file processing and reports

Disk Space

Field: Disk (GB) (number input)

  • Range: 1 - 1000 GB
  • Default: 10 GB
  • Recommendation:
    • Development: 10-20 GB
    • Staging: 20-50 GB
    • Production: 50-200 GB (based on expected data volume)

Disk Usage Breakdown:

  • PostgreSQL database: Grows with data (initial ~500 MB)
  • Odoo filestore: Attachments, images, documents
  • Custom addons: Your Git repositories
  • Docker images: Cached images (~800 MB per Odoo version)
  • System overhead: ~2-3 GB

Important: Disk space affects backup size and clone time. Plan for 3-6 months of growth.

Quota Validation

As you adjust resources, PaaSPortal checks your organization quota in real-time:

  • Green indicator: Resources available ✅
  • Yellow warning: Approaching quota limit ⚠️
  • Red indicator: Quota exceeded - reduce resources or upgrade plan ❌

Quota Sources:

  • Organization billing plan (Free, Starter, Professional, etc.)
  • Existing environments consume quota
  • Available quota = Total quota - Used quota

If quota exceeded:

  1. Navigate to SettingsUsage to see current allocation
  2. Option A: Stop or delete unused environments to free quota
  3. Option B: Navigate to SettingsBilling and upgrade your plan

Step 5: PostgreSQL Resource Override (Advanced)

By default, PostgreSQL receives 30% of total CPU and RAM allocation. The remaining 70% goes to Odoo.

Default Split Example (2 CPU cores, 4 GB RAM):

  • PostgreSQL: 0.6 cores, 1.2 GB RAM
  • Odoo: 1.4 cores, 2.8 GB RAM

Custom PostgreSQL Resources

To manually adjust PostgreSQL allocation:

  1. Click Advanced PostgreSQL Settings (expand section)
  2. Toggle Custom PostgreSQL Resources to ON
  3. Adjust sliders:
    • PostgreSQL CPU Cores: 0.1 - 16 cores
    • PostgreSQL RAM: 128 MB - 65,536 MB

When to customize:

  • Database-heavy workloads (complex queries, large datasets)
  • Read-heavy applications (more RAM for PostgreSQL cache)
  • Write-heavy applications (more CPU for database processing)

Recommendation: Use default 30% split unless you have specific performance needs.


Step 6: Configure Database Name

Field: Database Name (text input, auto-filled)

  • Default: {environment-uuid} (automatically generated unique ID)
  • Format: UUID format (e.g., a3b2c1d4-e5f6-7890-abcd-ef1234567890)
  • Validation: Lowercase letters, numbers, hyphens only

Why UUID naming:

  • Guarantees global uniqueness
  • Prevents naming conflicts
  • Simplifies container orchestration

Recommendation: Keep the auto-generated database name. Do not customize unless you have specific requirements.


Step 7: Configure Domain

Subdomain (System-Generated)

Field: Subdomain (text input, auto-filled)

PaaSPortal automatically generates a unique subdomain:

  • Format: {project-slug}-{env-type}.apps.paasportal.com
  • Example: acme-development.apps.paasportal.com
  • SSL Certificate: Automatically provisioned via Let's Encrypt
  • DNS: Automatically configured via Cloudflare

Validation:

  • Must match DNS label format: ^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$
  • Must be globally unique across all PaaSPortal environments
  • Maximum 63 characters (DNS label limit)

Availability Check: As you type, PaaSPortal checks availability:

  • ✅ Green checkmark: Available
  • ❌ Red X: Already in use

Full System URL: https://{subdomain}.apps.paasportal.com

Custom Domain (Optional)

Field: Custom Domain (text input)

If you want to use your own domain (e.g., erp.acme-corp.com):

  1. Enter your domain in the Custom Domain field
  2. After environment creation, configure DNS:
    • Create an A record pointing to your server's IP
    • Example: erp.acme-corp.com203.0.113.100
  3. PaaSPortal will automatically verify DNS and provision SSL certificate
  4. Verification takes 2-5 minutes after DNS propagation

Requirements:

  • You must own and control the domain
  • DNS A record pointing to server IP
  • Wait for DNS propagation (5-60 minutes)

Recommendation: Use system subdomain for Development/Staging, custom domain for Production.

See Also: ENV-002: Configure Custom Domain for detailed DNS setup.


Step 8: Git Branch Selection

Field: Git Branch (dropdown)

If you connected a Git repository in GST-005:

  • Display: Lists all branches from your repository
  • Default: Project's default branch (usually main or master)
  • Auto-Sync: PaaSPortal fetches latest branches every 5 minutes

How to Choose:

  • Development: Use develop or feature branches
  • Staging: Use staging or release branches
  • Production: Use main or master (stable releases only)

If no Git connection:

  • This section is disabled
  • Environment will deploy with base Odoo only (no custom addons)

Worker Count Configuration

Field: Odoo Workers (number input)

  • Default: Auto-calculated based on CPU allocation
    • Formula: workers = max(2, cpu_cores * 2)
    • Example: 2 CPU cores → 4 workers
  • Range: 0 - 32 workers
  • Recommendation: Use auto-calculated value

Worker Types:

  • 0 workers: Single-threaded mode (development only, not recommended)
  • 2-4 workers: Development and small production
  • 4-8 workers: Medium production
  • 8+ workers: High-traffic production

Memory Impact: Each worker uses ~150-250 MB RAM. Ensure sufficient RAM allocation.


Step 9: Review and Create Environment

Review Settings

Before creating, verify all settings:

  • Environment name: Unique and descriptive
  • Environment type: Development, Staging, or Production
  • Server selected: Running status, sufficient capacity
  • Resources allocated: CPU, RAM, disk meet your needs
  • Quota available: Green indicator showing resources available
  • Domain configured: Subdomain auto-generated or custom domain set
  • Git branch: Correct branch selected (if using Git)

Create Environment

Click Create Environment button (bottom of form)

What happens:

  1. Environment record is created in database
  2. Status set to pending (ready to deploy)
  3. Subdomain is reserved
  4. PostgreSQL resources are calculated
  5. Unique container names are generated

Response Time: Less than 1 second

Deploy Now or Later?

After successful creation, a modal dialog appears:

"Environment created successfully! Deploy now?"

Options:

  • Deploy Now (blue button)

    • Immediately starts deployment
    • Deployment Progress modal opens
    • Takes 3-5 minutes
    • Recommended for getting started
  • Deploy Later (gray button)

    • Environment saved but not deployed
    • Deploy manually from project page
    • Useful if you want to adjust settings first

Recommendation: Click Deploy Now to complete your first deployment.


Step 10: Monitor Deployment Progress

After clicking "Deploy Now", the Deployment Progress modal opens.

Progress Display

Header shows:

  • Deployment ID (UUID)
  • Status badge (Deploying / Success / Failed)
  • Start time
  • Elapsed duration (updates every second)

Progress Bar:

  • Overall percentage (0-100%)
  • Formula: (completed_steps / 16) * 100
  • Animates as steps complete

Step List (16 total steps): Each step shows:

  • Step number and name
  • Status icon:
    • ⏳ Pending (gray, waiting)
    • 🔄 In Progress (blue, spinner)
    • ✅ Completed (green, checkmark)
    • ❌ Failed (red, X)
  • Description
  • Real-time logs (expandable)

Auto-Refresh

The modal polls the deployment API every 2 seconds to fetch updated progress:

  • Steps update in real-time
  • Logs append continuously
  • Progress bar advances
  • Duration timer increments

Stops polling when: Deployment status changes to success or failed


Deployment Steps Explained

Your environment goes through exactly 16 steps during deployment. Here's what happens at each stage:

Step 1: Initializing (1-3 seconds)

What happens: Load deployment configuration from database

Actions:

  • Fetch environment details (CPU, RAM, disk, port)
  • Load project info (Odoo version, Git repo URL, branch)
  • Load server info (IP, SSH credentials)
  • Validate configuration completeness

Success: "Configuration loaded successfully"


Step 2: Connecting (1-2 seconds)

What happens: Establish SSH connection to target server

Actions:

  • Create SSH session using credentials
  • Authenticate with SSH key or password
  • Test connectivity with simple command

Success: "Connected to server SERVER_IP"

Potential Error: "Failed to connect - server offline or firewall blocking"

  • Solution: Check server status in SettingsServers, verify SSH credentials

Step 3: Creating Network (1 second)

What happens: Create isolated Docker network for environment

Actions:

  • Network name: paasportal_net_ENVIRONMENT_ID
  • Ensures containers can communicate
  • Isolated from other environments

Command: docker network create paasportal_net_ENV_ID

Success: "Docker network created"


Step 4: Configuring DNS (2-5 seconds)

What happens: Create DNS A record pointing to server

Actions:

  • Uses Cloudflare API (or configured DNS provider)
  • Record: SUBDOMAIN.apps.paasportal.com → Server IP
  • TTL: 300 seconds (5 minutes)

Success: "DNS record created for SUBDOMAIN"

Note: If custom domain configured, you must set DNS manually. This step configures system subdomain only.


Step 5: Creating PostgreSQL Database (5-10 seconds)

What happens: Start PostgreSQL container with optimized configuration

Container Details:

  • Container Name: ENVIRONMENT_ID_db
  • Image: postgres:15-alpine (optimized for size)
  • Database Name: ENVIRONMENT_ID (UUID)
  • User: odoo
  • Password: Auto-generated secure password (32 characters)
  • Volume: paasportal_pgdata_ENV_ID (persistent storage)
  • Network: Attached to paasportal_net_ENV_ID

Resource Limits:

  • Memory Limit: Configured postgres_ram_mb (default 30% of total)
  • CPU Limit: Configured postgres_cpu_cores (default 30% of total)

Command Example:

docker run -d --name a3b2c1d4-e5f6_db \
  --network paasportal_net_a3b2c1d4-e5f6 \
  -e POSTGRES_DB=a3b2c1d4-e5f6 \
  -e POSTGRES_USER=odoo \
  -e POSTGRES_PASSWORD=xyz123... \
  -v paasportal_pgdata_a3b2c1d4-e5f6:/var/lib/postgresql/data \
  --memory 614m \
  --cpus 0.3 \
  postgres:15-alpine

Health Check: Waits up to 60 seconds for PostgreSQL to accept connections

Success: "PostgreSQL container started and healthy"


Step 6: Cloning Platform Repos (5-15 seconds)

What happens: Clone platform-level addon repositories

Actions:

  • Location: /opt/paasportal/ENV_ID/addons/platform/
  • These are global addons provided by PaaSPortal (optional)
  • Consolidates apt.txt and requirements.txt files

Success: "Cloned COUNT platform repositories"

Note: If no platform repos configured, this step completes instantly.


Step 7: Cloning Organization Repos (5-15 seconds)

What happens: Clone organization-specific addon repositories

Actions:

  • Location: /opt/paasportal/ENV_ID/addons/org/
  • Custom addons shared across all org projects
  • Example: Custom theme, common integrations

Success: "Cloned COUNT organization repositories"

Note: If no org repos configured, this step completes instantly.


Step 8: Cloning Project Repository (10-30 seconds)

What happens: Clone primary project Git repository

Actions:

  • Location: /opt/paasportal/ENV_ID/addons/project/
  • Uses configured git_repo_url and git_branch
  • Authenticates with Git OAuth token for private repos
  • Checks out specific branch

Command Example:

git clone -b develop \
  https://oauth2:TOKEN@github.com/acme/odoo-addons.git \
  /opt/paasportal/a3b2c1d4-e5f6/addons/project/

Success: "Cloned project repository: REPO_NAME (branch: BRANCH_NAME)"

Potential Errors:

  • "Git authentication failed" → Reconnect Git in SettingsGit Connections
  • "Branch not found" → Verify branch exists, sync Git connection

Step 9: Cloning Additional Repos (5-20 seconds)

What happens: Clone any additional configured addon repositories

Actions:

  • Location: /opt/paasportal/ENV_ID/addons/additional/
  • Multi-repo support for complex projects
  • Each repo can have different branch

Success: "Cloned COUNT additional repositories"


Step 10: Pulling Odoo Image (30-120 seconds first time, <5s cached)

What happens: Download Odoo Docker image from Docker Hub

Actions:

  • Image: odoo:{version} (e.g., odoo:17.0, odoo:18.0)
  • First deployment: Full download (~500-800 MB)
  • Subsequent deploys: Uses cached image (less than 5 seconds)

Command Example:

docker pull odoo:17.0

Progress: Shows pull progress with percentage

Success: "Odoo Docker image pulled successfully"

Timeout: 600 seconds (10 minutes) for slow connections

Performance:

  • Cached: 2-5 seconds
  • Fast network: 30-60 seconds
  • Slow network: 60-120 seconds

Step 11: Generating Configuration (1-2 seconds)

What happens: Create Odoo configuration file (odoo.conf)

Actions:

  • Location: /opt/paasportal/ENV_ID/odoo.conf
  • Configures database connection
  • Sets addons paths (all cloned repos)
  • Applies custom Odoo configuration from environment settings
  • Generates admin password

Configuration Example:

[options]
# Database connection
db_host = a3b2c1d4-e5f6_db
db_port = 5432
db_user = odoo
db_password = xyz123...
db_name = a3b2c1d4-e5f6
 
# Addons paths (all repositories)
addons_path = /mnt/extra-addons/platform,/mnt/extra-addons/org,/mnt/extra-addons/project,/mnt/extra-addons/additional,/usr/lib/python3/dist-packages/odoo/addons
 
# Security
admin_passwd = admin_password_here
 
# Performance (auto-calculated based on resources)
workers = 4
max_cron_threads = 2
limit_memory_hard = 2684354560
limit_memory_soft = 2147483648
 
# Logging
log_level = info
 
# Custom configurations (from environment settings)
# ... additional odoo.conf parameters ...

Success: "Odoo configuration generated"


Step 12: Starting Odoo Container (5-15 seconds)

What happens: Create and start Odoo application container

Container Details:

  • Container Name: ENVIRONMENT_ID_odoo
  • Image: odoo:VERSION
  • Port: PORT:8069 (default 8069)
  • WebSocket Port (Odoo 18+): WS_PORT:8072
  • Network: Attached to paasportal_net_ENV_ID

Volume Mounts:

  • /opt/paasportal/ENV_ID//mnt/extra-addons (addons)
  • paasportal_odoo_data_ENV_ID/var/lib/odoo (filestore)

Environment Variables:

  • ODOO_RC=/mnt/extra-addons/odoo.conf
  • Custom environment variables from settings

Resource Limits:

  • Memory: Configured ram_mb - postgres_ram_mb
  • CPU: Configured cpu_cores - postgres_cpu_cores

Traefik Labels: For domain routing (HTTPS, WebSocket)

Command Example:

docker run -d --name a3b2c1d4-e5f6_odoo \
  --network paasportal_net_a3b2c1d4-e5f6 \
  -p 8069:8069 \
  -e ODOO_RC=/mnt/extra-addons/odoo.conf \
  -v /opt/paasportal/a3b2c1d4-e5f6/:/mnt/extra-addons \
  -v paasportal_odoo_data_a3b2c1d4-e5f6:/var/lib/odoo \
  --memory 3482m \
  --cpus 1.7 \
  -l traefik.enable=true \
  -l traefik.http.routers.a3b2c1d4-e5f6.rule=Host(\`acme-dev.apps.paasportal.com\`) \
  odoo:17.0

Success: "Odoo container started"


Step 13: Installing Dependencies (10-30 seconds)

What happens: Install system and Python dependencies

Actions:

  • Runs apt-get install from consolidated apt.txt (all repos)
  • Runs pip install -r requirements.txt from consolidated file
  • Executed inside running Odoo container

Commands Example:

# Inside container
apt-get update && apt-get install -y \
  python3-ldap \
  wkhtmltopdf \
  # ... additional packages from apt.txt
 
pip install -r /mnt/extra-addons/requirements.txt
# Installs: requests, pillow, reportlab, etc.

Success: "Dependencies installed successfully"

Potential Error: "Failed to install package X"

  • Cause: Invalid package name or unavailable on PyPI
  • Solution: Check requirements.txt format, verify package exists

Step 14: Initializing Database (10-60 seconds)

What happens: Initialize Odoo database or connect to existing

For New Databases:

  • Run odoo-bin -d DB_NAME -i base --stop-after-init
  • Installs base module (core Odoo functionality)
  • Creates default admin user
  • Sets up initial database schema
  • Loads demo data (if configured)

For Migrated Databases:

  • Skips initialization if migration_restore_completed is true
  • Prevents data loss on redeployment
  • Connects to existing database only

Command Example (new database):

docker exec a3b2c1d4-e5f6_odoo \
  odoo-bin -d a3b2c1d4-e5f6 -i base --stop-after-init

Success: "Database initialized successfully"

Duration: Varies based on modules to install:

  • Base only: 10-20 seconds
  • With custom modules: 20-60 seconds

Potential Errors:

  • "Database initialization failed" → Check custom module syntax errors
  • "Module dependency error" → Verify __manifest__.py dependencies exist

Step 15: Configuring Traefik (2-3 seconds)

What happens: Update Traefik routing configuration

Actions:

  • Adds Traefik labels to Odoo container
  • Configures domain routing rules
  • Sets up HTTPS/SSL via Let's Encrypt
  • Enables WebSocket routing (Odoo 18+)

Traefik Labels Example:

traefik.enable: true
traefik.http.routers.a3b2c1d4-e5f6.rule: Host(`acme-dev.apps.paasportal.com`)
traefik.http.routers.a3b2c1d4-e5f6.entrypoints: websecure
traefik.http.routers.a3b2c1d4-e5f6.tls.certresolver: letsencrypt
traefik.http.services.a3b2c1d4-e5f6.loadbalancer.server.port: 8069
 
# WebSocket support (Odoo 18+)
traefik.http.routers.a3b2c1d4-e5f6-ws.rule: Host(`acme-dev.apps.paasportal.com`) && PathPrefix(`/websocket`)
traefik.http.routers.a3b2c1d4-e5f6-ws.service: a3b2c1d4-e5f6-ws
traefik.http.services.a3b2c1d4-e5f6-ws.loadbalancer.server.port: 8072

SSL Certificate:

  • Automatically requested from Let's Encrypt
  • DNS-01 or HTTP-01 challenge
  • Certificate cached for 90 days
  • Auto-renewed before expiration

Success: "Traefik routing configured"


Step 16: Health Check (2-30 seconds)

What happens: Validate deployment by checking Odoo availability

Actions:

  • Sends HTTP request to http://localhost:PORT/web/database/selector
  • Retries up to 30 times (1 second interval)
  • Validates HTTP 200 or 303 response (redirect to login is OK)

Command Example:

curl -f http://localhost:8069/web/database/selector

Success: "Health check passed - Odoo is responding"

Potential Errors:

  • "Health check failed - Odoo not responding after 30 seconds"
    • Causes: Odoo crashed, OOM kill, port conflict
    • Solution: Check Odoo container logs, increase RAM, verify port availability

Final: Deployment Complete

What happens: Update environment and deployment records

Actions:

  • Environment status: PENDINGRUNNING
  • Deployment status: DEPLOYINGSUCCESS
  • Record container IDs and names
  • Update last_deployed_at timestamp
  • Send success notification (email/SSE)

Total Duration: 3-5 minutes (typical first deployment)

Subsequent Deploys: 2-3 minutes (Docker images cached)


Access Your Environment

After successful deployment:

Step 1: Get Your Environment URL

The Deployment Progress modal shows:

Primary URL: https://acme-development.apps.paasportal.com

Alternative URLs (if configured):

  • Custom domain: https://erp.acme-corp.com
  • Direct IP (fallback): http://203.0.113.100:8069

Click the URL to open your Odoo instance in a new tab.

Step 2: Access Odoo Database Selector

Your browser opens to the Odoo database selector page:

If Single Database:

  • Automatically redirects to login page

If Multi-Database Mode:

  • Shows list of databases on this instance
  • Click your database name (ENVIRONMENT_ID)

Step 3: Login with Admin Credentials

Default Credentials:

  • Email: admin
  • Password: Check the Environment Details page
    1. Go to Projects → Select project → Environments tab
    2. Click environment name
    3. OverviewAdmin Credentials section
    4. Click Reveal Password (requires permission)

First Login:

  1. Enter email: admin
  2. Enter password from environment details
  3. Click Log in

Security Recommendation: Change the admin password immediately after first login:

  1. Click user menu (top-right)
  2. Preferences
  3. Change Password
  4. Enter new secure password

Step 4: Explore Your Odoo Instance

You're now logged into your Odoo environment! You'll see:

  • Apps Menu: Install/uninstall Odoo modules
  • Settings: Configure company info, users, email
  • Database Manager: Manage database (backup, restore, duplicate)

First Steps:

  1. SettingsUsers & CompaniesCompanies
    • Update company name, logo, contact info
  2. Apps → Search for modules to install
    • Sales, Inventory, Accounting, etc.
  3. Create test records (products, customers, invoices)

Next Steps

Congratulations! You've successfully deployed your first Odoo environment. Here's what to do next:

1. Configure Environment Settings

Resource Scaling: Adjust CPU, RAM, disk as needed

Custom Domain: Use your own domain for production

2. Setup Backups

Automated Backups: Schedule daily/weekly backups

Manual Backup: Create a backup before making changes

3. Install Odoo Modules

Browse Apps: Install modules from Odoo Apps menu

  • Sales, CRM, Inventory, Accounting, etc.

Custom Modules: Deploy your custom addons

4. Clone to Staging/Production

Test in Development: Validate functionality

Clone to Staging: Create staging environment for UAT

Clone to Production: Deploy to production when ready

  • Apply sanitization presets for data privacy

5. Monitor Performance

View Metrics: Monitor CPU, RAM, disk usage

Check Logs: Review deployment and runtime logs

6. Setup Auto-Deploy (Optional)

Enable Auto-Deploy: Automatically deploy on Git push

  • Edit environment → Repositories tab → Toggle Auto-Deploy

Webhook Verification: Test Git webhook integration

  • Push to Git branch → Verify deployment triggers

Troubleshooting

Problem: Deployment Stuck at "Pulling Image"

Symptoms:

  • Step 10 (Pulling Image) takes longer than 5 minutes
  • Progress shows "Pulling odoo:17.0... 0%"

Causes:

  • Slow internet connection on server
  • Docker Hub rate limiting (anonymous pulls limited to 100/6 hours)
  • Network firewall blocking Docker Hub

Solutions:

  1. Wait and Retry:

    • Docker Hub can be slow during peak hours
    • Wait 5-10 minutes, then retry deployment
  2. Check Server Network:

    # SSH into server
    ssh root@203.0.113.100
     
    # Test Docker Hub connectivity
    curl -I https://hub.docker.com
     
    # Check Docker daemon status
    systemctl status docker
  3. Subsequent Deploys:

    • Image will be cached after first successful pull
    • Future deploys complete in <5 seconds (no re-download)

Problem: "Database initialization failed"

Symptoms:

  • Deployment fails at Step 14 (Initializing Database)
  • Error: "Failed to initialize Odoo database"

Causes:

  • Custom module has Python syntax errors
  • Missing dependencies in requirements.txt
  • Insufficient disk space
  • PostgreSQL container not healthy

Solutions:

  1. Check Custom Module Syntax:

    • Review recent Git commits for syntax errors
    • Look for issues in __init__.py or __manifest__.py
    • Test locally: python -m py_compile your_module/__init__.py
  2. Verify Dependencies:

    • Check requirements.txt format
    • Ensure packages exist on PyPI
    • Test locally: pip install -r requirements.txt
  3. Check Disk Space:

    • Navigate to SettingsServers
    • Check server disk usage
    • If full: Stop unused environments or scale up disk
  4. Verify PostgreSQL Health:

    • Go to environment detail page
    • Containers tab → PostgreSQL container logs
    • Look for errors

Problem: "Health check failed - Odoo not responding"

Symptoms:

  • Deployment fails at Step 16 (Health Check)
  • Error: "Odoo not responding after 30 seconds"
  • All previous steps completed successfully

Causes:

  • Odoo crashed during startup (check logs)
  • Insufficient memory (OOM kill)
  • Port conflict with another service
  • Module initialization error

Solutions:

  1. Check Odoo Container Logs:

    • Go to environment → Logs tab
    • Select "Odoo Container" from dropdown
    • Look for error messages:
      • MemoryError → Increase RAM allocation
      • ModuleNotFoundError → Missing Python dependency
      • DatabaseError → Database connection issue
  2. Increase Memory (if OOM):

    • Environment → SettingsResources tab
    • Increase RAM to at least 2 GB (4 GB recommended)
    • Click SaveRedeploy
  3. Verify Port Availability:

    # SSH into server
    ssh root@203.0.113.100
     
    # Check if port 8069 is in use
    sudo lsof -i :8069
     
    # If port in use by another process:
    # - Change environment port in settings, OR
    # - Stop the conflicting service
  4. Review Module Dependencies:

    • Check __manifest__.py in custom modules
    • Ensure all depends modules exist
    • Fix dependencies, push to Git, redeploy

Problem: "Server not found or offline"

Symptoms:

  • Deployment fails at Step 2 (Connecting)
  • Error: "Failed to connect to server 203.0.113.100"

Causes:

  • Server is powered off or in maintenance
  • SSH credentials expired or incorrect
  • Firewall blocking SSH (port 22)
  • Server removed from PaaSPortal

Solutions:

  1. Check Server Status:

    • Navigate to SettingsServers
    • Find target server
    • Check Status column:
      • Running (green): Server online
      • Offline (red): Server down
      • Provisioning (yellow): Wait for provisioning to complete
  2. Test SSH Connection:

    • On server detail page, click Test Connection
    • If fails:
      • Verify server IP address is correct
      • Check SSH port (default 22)
      • Verify SSH credentials are valid
  3. Check Firewall:

    • Ensure server firewall allows SSH from PaaSPortal backend
    • If using cloud provider (DigitalOcean, AWS):
      • Check security groups/firewall rules
      • Allow inbound SSH (port 22) from anywhere or PaaSPortal IP
  4. Verify Server Exists:

    • Server may have been deleted
    • Recreate server or select different server for environment

Problem: "Quota exceeded" Error

Symptoms:

  • Cannot create environment
  • Error: "CPU quota exceeded: 8/8 cores used"
  • Create button disabled

Causes:

  • Organization's resource quota limit reached
  • Too many running environments consuming quota

Solutions:

  1. Check Current Usage:

    • Navigate to SettingsUsage
    • View quota breakdown by environment
    • Identify unused environments
  2. Free Up Quota (Option A):

    • Stop unused development environments
    • Delete old test environments
    • Scale down over-provisioned environments
  3. Upgrade Plan (Option B):

    • Navigate to SettingsBilling
    • Click Upgrade Plan
    • Select higher tier (Starter → Professional → Business)
    • Quota increases immediately after payment

Problem: "Subdomain already exists"

Symptoms:

  • Cannot create environment
  • Error: "Subdomain 'acme-prod' is already in use"
  • Subdomain field shows red X

Causes:

  • Another environment is using this subdomain
  • Deleted environment still has subdomain reserved (cleanup pending)

Solutions:

  1. Change Subdomain:

    • Add suffix: acme-prod-2, acme-prod-new
    • Include date: acme-prod-2024
    • Include region: acme-prod-us, acme-prod-eu
  2. Check Existing Environments:

    • Navigate to ProjectsEnvironments
    • Search for environment using that subdomain
    • If found: Either delete it or choose different subdomain
  3. Wait for Cleanup (if recently deleted):

    • Deleted environments release subdomain after 5 minutes
    • Wait and retry

Best Practices

Resource Planning

Start Small, Scale Up:

  • Begin with Small preset (1 CPU, 2 GB RAM)
  • Monitor resource usage in Monitoring tab
  • Scale up if CPU/RAM consistently >80%

Environment Sizing Guide:

UsersCPURAMDiskEnvironment Type
1-51-2 cores2-4 GB10-20 GBDevelopment
5-202-4 cores4-8 GB20-50 GBStaging
20-504-8 cores8-16 GB50-100 GBProduction
50-2008-16 cores16-32 GB100-200 GBLarge Production
200+16+ cores32+ GB200+ GBEnterprise

Deployment Workflow

Recommended Flow:

  1. Create Development → Test features, install modules
  2. Create Staging → Clone from Development, UAT testing
  3. Create Production → Clone from Staging, go live
  4. Iterate: Dev → Staging → Production for each release

Never deploy directly to Production without testing in Staging first.

Git Branch Strategy

Branch Naming:

  • Development: develop, dev, feature branches
  • Staging: staging, uat, release
  • Production: main, master, stable releases only

Auto-Deploy Settings:

  • Development: Enable (fast iteration)
  • Staging: Optional (automated testing)
  • Production: Disable (manual control)

Security

Production Checklist:

  • ✅ Use custom domain (not system subdomain)
  • ✅ Change default admin password immediately
  • ✅ Disable database manager in production
  • ✅ Configure db_filter in Odoo config to restrict database access
  • ✅ Enable two-factor authentication for admin users
  • ✅ Setup automated daily backups
  • ✅ Test restore process before going live

Related Documentation

Getting Started:

Environment Management:

Backup & Restore:

Monitoring:


API Reference

Create Environment Endpoint

POST /api/v1/projects/{project_id}/environments
Content-Type: application/json
Authorization: Bearer {jwt_token}

Request Body:

{
  "name": "acme-development",
  "env_type": "development",
  "vm_id": "server-uuid-here",
  "subdomain": "acme-dev",
  "cpu_cores": 2.0,
  "ram_mb": 4096,
  "disk_gb": 20,
  "postgres_cpu_cores": 0.6,
  "postgres_ram_mb": 1229,
  "git_branch": "develop",
  "odoo_config": {
    "workers": 4,
    "max_cron_threads": 2,
    "log_level": "info"
  }
}

Response (201 Created):

{
  "id": "env-uuid",
  "name": "acme-development",
  "environment_type": "development",
  "status": "pending",
  "system_url": "https://acme-dev.apps.paasportal.com",
  "created_at": "2024-12-11T10:30:00Z"
}

Deploy Environment Endpoint

POST /api/v1/projects/{project_id}/environments/{env_id}/deploy
Content-Type: application/json
Authorization: Bearer {jwt_token}

Response (202 Accepted):

{
  "deployment_id": "deployment-uuid",
  "environment_id": "env-uuid",
  "status": "pending",
  "message": "Deployment started successfully"
}

Full API Documentation: See API Reference - Environments


Last Updated: December 11, 2025 Applies to: PaaSPortal v2.0+ Related Sprint: Sprint 2E42 - Phase 1 Documentation (Getting Started)