Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ If you are coming from WSO2 Kubernetes gateway `1.3.0`, treat this as the succes

### High Availability and Production-Ready

- Controller uses PostgreSQL for persistent, shared API configuration storage.
- Controller uses an external database (PostgreSQL or SQL Server) for persistent, shared API configuration storage.
- Runtime uses Redis for distributed rate limiting across replicas.

### Built-In Observability
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: "High-Availability Production Deployment"
description: "Deploy API Platform Gateway in a highly available, production-grade configuration on Kubernetes with Helm, PostgreSQL, and replicated workloads."
description: "Deploy API Platform Gateway in a highly available, production-grade configuration on Kubernetes with Helm, an external database (PostgreSQL or SQL Server), and replicated workloads."
canonical_url: https://wso2.com/api-platform/docs/api-gateway/deployment/high-availability-production-deployment/
md_url: https://wso2.com/api-platform/docs/api-gateway/deployment/high-availability-production-deployment.md
tags:
Expand All @@ -9,13 +9,13 @@ tags:
- kubernetes
- devops
author: WSO2 API Platform Documentation Team
last_updated: 2026-06-11
last_updated: 2026-06-26
content_type: "how-to"
---

# High-Availability Production Deployment

This guide covers deploying the API Platform Gateway in a production-grade, highly available configuration using Helm on Kubernetes. Development mode is disabled, security is hardened, PostgreSQL backs the deployment state, and workloads are replicated across nodes.
This guide covers deploying the API Platform Gateway in a production-grade, highly available configuration using Helm on Kubernetes. Development mode is disabled, security is hardened, an external database (PostgreSQL or SQL Server) backs the deployment state, and workloads are replicated across nodes.

## Prerequisites

Expand Down Expand Up @@ -62,7 +62,7 @@ This separation provides:

The self-hosted gateway can be deployed in a highly available manner by running multiple **Gateway Controller** replicas and multiple **Gateway Runtime** replicas across different network zones or environments.

In this deployment model, API deployments are received by one of the Gateway Controller replicas. The controller persists the API deployment information in the shared PostgreSQL database. Other Gateway Controller replicas then read the updated deployment state from the database and synchronize the relevant configuration with the Gateway Runtime instances connected to them.
In this deployment model, API deployments are received by one of the Gateway Controller replicas. The controller persists the API deployment information in the shared database. Other Gateway Controller replicas then read the updated deployment state from the database and synchronize the relevant configuration with the Gateway Runtime instances connected to them.

This ensures that all Gateway Controller replicas operate with a consistent deployment state and that each runtime environment receives the latest API configuration.

Expand All @@ -75,14 +75,14 @@ The deployment consists of the following main components:
| Component | Description |
| ----- | ----- |
| **Gateway Controller** | Receives API deployment requests, stores deployment state in the database, and synchronizes runtime configuration with connected Gateway Runtime instances. |
| **PostgreSQL Database** | Acts as the shared source of truth for API metadata, deployment state, and gateway configuration. |
| **Database (PostgreSQL / SQL Server)** | Acts as the shared source of truth for API metadata, deployment state, and gateway configuration. |
| **Gateway Runtime** | Receives configuration from its connected Gateway Controller and enforces API gateway policies at runtime. |

### Deployment Synchronization Flow

When an API deployment request is received, it is handled by one of the available Gateway Controller replicas.

The controller that receives the request validates the deployment and stores the API metadata and deployment state in the shared PostgreSQL database. This database acts as the common source of truth for all Gateway Controller replicas.
The controller that receives the request validates the deployment and stores the API metadata and deployment state in the shared database. This database acts as the common source of truth for all Gateway Controller replicas.

Other Gateway Controller replicas continuously read or synchronize the latest deployment state from the database. Once a controller detects a new or updated API deployment, it generates the required runtime configuration and synchronizes it with the Gateway Runtime instances connected to that controller.

Expand All @@ -94,7 +94,7 @@ Each Gateway Controller replica can manage one or more Gateway Runtime replicas.

High availability is achieved by removing dependency on a single controller instance.

If an API deployment request is received by **Gateway Controller Replica 01**, that replica stores the deployment state in PostgreSQL. **Gateway Controller Replica 02** can then read the same deployment state from the database and synchronize it with the Gateway Runtime replicas connected to it.
If an API deployment request is received by **Gateway Controller Replica 01**, that replica stores the deployment state in the shared database. **Gateway Controller Replica 02** can then read the same deployment state from the database and synchronize it with the Gateway Runtime replicas connected to it.

![High-availability behavior](../../../assets/img/api-gateway/high-availability-deployment-example.png)

Expand All @@ -104,7 +104,7 @@ Similarly, multiple Gateway Runtime replicas can be deployed in each environment

### Configuration Synchronization

The PostgreSQL database is the central synchronization point between Gateway Controller replicas. It maintains the latest API deployment state and allows all controller replicas to operate consistently.
The shared database is the central synchronization point between Gateway Controller replicas. It maintains the latest API deployment state and allows all controller replicas to operate consistently.

Gateway Runtime replicas do not directly read from the database. Instead, they receive the required runtime configuration from their connected Gateway Controller. This keeps the runtime layer lightweight and allows the controller layer to manage configuration generation and synchronization.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,111 +1,209 @@
---
title: "Database Configuration"
description: "Configure PostgreSQL as the shared database for Gateway Controller replicas in high-availability production deployments."
description: "Configure PostgreSQL or SQL Server as the shared database for Gateway Controller replicas in high-availability production deployments."
canonical_url: https://wso2.com/api-platform/docs/api-gateway/deployment/production-deployment/database-configuration/
md_url: https://wso2.com/api-platform/docs/api-gateway/deployment/production-deployment/database-configuration.md
tags:
- api-gateway
- deployment
- postgresql
- sqlserver
- devops
author: WSO2 API Platform Documentation Team
last_updated: 2026-06-11
last_updated: 2026-06-26
content_type: "how-to"
---

# Database Configuration

PostgreSQL is required for high-availability production deployments. It removes the single-replica constraint of the default SQLite backend and acts as the shared source of truth across all Gateway Controller replicas. See [Architecture](../high-availability-production-deployment.md#architecture) for how replicas coordinate via the shared database.
An external database is required for high-availability production deployments. It removes the single-replica constraint of the default SQLite backend and acts as the shared source of truth across all Gateway Controller replicas. Both **PostgreSQL** and **SQL Server** are supported — use the tabs in each step below to follow the instructions for your database. See [Architecture](../high-availability-production-deployment.md#architecture) for how replicas coordinate via the shared database.

## Create the Database

Connect to your PostgreSQL instance:
=== "PostgreSQL"

```bash
psql "host=gateway-postgres.postgres.database.azure.com \
port=5432 \
dbname=postgres \
user=<admin-user> \
sslmode=require"
```
Connect to your PostgreSQL instance:

Create the application database, user, and grant privileges:
```bash
psql "host=gateway-postgres.postgres.database.azure.com \
port=5432 \
dbname=postgres \
user=<admin-user> \
sslmode=require"
```

```sql
CREATE DATABASE gateway_controller;
CREATE USER gateway WITH PASSWORD 'your-db-password';
GRANT ALL PRIVILEGES ON DATABASE gateway_controller TO gateway;
```
Create the application database, user, and grant privileges:

```sql
CREATE DATABASE gateway_controller;
CREATE USER gateway WITH PASSWORD 'your-db-password';
GRANT ALL PRIVILEGES ON DATABASE gateway_controller TO gateway;
```

=== "SQL Server"

Connect to your SQL Server instance (for example, using `sqlcmd`):

```bash
sqlcmd -S gateway-sqlserver.database.windows.net,1433 \
-U <admin-user> -P '<admin-password>'
```

Create the application database, login, and user:

```sql
CREATE DATABASE gateway_controller;
GO
CREATE LOGIN gateway WITH PASSWORD = 'your-db-password';
GO
USE gateway_controller;
GO
CREATE USER gateway FOR LOGIN gateway;
ALTER ROLE db_owner ADD MEMBER gateway;
GO
```

## Store the Password in a Kubernetes Secret

The database password is injected as an environment variable from a Kubernetes secret rather than stored in the chart values:

```bash
kubectl create secret generic gateway-postgres-password \
kubectl create secret generic gateway-db-password \
--namespace <your-namespace> \
--from-literal=password='your-db-password'
```

## Configure the Chart

```yaml
gateway:
config:
controller:
storage:
type: postgres
=== "PostgreSQL"

```yaml
gateway:
config:
controller:
storage:
type: postgres
postgres:
host: "gateway-postgres.postgres.database.azure.com"
port: 5432
database: "gateway_controller"
user: "gateway"
sslmode: require
connect_timeout: 5s
max_open_conns: 10
max_idle_conns: 5
conn_max_lifetime: 30m
conn_max_idle_time: 5m
application_name: gateway-controller

controller:
storage:
type: postgres
postgres:
host: "gateway-postgres.postgres.database.azure.com"
port: 5432
database: "gateway_controller"
user: "gateway"
sslmode: require
connect_timeout: 5s
max_open_conns: 10
max_idle_conns: 5
conn_max_lifetime: 30m
conn_max_idle_time: 5m
application_name: gateway-controller

controller:
storage:
type: postgres
postgres:
passwordSecretRef:
name: gateway-postgres-password
key: password
# Disable the SQLite PVC — not needed with PostgreSQL
persistence:
enabled: false
```
passwordSecretRef:
name: gateway-db-password
key: password
# Disable the SQLite PVC — not needed with an external database
persistence:
enabled: false
```

=== "SQL Server"

SQL Server uses the unified `database` configuration block. The `options` field controls TLS behavior (`encrypt` and `trust_server_certificate`) in place of PostgreSQL's `sslmode`.

```yaml
gateway:
config:
controller:
storage:
type: sqlserver
database:
driver: sqlserver
host: "gateway-sqlserver.database.windows.net"
port: 1433
database: "gateway_controller"
user: "gateway"
connect_timeout: 5s
max_open_conns: 10
max_idle_conns: 5
conn_max_lifetime: 30m
conn_max_idle_time: 5m
application_name: gateway-controller
options:
encrypt: "true" # disable, false, true, strict
trust_server_certificate: "false"

controller:
storage:
type: sqlserver
sqlserver:
passwordSecretRef:
name: gateway-db-password
key: password
# Disable the SQLite PVC — not needed with an external database
persistence:
enabled: false
```

## DSN Alternative

If your PostgreSQL connection string is managed externally (for example, from a secrets manager), you can supply a full DSN instead of individual fields.
If your database connection string is managed externally (for example, from a secrets manager), you can supply a full DSN instead of individual fields.

Create a secret containing the DSN:
=== "PostgreSQL"

```bash
kubectl create secret generic gateway-postgres-dsn \
--namespace <your-namespace> \
--from-literal=dsn='postgres://gateway:your-db-password@postgres.example.internal:5432/gateway_controller?sslmode=require'
```
Create a secret containing the DSN:

Reference the secret in values:
```bash
kubectl create secret generic gateway-db-dsn \
--namespace <your-namespace> \
--from-literal=dsn='postgres://gateway:your-db-password@postgres.example.internal:5432/gateway_controller?sslmode=require'
```

```yaml
gateway:
config:
controller:
storage:
type: postgres
Reference the secret in values:

```yaml
gateway:
config:
controller:
storage:
type: postgres
postgres:
dsn: "postgres://gateway:@postgres.example.internal:5432/gateway_controller?sslmode=require"
controller:
postgres:
dsn: "postgres://gateway:@postgres.example.internal:5432/gateway_controller?sslmode=require"
controller:
postgres:
passwordSecretRef:
name: gateway-postgres-dsn
key: dsn
```
passwordSecretRef:
name: gateway-db-dsn
key: dsn
```

=== "SQL Server"

Create a secret containing the DSN:

```bash
kubectl create secret generic gateway-db-dsn \
--namespace <your-namespace> \
--from-literal=dsn='sqlserver://gateway:your-db-password@sqlserver.example.internal:1433?database=gateway_controller&encrypt=true'
```

Reference the secret in values:

```yaml
gateway:
config:
controller:
storage:
type: sqlserver
database:
driver: sqlserver
dsn: "sqlserver://gateway:@sqlserver.example.internal:1433?database=gateway_controller&encrypt=true"
controller:
sqlserver:
passwordSecretRef:
name: gateway-db-dsn
key: dsn
```

!!! note
When `dsn` is set, it takes precedence over all individual connection fields. The password environment variable is still injected from the referenced secret.
Expand Down
2 changes: 1 addition & 1 deletion en/docs/api-gateway/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ You can extend the gateway with your own policies or include specific policies f

In a production HA deployment:

- **Gateway Controller** instances connect to a shared **PostgreSQL** database for persistent storage of API configurations, subscriptions, and other metadata.
- **Gateway Controller** instances connect to a shared external database (**PostgreSQL** or **SQL Server**) for persistent storage of API configurations, subscriptions, and other metadata.
- **Gateway Runtime** instances connect to a shared **Redis** instance used for distributed rate limiting, ensuring rate limit counters are synchronized across all runtime instances.

![HA diagram with two Gateway Controller replicas sharing PostgreSQL, three Gateway Runtime replicas sharing Redis, and all runtimes reporting to Moesif analytics](../assets/img/api-gateway/gateway-ha-setup.png)
Expand Down
Loading