> For the complete documentation index, see [llms.txt](https://docs.carto.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.carto.com/carto-self-hosted/best-practices/deployment/deployment-best-practices.md).

# Deployment best practices

## Overview

Follow these best practices to ensure a smooth and reliable CARTO Self-Hosted deployment.

## Infrastructure

{% hint style="info" %}
The recommendations in this section apply primarily to **Kubernetes (Helm or Kots)** deployments. For **Single VM (embedded cluster)** deployments, namespace and node pool management are handled automatically. We recommend focusing on choosing the right VM size, hardening the OS, and locking down firewall rules for ports 443 and 8800.
{% endhint %}

**Use a dedicated Kubernetes namespace:** We recommend deploying CARTO in its own namespace (e.g., `carto` or `carto-prod`). This isolates CARTO workloads from other applications, simplifies access control, and makes it easier to apply NetworkPolicies.

```bash
kubectl create namespace carto
```

**Separate dev and prod environments:** Never share a cluster or VM between development and production CARTO deployments. Use separate environments with separate licenses. See [Instances, Licenses & Organizations](/carto-self-hosted/concepts/instances-tenants-organizations.md).

## Database

**Use a managed PostgreSQL service:** We recommend using a cloud-managed PostgreSQL service (Cloud SQL, RDS, Azure Database for PostgreSQL) for production. Enable:

* Automated daily backups with at least 7-day retention
* High availability / Multi-AZ failover
* Automated storage scaling

**Set connection limits appropriately:** Configure `max_connections` on PostgreSQL to be at least 100, plus additional headroom for admin connections. CARTO's connection pool should be sized below this limit.

**Use a dedicated database user:** Create a dedicated PostgreSQL user for CARTO with only the permissions it needs (`CREATE`, `CONNECT`, schema ownership). Do not use the `postgres` superuser.

## Networking

**Use a dedicated domain:** Assign a dedicated subdomain to CARTO (e.g., `carto.yourcompany.com`). This must match your CARTO license domain and cannot be a subdirectory path.

**Terminate TLS at the ingress:** Use [TLS offloading](/carto-self-hosted/configuration/networking/tls-offloading.md) at your load balancer or ingress controller. Automate certificate renewal using cert-manager + Let's Encrypt or your cloud provider's certificate management service.

**Keep the cluster private:** Deploy your Kubernetes cluster in a private VPC. Expose only the ingress controller to the internet. Nodes, database, and Valkey should have no public endpoints.

**Use your cloud provider's native ingress controller (Kubernetes only):** Prefer the cloud-native ingress controller (GKE Ingress, AWS ALB Controller, Azure AGIC) for better integration with cloud load balancing, certificate management, and observability. The Single VM embedded cluster uses its own built-in load balancer, so no external ingress controller is needed.

## Cloud-specific recommendations

### Google Cloud Platform

* Use **GKE Standard** for reduced operational overhead
* Enable **Workload Identity** so CARTO pods authenticate to GCS and other GCP services without long-lived service account keys. See [Use Workload Identity in GCP](/carto-self-hosted/configuration/security/cloud-identities/use-workload-identity-in-gcp.md)
* Deploy the PostgreSQL database on **Cloud SQL with a Private IP** — no public endpoint

### Amazon Web Services

* Use **EKS with Managed Node Groups** to reduce node lifecycle management overhead
* Enable **EKS Pod Identity** so CARTO pods authenticate to S3 without long-lived access keys. See [Use EKS Pod Identity in AWS](/carto-self-hosted/configuration/security/cloud-identities/use-eks-pod-identity-in-aws.md)
* Deploy PostgreSQL on **Amazon RDS for PostgreSQL with Multi-AZ** enabled
* Use a **VPC with private subnets** and a NAT gateway for outbound traffic
* Use **AWS Certificate Manager (ACM)** with an ALB for free, auto-renewing TLS certificates

### Microsoft Azure

* Use **AKS with a system-managed identity** to avoid managing service principal credentials
* Deploy PostgreSQL on **Azure Database for PostgreSQL – Flexible Server** (Single Server is deprecated)
* Use **Azure Private Link** to connect to the database and storage from within your VNet without traversing the internet
* Use **Azure Application Gateway** with **Azure Key Vault** certificates for TLS management


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.carto.com/carto-self-hosted/best-practices/deployment/deployment-best-practices.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
