Hosted SaaS¶
Hosted SaaS means your product runs in cloud accounts you own and operate. Customers get a managed service without provisioning cloud infrastructure or taking responsibility for upgrades, scaling, monitoring, and recovery. You retain ownership of the infrastructure and the customer experience; Omnistrate generates the control plane that automates provisioning, tenant management, operations, and monetization.
Hosted SaaS does not have to mean putting every customer into one shared application stack. You can offer the convenience of SaaS with a dedicated environment for each customer, or group customers into smaller shared cells to balance isolation and cost.
One Deployment Model, Multiple Customer Experiences¶
Customers can use a ready-to-use application, create and configure their own managed service instance, or run an AI agent with customer-specific data and tools. You decide how much configuration to expose, but in every case you host the service in your cloud accounts and remain responsible for provisioning, scaling, upgrades, and recovery. A customer who provisions a database or configures an agent is choosing how to use your service—not taking over infrastructure management.
| Customer experience | What customers do | What you operate |
|---|---|---|
| Applications | Sign in to a web application or call an API without managing deployments. | The application, its backing services, tenant access, and runtime capacity. |
| Self-service platforms | Provision and configure a managed database, analytics service, application runtime, or integration stack on demand. | Customer-specific deployments, resource limits, endpoints, backups, and upgrades. |
| AI agents | Invoke an agent or configure a workspace that executes multi-step workflows on their behalf. | Agent runtimes, tool integrations, model endpoints, memory and vector stores, and execution boundaries. |
All three experiences need repeatable onboarding, lifecycle management, observability, and billing. Customer self-service can expose application access, deployment configuration, or agent settings while keeping infrastructure operations under your control.
Choose the Right Tenant Isolation¶
Tenancy and deployment ownership are separate decisions. Hosted SaaS tells you where the product runs; tenancy tells you which resources customers share. Choose a boundary based on workload risk, performance requirements, regional placement, and the economics of each service plan.
Cellular Multi-Tenancy¶
Cellular multi-tenancy groups customer deployments into bounded shared environments. Instead of operating one large shared fleet as a single failure domain, you use cells to organize capacity, tenant placement, observability, and upgrade rollouts.
This is a good fit for cost-efficient plans and high customer density. Cells can separate customer groups by region, tier, workload, or capacity profile, and help limit the impact of failures and upgrades. Sharing resources within a cell still requires tenant-aware application behavior and appropriate access controls; a cell is not a dedicated environment for every customer.
See the Cellular Multi-Tenancy Overview and Deployment Guide.
Dedicated Tenancy (Single-Tenant SaaS)¶
Dedicated tenancy gives each customer deployment its own infrastructure stack while you continue to host and manage it as SaaS. This is useful when customers need predictable performance, stronger separation of data and workloads, or customer-specific configuration and lifecycle policies.
The isolation boundary must cover more than application compute. Evaluate databases, storage, networks, credentials, endpoints, and backups as well. With Omnistrate, dedicated tenancy provisions dedicated VMs and attached storage; you can extend the boundary with one deployment per cell and Customer Networks.
See the Dedicated Tenancy Overview and Deployment Guide.
Offer Both Through Service Plans¶
You do not need the same isolation level for every customer. A starter plan can use cellular multi-tenancy for efficient resource sharing, while an enterprise plan uses dedicated tenancy for stronger isolation. Both remain Hosted SaaS and use the same control-plane framework for onboarding, operations, and billing.
For Helm, Kustomize, Terraform, and OpenTofu deployments, define the required isolation in your deployment artifacts and use Custom Tenancy.
Why Isolation Matters for Enterprise SaaS¶
Enterprise requirements often go beyond a login and a shared application endpoint:
- AI execution boundaries: Agents can retrieve sensitive context, invoke tools, and take actions across connected systems. Isolate customer state and credentials, scope tool permissions, and separate development, test, and production environments. Infrastructure isolation complements, rather than replaces, application-level authorization and sandboxing.
- Regional placement and data residency: Place workloads where customers need them and account for where databases, logs, backups, and external integrations process data. An isolation model alone does not establish regulatory compliance.
- Predictable performance: Dedicated resources can reduce contention between customers; cells help partition capacity and workload profiles.
- Smaller operational blast radius: Use bounded cells, staged upgrades, health checks, and customer-specific operational policies so an incident or release does not have to affect the entire fleet.
The goal is to offer the right level of isolation without turning every enterprise customer into a manually operated deployment.
How Omnistrate Helps You Deliver Hosted SaaS¶
Define your application stack and service plans once, then use the generated control plane to manage the customer lifecycle:
- Provisioning and infrastructure: Onboard your provider accounts and automate deployment of versioned application stacks. Start with Deployment Models.
- Tenant access and self-service: Provide customer onboarding, subscriptions, deployment APIs, and a portal with the configuration options you choose to expose. See Tenant Management.
- Application operations: Configure scaling, health checks, observability, backups, and recovery for your workload. See Runtime Management.
- Fleet operations: Monitor deployments and manage upgrades across customers, regions, and service plans. See Fleet Management.
- Monetization: Configure pricing, usage metering, and billing workflows for your product. See FinOps.
For AI products, include the agent runtime and its backing services in the same deployment definition. This keeps models, memory stores, vector databases, and tool integrations within the isolation boundary you design, rather than treating the agent as a standalone container with unmanaged dependencies.
PostgreSQL Hosted SaaS Example¶
This example builds a dedicated, provider-hosted PostgreSQL service, starting with a basic container and adding multi-cloud deployment, customer configuration, observability, read replicas, and operational capabilities. Customers request a database through your service; the underlying infrastructure remains in your cloud accounts.
Note
This walkthrough retains the PostgreSQL configuration from the original example and is illustrative, not a production-ready database deployment. Select and pin an available, tested container image; replace sample passwords and password defaults; and validate TLS, network access, backups, restore, and failover before launch. Review scaling policies per resource: scaling a PostgreSQL writer requires database-aware coordination, and read replicas alone do not provide automatic writer failover.
Basic PostgreSQL Service¶
Here's a simple PostgreSQL service definition:
version: '3.9'
services:
PostgreSQL:
image: bitnami/postgresql:latest
ports:
- 5432:5432
volumes:
- ./data:/var/lib/postgresql/data
environment:
- POSTGRESQL_PASSWORD=defaultpassword
- POSTGRESQL_DATABASE=postgres
- POSTGRESQL_USERNAME=postgres
- POSTGRESQL_POSTGRES_PASSWORD=your-secure-password
While this works, it lacks the enterprise features needed for a production Hosted SaaS offering. Let's enhance it step by step.
Step 1: Configure Cloud Provider Account¶
First, follow Account Onboarding to connect the provider accounts where you will host PostgreSQL. Configure hostedDeployment with the values from onboarding, keeping only the cloud providers you intend to support. Customers do not need to supply their own cloud accounts.
Hosted SaaS Deployment (Multi-Cloud)¶
x-omnistrate-service-plan:
name: 'PostgreSQL Service'
tenancyType: 'OMNISTRATE_DEDICATED_TENANCY'
deployment:
hostedDeployment:
awsAccountId: "<AWS_ACCOUNT_ID>"
awsBootstrapRoleAccountArn: arn:aws:iam::<AWS_ACCOUNT_ID>:role/omnistrate-bootstrap-role
gcpProjectId: "<GCP_INFO>"
gcpProjectNumber: "<GCP_INFO>"
gcpServiceAccountEmail: "<GCP_INFO>"
azureSubscriptionId: '<AZURE_INFO>'
azureTenantId: '<AZURE_INFO>'
Step 2: Add Observability and Integrations¶
Enable comprehensive monitoring and logging:
Step 3: Add Customer Customization¶
Allow customers to configure their PostgreSQL instances:
services:
PostgreSQL:
image: bitnami/postgresql:latest
ports:
- 5432:5432
volumes:
- ./data:/var/lib/postgresql/data
x-omnistrate-compute:
instanceTypes:
- cloudProvider: aws
apiParam: instanceType
- cloudProvider: gcp
apiParam: instanceType
- cloudProvider: azure
apiParam: instanceType
x-omnistrate-storage:
aws:
instanceStorageType: AWS::EBS_GP3
instanceStorageSizeGiAPIParam: storageSize
instanceStorageIOPSAPIParam: storageIOPS
gcp:
instanceStorageType: GCP::PD_SSD
instanceStorageSizeGiAPIParam: storageSize
azure:
instanceStorageType: AZURE::PREMIUM_LRS
instanceStorageSizeGiAPIParam: storageSize
environment:
- POSTGRESQL_PASSWORD=$var.postgresqlPassword
- POSTGRESQL_DATABASE=$var.postgresqlDatabase
- POSTGRESQL_USERNAME=$var.postgresqlUsername
- POSTGRESQL_POSTGRES_PASSWORD=$var.postgresqlRootPassword
- POSTGRESQL_PGAUDIT_LOG=READ,WRITE
- POSTGRESQL_LOG_HOSTNAME=true
x-omnistrate-api-params:
- key: instanceType
description: Instance Type for PostgreSQL
name: Instance Type
type: String
modifiable: true
required: true
export: true
- key: storageSize
description: Storage Size in GB
name: Storage Size (GB)
type: Float64
modifiable: true
required: true
export: true
defaultValue: "100"
limits:
min: 20
max: 1000
- key: storageIOPS
description: Storage IOPS
name: Storage IOPS
type: Float64
modifiable: true
required: false
export: true
defaultValue: "3000"
- key: postgresqlUsername
description: Database Username
name: Database Username
type: String
modifiable: false
required: true
export: true
- key: postgresqlPassword
description: Database Password
name: Database Password
type: String
modifiable: false
required: true
export: false
- key: postgresqlDatabase
description: Database Name
name: Database Name
type: String
modifiable: false
required: true
export: true
defaultValue: "postgres"
- key: postgresqlRootPassword
description: Root Password
name: Root Password
type: String
modifiable: false
required: false
export: false
defaultValue: "generate-secure-password"
Step 4: Add Read Replicas and Multi-Zone Placement¶
Add a primary and configurable read replicas. Replication and multi-zone placement are building blocks for availability; validate database failover and recovery separately:
services:
Master:
image: bitnami/postgresql:latest
ports:
- 5432:5432
volumes:
- ./data:/var/lib/postgresql/data
x-omnistrate-compute:
instanceTypes:
- cloudProvider: aws
apiParam: masterInstanceType
- cloudProvider: gcp
apiParam: masterInstanceType
- cloudProvider: azure
apiParam: masterInstanceType
x-omnistrate-capabilities:
enableEndpointPerReplica: true
enableMultiZone: true
environment:
- POSTGRESQL_PASSWORD=$var.postgresqlPassword
- POSTGRESQL_DATABASE=$var.postgresqlDatabase
- POSTGRESQL_USERNAME=$var.postgresqlUsername
- POSTGRESQL_POSTGRES_PASSWORD=$var.postgresqlRootPassword
- POSTGRESQL_REPLICATION_MODE=master
- POSTGRESQL_REPLICATION_USER=repl_user
- POSTGRESQL_REPLICATION_PASSWORD=$var.replicationPassword
- POSTGRESQL_PGAUDIT_LOG=READ,WRITE
- POSTGRESQL_LOG_HOSTNAME=true
x-omnistrate-api-params:
- key: masterInstanceType
description: Master Instance Type
name: Master Instance Type
type: String
modifiable: true
required: true
export: true
- key: postgresqlUsername
description: Database Username
name: Database Username
type: String
modifiable: false
required: true
export: true
- key: postgresqlPassword
description: Database Password
name: Database Password
type: String
modifiable: false
required: true
export: false
- key: postgresqlDatabase
description: Database Name
name: Database Name
type: String
modifiable: false
required: true
export: true
- key: postgresqlRootPassword
description: Root Password
name: Root Password
type: String
modifiable: false
required: false
export: false
defaultValue: "rootpassword123"
- key: replicationPassword
description: Replication Password
name: Replication Password
type: String
modifiable: false
required: false
export: false
Replica:
image: bitnami/postgresql:latest
ports:
- 5433:5432
volumes:
- ./data:/var/lib/postgresql/data
x-omnistrate-compute:
replicaCountAPIParam: numReadReplicas
instanceTypes:
- cloudProvider: aws
apiParam: replicaInstanceType
- cloudProvider: gcp
apiParam: replicaInstanceType
- cloudProvider: azure
apiParam: replicaInstanceType
x-omnistrate-capabilities:
enableMultiZone: true
enableEndpointPerReplica: true
environment:
- POSTGRESQL_PASSWORD=$var.postgresqlPassword
- POSTGRESQL_MASTER_HOST=Master
- POSTGRESQL_MASTER_PORT_NUMBER=5432
- POSTGRESQL_REPLICATION_MODE=slave
- POSTGRESQL_REPLICATION_USER=repl_user
- POSTGRESQL_REPLICATION_PASSWORD=$var.replicationPassword
- POSTGRESQL_PGAUDIT_LOG=READ,WRITE
- POSTGRESQL_LOG_HOSTNAME=true
x-omnistrate-api-params:
- key: replicaInstanceType
description: Replica Instance Type
name: Replica Instance Type
type: String
modifiable: true
required: true
export: true
- key: numReadReplicas
description: Number of Read Replicas
name: Number of Read Replicas
type: Float64
modifiable: true
required: false
export: true
defaultValue: "1"
limits:
min: 0
max: 5
- key: postgresqlPassword
description: Database Password
name: Database Password
type: String
modifiable: false
required: true
export: false
- key: replicationPassword
description: Replication Password
name: Replication Password
type: String
modifiable: false
required: false
export: false
defaultValue: "replpassword123"
Step 5: Add Enterprise Features¶
Enable autoscaling, backup, and advanced capabilities:
x-omnistrate-capabilities:
enableMultiZone: true
enableEndpointPerReplica: true
autoscaling:
minReplicas: 1
maxReplicas: 10
idleMinutesBeforeScalingDown: 5
idleThreshold: 20
overUtilizedMinutesBeforeScalingUp: 2
overUtilizedThreshold: 80
backupConfiguration:
backupRetentionInDays: 7
backupPeriodInHours: 2
Complete PostgreSQL Hosted SaaS Example¶
The following combines the preceding configuration into one Compose specification. Save it as omnistrate-compose.yaml and adapt it to your provider accounts and database operating requirements:
version: '3.9'
x-omnistrate-service-plan:
name: 'PostgreSQL Service'
tenancyType: 'OMNISTRATE_DEDICATED_TENANCY'
deployment:
hostedDeployment:
awsAccountId: "<AWS_ACCOUNT_ID>"
awsBootstrapRoleAccountArn: arn:aws:iam::<AWS_ACCOUNT_ID>:role/omnistrate-bootstrap-role
gcpProjectId: "<GCP_INFO>"
gcpProjectNumber: "<GCP_INFO>"
gcpServiceAccountEmail: "<GCP_INFO>"
azureSubscriptionId: '<AZURE_INFO>'
azureTenantId: '<AZURE_INFO>'
x-customer-integrations:
logs:
metrics:
services:
Master:
image: bitnami/postgresql:latest
ports:
- 5432:5432
volumes:
- ./data:/var/lib/postgresql/data
x-omnistrate-compute:
instanceTypes:
- cloudProvider: aws
apiParam: masterInstanceType
- cloudProvider: gcp
apiParam: masterInstanceType
- cloudProvider: azure
apiParam: masterInstanceType
x-omnistrate-storage:
aws:
instanceStorageType: AWS::EBS_GP3
instanceStorageSizeGiAPIParam: storageSize
instanceStorageIOPSAPIParam: storageIOPS
gcp:
instanceStorageType: GCP::PD_SSD
instanceStorageSizeGiAPIParam: storageSize
azure:
instanceStorageType: AZURE::PREMIUM_LRS
instanceStorageSizeGiAPIParam: storageSize
x-omnistrate-capabilities:
enableEndpointPerReplica: true
enableMultiZone: true
autoscaling:
minReplicas: 1
maxReplicas: 3
idleMinutesBeforeScalingDown: 5
idleThreshold: 20
overUtilizedMinutesBeforeScalingUp: 2
overUtilizedThreshold: 80
environment:
- POSTGRESQL_PASSWORD=$var.postgresqlPassword
- POSTGRESQL_DATABASE=$var.postgresqlDatabase
- POSTGRESQL_USERNAME=$var.postgresqlUsername
- POSTGRESQL_POSTGRES_PASSWORD=$var.postgresqlRootPassword
- POSTGRESQL_REPLICATION_MODE=master
- POSTGRESQL_REPLICATION_USER=repl_user
- POSTGRESQL_REPLICATION_PASSWORD=$var.replicationPassword
- POSTGRESQL_PGAUDIT_LOG=READ,WRITE
- POSTGRESQL_LOG_HOSTNAME=true
- POSTGRESQL_DATA_DIR=/var/lib/postgresql/data/dbdata
- SECURITY_CONTEXT_USER_ID=1001
- SECURITY_CONTEXT_FS_GROUP=1001
- SECURITY_CONTEXT_GROUP_ID=0
x-omnistrate-api-params:
- key: masterInstanceType
description: Master Instance Type
name: Master Instance Type
type: String
modifiable: true
required: true
export: true
- key: storageSize
description: Storage Size in GB
name: Storage Size (GB)
type: Float64
modifiable: true
required: true
export: true
defaultValue: "100"
limits:
min: 20
max: 1000
- key: storageIOPS
description: Storage IOPS
name: Storage IOPS
type: Float64
modifiable: true
required: false
export: true
defaultValue: "3000"
- key: postgresqlUsername
description: Database Username
name: Database Username
type: String
modifiable: false
required: true
export: true
- key: postgresqlPassword
description: Database Password
name: Database Password
type: String
modifiable: false
required: true
export: false
- key: postgresqlDatabase
description: Database Name
name: Database Name
type: String
modifiable: false
required: true
export: true
defaultValue: "postgres"
- key: postgresqlRootPassword
description: Root Password
name: Root Password
type: String
modifiable: false
required: false
export: false
defaultValue: "CHANGEME_SECURE_PASSWORD"
- key: replicationPassword
description: Replication Password
name: Replication Password
type: String
modifiable: false
required: false
export: false
defaultValue: "CHANGEME_SECURE_PASSWORD"
x-omnistrate-mode-internal: true
Replica:
image: bitnami/postgresql:latest
ports:
- 5433:5432
volumes:
- ./data:/var/lib/postgresql/data
x-omnistrate-compute:
replicaCountAPIParam: numReadReplicas
instanceTypes:
- cloudProvider: aws
apiParam: replicaInstanceType
- cloudProvider: gcp
apiParam: replicaInstanceType
- cloudProvider: azure
apiParam: replicaInstanceType
x-omnistrate-capabilities:
enableMultiZone: true
enableEndpointPerReplica: true
environment:
- POSTGRESQL_PASSWORD=$var.postgresqlPassword
- POSTGRESQL_MASTER_HOST=Master
- POSTGRESQL_MASTER_PORT_NUMBER=5432
- POSTGRESQL_REPLICATION_MODE=slave
- POSTGRESQL_REPLICATION_USER=repl_user
- POSTGRESQL_REPLICATION_PASSWORD=$var.replicationPassword
- POSTGRESQL_PGAUDIT_LOG=READ,WRITE
- POSTGRESQL_LOG_HOSTNAME=true
- POSTGRESQL_DATA_DIR=/var/lib/postgresql/data/dbdata
- SECURITY_CONTEXT_USER_ID=1001
- SECURITY_CONTEXT_FS_GROUP=1001
- SECURITY_CONTEXT_GROUP_ID=0
x-omnistrate-api-params:
- key: replicaInstanceType
description: Replica Instance Type
name: Replica Instance Type
type: String
modifiable: true
required: true
export: true
- key: numReadReplicas
description: Number of Read Replicas
name: Number of Read Replicas
type: Float64
modifiable: true
required: false
export: true
defaultValue: "1"
limits:
min: 0
max: 5
- key: postgresqlPassword
description: Database Password
name: Database Password
type: String
modifiable: false
required: true
export: false
- key: replicationPassword
description: Replication Password
name: Replication Password
type: String
modifiable: false
required: false
export: false
defaultValue: "CHANGEME_SECURE_PASSWORD"
x-omnistrate-mode-internal: true
Cluster:
image: omnistrate/noop
x-omnistrate-api-params:
- key: instanceType
description: Instance Type
name: Instance Type
type: String
modifiable: true
required: true
export: true
parameterDependencyMap:
Master: masterInstanceType
Replica: replicaInstanceType
- key: postgresqlPassword
description: Database Password
name: Database Password
type: String
modifiable: false
required: true
export: false
parameterDependencyMap:
Master: postgresqlPassword
Replica: postgresqlPassword
- key: postgresqlUsername
description: Database Username
name: Database Username
type: String
modifiable: false
required: true
export: true
parameterDependencyMap:
Master: postgresqlUsername
- key: postgresqlDatabase
description: Database Name
name: Database Name
type: String
modifiable: false
required: true
export: true
defaultValue: "postgres"
parameterDependencyMap:
Master: postgresqlDatabase
- key: numReadReplicas
description: Number of Read Replicas
name: Number of Read Replicas
type: Float64
modifiable: true
required: false
export: true
defaultValue: "1"
limits:
min: 0
max: 5
parameterDependencyMap:
Replica: numReadReplicas
- key: storageSize
description: Storage Size in GB
name: Storage Size (GB)
type: Float64
modifiable: true
required: true
export: true
defaultValue: "100"
limits:
min: 20
max: 1000
parameterDependencyMap:
Master: storageSize
depends_on:
- Master
- Replica
x-omnistrate-mode-internal: false
Build and Test the Service¶
Follow CLI Setup, then build the product from the complete specification:
omnistrate-ctl build --file omnistrate-compose.yaml --product-name "Hosted PostgreSQL" --description "Dedicated provider-hosted PostgreSQL service"
Use the generated Customer Portal to create a subscription and provision a test deployment. Supply the database credentials, instance type, storage settings, and replica count, then check connectivity, replication, monitoring, and your recovery workflows before launch.
For additional PostgreSQL implementations using Compose, Helm, and Kubernetes operators, see the Omnistrate Community PostgreSQL repository.
Further Reading¶
- Why Enterprise SaaS Is Moving Toward Isolated Tenancy Models — the architectural motivation for dedicated and cellular Hosted SaaS.
- Tenancy Types — supported tenancy options and isolation boundaries.
- Build from Compose — the full Compose onboarding workflow and additional examples.