Configure Services
CAP offers a few services that can be deployed or connected with through our config file.
You can always connect to an external service by using environments variables as well. But using CAP simplifies things like framework specific logic and CAP will also handle your migrations when it manages your database connection.
Compatibility
| App Deployment | Cluster Deployment | External Connection | Remote Access | |
|---|---|---|---|---|
| MariaDB | ✅ | ✅ | ✅ | ✅ |
| PostgreSQL | ✅ | ✅ | ✅ | ✅ |
| MySQL | ❌ | ❌ | ✅ | ❌ |
| CockroachDB | ✅ | ✅ | ✅ | ✅ |
| Dragonfly | ✅ | ❌ | ❌ | ✅ |
| RabbitMQ | ✅ | ✅ | ❌ | ✅ |
| Mercure | ✅ | ❌ | ❌ | ❌ |
| OpenSearch | ✅ | ✅ | ❌ | ✅ |
Any service marked for remote access can be reached with your own client over Cloudbear Mesh; see Remote Access.
MariaDB
To deploy a MariaDB server, define it in your services block. CAP will automatically handle the deployment, including daily backups.
services:
db:
type: mariadb
version: 11.4.5
Options
| Property | Type | Description | Default |
|---|---|---|---|
type |
string |
Set to mariadb. |
None |
version |
string |
The MariaDB version to run. | 11.4.5 |
replicas |
integer |
The number of database nodes. Even numbers are rejected. | 3 in production, 1 elsewhere |
resources.cpu |
integer or string |
CPU allocated to each node. | 250m |
resources.memory |
integer or string |
Memory allocated to each node. | 1Gi |
resources.storage |
integer or string |
Storage allocated to each node. | 10Gi |
databases |
string[] |
Databases created when the service is provisioned. See Predefined databases. | [] |
config |
string[] |
Extra server configuration lines, appended to the settings CAP sets. See Server configuration. | [] |
backup.enable |
boolean |
Whether backups are taken. See Backups. | true |
backup.schedule |
string |
A cron expression defining when backups run. See YAML Schema Reference. | 0 1 * * * |
access |
boolean or object |
Whether you can reach the service with your own client. See Remote Access. | false |
Connecting your application
Database connections arrive under the names your framework already reads, so the stock configuration works unchanged. This applies to MariaDB, MySQL, PostgreSQL and CockroachDB alike.
| Type | Variables |
|---|---|
laravel |
DB_*, plus DB_CONNECTION set to the type of the first database service you defined |
symfony |
DATABASE_URL, including the serverVersion the connection needs |
shopware |
DATABASE_URL, as Symfony |
cakephp |
DATABASE_URL, with the query parameters CakePHP expects appended |
whmcs |
MYSQL_* |
| others | DATABASE_URL |
Naming the connection prefixes these variables; see Connections.
CockroachDB is the exception to the credentials part: it accepts connections from your application without a username or password, so its URL carries neither.
Predefined databases
You can create additional databases when the MariaDB service is provisioned.
services:
db:
type: mariadb
databases:
- my_first_app
- my_second_app
Server configuration
Every line under config is added to the server's settings, after the ones CAP sets. Use it to
override a default or to set an option CAP does not set itself.
services:
db:
type: mariadb
config:
- max_connections = 2000
- innodb_lock_wait_timeout = 120
Backups
CAP takes a daily backup of your database services. Set backup.schedule to a cron expression to
run them at a different time, or backup.enable to false to turn them off.
Manual setup required. Defining backup in your config.cap.yaml only configures the backup schedule. To ensure your backups are actually stored and restorable, additional manual configuration is required on the Cloudbear platform side. Please contact Cloudbear support to complete the setup for your database backups.
services:
db:
type: mariadb
backup:
enable: true
schedule: 0 2 * * *
MySQL
MySQL is not available for deployment directly through CAP, but you can connect to an external MySQL server. See the Connections documentation for more details.
An external MySQL server is declared under connections rather than services, so none of the
service options on this page apply to it. Your application receives the same variables as for a
MariaDB service; see MariaDB.
CockroachDB and PostgreSQL
To deploy a CockroachDB or PostgreSQL server, define it in your services block.
services:
pg-database:
type: postgresql
version: "17.8"
backup:
enable: true
schedule: "@daily"
PostgreSQL options
| Property | Type | Description | Default |
|---|---|---|---|
type |
string |
Set to postgresql. |
None |
version |
string |
The PostgreSQL version to run. | 17.8 |
replicas |
integer |
The number of database nodes. Even numbers are rejected. | 3 in production, 1 elsewhere |
resources.cpu |
integer or string |
CPU allocated to each node. | 250m |
resources.memory |
integer or string |
Memory allocated to each node. | 1Gi |
resources.storage |
integer or string |
Storage allocated to each node. | 10Gi |
databases |
string[] |
Databases created when the service is provisioned. See Predefined PostgreSQL databases. | [] |
backup.enable |
boolean |
Whether backups are taken. See Backups. | true |
backup.schedule |
string |
A cron expression defining when backups run. See YAML Schema Reference. | 0 1 * * * |
access |
boolean or object |
Whether you can reach the service with your own client. See Remote Access. | false |
CockroachDB options
| Property | Type | Description | Default |
|---|---|---|---|
type |
string |
Set to cockroachdb. |
None |
version |
string |
The CockroachDB version to run. | 24.3.18 |
replicas |
integer |
The number of database nodes. Values below 3, and values that are not a multiple of 3, are rejected. |
3 |
resources.cpu |
integer or string |
CPU allocated to each node. | 500m |
resources.memory |
integer or string |
Memory allocated to each node. | 2Gi |
resources.storage |
integer or string |
Storage allocated to each node. | 10Gi |
backup.enable |
boolean |
Whether backups are taken. See Backups. | true |
backup.schedule |
string |
A cron expression defining when backups run. See YAML Schema Reference. | 0 1 * * * |
access |
boolean or object |
Whether you can reach the service with your own client. See Remote Access. | false |
services:
crdb:
type: cockroachdb
version: 24.3.18
backup:
enable: true
schedule: 0 3 * * *
CockroachDB has no databases option: a database is created for each connection instead.
Predefined PostgreSQL databases
You can create additional databases when the PostgreSQL service is provisioned.
services:
pg-database:
type: postgresql
databases:
- my_first_app
- my_second_app
Manual setup required. Like MariaDB, defining backup for PostgreSQL and CockroachDB only configures the backup schedule. Additional manual configuration is required on the Cloudbear platform side to ensure your backups are actually stored and restorable. Please contact Cloudbear support to complete the setup.
Dragonfly
Dragonfly is a modern, in-memory datastore that is compatible with Redis.
services:
cache:
type: dragonfly
Options
| Property | Type | Description | Default |
|---|---|---|---|
type |
string |
Set to dragonfly. |
None |
version |
string |
The Dragonfly version to run. | 1.27.1 |
replicas |
integer |
The number of datastore instances. | 2 in production, 1 elsewhere |
resources.cpu |
integer or string |
CPU allocated to each instance. | 125m |
resources.memory |
integer or string |
Memory allocated to each instance. | 256Mi |
resources.storage |
integer or string |
Storage for snapshots. Setting it turns on persistence. See Persistence. | None |
access |
boolean or object |
Whether you can reach the service with your own client. See Remote Access. | false |
Dragonfly services keep their data in memory only, unless you request storage for them.
Connecting your application
| Type | Variables |
|---|---|
laravel |
REDIS_URL, plus CACHE_STORE set to redis |
cakephp |
CACHE_DEFAULT_URL for an unnamed connection, CACHE_<name>_URL otherwise |
| others | REDIS_URL |
Persistence
By default a Dragonfly service holds its data in memory, and that data is gone when the
service restarts. Requesting resources.storage gives each instance storage of its own and
Dragonfly starts snapshotting to it: on shutdown, and once an hour while it runs.
The snapshot is loaded back on start, so cached data survives restarts and version upgrades.
services:
cache:
type: dragonfly
resources:
memory: 1Gi
storage: 2Gi
Size the storage to at least the memory you gave the service, since a snapshot holds the full dataset.
Snapshots are not a backup and not a substitute for replication. A graceful restart loses nothing, but a service that is killed abruptly falls back to its last hourly snapshot. Treat this as a cache that comes back warm, not as a durable store.
RabbitMQ
To deploy a RabbitMQ message broker, define it in your services block. When you connect an application to it, a unique vhost is automatically created for your connection.
services:
queue:
type: rabbitmq
Options
| Property | Type | Description | Default |
|---|---|---|---|
type |
string |
Set to rabbitmq. |
None |
version |
string |
The RabbitMQ version to run. | 4.0.7 |
replicas |
integer |
The number of broker nodes. Values other than 1 or a multiple of 3 are rejected. |
3 in production, 1 elsewhere |
resources.cpu |
integer or string |
CPU allocated to each node. | 250m |
resources.memory |
integer or string |
Memory allocated to each node. | 2Gi |
resources.storage |
integer or string |
Storage allocated to each node. | 10Gi |
vhosts |
string[] |
Vhosts created when the service is provisioned. See Predefined vhosts. | [] |
access |
boolean or object |
Whether you can reach the service with your own client. See Remote Access. | false |
Connecting your application
Each connection gets its own vhost, so two applications on one broker stay separate.
| Type | Variables |
|---|---|
laravel |
RABBITMQ_* as separate values, plus QUEUE_CONNECTION set to rabbitmq |
symfony |
MESSENGER_TRANSPORT_DSN |
cakephp |
RABBITMQ_* as separate values |
| others | RABBITMQ_URL |
Predefined vhosts
You can predefine vhosts for your RabbitMQ service.
services:
queue:
type: rabbitmq
vhosts:
- my_first_vhost
- my_second_vhost
Mercure
Mercure is a hub for pushing real-time updates to browsers and other clients over Server-Sent Events. Your application publishes an update to the hub, and the hub fans it out to everyone subscribed to that topic.
services:
hub:
type: mercure
connections:
- service: hub
Options
| Property | Type | Description | Default |
|---|---|---|---|
type |
string |
Set to mercure. |
None |
version |
string |
The hub version to run. | 0.24.2 |
hostname |
string |
Serve the hub under your own domain instead of the derived name. See Hostname. | derived |
replicas |
integer |
The number of hub instances. Above 1 requires a transport; see Redundancy. |
1 |
resources.cpu |
integer or string |
CPU allocated to each instance. | 125m |
resources.memory |
integer or string |
Memory allocated to each instance. | 256Mi |
resources.storage |
integer or string |
Storage for the update history. See Update history. | 1Gi |
cors |
string[] |
Origins allowed to subscribe from a browser. See Browser subscribers. | [] |
anonymous |
boolean |
Allow subscribers without a valid JWT. Only for topics where every subscriber may see every update. | false |
subscriptions |
boolean |
Expose the subscription API and dispatch private updates when a subscription opens or closes. | false |
transport.service |
string |
The name of a dragonfly or postgresql service the instances share. See Redundancy. |
None |
Hostname
Unlike the other services, a hub is reached by browsers, so it gets a public hostname and
certificate of its own. By default that is <service>.<environment>.<application>.app.cloudbear.it,
which resolves without any DNS work on your side. Set hostname to serve it under your own domain
instead, and point a CNAME at the derived name.
services:
hub:
type: mercure
version: 0.24.2
hostname: mercure.example.com
resources:
cpu: 250m
memory: 512Mi
storage: 2Gi
Connecting your application
| Variable | Description |
|---|---|
MERCURE_URL |
Where your application publishes. Private, so updates never leave Cloudbear. |
MERCURE_PUBLIC_URL |
Where browsers subscribe. Use this in anything you send to a client. |
MERCURE_PUBLISHER_JWT_KEY |
Key to sign publisher tokens with. |
MERCURE_SUBSCRIBER_JWT_KEY |
Key to sign subscriber tokens with. |
The two keys are generated once and stored for you. They are deliberately different, so a token you hand to a browser to subscribe with cannot also be used to publish.
| Type | Variables |
|---|---|
symfony |
The above, plus MERCURE_JWT_SECRET, where symfony/mercure reads the publisher key |
| others | The above |
Naming the connection prefixes these variables, and you can template the hub's values into names of your own choosing; see Connections.
Browser subscribers
Subscribers connecting from a browser need their origin allowed, otherwise the request is blocked before it reaches the hub:
services:
hub:
type: mercure
cors:
- https://app.example.com
Update history
A hub keeps recent updates so a client that reconnects can replay what it missed using the
Last-Event-ID header. That history is held in the storage sized by resources.storage, 1Gi by
default.
Redundancy
By default a hub runs as a single instance, which means a restart briefly interrupts every open connection. Clients reconnect on their own, so this is usually acceptable outside production.
A redundant hub runs several instances that share their updates through a transport, so no single
instance is a point of failure and updates published to one reach subscribers on all of them. Point
transport.service at a dragonfly or postgresql service to enable it:
services:
hub:
type: mercure
replicas: 3
transport:
service: cache
cache:
type: dragonfly
Either service type works, and which to pick depends on what the hub is doing:
| Transport | Update history | Subscription API | Notes |
|---|---|---|---|
dragonfly |
Yes | Yes | Recommended. Bounded history, lowest overhead. |
postgresql |
Yes | No | Use when you already run one and want fewer parts. |
A postgresql transport gets a database of its own on the service you point it at, separate from
any database your application connects to, so it never shares credentials with your application:
services:
hub:
type: mercure
replicas: 3
transport:
service: db
db:
type: postgresql
No subscription API on PostgreSQL. The subscriptions option needs the
transport to track which subscribers are connected, which the PostgreSQL transport does not do.
Combining the two leaves subscription events undelivered without reporting an error, so use a
dragonfly transport if your application relies on them.
Paid option. Redundancy is only available in the commercial edition of Mercure,
so a redundant hub is a paid add-on and has to be enabled by Cloudbear before it will
deploy. Contact Cloudbear support to arrange it. Without it, replicas has to
stay at 1: a single hub cannot be scaled out, because instances would not see each other's
updates.
A redundant hub keeps its update history in the Dragonfly service rather than in its own storage, so
resources.storage no longer applies. Note that redundancy covers the hub instances
themselves; the Dragonfly service behind them has its own availability.
OpenSearch
OpenSearch is a search and analytics engine. Define it in your services block and CAP deploys it,
creates a user for each connection, and grants that user read and write access.
services:
search:
type: opensearch
connections:
- service: search
Options
| Property | Type | Description | Default |
|---|---|---|---|
type |
string |
Set to opensearch. |
None |
version |
string |
The OpenSearch version to run. | 3.7.0 |
replicas |
integer |
The number of nodes in the cluster. Values below 3 are rejected. |
3 |
resources.cpu |
integer or string |
CPU allocated to each node. | 250m |
resources.memory |
integer or string |
Memory allocated to each node. | 1Gi |
resources.storage |
integer or string |
Storage allocated to each node. | 10Gi |
access |
boolean or object |
Whether you can reach the service with your own client. See Remote Access. | false |
The defaults are sized for a small production workload. Override them per service:
services:
search:
type: opensearch
version: 3.7.0
replicas: 5
resources:
cpu: 500m
memory: 2Gi
storage: 50Gi
Connecting your application
A connection injects the host, a dedicated user, and an index prefix:
| Variable | Description |
|---|---|
OPENSEARCH_HOST |
Where to reach OpenSearch. Private to your application. |
OPENSEARCH_USERNAME |
The user created for this connection. |
OPENSEARCH_PASSWORD |
That user's password, read from a secret. |
OPENSEARCH_INDEX_PREFIX |
Prefix your indexes with this to keep them apart from other connections. |
Naming the connection prefixes these variables; see Connections.
Some application types get the names their usual client already reads, so the stock configuration works unchanged:
| Type | Variables |
|---|---|
laravel |
OS_HOSTS, OS_USERNAME, OS_PASSWORD, OS_INDEX_PREFIX |
shopware |
OPENSEARCH_URL, OPENSEARCH_USERNAME, OPENSEARCH_PASSWORD, SHOPWARE_ES_INDEX_PREFIX |
cakephp |
OPENSEARCH_HOST, OPENSEARCH_PORT, OPENSEARCH_USERNAME, OPENSEARCH_PASSWORD, OPENSEARCH_INDEX |
For shopware, search is switched on for you: CAP sets
SHOPWARE_ES_ENABLED and SHOPWARE_ES_INDEXING_ENABLED as part of the
connection, so you do not have to enable indexing yourself.
Shared services
In some cases, you might want to define a service once and have multiple applications connect to it. This can be achieved using "Shared Services". A shared service is a service that is not tied to a specific application's lifecycle. Unlike regular services, shared services are defined at the project level and do not need to be explicitly declared in your application's config.cap.yaml file to be accessible.
Example
Here's how you might define a shared database that can be used by multiple applications:
shared:
services:
shared-db:
type: mariadb
version: 11.4.5
To connect to this shared service from your application, you would then use a shared-connection in your connections block, referencing the name of the shared service.
connections:
- shared: shared-db
name: db
Learn more about connecting to shared services in the Connections documentation.