On-Premises Configuration
Configure the On-Premises deployment through a Docker Compose .env file or Helm values, depending on how you install the control plane.
Use this reference with On-Premises Installation when you need to review or customize the generated deployment configuration.
Preserve these settings with the matching database backup. See Backup and Recovery for the complete recovery set and restore order.
These settings configure the on-premises control plane package. They are separate from AISIX gateway runtime environment variables. For gateway runtime variables, see Environment Variables.
Docker Compose Environment Variables
The Docker Compose package reads environment variables from ./aisix-self-hosted/.env. The quickstart and offline package generate this file on first start. Back it up with the database: it contains the database password and master key, and it is not included in later package archives.
During a normal in-place upgrade, run.sh updates AISIX_VERSION to match the extracted package. It preserves the other settings and secrets in .env.
Run the Docker Compose commands on this page from the ./aisix-self-hosted directory.
Images and Release Version
| Variable | Purpose |
|---|---|
AISIX_VERSION | Package-owned release tag used by the images unless you set an individual image override. run.sh updates it during an upgrade. |
AISIX_API_IMAGE | Optional image override for cp-api. |
AISIX_DPM_IMAGE | Optional image override for dp-manager. |
AISIX_UI_IMAGE | Optional image override for the dashboard. |
AISIX_CLOUD_DP_IMAGE | Optional AISIX gateway image override used in generated gateway install snippets. |
Individual image overrides remain in effect across package upgrades.
Database
| Variable | Purpose |
|---|---|
POSTGRES_USER | PostgreSQL user for the bundled database. |
POSTGRES_PASSWORD | PostgreSQL password for the bundled database. Use a strong URL-safe value because it is embedded in a postgres:// URL. |
POSTGRES_DB | PostgreSQL database name. |
These variables configure only the bundled PostgreSQL service. The package does not expose external database URL overrides in .env. Use the Helm installation when the control plane must connect to an external PostgreSQL database.
Secrets
| Variable | Purpose |
|---|---|
AISIX_CLOUD_MASTER_KEY | Base64-encoded 32-byte AES key used for envelope encryption. The same value is also used by dp-manager. |
AISIX_CLOUD_MASTER_KEY_ID | Identifier stored with encrypted rows so the control plane can identify the wrapping key. |
BETTER_AUTH_SECRET | Session-signing secret for dashboard authentication. |
Do not change AISIX_CLOUD_MASTER_KEY on an existing deployment unless you are following a master-key rotation procedure. Changing it without preserving the previous key can make encrypted data unreadable.
Recover a Missing CA Root
Use this recovery override only when cp-api or dp-manager refuses to start with ca_root row missing but dp_certificates has rows, and only after confirming that the control plane is connected to the intended database. Minting a new root CA invalidates every existing gateway mTLS chain. It does not recover the missing root.
If you cannot restore the missing root from a complete database backup and intend to replace it, add the following setting to .env:
AISIX_CLOUD_ALLOW_FRESH_BOOTSTRAP=1
Recreate both services so either process can bootstrap the replacement CA:
docker compose up -d --wait api dpm
After both services are healthy, remove AISIX_CLOUD_ALLOW_FRESH_BOOTSTRAP from .env and run the same command again to recreate them without the override. When both services are healthy again, re-enroll every AISIX gateway; certificates issued under the missing root no longer authenticate.
Runtime URLs
| Variable | Purpose |
|---|---|
AISIX_CLOUD_PUBLIC_BASE_URL | Browser-facing control-plane origin, such as https://aisix.example.com. Login validates the session issuer against this value. |
AISIX_CLOUD_DPMGR_BASE_URL | dp-manager mTLS endpoint that AISIX gateway hosts can reach. An https:// URL such as https://dpm.example.com:7944, whose host may be a DNS name or an IP address. |
AISIX_CLOUD_DASHBOARD_URL | Internal dashboard URL used by cp-api. The Compose default points to the dashboard service. |
AISIX_TRUSTED_ORIGINS | Additional browser origins allowed to sign in, provided as a comma-separated list. The public base URL and its loopback twin are trusted automatically. |
AISIX_CLOUD_CORS_ALLOWED_ORIGINS | Browser origins allowed to call cp-api routes under /api/* cross-origin, including /api/auth/*, provided as a comma-separated list. Empty by default, which writes no CORS headers at all. For cross-origin sign-in, add the origin to AISIX_TRUSTED_ORIGINS as well. See Cross-Origin Browser Access for the accepted entries. |
Set AISIX_CLOUD_PUBLIC_BASE_URL and AISIX_CLOUD_DPMGR_BASE_URL before exposing the deployment outside the local host or container network.
Compose passes AISIX_CLOUD_DPMGR_BASE_URL to the dpm service as well, because dp-manager issues its TLS server certificate for that host. Recreate both api and dpm after changing it.
Pricing Catalog
The packaged Docker Compose file runs cp-api in offline pricing mode by default. It sets AISIX_CLOUD_PRICESYNC_SNAPSHOT_PATH on the api service to a snapshot baked into the cp-api image, so the control plane can initialize model pricing without contacting models.dev.
The package exposes the pricing mode through .env:
| Variable | Purpose |
|---|---|
AISIX_CLOUD_PRICESYNC_SNAPSHOT_PATH | Select offline mode when it contains a snapshot path. When the variable is absent, Compose uses the in-image snapshot. An explicitly empty value selects online mode. |
AISIX_CLOUD_PRICESYNC_URL | Override the models.dev catalog URL in online mode, for example with an internal mirror. When it is empty, online mode uses https://models.dev/api.json. |
To use online pricing, add an empty snapshot-path assignment to .env. Add the URL only when you need to use a different catalog endpoint:
AISIX_CLOUD_PRICESYNC_SNAPSHOT_PATH=
Recreate cp-api after changing either setting:
docker compose up -d api
Keep these overrides in .env, not docker-compose.yaml, because extracting a later package replaces the Compose file.
Private Network Access
By default, cp-api refuses these outbound connections when the destination resolves to a private, internal, or loopback address. Enable only the access required for services on networks that you trust and that cp-api can reach.
| Variable | Purpose |
|---|---|
AISIX_PLAYGROUND_ALLOW_PRIVATE_IPS | Set to 1 to let the dashboard playground reach LLM endpoints on private, internal, or loopback addresses. Off by default as an SSRF protection; enable it only for self-hosted models on an internal network. See Playground. |
AISIX_CLOUD_NOTIFY_ALLOW_PRIVATE_URLS | Set to true to let budget notifications reach a private webhook receiver or Slack proxy. |
AISIX_CLOUD_MCP_SPEC_ALLOW_PRIVATE_URLS | Set to true to let the control plane fetch an MCP server's OpenAPI document from a private spec_url. If the document is on a private URL and you leave this setting disabled, provide spec_content instead. |
Set the required variables in .env, then recreate cp-api:
docker compose up -d api
Dashboard and Ports
| Variable | Purpose |
|---|---|
AISIX_DASHBOARD_LOCALE | Dashboard language for the deployment. Supported values are en and zh. |
POSTGRES_HOST_PORT | Host port binding for bundled PostgreSQL. |
API_HOST_PORT | Host port binding for cp-api and the dashboard reverse proxy. |
DPM_HOST_PORT | Host port binding for dp-manager. |
Prefix a host port with 127.0.0.1: when the service should bind only to loopback.
Helm Values
The api7/aisix-cp chart uses Helm values instead of a Compose .env file. Add the API7 Helm repository before inspecting or installing the chart:
helm repo add api7 https://charts.api7.ai
helm repo update
To inspect every chart value, run:
helm show values api7/aisix-cp
The chart source and values are published in the api7/api7-helm-chart repository.
Images and Services
| Value | Purpose |
|---|---|
api.image.repository, api.image.tag | cp-api image. |
dpm.image.repository, dpm.image.tag | dp-manager image. |
ui.image.repository, ui.image.tag | Dashboard image. |
api.replicaCount, dpm.replicaCount, ui.replicaCount | Number of replicas for each control-plane component. |
api.affinity, dpm.affinity, ui.affinity | Kubernetes scheduling rules used to spread replicas across nodes or failure domains. |
api.nodeSelector, dpm.nodeSelector, ui.nodeSelector | Node label constraints for each control-plane component. |
api.tolerations, dpm.tolerations, ui.tolerations | Kubernetes taint exceptions for each control-plane component. |
api.service.type, api.service.port, api.service.nodePort | Kubernetes Service settings for cp-api. Direct NodePort connections use plain HTTP. |
dpm.service.type, dpm.service.port, dpm.service.nodePort | Kubernetes Service settings for the dp-manager mTLS endpoint. |
ui.service.type, ui.service.port, ui.service.nodePort | Kubernetes Service settings for the dashboard service behind cp-api. Direct NodePort connections use plain HTTP. |
The chart renders a configured nodePort only when the corresponding Service type is NodePort. Leave the value empty to let Kubernetes allocate a port dynamically. For other Service types, the chart ignores the value.
Operators normally reach the dashboard through cp-api, which proxies dashboard traffic to the UI service. Do not use the UI NodePort as a standalone dashboard entry point. If an external same-origin proxy uses it as an upstream, route dashboard pages to the UI service and /api/* requests to cp-api. Terminate TLS at the proxy unless it runs only on a trusted private network.
Control Plane Metrics
cp-api exposes Prometheus metrics about the control plane's write path on a dedicated cluster-internal listener. It does not serve them from the API port used by the Admin API and dashboard, and the dashboard does not read them. Metric names use the aisix_cp_ prefix to distinguish them from gateway metrics in the same Prometheus deployment.
| Value | Purpose |
|---|---|
api.metrics.enabled | Serve Prometheus metrics from cp-api. true by default, matching the gateway chart. |
api.metrics.port | Port the metrics listener binds inside the container. Defaults to 9090. |
api.metrics.service.port | Port of the separate ClusterIP Service that exposes the metrics endpoint, so scraping never rides the API Service. Defaults to 9090. |
api.metrics.service.annotations | Extra annotations for the metrics Service, such as scrape hints for a Prometheus that discovers by annotation. |
api.metrics.serviceMonitor.enabled | Create a Prometheus Operator ServiceMonitor for the metrics Service. false by default. |
api.metrics.serviceMonitor.namespace | Namespace for the ServiceMonitor. Empty uses the release namespace. |
api.metrics.serviceMonitor.interval, api.metrics.serviceMonitor.scrapeTimeout | Scrape interval (30s by default) and timeout. An empty timeout leaves the Prometheus default. |
api.metrics.serviceMonitor.labels | Extra labels, such as the release label your Prometheus selects on. |
api.metrics.serviceMonitor.relabelings, api.metrics.serviceMonitor.metricRelabelings | Scrape-time and metric relabeling rules. |
When api.metrics.enabled is true, the chart sets AISIX_CLOUD_METRICS_LISTEN on the cp-api deployment and serves Prometheus text at /metrics. Setting the value to false omits the environment variable and leaves the metrics port unbound inside the pod, rather than only removing its Service.
The metrics address must differ from AISIX_CLOUD_LISTEN. cp-api refuses to start if both listeners use the same address.
Two metrics are exported today, both about how much a single control-plane write projects to the data plane:
| Metric | Type | Labels | Meaning |
|---|---|---|---|
aisix_cp_outbox_rows_per_transaction | Histogram | operation, declared | Resource-outbox rows one control-plane write transaction added to the queue. operation names the declared fan-out, or none when nothing declared one. |
aisix_cp_outbox_undeclared_fanout_total | Counter | — | Write transactions that queued more outbox rows than the guard threshold without declaring a fan-out. |
Control Plane URLs
| Value | Purpose |
|---|---|
api.publicBaseURL | Browser-facing control-plane origin. When cp-api uses a NodePort, set this to the externally reachable origin at that port or the origin of the TLS reverse proxy in front of it. |
api.dpmgrBaseURL | dp-manager mTLS endpoint that AISIX gateway hosts can reach. An https:// URL such as https://dpm.example.com:7944, whose host may be a DNS name or an IP address. When dp-manager uses a NodePort, set this to its externally reachable HTTPS endpoint. The chart also passes the value to the dp-manager deployment, which issues its TLS server certificate for that host. |
api.dpImage | AISIX gateway image shown in generated AISIX Cloud gateway install snippets. |
api.corsAllowedOrigins | Browser origins allowed to call cp-api routes under /api/* cross-origin, including /api/auth/*, as a list. Empty by default, which writes no CORS headers at all. For cross-origin sign-in, add the origin to AISIX_TRUSTED_ORIGINS as well. See Cross-Origin Browser Access for the accepted entries. |
Playground
| Value | Purpose |
|---|---|
api.playgroundAllowPrivateIPs | Let the dashboard playground reach LLM endpoints on private, internal, or loopback addresses. false by default as an SSRF protection. |
Notification Destinations
| Value | Purpose |
|---|---|
api.notifyAllowPrivateURLs | Let cp-api send budget notifications to private, internal, or loopback addresses. false by default as an SSRF protection. |
Secrets
| Value | Purpose |
|---|---|
secrets.masterKey | Base64-encoded 32-byte AES key used for envelope encryption. |
secrets.masterKeyID | Identifier stored with encrypted rows so the control plane can identify the wrapping key. |
secrets.betterAuthSecret | Session-signing secret for dashboard authentication. |
Replace the chart's placeholder secrets before installing. The chart rejects placeholder secret values.
PostgreSQL
| Value | Purpose |
|---|---|
postgresql.builtin | Deploy the bundled PostgreSQL chart when set to true. |
postgresql.auth.password | Password for the bundled chart's configured PostgreSQL user. The chart requires a non-placeholder value even when applications connect as the postgres user. |
postgresql.auth.postgresPassword | PostgreSQL superuser password. The chart uses this for control-plane connections by default. |
postgresql.auth.usePostgresUserForAppConnections | Use the postgres user for control-plane connections. The default is true. |
postgresql.auth.existingSecret | Existing Kubernetes Secret for bundled PostgreSQL credentials. |
externalDatabase.* | Top-level values for an existing PostgreSQL database when postgresql.builtin=false. |
Use URL-safe PostgreSQL passwords, such as values generated with openssl rand -hex 24, because the chart builds a postgres:// connection URL from the configured credentials.
Private PostgreSQL CA for the Dashboard
Starting with aisix-cp chart 1.2.1 (application version 1.2.0), ui.extraVolumes and ui.extraVolumeMounts let the dashboard mount a private database CA. Both default to empty lists. They append to the built-in Next.js cache volume and mount.
If external PostgreSQL uses a private CA, the dashboard's Node.js client must trust it. Otherwise registration and login can fail with SELF_SIGNED_CERT_IN_CHAIN even while dashboard pages load.
Create a ConfigMap containing the public PEM CA certificate in the dashboard namespace. This example uses release and namespace aisix-cp; replace them with your deployment's names:
kubectl create configmap aisix-postgres-ca \
--namespace aisix-cp --from-file=ca.crt=./ca.crt
Add these settings to your existing Helm values file. Keep your database settings and any existing entries in the three ui lists:
ui:
extraEnvVars:
- name: NODE_EXTRA_CA_CERTS
value: /etc/aisix/postgres-ca/ca.crt
extraVolumes:
- name: postgres-ca
configMap:
name: aisix-postgres-ca
items:
- key: ca.crt
path: ca.crt
extraVolumeMounts:
- name: postgres-ca
mountPath: /etc/aisix/postgres-ca
readOnly: true
For a Secret, replace the configMap block with:
secret:
secretName: aisix-postgres-ca
items:
- key: ca.crt
path: ca.crt
Provision that Secret in the same namespace. Only the public CA certificate is needed; keep the CA private key with the certificate issuer. Use unique volume names and mount paths, preserving next-cache and /app/.next/cache for the built-in cache. These settings affect the dashboard; configure database TLS for the other control-plane components separately as needed.
Apply the values with a chart version that supports these fields and keep PostgreSQL TLS verification enabled. Manage the certificate resource and values in your deployment source so later GitOps syncs retain the mount.
After a CA update or rotation, restart the dashboard so Node.js reloads NODE_EXTRA_CA_CERTS. The chart does not automatically restart Pods when an external ConfigMap or Secret changes:
kubectl rollout restart deployment/aisix-cp-ui --namespace aisix-cp
kubectl rollout status deployment/aisix-cp-ui --namespace aisix-cp
Dashboard Locale
| Value | Purpose |
|---|---|
ui.defaultLocale | Dashboard language for the deployment. Supported values are en and zh. |
Cross-Origin Browser Access
AISIX_CLOUD_CORS_ALLOWED_ORIGINS and api.corsAllowedOrigins take the same entries. A normal installation needs neither: cp-api serves the APIs and proxies the dashboard, so the browser has one origin and nothing is cross-origin. Populate the setting only to let a dashboard served from somewhere else call /api/* directly. The allowlist covers both Admin API routes and Better Auth routes under /api/auth/*.
If users sign in from that dashboard origin, add it to AISIX_TRUSTED_ORIGINS as well. CORS lets the browser reach the routes. The trusted-origin setting lets Better Auth accept the sign-in origin.
With Helm, add the dashboard origin to both settings:
api:
corsAllowedOrigins:
- https://dashboard.example.com
ui:
extraEnvVars:
# Required when users sign in from this origin.
- name: AISIX_TRUSTED_ORIGINS
value: https://dashboard.example.com
Each entry takes one of two forms:
- A bare origin,
https://hostorhttps://host:port, written the way a browser serializes it in anOriginheader. Lowercase scheme and host, no path, no query, no fragment, no trailing slash and no trailing dot; the scheme's default port omitted, and a port written without leading zeros. An internationalized name is written in its punycode form, an IPv6 address in the bracketed form a browser sends, and a host whose last label is numeric must already be a dotted-quad IPv4 address. Onlyhttpsis accepted, except onlocalhost,127.0.0.1and::1, wherehttpis also accepted. - A suffix pattern,
https://*followed by a host suffix, for a dashboard whose hostname changes per deployment. The suffix starts with.or-, names at least three labels, and carries no port, path, query, fragment or trailing dot. It is matched as a byte suffix, not a DNS boundary, so it bounds a typo rather than guaranteeing that nobody else can claim a matching name on a shared hosting domain.
A bare * is refused, and so is any entry that could never equal a browser's Origin. cp-api refuses to start when an entry does not match this grammar, naming the entry's position and the rule it broke. Responses to an allowed origin never carry Access-Control-Allow-Credentials; the dashboard attaches API and session credentials as request headers.
The chart applies the same grammar at render time that cp-api applies at startup, so a value the chart accepts is one the control plane starts with.