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
- Server status must be
- ✅ Organization quota available: Check Settings → Usage
- CPU quota available
- RAM quota available
- Disk quota available
Project Configuration
- ✅ Project created: See GST-004: Create Your First Project
- ✅ Git repository connected (optional): See GST-005: Connect Git Repository
- If using custom addons, connect your Git repository first
- If testing with base Odoo, Git connection is optional
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
- Go to Dashboard → Projects
- Click on your project from the project list
- Click the Environments tab in the project detail page
- 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} GBExample:
Production Server 1 | 203.0.113.100 | Available: 6 cores, 24 GB, 150 GBServer 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 Settings → Servers)
If no servers available:
- Navigate to Settings → Servers
- Click Add Server
- Follow GST-003: Add Your First Server guide
- Wait for server status to change to
RUNNING - 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:
| Preset | CPU Cores | RAM | Disk | Best For |
|---|---|---|---|---|
| Small | 1.0 | 2 GB | 10 GB | Development, small apps |
| Medium | 2.0 | 4 GB | 20 GB | Staging, medium traffic |
| Large | 4.0 | 8 GB | 50 GB | Production, high traffic |
| X-Large | 8.0 | 16 GB | 100 GB | Enterprise, 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:
- Navigate to Settings → Usage to see current allocation
- Option A: Stop or delete unused environments to free quota
- Option B: Navigate to Settings → Billing 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:
- Click Advanced PostgreSQL Settings (expand section)
- Toggle Custom PostgreSQL Resources to ON
- 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):
- Enter your domain in the Custom Domain field
- After environment creation, configure DNS:
- Create an A record pointing to your server's IP
- Example:
erp.acme-corp.com→203.0.113.100
- PaaSPortal will automatically verify DNS and provision SSL certificate
- 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
mainormaster) - Auto-Sync: PaaSPortal fetches latest branches every 5 minutes
How to Choose:
- Development: Use
developor feature branches - Staging: Use
stagingorreleasebranches - Production: Use
mainormaster(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
- Formula:
- 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:
- Environment record is created in database
- Status set to
pending(ready to deploy) - Subdomain is reserved
- PostgreSQL resources are calculated
- 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 Settings → Servers, 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-alpineHealth 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.txtandrequirements.txtfiles
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_urlandgit_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 Settings → Git 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.0Progress: 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.0Success: "Odoo container started"
Step 13: Installing Dependencies (10-30 seconds)
What happens: Install system and Python dependencies
Actions:
- Runs
apt-get installfrom consolidatedapt.txt(all repos) - Runs
pip install -r requirements.txtfrom 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.txtformat, 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
basemodule (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_completedis 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-initSuccess: "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__.pydependencies 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: 8072SSL 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/selectorSuccess: "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:
PENDING→RUNNING - Deployment status:
DEPLOYING→SUCCESS - Record container IDs and names
- Update
last_deployed_attimestamp - 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
- Go to Projects → Select project → Environments tab
- Click environment name
- Overview → Admin Credentials section
- Click Reveal Password (requires permission)
First Login:
- Enter email:
admin - Enter password from environment details
- Click Log in
Security Recommendation: Change the admin password immediately after first login:
- Click user menu (top-right)
- Preferences
- Change Password
- 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:
- Settings → Users & Companies → Companies
- Update company name, logo, contact info
- Apps → Search for modules to install
- Sales, Inventory, Accounting, etc.
- 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:
-
Wait and Retry:
- Docker Hub can be slow during peak hours
- Wait 5-10 minutes, then retry deployment
-
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 -
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:
-
Check Custom Module Syntax:
- Review recent Git commits for syntax errors
- Look for issues in
__init__.pyor__manifest__.py - Test locally:
python -m py_compile your_module/__init__.py
-
Verify Dependencies:
- Check
requirements.txtformat - Ensure packages exist on PyPI
- Test locally:
pip install -r requirements.txt
- Check
-
Check Disk Space:
- Navigate to Settings → Servers
- Check server disk usage
- If full: Stop unused environments or scale up disk
-
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:
-
Check Odoo Container Logs:
- Go to environment → Logs tab
- Select "Odoo Container" from dropdown
- Look for error messages:
MemoryError→ Increase RAM allocationModuleNotFoundError→ Missing Python dependencyDatabaseError→ Database connection issue
-
Increase Memory (if OOM):
- Environment → Settings → Resources tab
- Increase RAM to at least 2 GB (4 GB recommended)
- Click Save → Redeploy
-
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 -
Review Module Dependencies:
- Check
__manifest__.pyin custom modules - Ensure all
dependsmodules exist - Fix dependencies, push to Git, redeploy
- Check
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:
-
Check Server Status:
- Navigate to Settings → Servers
- Find target server
- Check Status column:
- Running (green): Server online
- Offline (red): Server down
- Provisioning (yellow): Wait for provisioning to complete
-
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
-
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
-
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:
-
Check Current Usage:
- Navigate to Settings → Usage
- View quota breakdown by environment
- Identify unused environments
-
Free Up Quota (Option A):
- Stop unused development environments
- Delete old test environments
- Scale down over-provisioned environments
-
Upgrade Plan (Option B):
- Navigate to Settings → Billing
- 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:
-
Change Subdomain:
- Add suffix:
acme-prod-2,acme-prod-new - Include date:
acme-prod-2024 - Include region:
acme-prod-us,acme-prod-eu
- Add suffix:
-
Check Existing Environments:
- Navigate to Projects → Environments
- Search for environment using that subdomain
- If found: Either delete it or choose different subdomain
-
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:
| Users | CPU | RAM | Disk | Environment Type |
|---|---|---|---|---|
| 1-5 | 1-2 cores | 2-4 GB | 10-20 GB | Development |
| 5-20 | 2-4 cores | 4-8 GB | 20-50 GB | Staging |
| 20-50 | 4-8 cores | 8-16 GB | 50-100 GB | Production |
| 50-200 | 8-16 cores | 16-32 GB | 100-200 GB | Large Production |
| 200+ | 16+ cores | 32+ GB | 200+ GB | Enterprise |
Deployment Workflow
Recommended Flow:
- Create Development → Test features, install modules
- Create Staging → Clone from Development, UAT testing
- Create Production → Clone from Staging, go live
- 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_filterin 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:
- ENV-001: Create Environment - Detailed creation guide
- ENV-002: Edit Environment Configuration - Modify resources
- ENV-003: Deploy Environment - Deployment reference
- ENV-006: Clone Environment - Duplicate environments
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)