From d1e627303c92d8dd5690766680f40d1be2eead44 Mon Sep 17 00:00:00 2001 From: Joe Duffy Date: Tue, 11 Aug 2026 15:46:29 -0700 Subject: [PATCH 01/12] Surface security and fix the stale self-hosted framing Groundwork for making self-hosted Pulumi Cloud a first-class story. This is the subset that needed no design, legal, or engineering input. The /security/ "Read Whitepaper" button has been dead since January 2026. Commit 30aa059ca7 converted the whitepaper from a PDF page resource into a markdown content page and adjusted the .Resources.GetMatch call by dropping the .pdf suffix, but GetMatch only ever matches page resources -- content pages are not resources of their branch bundle, so the lookup returned nil and the button rendered href="". Switching to site.GetPage keeps the link resilient to a future rename, and the else branch errorf's rather than silently emitting nothing, since silent nil is what let this rot unnoticed for seven months. /security/ was also absent from the site header entirely. It now sits in the Product dropdown under a new "Security & trust" heading, which is deliberately named to accommodate the self-hosted entry that lands once that page is rebuilt -- self-hosting is a data-control decision before it is a deployment one, so the two belong together. The enterprise page advertised "VMWare vSphere" as a deployment option. No vSphere installer exists, and the tile behind that claim only ever pointed at a contact form, so the copy now names the six installations we actually ship. It also offered a "Request Free Trial" for self-hosting, which sets up a bad first interaction: there is no free trial, only a guided proof of concept gated at Business Critical. Spear AI moves from ai-ml to public-sector. The customer is the US Navy and the story is ATO, GovCloud, and air-gapped Secret Cloud; filing it under ai-ml left our one genuine defense reference invisible to anyone browsing public sector, a term page that had exactly one entry. Co-Authored-By: Claude Opus 5 (1M context) --- content/case-studies/spear-ai.md | 2 +- content/enterprise/_index.md | 8 ++++---- data/footer.yml | 2 +- data/header_nav.yaml | 8 ++++++++ data/pulumi_pricing.yaml | 2 +- layouts/security/section.html | 7 ++++++- 6 files changed, 21 insertions(+), 8 deletions(-) diff --git a/content/case-studies/spear-ai.md b/content/case-studies/spear-ai.md index 786bac718743..fd4bd9ef6138 100644 --- a/content/case-studies/spear-ai.md +++ b/content/case-studies/spear-ai.md @@ -6,7 +6,7 @@ description: | meta_desc: Learn how Spear AI used Pulumi to achieve government Authorization to Operate in 3 months. customer_name: Spear AI -industry: ai-ml +industry: public-sector customer_logo: /logos/customers/spearAI.svg logo_bg_color: "#000031" logo_style: white diff --git a/content/enterprise/_index.md b/content/enterprise/_index.md index 22f8c638cdf9..98651d3aef02 100644 --- a/content/enterprise/_index.md +++ b/content/enterprise/_index.md @@ -143,7 +143,7 @@ capabilities: icon: buildings icon_color: blue description: | - Enterprises that require specific data controls can use the self-hosted Pulumi service in their own cloud or datacenter and maintain complete control over their hosting, network isolation, identity, and data ownership. Deployment options include Kubernetes clusters, VMWare vSphere, virtual private clouds in AWS, Azure, Google Cloud, and many other configurations. + Enterprises that require specific data controls can run [self-hosted Pulumi Cloud](/product/self-hosted/) in their own cloud account or data center and maintain complete control over their hosting, network isolation, identity, and data ownership. Supported installations include AWS ECS and EKS, Azure AKS, Google GKE, any conformant Kubernetes cluster, and Docker on your own hosts. - title: Security icon: shield @@ -165,7 +165,7 @@ support: partners: title: Cloud Partners description: | - Pulumi works with the leading cloud providers including AWS, Google Cloud, and Microsoft Azure to ensure best-in-class support of the Pulumi Cloud Engineering Platform across each cloud. Pulumi provides Native Providers which enables same-day support of all new products and features in each cloud. Pulumi is also available for purchase through [AWS Marketplace](https://aws.amazon.com/marketplace/pp/prodview-dwn22batkhsyg) with support for additional cloud provider marketplaces coming soon. + Pulumi works with the leading cloud providers including AWS, Google Cloud, and Microsoft Azure to ensure best-in-class support of the Pulumi platform across each cloud. Pulumi provides Native Providers which enables same-day support of all new products and features in each cloud. Pulumi is also available for purchase through [AWS Marketplace](https://aws.amazon.com/marketplace/pp/prodview-dwn22batkhsyg) with support for additional cloud provider marketplaces coming soon. get_started: title: Get Started @@ -174,9 +174,9 @@ get_started: link: https://app.pulumi.com/site/trial/ link_text: Start Free Trial - - title: Self-Hosted Pulumi Service + - title: Self-Hosted Pulumi Cloud link: /product/self-hosted/#self-hosted-trial - link_text: Request Free Trial + link_text: Request a Proof of Concept - title: Migration Guide link: /docs/iac/guides/migration/ diff --git a/data/footer.yml b/data/footer.yml index 174f6c859337..d851307ff932 100644 --- a/data/footer.yml +++ b/data/footer.yml @@ -107,7 +107,7 @@ columns: - label: Awards href: /awards/ track: footer-awards - - label: Security + - label: Security & compliance href: /security/ track: footer-security - label: Brand diff --git a/data/header_nav.yaml b/data/header_nav.yaml index cbe1755e512f..fd70e7532b16 100644 --- a/data/header_nav.yaml +++ b/data/header_nav.yaml @@ -41,6 +41,14 @@ items: description: The fastest, most secure way to deliver cloud infrastructure icon: custom/pulumi-idp track: header-product-idp + - heading: Security & trust + columns: 2 + items: + - label: Security & compliance + href: /security/ + description: SOC 2 Type II, our security architecture, and the Pulumi Cloud security whitepaper + icon: shield-check + track: header-product-security - label: For engineers wide: true diff --git a/data/pulumi_pricing.yaml b/data/pulumi_pricing.yaml index 5cfb032e7424..349a1d00c1b3 100644 --- a/data/pulumi_pricing.yaml +++ b/data/pulumi_pricing.yaml @@ -212,7 +212,7 @@ editions: style: primary features_intro: "Everything in **Enterprise**, plus:" features: - - "[Self-hosting available](/product/self-hosted)" + - "[Self-hosting available](/product/self-hosted/)" - Built-in compliance (NIST, PCI, and more) - Automatic group & user sync (SCIM) - Audit logs export diff --git a/layouts/security/section.html b/layouts/security/section.html index beebc4c0048c..78c5dc78ba9a 100644 --- a/layouts/security/section.html +++ b/layouts/security/section.html @@ -21,7 +21,12 @@

{{ .Title }}

Learn more

Read our whitepaper to learn more about our product architecture and security practices.

- Read Whitepaper + {{/* The whitepaper is a content page, not a page resource, so .Resources.GetMatch never finds it. */}} + {{ with site.GetPage "/security/pulumi-cloud-security-whitepaper" }} + Read the whitepaper + {{ else }} + {{ errorf "layouts/security/section.html: security whitepaper page not found" }} + {{ end }}
From 4c3d925a05594f5a30d936beaf7169baed978a83 Mon Sep 17 00:00:00 2001 From: Joe Duffy Date: Tue, 11 Aug 2026 17:15:47 -0700 Subject: [PATCH 02/12] Adopt the June self-hosting work, corrected against installer source Revives the unmerged self-hosted-first-class branch from June 17 (e8405d50ee), rebased onto current master and reframed. Three pieces were worth keeping: the install front door, the Docker Compose quickstart rewrite, and the Terraform Enterprise migration guide. The original premise was self-serve -- "deploy it yourself," with the guided proof of concept demoted to a fallback. That premise depended on an evaluation license a user could obtain without a sales call, which the commit message itself flagged as not yet existing. It still doesn't, so a reader was told they could try it themselves and then hit a sales gate. The copy now says plainly that a license key comes from a proof of concept, while keeping every mechanical step documented, so when a self-serve license does ship only the license-acquisition sentence changes. The quickstart carried two errors forward from the page it replaced, both verified against quickstart-docker-compose/scripts/run-ee.sh: the script reads PULUMI_LOCAL_DATABASE_HOST, not PULUMI_LOCAL_DATABASE_NAME, and it creates a Docker network named pulumi-self-hosted-installers, not pulumi-ee. The bring-your-own-database section also told readers to ask sales for the migrations folder; the compose file pulls pulumi/migrations from Docker Hub. The Terraform Enterprise guide claimed air-gapped operation covers "environments that require FedRAMP." Pulumi holds no FedRAMP authorization, and self-hosting does not change that -- it changes who owns the boundary, so the bullet now says that instead. Self-hosting joins the header nav under the Security & trust heading added for it, alongside Security & compliance, because self-hosting is a data-control decision before it is a deployment one. Two page-level meta_image overrides were dropped: AGENTS.md discourages them for docs pages, where the build generates an on-brand card from the title. Co-Authored-By: Claude Opus 5 (1M context) --- .../administration/self-hosting/_index.md | 10 ++- .../self-hosting/deployment-options/_index.md | 4 +- .../quickstart-docker-compose.md | 83 +++++++++++------- .../self-hosting/install/_index.md | 85 +++++++++++++++++++ .../docs/iac/comparisons/terraform/_index.md | 12 ++- .../terraform/from-terraform-enterprise.md | 46 ++++++++++ content/docs/install/_index.md | 2 + content/pricing/_index.md | 2 +- content/product/_index.md | 9 ++ content/product/infrastructure-as-code.md | 6 +- data/header_nav.yaml | 10 +++ layouts/index.llms.txt | 1 + 12 files changed, 235 insertions(+), 35 deletions(-) create mode 100644 content/docs/administration/self-hosting/install/_index.md create mode 100644 content/docs/iac/comparisons/terraform/from-terraform-enterprise.md diff --git a/content/docs/administration/self-hosting/_index.md b/content/docs/administration/self-hosting/_index.md index 0646a6bc8e39..d177fd11558f 100644 --- a/content/docs/administration/self-hosting/_index.md +++ b/content/docs/administration/self-hosting/_index.md @@ -12,7 +12,7 @@ menu: administration: name: Self-Hosting parent: administration-home - weight: 40 + weight: 25 identifier: administration-self-hosting aliases: - /docs/guides/self-hosted/ @@ -32,6 +32,14 @@ sections: Pulumi can be deployed in any on-premise or cloud environment and integrated with your preferred identity provider: GitHub Enterprise, GitLab Enterprise, SAML SSO, or email/password authentication. +- type: button-cards + heading: Get started + cards: + - icon: rocket-launch + heading: Install Self-Hosted Pulumi Cloud + link: /docs/administration/self-hosting/install/ + description: Pick your platform and install. Evaluate with Docker Compose in minutes, or deploy to production on AWS, Azure, Google Cloud, or Kubernetes. + - type: button-cards heading: Deployment options cards: diff --git a/content/docs/administration/self-hosting/deployment-options/_index.md b/content/docs/administration/self-hosting/deployment-options/_index.md index 119c8c56f840..d004ca5ffad3 100644 --- a/content/docs/administration/self-hosting/deployment-options/_index.md +++ b/content/docs/administration/self-hosting/deployment-options/_index.md @@ -14,9 +14,9 @@ aliases: - /docs/pulumi-cloud/admin/self-hosted/deployment-options/ pulumi_cloud_feature: self-hosting --- -Pulumi offers a number of deployment options for self-hosting the Pulumi Cloud. +Pulumi offers a number of deployment options for self-hosting the Pulumi Cloud. To get started, see [Install Self-Hosted Pulumi Cloud](/docs/administration/self-hosting/install/), which walks you through each platform. Use Docker Compose to evaluate on a single host in minutes; the other options are production deployments. -* [Docker Compose](quickstart-docker-compose/) +* [Docker Compose](quickstart-docker-compose/) — evaluation and testing * [ECS](ecs-hosted/) * [EKS](eks-hosted/) * [AKS](aks-hosted/) diff --git a/content/docs/administration/self-hosting/deployment-options/quickstart-docker-compose.md b/content/docs/administration/self-hosting/deployment-options/quickstart-docker-compose.md index c0d19ef51d64..77277f852305 100644 --- a/content/docs/administration/self-hosting/deployment-options/quickstart-docker-compose.md +++ b/content/docs/administration/self-hosting/deployment-options/quickstart-docker-compose.md @@ -1,8 +1,8 @@ --- -title_tag: Quickstart Docker Compose | Self-Hosting Pulumi -meta_desc: Quickstart Docker compose installer for testing of the self-hosted Pulumi Cloud. +title_tag: Try Self-Hosted Pulumi Cloud with Docker Compose +meta_desc: Evaluate self-hosted Pulumi Cloud in about ten minutes with the all-in-one Docker Compose stack. title: Docker Compose -h1: Pulumi Cloud self-hosted Docker Compose install +h1: Try Self-Hosted Pulumi Cloud with Docker Compose menu: administration: name: Docker Compose @@ -16,49 +16,74 @@ aliases: pulumi_cloud_feature: self-hosting --- -The Pulumi Cloud Docker container images can be run using any OCI-compatible container orchestrator. We provide sample docker-compose files that can help you get started with your self-evaluation quickly. +The fastest way to try self-hosted Pulumi Cloud is the all-in-one Docker Compose stack. It runs the API, the web Console, a migrated MySQL database, and OpenSearch on a single host with working defaults, so you can evaluate the full platform in about ten minutes. Use it for evaluation and testing; for production, see the [production deployment options](/docs/administration/self-hosting/deployment-options/). -> **Note**: docker-compose is not required to run these containers. We recommend that you choose a container orchestrator with which your IT team has experience. +## Prerequisites -In addition to the environment variables that each container exposes, the following can be set when using either of the quickstart solutions below. These are used by the `run-ee.sh` script provided to you as part of the self-evaluation package. If any of these variables are not set when you run `run-ee.sh`, the default values will be used. +- [Docker Engine](https://docs.docker.com/engine/install/) with the Docker Compose plugin (v2). +- A host with at least 2 CPU cores, 8 GB of memory, and 20 GB of free disk. +- Ports `3000` (Console), `8080` (API), and `9200`/`5601` (OpenSearch) available on the host. +- A Pulumi license key. -`PULUMI_DATA_PATH`: The persistent path where the service should store the checkpoint objects. Default uses `/tmp/pulumi-ee/data`. +{{% notes type="info" %}} +`run-ee.sh` exits immediately if `PULUMI_LICENSE_KEY` is not set. [Request an evaluation license](/product/self-hosted/#self-hosted-trial) and a solutions architect will get you a key. +{{% /notes %}} -`PULUMI_LOCAL_DATABASE_NAME`: The database instance’s hostname. Default is `pulumi-db`. +## Run the all-in-one stack -`PULUMI_LOCAL_DATABASE_PORT`: The database instance’s port. Default is `3306`. +1. Clone the installer and change into the quickstart directory: -For example, `PULUMI_DATA_PATH=/my/persistent/dir LOCAL_DATABASE_NAME=my-db LOCAL_DATABASE_PORT=3306 ./scripts/run-ee.sh`. + ```bash + git clone https://github.com/pulumi/pulumi-self-hosted-installers.git + cd pulumi-self-hosted-installers/quickstart-docker-compose + ``` -Regardless of the quickstart option you choose below, `run-ee.sh` will be the way to start the necessary containers. There will be at most 3 containers (including the DB) for the system to be considered complete. +1. Set your license key: -## Quickstart Docker Compose Deployment Options + ```bash + export PULUMI_LICENSE_KEY= + ``` -The [Quickstart Docker Compose Installer](https://github.com/pulumi/pulumi-self-hosted-installers/tree/master/quickstart-docker-compose) is used to deploy a test system using Docker. +1. Start the stack: -### Option #1 - Using the all-in-one approach + ```bash + ./scripts/run-ee.sh -f ./all-in-one/docker-compose.yml + ``` -If you would like to use Pulumi’s all-in-one solution, you just need to run `run-ee.sh` like this: `run-ee.sh -f ./all-in-one/docker-compose.yml`. This will start all components using working defaults, including a DB container that is migrated using our DB scripts. + This starts every component with working defaults, including a MySQL container that is migrated automatically. Checkpoint data is stored under `$HOME/pulumi-self-hosted-installers/data` by default; override it with `PULUMI_DATA_PATH`. -{{% notes type="info" %}} -Environment variables should be set in the `./all-in-one/docker-compose.yml` file. -{{% /notes %}} +1. Open the Console at [http://localhost:3000](http://localhost:3000) and create the first account. The first user to register becomes an administrator. -### Option #2 - Provide your own Database +1. Point the CLI at your instance and follow the prompt to create an access token: -The service is tested against a MySQL version 8.0 instance. It is assumed that you have a DB instance called `pulumi-db` running at port `3306` and accessible within a network called `pulumi-ee`. + ```bash + pulumi login http://localhost:8080 + ``` -{{% notes type="info" %}} -You will need the `migrations` folder downloaded locally, which contains the DB scripts that need to be applied against your DB instance. -Your Pulumi sales contact should be able to provide you with this. -{{% /notes %}} +1. Verify the connection: + + ```bash + pulumi whoami + ``` + +To stop the stack, press `Ctrl+C`, then remove the containers with `docker compose -f ./all-in-one/docker-compose.yml down`. Delete the data directory to discard evaluation state. + +## Advanced configuration + +The `run-ee.sh` script honors the following environment variables; unset variables fall back to working defaults: + +- `PULUMI_DATA_PATH`: persistent path for checkpoint objects. Defaults to `$HOME/pulumi-self-hosted-installers/data`. +- `PULUMI_LOCAL_DATABASE_HOST`: the database hostname. Defaults to `pulumi-db`. +- `PULUMI_LOCAL_DATABASE_PORT`: the database port. Defaults to `3306`. + +Other settings — identity providers, object storage, encryption keys — are configured in the `environment` blocks of `./all-in-one/docker-compose.yml`. See [Components](/docs/administration/self-hosting/components/) for the full set of variables each container accepts. -## Quickstart Docker Compose System Management and Maintenance +### Bring your own database -Since the quickstart option is meant to be used for testing purposes, there is no real maintenance or management needed other than perhaps updating the service containers with the latest versions. +To run against an existing MySQL 8.0 instance instead of the bundled database, start the service with the base `docker-compose.yml` and point `PULUMI_LOCAL_DATABASE_HOST` and `PULUMI_LOCAL_DATABASE_PORT` at it. The script creates and uses a Docker network named `pulumi-self-hosted-installers`, so the database must be reachable from that network. -### Updating the Pulumi Cloud Containers +The schema is applied by the `pulumi/migrations` container, which the compose file pulls from Docker Hub — you do not need to obtain migration scripts separately. -For testing purposes, it is recommended to use the `latest` image tag in the docker compose file and re-run the `run-ee.sh` script when there are newer versions of the service image pushed to docker hub. +## Updating -If you specified a specific image version in the docker compose file, then update the version tag and re-run the `run-ee.sh` script. +For evaluation, pin the `latest` image tag in the compose file and re-run `run-ee.sh` to pull newer service images. If you pinned a specific version, update the tag and re-run the script. diff --git a/content/docs/administration/self-hosting/install/_index.md b/content/docs/administration/self-hosting/install/_index.md new file mode 100644 index 000000000000..a85f2ab84901 --- /dev/null +++ b/content/docs/administration/self-hosting/install/_index.md @@ -0,0 +1,85 @@ +--- +title_tag: Install Self-Hosted Pulumi Cloud +meta_desc: Install self-hosted Pulumi Cloud on your platform — evaluate in minutes with Docker Compose, or deploy to production on AWS, Azure, Google Cloud, or Kubernetes. +title: Install +h1: Install Self-Hosted Pulumi Cloud +weight: 1 +menu: + administration: + name: Install + parent: administration-self-hosting + weight: 0 + identifier: administration-self-hosting-install +aliases: + - /self-hosted/install/ +pulumi_cloud_feature: self-hosting +--- + +Run the full Pulumi Cloud platform in your own cloud account or data center. Start with the all-in-one Docker Compose stack to evaluate on a single host, then choose a production deployment for your platform. + +{{% notes type="info" %}} +Every installation needs a license key. [Request a Proof of Concept (PoC)](/product/self-hosted/#self-hosted-trial) and a solutions architect will get you an evaluation key and walk through sizing. Self-hosting is available with the [Business Critical edition](/pricing/). +{{% /notes %}} + +## Choose your platform + +{{< chooser cloud "docker,kubernetes,aws,azure,gcp" >}} + +{{% choosable cloud docker %}} + +The all-in-one Docker Compose stack runs the API, Console, database, and search on a single host — the fastest way to try self-hosted Pulumi Cloud. + +```bash +git clone https://github.com/pulumi/pulumi-self-hosted-installers.git +cd pulumi-self-hosted-installers/quickstart-docker-compose +export PULUMI_LICENSE_KEY= +./scripts/run-ee.sh -f ./all-in-one/docker-compose.yml +``` + +Then open the Console at [http://localhost:3000](http://localhost:3000), create the first account, and run `pulumi login http://localhost:8080`. + +See the [Docker Compose quickstart](/docs/administration/self-hosting/deployment-options/quickstart-docker-compose/) for prerequisites, first login, verification, and teardown. + +{{% /choosable %}} + +{{% choosable cloud kubernetes %}} + +Deploy to your own Kubernetes cluster with MySQL and S3-compatible object storage. This is the most flexible production option and works in any environment, including air-gapped networks. + +See [Bring your own infrastructure](/docs/administration/self-hosting/deployment-options/byo-infra-hosted/) for the Kubernetes deployment guide. + +{{% /choosable %}} + +{{% choosable cloud aws %}} + +Deploy a production system on AWS. Two managed options are available: + +- [Amazon EKS](/docs/administration/self-hosting/deployment-options/eks-hosted/) — Kubernetes-based, with RDS Aurora, S3, and CloudWatch. +- [Amazon ECS](/docs/administration/self-hosting/deployment-options/ecs-hosted/) — ECS and Fargate, with RDS Aurora, S3, and an Application Load Balancer. + +{{% /choosable %}} + +{{% choosable cloud azure %}} + +Deploy a production system on [Azure Kubernetes Service](/docs/administration/self-hosting/deployment-options/aks-hosted/) with Azure Database for MySQL and Azure Blob Storage. + +{{% /choosable %}} + +{{% choosable cloud gcp %}} + +Deploy a production system on [Google Kubernetes Engine](/docs/administration/self-hosting/deployment-options/gke-hosted/) with Cloud SQL for MySQL and Cloud Storage. + +{{% /choosable %}} + +{{< /chooser >}} + +## Before you go to production + +The deployment guides stand up a working system. Before you run production workloads, review the [Operations guide](/docs/administration/self-hosting/operations/) for high availability, backup and recovery, monitoring, sizing, and security hardening, and the [Network requirements](/docs/administration/self-hosting/network/) for ingress, egress, and air-gapped configurations. + +## Next steps + +- [Docker Compose quickstart](/docs/administration/self-hosting/deployment-options/quickstart-docker-compose/) +- [All deployment options](/docs/administration/self-hosting/deployment-options/) +- [Components and configuration](/docs/administration/self-hosting/components/) +- [Operations guide](/docs/administration/self-hosting/operations/) diff --git a/content/docs/iac/comparisons/terraform/_index.md b/content/docs/iac/comparisons/terraform/_index.md index d97d2a33f6d1..0f18728fc8c5 100644 --- a/content/docs/iac/comparisons/terraform/_index.md +++ b/content/docs/iac/comparisons/terraform/_index.md @@ -52,8 +52,9 @@ Terraform is an infrastructure as code tool created by HashiCorp (acquired by IB | Modularity and reuse | [Component Resources](/docs/iac/concepts/components/) authored in any supported language; [Pulumi Packages](/docs/iac/concepts/packages/) let a component written in one language be consumed from any Pulumi language; language-native package managers (npm, PyPI, NuGet, Maven, Go modules); the [Pulumi Registry](/registry/) for publicly available packages; plus existing [Terraform modules](/docs/iac/guides/building-extending/using-existing-tools/use-terraform-module/) consumed directly and [hosted in Pulumi Cloud's registry](/docs/idp/concepts/terraform-modules/) | [Terraform modules](https://developer.hashicorp.com/terraform/language/modules) (HCL) and the [Terraform Registry](https://registry.terraform.io/) for public modules | | Import existing resources | [`pulumi import`](/docs/iac/guides/migration/import/) and the [`import` resource option](/docs/iac/concepts/resources/options/import/), both of which generate code in your language | [`terraform import`](https://developer.hashicorp.com/terraform/cli/commands/import) and [`import` blocks](https://developer.hashicorp.com/terraform/language/import); HCL must be hand-authored, though `terraform plan -generate-config-out` can emit a draft | | Policy as code | [Pulumi Policies](/docs/insights/policy/) — open source, with rules written in Python, TypeScript, or Open Policy Agent Rego; Pulumi Cloud commercial plans add centralized policy management plus [Pulumi-maintained policy packs](/docs/insights/policy/policy-packs/pre-built-packs/) for compliance frameworks like CIS, HITRUST, NIST, and PCI DSS | [Sentinel](https://developer.hashicorp.com/sentinel) (proprietary, HCP Terraform / Enterprise only) and Open Policy Agent | +| Self-hosting and on-prem | [Self-hosted Pulumi Cloud](/product/self-hosted/) runs the entire platform — state, secrets, RBAC, policy, and deployments — in your own cloud account or data center, including air-gapped environments, with the same capabilities as the SaaS | [Terraform Enterprise](https://developer.hashicorp.com/terraform/enterprise) is HashiCorp's self-managed offering; Sentinel policy, run tasks, and no-code provisioning are gated to HCP Terraform and Enterprise tiers | | Open source | Yes — [Apache License 2.0](https://github.com/pulumi/pulumi/blob/master/LICENSE) | No — [Business Source License 1.1](https://github.com/hashicorp/terraform/blob/main/LICENSE) | -| Commercial option | [Pulumi Cloud](/docs/iac/guides/basics/pulumi-cloud-vs-oss/) | HCP Terraform / Terraform Enterprise | +| Commercial option | [Pulumi Cloud](/docs/iac/guides/basics/pulumi-cloud-vs-oss/) — SaaS or [self-hosted](/product/self-hosted/) | HCP Terraform (SaaS) / Terraform Enterprise (self-managed) | ## Real-world results @@ -83,6 +84,10 @@ Pulumi Cloud manages state by default — encrypted in transit and at rest, vers Pulumi Cloud can also serve as the [state backend for Terraform and OpenTofu](/docs/iac/get-started/terraform/terraform-state-backend/). It implements Terraform's remote backend API, so a team points the Terraform CLI at Pulumi Cloud with a standard `backend "remote"` block and keeps its existing HCL and day-to-day workflow unchanged. In return they get encrypted state, update history, automatic state locking, RBAC, audit policies, and a unified view of Terraform-managed resources alongside Pulumi-managed ones in [Resource Search](/docs/pulumi-cloud/insights/search/). Root module outputs surface as Pulumi [stack outputs](/docs/iac/concepts/stacks/#stackreferences), so other stacks can consume them without extra credentials. This makes Pulumi Cloud a governance and visibility plane you can adopt on its own merits, not only a stepping stone to converting code. +### Self-hosting and data control + +Both platforms offer a self-managed deployment for teams that can't use SaaS. Terraform Enterprise is HashiCorp's self-managed product. [Self-hosted Pulumi Cloud](/product/self-hosted/) runs the complete platform — state, secrets, RBAC, policy enforcement, and deployments — inside your own cloud account or data center, including fully air-gapped networks with no egress to the public internet. Data lives in a database and object store you control, and you integrate your own identity provider (GitHub Enterprise, GitLab, SAML SSO, and others). The self-hosted edition tracks the same capabilities as the SaaS, so teams evaluate features once and choose the deployment topology that fits their compliance posture. See the [self-hosting docs](/docs/administration/self-hosting/) for deployment options across AWS, Azure, Google Cloud, Kubernetes, and Docker. + ### Secrets handling Pulumi treats secrets as a first-class primitive. Values marked as secrets are encrypted in transit and at rest in the state file, anything derived from a secret is also encrypted, and each stack has its own encryption key. The default encryption provider can be replaced with [AWS KMS, Azure Key Vault, Google Cloud KMS, or HashiCorp Vault](/docs/iac/concepts/secrets/#available-encryption-providers). Terraform does not encrypt sensitive values in its state file; the recommended approach is to integrate with HashiCorp Vault, which is a separate product. HCP Terraform encrypts state at rest, but values inside that state are still readable to anyone with access to the workspace. @@ -166,9 +171,14 @@ Yes. [Pulumi HCL](/docs/iac/languages-sdks/hcl/) is a supported language: a proj [`pulumi refresh`](/docs/iac/cli/commands/pulumi_refresh/) compares the state file to the actual state in the cloud and reports differences, and `pulumi preview --diff` shows what would change on the next update. Pulumi Cloud commercial plans add [scheduled drift detection and remediation](/docs/deployments/concepts/drift/) that runs on a configurable cadence and can auto-remediate. +### Can I run Pulumi on-prem like Terraform Enterprise? + +Yes. [Self-hosted Pulumi Cloud](/product/self-hosted/) runs the full platform in your own cloud account or data center, including air-gapped environments, with the same state, secrets, RBAC, policy, and deployment capabilities as the SaaS. It's available with the Business Critical edition; see the [self-hosting documentation](/docs/administration/self-hosting/) for deployment options and requirements. + ## Next steps * [Get started with Pulumi](/docs/iac/get-started/) +* [Migrating from Terraform Enterprise to self-hosted Pulumi Cloud](/docs/iac/comparisons/terraform/from-terraform-enterprise/) * [Pulumi HCL: run Terraform HCL on Pulumi](/docs/iac/languages-sdks/hcl/) * [Pulumi terms and command equivalents for Terraform users](/docs/iac/comparisons/terraform/terminology/) * [Using Pulumi Cloud as a Terraform state backend](/docs/iac/get-started/terraform/terraform-state-backend/) diff --git a/content/docs/iac/comparisons/terraform/from-terraform-enterprise.md b/content/docs/iac/comparisons/terraform/from-terraform-enterprise.md new file mode 100644 index 000000000000..6d36bd011fdd --- /dev/null +++ b/content/docs/iac/comparisons/terraform/from-terraform-enterprise.md @@ -0,0 +1,46 @@ +--- +title_tag: "Migrating from Terraform Enterprise to Pulumi" +meta_desc: How teams running self-managed Terraform Enterprise move to self-hosted Pulumi Cloud — the same on-prem operating model, with a phased migration path. +title: From Terraform Enterprise +h1: Migrating from Terraform Enterprise to Self-Hosted Pulumi Cloud +menu: + iac: + name: From Terraform Enterprise + parent: iac-comparisons-terraform + weight: 3 +aliases: + - /docs/iac/comparisons/terraform/migrating-from-terraform-enterprise/ +--- + +Terraform Enterprise teams run infrastructure as code on their own infrastructure for data control, network isolation, and compliance. [Self-hosted Pulumi Cloud](/product/self-hosted/) offers the same operating model: the complete Pulumi Cloud platform — state, secrets, RBAC, policy, and deployments — running in your own cloud account or data center, including fully air-gapped networks. This guide is for teams evaluating a move from Terraform Enterprise to Pulumi without giving up self-management. + +## What you get with self-hosted Pulumi Cloud + +Self-hosted Pulumi Cloud runs the same platform as the [SaaS](https://app.pulumi.com/), so teams evaluate features once and choose the deployment topology that fits their compliance posture: + +- **The full platform in your environment.** State management, secrets, role-based access control, [policy enforcement](/docs/insights/policy/), and [deployments](/docs/deployments/) all run on infrastructure you operate. +- **Data you control.** State and secrets live in a MySQL database and an object store within your own network. Encryption keys can be managed locally or through AWS KMS or Azure Key Vault. +- **Air-gapped operation.** Run with no egress to the public internet. Because you install and operate it, the deployment sits inside a compliance boundary you own and assess. +- **Your identity provider.** Integrate GitHub Enterprise, GitLab, SAML SSO, and others. + +For a feature-by-feature comparison of the two tools, see [Pulumi vs. Terraform](/docs/iac/comparisons/terraform/). + +## How migration works + +You don't rewrite everything at once. Pulumi is designed to adopt incrementally, and these paths combine: + +1. **Run side by side.** Pulumi programs can [reference existing Terraform state](/docs/iac/guides/migration/migrating-to-pulumi/from-terraform/#referencing-terraform-state) and read its outputs, so you keep existing infrastructure in Terraform while adopting Pulumi for new work. +1. **Store Terraform state in Pulumi.** [Pulumi Cloud can act as a Terraform state backend](/docs/iac/get-started/terraform/terraform-state-backend/), giving you encrypted state, history, locking, RBAC, and audit policies while you continue to run Terraform day-to-day. +1. **Convert HCL.** [`pulumi convert --from terraform`](/docs/iac/guides/migration/migrating-to-pulumi/from-terraform/#converting-terraform-hcl-to-pulumi) translates Terraform HCL into a Pulumi program in the language of your choice, preserving names, modules, and structure where possible. +1. **Import existing resources.** [`pulumi import`](/docs/iac/guides/migration/import/) brings already-provisioned resources under Pulumi management and generates the corresponding code. + +For a complete walkthrough including bulk conversion and state migration, see [Migrating from Terraform to Pulumi](/docs/iac/guides/migration/migrating-to-pulumi/from-terraform/). + +## Pricing + +Self-hosted Pulumi Cloud is available with the Business Critical edition. See [pricing](/pricing/) for what each edition includes, and [contact us](/contact/) to discuss licensing and an evaluation for your environment. + +## Get started + +1. [Request a Proof of Concept (PoC)](/product/self-hosted/#self-hosted-trial) to get an evaluation license key and a solutions architect to size the install. +1. Follow the [install guide](/docs/administration/self-hosting/install/) — evaluate on a single host with Docker Compose, then deploy to production on AWS, Azure, Google Cloud, or Kubernetes. diff --git a/content/docs/install/_index.md b/content/docs/install/_index.md index fb3f7d465cab..92e4589a71f2 100644 --- a/content/docs/install/_index.md +++ b/content/docs/install/_index.md @@ -38,6 +38,8 @@ The latest version of Pulumi is **{{< latest-version >}}**. For previous version By default, the Pulumi CLI stores state in [Pulumi Cloud](/docs/iac/guides/basics/pulumi-cloud-vs-oss/), our free, hosted state-management backend. Pulumi Cloud is free for individuals and is the recommended backend when you're learning Pulumi — no credit card required. If you'd rather host state yourself (S3, Azure Blob, GCS, or local), see [self-managed state backends](/docs/iac/concepts/state-and-backends/). +Organizations that need to keep everything in their own environment can run the full Pulumi Cloud platform self-hosted — the same managed experience as the SaaS, in your own cloud account or data center. See [self-hosted Pulumi Cloud](/product/self-hosted/) and the [self-hosting docs](/docs/administration/self-hosting/). + {{% notes type="info" %}} You don't need a Pulumi Cloud account to install the CLI. You'll be prompted to sign in (or to pick a self-managed backend) the first time you run `pulumi login`. {{% /notes %}} diff --git a/content/pricing/_index.md b/content/pricing/_index.md index 1f537bf84db2..03d13d72662e 100644 --- a/content/pricing/_index.md +++ b/content/pricing/_index.md @@ -138,7 +138,7 @@ faq: - question: Is Pulumi SOC 2 compliant? answer: Yes, Pulumi has completed the SOC 2 Type 2 compliance process. Pulumi is committed to operational excellence for our customers. - question: Can I host Pulumi Cloud in my cloud or datacenter? - answer: Yes, we offer a self-hosted Pulumi Cloud for companies that have specific data control requirements and want to maintain complete control over hosting Pulumi Cloud. This option is available in Business Critical Edition. You can [request a Proof of Concept (PoC)](/product/self-hosted/#self-hosted-trial) to get started. + answer: Yes, we offer a self-hosted Pulumi Cloud for companies that have specific data control requirements and want to maintain complete control over hosting Pulumi Cloud. This option is available in Business Critical Edition. The [install guide](/docs/administration/self-hosting/install/) covers every deployment option, from a single-host Docker Compose evaluation to production on AWS, Azure, Google Cloud, and Kubernetes. [Request a Proof of Concept (PoC)](/product/self-hosted/#self-hosted-trial) to get an evaluation license key. - question: How do I convince my boss? answer: | Do you want to use Pulumi in your organization, but aren't sure how to bring it up with your boss? We've created a sample email to help you explain its benefits. Feel free to use the full letter or pieces of it. We are always happy to meet to learn more about your needs and explain these benefits in person — just [contact us](/contact/?form=sales). diff --git a/content/product/_index.md b/content/product/_index.md index 15ee2068de80..f526b40cefbd 100644 --- a/content/product/_index.md +++ b/content/product/_index.md @@ -149,6 +149,15 @@ sections: Drift detection, dependency management, and enterprise RBAC give you visibility and control across the full infrastructure lifecycle. anchor: idp + - type: section_header + tag_line: Deployment options + title: Run Pulumi Cloud anywhere + description: | + Use Pulumi Cloud as a fully managed SaaS, or run the same platform yourself in your own cloud account or data center. Self-hosted Pulumi Cloud gives you complete control over data, identity, and network isolation, including air-gapped environments, with the same IaC, secrets, insights, and governance capabilities. + cta_text: Explore self-hosted Pulumi Cloud + cta_link: /product/self-hosted/ + anchor: self-hosted + - type: two_column anchor: get-started highlight_first_card: true diff --git a/content/product/infrastructure-as-code.md b/content/product/infrastructure-as-code.md index 47afedd34240..77a7167749e5 100644 --- a/content/product/infrastructure-as-code.md +++ b/content/product/infrastructure-as-code.md @@ -144,7 +144,7 @@ sections: title: Open source core. title_line_2: Pulumi Cloud built-in. description: | - Get started with Pulumi Cloud for free, state management and secrets included. Our [open source engine](https://github.com/pulumi/pulumi) powers everything underneath. Scale to enterprise features when you need them, or self-host if required. + Get started with Pulumi Cloud for free, state management and secrets included. Our [open source engine](https://github.com/pulumi/pulumi) powers everything underneath. Scale to enterprise features when you need them, and run the same platform [fully self-hosted](/product/self-hosted/) in your own cloud or data center. image: /images/product/infrastructure-as-code/pulumi-concentric-circles.svg image_alt: Open source core and Pulumi Cloud image_above: true @@ -397,4 +397,8 @@ sections: title: Complete audit trail description: | Every action logged. Who changed what, when, and why. Export to SIEM. Compliance reports at your fingertips. + - icon: buildings + title: Self-host the whole platform + description: | + Run all of Pulumi Cloud in your own cloud account or data center. Full control over data, identity, and network, including air-gapped deployments. [Learn about self-hosting](/product/self-hosted/). --- diff --git a/data/header_nav.yaml b/data/header_nav.yaml index fd70e7532b16..1281347ee5c9 100644 --- a/data/header_nav.yaml +++ b/data/header_nav.yaml @@ -44,6 +44,11 @@ items: - heading: Security & trust columns: 2 items: + - label: Self-hosted Pulumi Cloud + href: /product/self-hosted/ + description: Run the full Pulumi Cloud platform in your own cloud account or data center + icon: buildings + track: header-product-self-hosted - label: Security & compliance href: /security/ description: SOC 2 Type II, our security architecture, and the Pulumi Cloud security whitepaper @@ -114,6 +119,11 @@ items: description: Security, compliance, and support for teams icon: buildings track: header-enterprise-solutions + - label: Self-hosted Pulumi Cloud + href: /product/self-hosted/ + description: Full data control, air-gapped and on-prem deployment options + icon: shield-check + track: header-enterprise-self-hosted - label: Case studies href: /case-studies/ description: How Snowflake, Mercedes-Benz, and others use Pulumi diff --git a/layouts/index.llms.txt b/layouts/index.llms.txt index f0e576c5fb99..1b2ce3ab21db 100644 --- a/layouts/index.llms.txt +++ b/layouts/index.llms.txt @@ -74,6 +74,7 @@ If you are an AI agent or programmatic consumer, start with these endpoints. Eac This llms.txt covers www.pulumi.com, which includes: - [Product](https://www.pulumi.com/product/): Pulumi Cloud platform overview and capabilities +- [Self-hosted Pulumi Cloud](https://www.pulumi.com/product/self-hosted/): Run the full Pulumi Cloud platform in your own cloud account or data center, including air-gapped environments - [Pricing](https://www.pulumi.com/pricing/): Plans and pricing for Pulumi Cloud (Individual, Team, Enterprise, Business Critical) - [Pulumi Registry](https://www.pulumi.com/registry/): Documentation for 150+ cloud providers and components, available at `https://www.pulumi.com/registry/packages//` - [Infrastructure AI](https://www.pulumi.com/docs/ai/): Using AI agents with Pulumi — bring your own agent via [Agent Skills](https://www.pulumi.com/docs/ai/skills/) and the [MCP server](https://www.pulumi.com/docs/ai/mcp-server/), or use [Pulumi Neo](https://www.pulumi.com/neo/), Pulumi's purpose-built infrastructure agent From d89f6dae3961bea9089a4e2b133c1b065475cc3a Mon Sep 17 00:00:00 2001 From: Joe Duffy Date: Tue, 11 Aug 2026 17:20:46 -0700 Subject: [PATCH 03/12] Correct self-hosting docs against installer source Every fix here was verified against pulumi-self-hosted-installers rather than reasoned about, because the errors all share a cause: prose that was written once and never rechecked against the code it describes. The console page told readers "the container image repository is private. Contact us if you would like to evaluate." Both images are public -- pulumi/service reports 220,518 pulls and pulumi/console 114,034 against the Docker Hub API -- so that sentence was turning away self-evaluation for no reason. The API page repeated the PULUMI_LOCAL_DATABASE_NAME error corrected on the quickstart page; run-ee.sh reads PULUMI_LOCAL_DATABASE_HOST. The EKS page documented Kubernetes 1.18 through 1.21 and an `npm run install -- update --` command. Both describe eks-hosted-deprecated, whose README now opens with DEPRECATED and whose revision table stops at K8s 1.24 in February 2024. The current installer is v4.0 and the version is set through `clusterVersion` in the 05-eks-cluster project. Note an upstream inconsistency worth chasing: that project's Pulumi.README.yaml still ships clusterVersion "1.30" while the installer README's revision history claims 1.34.0 for v4.0, so the table here follows the revision history and the page deliberately states no default. The air-gapped guide told readers to deploy with Helm. No chart exists in the installers repo or anywhere else, so it now points at the bring-your-own-infra installer, which is what actually applies manifests to an existing cluster. It also linked to /docs/administration/self-hosting/pulumi-cloud, an alias of the section index -- a self-referential link. The operations database page presented db.r5.large as "the self-hosted installers default," which is true only for EKS; the ECS installer defaults to db.t3.small, a burstable instance nobody should reach production on unknowingly. The table is now per-installer. Finally, the nine pages that were missing the edition callout now carry {{< self-hosting-trial-note />}}, so every self-hosting page states how to get a license instead of only some of them. Co-Authored-By: Claude Opus 5 (1M context) --- .../administration/self-hosting/airgapped.md | 6 ++--- .../self-hosting/components/api.md | 4 ++-- .../self-hosting/components/console.md | 2 +- .../self-hosting/deployment-options/_index.md | 3 +++ .../deployment-options/aks-hosted.md | 2 ++ .../deployment-options/byo-infra-hosted.md | 2 ++ .../deployment-options/ecs-hosted.md | 2 ++ .../deployment-options/eks-hosted.md | 23 +++++++++++++------ .../deployment-options/gke-hosted.md | 2 ++ .../deployment-options/local-docker.md | 2 ++ .../quickstart-docker-compose.md | 2 ++ .../self-hosting/install/_index.md | 6 ++--- .../self-hosting/operations/database.md | 9 ++++---- .../administration/self-hosting/saml-sso.md | 2 ++ 14 files changed, 47 insertions(+), 20 deletions(-) diff --git a/content/docs/administration/self-hosting/airgapped.md b/content/docs/administration/self-hosting/airgapped.md index 4092b89e3586..d1368bef0f58 100644 --- a/content/docs/administration/self-hosting/airgapped.md +++ b/content/docs/administration/self-hosting/airgapped.md @@ -19,7 +19,7 @@ pulumi_cloud_feature: self-hosting For organizations operating in highly regulated industries or environments with strict security requirements, deploying cloud infrastructure in an air-gapped environment is often a requirement. Such environments do not have network connectivity with the outside world, which many of Pulumi's default workflows assume. -Pulumi can be configured to run in air-gapped environments through [self-hosting](/docs/administration/self-hosting/pulumi-cloud), enabling enterprises to manage infrastructure as code securely within their private networks, remaining compliant while gaining the benefits of modern infrastructure automation. +Pulumi can be configured to run in air-gapped environments through [self-hosting](/docs/administration/self-hosting/), enabling enterprises to manage infrastructure as code securely within their private networks, remaining compliant while gaining the benefits of modern infrastructure automation. In this guide, we will explore how to deploy Pulumi Self-Hosted in an air-gapped environment, covering the key requirements, setup process, and best practices. @@ -93,8 +93,8 @@ Pulumi Self-Hosted can be installed using Kubernetes, Docker, or virtual machine 2. Download the [Pulumi Self-Hosted images](/docs/administration/self-hosting/components) * Retrieve the necessary installation files and images from a networked machine. * Transfer them to your air-gapped environment using an offline medium (USB drive, offline repository, etc.). -3. Install Pulumi Self-Hosted (for instance, on Kubernetes) per [these instructions](/docs/administration/self-hosting/deployment-options) - * Deploy the Pulumi API server, database, and storage backend using Helm or static manifests. +3. Install Pulumi Self-Hosted (for instance, on Kubernetes) per the [install guide](/docs/administration/self-hosting/install/) + * Deploy the Pulumi API server, database, and storage backend with the [bring-your-own-infrastructure installer](/docs/administration/self-hosting/deployment-options/byo-infra-hosted/), which applies Kubernetes manifests to a cluster you already operate. * Configure internal object storage (e.g., MinIO or an internal S3-compatible service) for state management. 4. Configure Authentication and Access Control * Integrate with your organization's internal identity provider (OIDC, LDAP, SAML). diff --git a/content/docs/administration/self-hosting/components/api.md b/content/docs/administration/self-hosting/components/api.md index a29ba0f3d510..db082c91d184 100644 --- a/content/docs/administration/self-hosting/components/api.md +++ b/content/docs/administration/self-hosting/components/api.md @@ -26,9 +26,9 @@ The Pulumi API is one of the components required for self-hosting the Pulumi Clo * Provide a server or virtual machine to install and run the Pulumi components (see Minimum System Requirements below). * Provide a persistent volume for the service to store checkpoint objects. -* Provider a persistent volume for the MySQL data (optional if you are providing your own DB.) +* Provide a persistent volume for the MySQL data (optional if you are providing your own DB.) * If you are providing your own DB instance, ensure that it is accessible within the same Docker network that the service and the UI containers will be running in. - * The default DB endpoint is `pulumi-db:3306`. If you wish to change this, set `PULUMI_LOCAL_DATABASE_NAME` and `PULUMI_LOCAL_DATABASE_PORT` accordingly (see Script Variables.) + * The default DB endpoint is `pulumi-db:3306`. If you wish to change this, set `PULUMI_LOCAL_DATABASE_HOST` and `PULUMI_LOCAL_DATABASE_PORT` accordingly (see Script Variables.) * If you do not create this network prior to running `run-ee.sh`, it will create only a bridged network on your local host. Ensure that the DB can be accessed by the API service container. * Provide an external load balancer with TLS termination. diff --git a/content/docs/administration/self-hosting/components/console.md b/content/docs/administration/self-hosting/components/console.md index d0e65bfd01f8..01b3e69fc9e6 100644 --- a/content/docs/administration/self-hosting/components/console.md +++ b/content/docs/administration/self-hosting/components/console.md @@ -43,7 +43,7 @@ You can run this container on the same host that your API container is running o ## What's In The Container? {{% notes type="info" %}} -The container image repository is private. [Contact us](/contact/) if you would like to evaluate the Self-Hosted Pulumi Cloud. +The console image is published publicly at [`pulumi/console`](https://hub.docker.com/r/pulumi/console). Running it still requires a license key — see [Components](/docs/administration/self-hosting/components/) for the full image list. {{% /notes %}} The Console container runs a web server using a Node 18-based image. diff --git a/content/docs/administration/self-hosting/deployment-options/_index.md b/content/docs/administration/self-hosting/deployment-options/_index.md index d004ca5ffad3..ca4cc391aed0 100644 --- a/content/docs/administration/self-hosting/deployment-options/_index.md +++ b/content/docs/administration/self-hosting/deployment-options/_index.md @@ -14,6 +14,9 @@ aliases: - /docs/pulumi-cloud/admin/self-hosted/deployment-options/ pulumi_cloud_feature: self-hosting --- + +{{< self-hosting-trial-note />}} + Pulumi offers a number of deployment options for self-hosting the Pulumi Cloud. To get started, see [Install Self-Hosted Pulumi Cloud](/docs/administration/self-hosting/install/), which walks you through each platform. Use Docker Compose to evaluate on a single host in minutes; the other options are production deployments. * [Docker Compose](quickstart-docker-compose/) — evaluation and testing diff --git a/content/docs/administration/self-hosting/deployment-options/aks-hosted.md b/content/docs/administration/self-hosting/deployment-options/aks-hosted.md index f9d527124345..769ebadf0c24 100644 --- a/content/docs/administration/self-hosting/deployment-options/aks-hosted.md +++ b/content/docs/administration/self-hosting/deployment-options/aks-hosted.md @@ -16,6 +16,8 @@ aliases: pulumi_cloud_feature: self-hosting --- +{{< self-hosting-trial-note />}} + The [AKS-Hosted Installer](https://github.com/pulumi/pulumi-self-hosted-installers/tree/master/aks-hosted) installer is used to deploy the self-hosted Pulumi Cloud in Azure Kubernetes Service (AKS) ## AKS-Hosted Deployment diff --git a/content/docs/administration/self-hosting/deployment-options/byo-infra-hosted.md b/content/docs/administration/self-hosting/deployment-options/byo-infra-hosted.md index e4673f6b8494..ca68cbb0578c 100644 --- a/content/docs/administration/self-hosting/deployment-options/byo-infra-hosted.md +++ b/content/docs/administration/self-hosting/deployment-options/byo-infra-hosted.md @@ -16,6 +16,8 @@ aliases: pulumi_cloud_feature: self-hosting --- +{{< self-hosting-trial-note />}} + The [BYO-Infrastructure Installer](https://github.com/pulumi/pulumi-self-hosted-installers/tree/master/byo-infra) installer is used to deploy the self-hosted Pulumi Cloud on your own K8s, MySQL and S3-compatible infrastructure. ## BYO-Infra Deployment diff --git a/content/docs/administration/self-hosting/deployment-options/ecs-hosted.md b/content/docs/administration/self-hosting/deployment-options/ecs-hosted.md index 43a0309ed515..d77e4409471a 100644 --- a/content/docs/administration/self-hosting/deployment-options/ecs-hosted.md +++ b/content/docs/administration/self-hosting/deployment-options/ecs-hosted.md @@ -16,6 +16,8 @@ aliases: pulumi_cloud_feature: self-hosting --- +{{< self-hosting-trial-note />}} + The [ECS-Hosted Installer](https://github.com/pulumi/pulumi-self-hosted-installers/tree/master/ecs-hosted) is used to deploy the self-hosted Pulumi Cloud in Amazon Elastic Container Service. You can choose between using a TypeScript or Golang installer. ## Prerequisites diff --git a/content/docs/administration/self-hosting/deployment-options/eks-hosted.md b/content/docs/administration/self-hosting/deployment-options/eks-hosted.md index 2b49e7dd6325..a8392fcf37c9 100644 --- a/content/docs/administration/self-hosting/deployment-options/eks-hosted.md +++ b/content/docs/administration/self-hosting/deployment-options/eks-hosted.md @@ -16,6 +16,8 @@ aliases: pulumi_cloud_feature: self-hosting --- +{{< self-hosting-trial-note />}} + The [EKS-Hosted Installer](https://github.com/pulumi/pulumi-self-hosted-installers/tree/master/eks-hosted) installer is used to deploy the self-hosted Pulumi Cloud in Amazon Elastic Kubernetes Service (EKS). ## Prerequisites @@ -73,15 +75,22 @@ The buckets will have names of the form: * `pulumi-checkpoint-XXX` * `pulumi-policy-XXX` -### Updating the EKS Cluster Kubernetes Version +### Supported Kubernetes versions -If your EKS-hosted installation was deployed on Kubernetes version 1.19 or later, you can update the `clusterConfig:ClusterVersion` configuration property to the desired version. -Then, rerun the `npm run install -- update --` command to update the cluster with the new version. +| Installer version | Released | Kubernetes | +| :-- | :-- | :-- | +| 4.0 | March 2026 | 1.34.0 | +| 3.1 | February 2025 | 1.31.0 | +| 3.0 | December 2024 | 1.30.3 | +| 2.1 | November 2024 | 1.30.3 | +| 1.0 | October 2024 | 1.30.3 | -{{% notes type="info" %}} -AWS requires moving one Kubernetes release at a time. So if moving from 1.19 to 1.21, perform the steps twice: once to move to 1.20 and wait for that to complete before moving to 1.21. -{{% /notes %}} +### Updating the EKS cluster Kubernetes version + +Set `clusterVersion` in the `05-eks-cluster` project's stack configuration to the version you want, then run `pulumi up` in that project. {{% notes type="info" %}} -If running the Pulumi Cloud with Kubernetes version 1.18, please refer to the installation package README for details on how to upgrade to V2.0 of the EKS installer before upgrading the Kubernetes version. +AWS upgrades the EKS control plane one minor release at a time. To move from 1.31 to 1.34, repeat the step for each intervening release, waiting for each upgrade to finish before starting the next. {{% /notes %}} + +If you are still running an EKS installer released before October 2024, contact [Pulumi support](/support/) to plan a migration to the current installer before changing the Kubernetes version. diff --git a/content/docs/administration/self-hosting/deployment-options/gke-hosted.md b/content/docs/administration/self-hosting/deployment-options/gke-hosted.md index ab691c41a1b9..f62f0a024df7 100644 --- a/content/docs/administration/self-hosting/deployment-options/gke-hosted.md +++ b/content/docs/administration/self-hosting/deployment-options/gke-hosted.md @@ -16,6 +16,8 @@ aliases: pulumi_cloud_feature: self-hosting --- +{{< self-hosting-trial-note />}} + The [GKE-Hosted Installer](https://github.com/pulumi/pulumi-self-hosted-installers/tree/master/gke-hosted) installer is used to deploy the self-hosted Pulumi Cloud in Google Kubernetes Engine (GKE). ## GKE-Hosted Deployment diff --git a/content/docs/administration/self-hosting/deployment-options/local-docker.md b/content/docs/administration/self-hosting/deployment-options/local-docker.md index bc3df7e6ec28..714f0eca4179 100644 --- a/content/docs/administration/self-hosting/deployment-options/local-docker.md +++ b/content/docs/administration/self-hosting/deployment-options/local-docker.md @@ -16,6 +16,8 @@ aliases: pulumi_cloud_feature: self-hosting --- +{{< self-hosting-trial-note />}} + The [Local-Docker Installer](https://github.com/pulumi/pulumi-self-hosted-installers/tree/master/local-docker) is generally meant to be used where an on-premise solution is needed or where the cloud-based installation solutions (i.e. EKS, ECS, AKS) are not possible. ## Prerequisites diff --git a/content/docs/administration/self-hosting/deployment-options/quickstart-docker-compose.md b/content/docs/administration/self-hosting/deployment-options/quickstart-docker-compose.md index 77277f852305..df9412999fe1 100644 --- a/content/docs/administration/self-hosting/deployment-options/quickstart-docker-compose.md +++ b/content/docs/administration/self-hosting/deployment-options/quickstart-docker-compose.md @@ -16,6 +16,8 @@ aliases: pulumi_cloud_feature: self-hosting --- +{{< self-hosting-trial-note />}} + The fastest way to try self-hosted Pulumi Cloud is the all-in-one Docker Compose stack. It runs the API, the web Console, a migrated MySQL database, and OpenSearch on a single host with working defaults, so you can evaluate the full platform in about ten minutes. Use it for evaluation and testing; for production, see the [production deployment options](/docs/administration/self-hosting/deployment-options/). ## Prerequisites diff --git a/content/docs/administration/self-hosting/install/_index.md b/content/docs/administration/self-hosting/install/_index.md index a85f2ab84901..17d7294c61f0 100644 --- a/content/docs/administration/self-hosting/install/_index.md +++ b/content/docs/administration/self-hosting/install/_index.md @@ -17,9 +17,9 @@ pulumi_cloud_feature: self-hosting Run the full Pulumi Cloud platform in your own cloud account or data center. Start with the all-in-one Docker Compose stack to evaluate on a single host, then choose a production deployment for your platform. -{{% notes type="info" %}} -Every installation needs a license key. [Request a Proof of Concept (PoC)](/product/self-hosted/#self-hosted-trial) and a solutions architect will get you an evaluation key and walk through sizing. Self-hosting is available with the [Business Critical edition](/pricing/). -{{% /notes %}} +{{< self-hosting-trial-note >}} +Every installation needs a license key, which you receive as part of the proof of concept. +{{< /self-hosting-trial-note >}} ## Choose your platform diff --git a/content/docs/administration/self-hosting/operations/database.md b/content/docs/administration/self-hosting/operations/database.md index d6a78dbb709c..8d48beb78141 100644 --- a/content/docs/administration/self-hosting/operations/database.md +++ b/content/docs/administration/self-hosting/operations/database.md @@ -64,11 +64,12 @@ Deploy your database cluster across multiple availability zones with at least on The self-hosted installers default to the following database instance types: -| Cloud | Default instance type | Notes | +| Installer | Default instance type | Notes | | :-- | :-- | :-- | -| AWS | db.r5.large (16 GB RAM) | Memory-optimized, recommended for production | -| Azure | General Purpose D2ads_v5 or equivalent | 2 vCPU / 8 GB RAM | -| GCP | db-g1-small (1.7 GB RAM) | Minimal; upgrade for production use | +| AWS EKS | db.r5.large (16 GB RAM) | Memory-optimized, recommended for production. Set via `dbInstanceType` in the `20-database` project | +| AWS ECS | db.t3.small | Burstable; raise `dbInstanceType` before running production workloads | +| Azure AKS | General Purpose D2ads_v5 or equivalent | 2 vCPU / 8 GB RAM | +| GCP GKE | db-g1-small (1.7 GB RAM) | Minimal; upgrade for production use | For production workloads, start with a memory-optimized instance with at least 16 GB RAM (db.r5.large, db.r6g.large, General Purpose D4s_v3, or equivalent) and scale based on monitoring. Burstable instances (db.t3.*) are acceptable for development and light workloads but may throttle under sustained load. diff --git a/content/docs/administration/self-hosting/saml-sso.md b/content/docs/administration/self-hosting/saml-sso.md index 28a0e9d8622d..a60ae3f6c9da 100644 --- a/content/docs/administration/self-hosting/saml-sso.md +++ b/content/docs/administration/self-hosting/saml-sso.md @@ -17,6 +17,8 @@ aliases: pulumi_cloud_feature: self-hosting --- +{{< self-hosting-trial-note />}} + The self-hosted option allows you to control various aspects of Pulumi Cloud including how users will sign in to the [Pulumi Cloud console](/docs/administration/self-hosting/components/console/). ## Creating the keys From 4c7c3c72c87a55f1393792784d601b2ac772cada Mon Sep 17 00:00:00 2001 From: Joe Duffy Date: Tue, 11 Aug 2026 17:28:01 -0700 Subject: [PATCH 04/12] Make the V2 schema migration a visible upgrade gate Every modern installer README opens with a hard stop: do not point this installer at an existing install, contact support to migrate the database first. That warning existed nowhere in the docs. The only trace was two rows in the API component's environment-variable table, on a 510-line reference page nobody reads before running `pulumi config set imageTag`. The gate now lives in a shortcode and appears on the upgrades guide and in the update section of all six production deployment pages -- the exact places a reader is about to change an image tag and run `pulumi up`. Stating it once and including it keeps the six copies from drifting the way the original warning did. It supports .Inner for the same reason self-hosting-trial-note does: Hugo only accepts the self-closing form for shortcodes that evaluate it, and matching the sibling keeps both usable the same way. Co-Authored-By: Claude Opus 5 (1M context) --- .../self-hosting/deployment-options/aks-hosted.md | 2 ++ .../deployment-options/byo-infra-hosted.md | 2 ++ .../self-hosting/deployment-options/ecs-hosted.md | 2 ++ .../self-hosting/deployment-options/eks-hosted.md | 2 ++ .../self-hosting/deployment-options/gke-hosted.md | 2 ++ .../deployment-options/local-docker.md | 2 ++ .../self-hosting/operations/upgrades.md | 2 ++ .../shortcodes/self-hosting-schema-v2-note.html | 15 +++++++++++++++ .../self-hosting-schema-v2-note.markdown.md | 3 +++ 9 files changed, 32 insertions(+) create mode 100644 layouts/shortcodes/self-hosting-schema-v2-note.html create mode 100644 layouts/shortcodes/self-hosting-schema-v2-note.markdown.md diff --git a/content/docs/administration/self-hosting/deployment-options/aks-hosted.md b/content/docs/administration/self-hosting/deployment-options/aks-hosted.md index 769ebadf0c24..e86e9ac0a9ed 100644 --- a/content/docs/administration/self-hosting/deployment-options/aks-hosted.md +++ b/content/docs/administration/self-hosting/deployment-options/aks-hosted.md @@ -46,6 +46,8 @@ See the [README](https://github.com/pulumi/pulumi-self-hosted-installers/tree/ma ### Pulumi Cloud Updates +{{< self-hosting-schema-v2-note />}} + When deploying the Service, it is recommended to pin the Pulumi Cloud image tag to a specific version. See the [installer's README](https://github.com/pulumi/pulumi-self-hosted-installers/tree/master/aks-hosted/README.md) file to set the `imageTag` configuration property for the installer to use. When ready to update the Pulumi Cloud containers to use a different version, do the following: diff --git a/content/docs/administration/self-hosting/deployment-options/byo-infra-hosted.md b/content/docs/administration/self-hosting/deployment-options/byo-infra-hosted.md index ca68cbb0578c..c2d41d539375 100644 --- a/content/docs/administration/self-hosting/deployment-options/byo-infra-hosted.md +++ b/content/docs/administration/self-hosting/deployment-options/byo-infra-hosted.md @@ -46,6 +46,8 @@ See the [README](https://github.com/pulumi/pulumi-self-hosted-installers/tree/ma ### Pulumi Cloud Updates +{{< self-hosting-schema-v2-note />}} + When deploying the Pulumi Cloud, it is recommended to pin the image tag to a specific version. See the [installer's README](https://github.com/pulumi/pulumi-self-hosted-installers/tree/master/byo-infra/README.md) file to set the `imageTag` configuration property for the installer to use. When ready to update the Pulumi Cloud containers to use a different version, do the following: diff --git a/content/docs/administration/self-hosting/deployment-options/ecs-hosted.md b/content/docs/administration/self-hosting/deployment-options/ecs-hosted.md index d77e4409471a..65466c80569f 100644 --- a/content/docs/administration/self-hosting/deployment-options/ecs-hosted.md +++ b/content/docs/administration/self-hosting/deployment-options/ecs-hosted.md @@ -66,6 +66,8 @@ See the [README](https://github.com/pulumi/pulumi-self-hosted-installers/tree/ma ### Pulumi Cloud Updates +{{< self-hosting-schema-v2-note />}} + When deploying the Pulumi Cloud, it is recommended to pin the image tag to a specific version. See the [installer's README](https://github.com/pulumi/pulumi-self-hosted-installers/tree/master/ecs-hosted) file to set the `imageTag` configuration property for the installer to use. When ready to update the Pulumi Cloud containers to use a different version, do the following: diff --git a/content/docs/administration/self-hosting/deployment-options/eks-hosted.md b/content/docs/administration/self-hosting/deployment-options/eks-hosted.md index a8392fcf37c9..9f5a2c3529af 100644 --- a/content/docs/administration/self-hosting/deployment-options/eks-hosted.md +++ b/content/docs/administration/self-hosting/deployment-options/eks-hosted.md @@ -55,6 +55,8 @@ See the [README](https://github.com/pulumi/pulumi-self-hosted-installers/tree/ma ### Pulumi Cloud Updates +{{< self-hosting-schema-v2-note />}} + When deploying the service, it is recommended to pin the Pulumi Cloud image tag to a specific version. See the installer's [README](https://github.com/pulumi/pulumi-self-hosted-installers/tree/master/eks-hosted/README.md) file to set the `imageTag` configuration property for the installer to use. When ready to update the Pulumi Cloud containers to use a different version, do the following: diff --git a/content/docs/administration/self-hosting/deployment-options/gke-hosted.md b/content/docs/administration/self-hosting/deployment-options/gke-hosted.md index f62f0a024df7..8375366e56c1 100644 --- a/content/docs/administration/self-hosting/deployment-options/gke-hosted.md +++ b/content/docs/administration/self-hosting/deployment-options/gke-hosted.md @@ -45,6 +45,8 @@ See the [README](https://github.com/pulumi/pulumi-self-hosted-installers/tree/ma ### Pulumi Cloud Updates +{{< self-hosting-schema-v2-note />}} + When deploying the Pulumi Cloud, it is recommended to pin the image tag to a specific version. See the [installer's README](https://github.com/pulumi/pulumi-self-hosted-installers/tree/master/gke-hosted/README.md) file to set the `imageTag` configuration property for the installer to use. When ready to update the Pulumi Cloud containers to use a different version, do the following: diff --git a/content/docs/administration/self-hosting/deployment-options/local-docker.md b/content/docs/administration/self-hosting/deployment-options/local-docker.md index 714f0eca4179..8c1b2c174816 100644 --- a/content/docs/administration/self-hosting/deployment-options/local-docker.md +++ b/content/docs/administration/self-hosting/deployment-options/local-docker.md @@ -57,6 +57,8 @@ See the [README](https://github.com/pulumi/pulumi-self-hosted-installers/tree/ma ### Pulumi Cloud Updates +{{< self-hosting-schema-v2-note />}} + When deploying the Pulumi Cloud, it is recommended to pin the image tag to a specific version. See the [installer's README](https://github.com/pulumi/pulumi-self-hosted-installers/tree/master/local-docker/README.md) file to set the `imageTag` configuration property for the installer to use. When ready to update the Pulumi Cloud containers to use a different version, do the following: diff --git a/content/docs/administration/self-hosting/operations/upgrades.md b/content/docs/administration/self-hosting/operations/upgrades.md index 147499d664ec..34194023cdd3 100644 --- a/content/docs/administration/self-hosting/operations/upgrades.md +++ b/content/docs/administration/self-hosting/operations/upgrades.md @@ -16,6 +16,8 @@ pulumi_cloud_feature: self-hosting This page covers how to safely update your self-hosted Pulumi Cloud deployment. For version-specific changes, see the [Changelog](/docs/administration/self-hosting/changelog/). +{{< self-hosting-schema-v2-note />}} + ## Staged rollouts Deploy updates through staged environments: diff --git a/layouts/shortcodes/self-hosting-schema-v2-note.html b/layouts/shortcodes/self-hosting-schema-v2-note.html new file mode 100644 index 000000000000..daabe4b10d72 --- /dev/null +++ b/layouts/shortcodes/self-hosting-schema-v2-note.html @@ -0,0 +1,15 @@ +{{- /* The V2 engine-events schema gate. Stated once here and included wherever a + reader is about to upgrade an install, because the installer READMEs carry + this as a hard stop and the API reference buries it in a table row. */ -}} +
+
+ {{ partial "icon.html" (dict "name" "warning" "weight" "fill") }} +
+
+
+ {{ printf "**Upgrading an existing installation?** The current installers enable the V2 engine events database schema (`PULUMI_ENGINE_EVENTS_SCHEMA_V2`). Moving an existing installation onto it requires a database migration that Pulumi performs with you. [Contact Pulumi support](/support/) before pointing an existing install at a current installer version or changing `PULUMI_ENGINE_EVENTS_SCHEMA_V2` or `PULUMI_ENGINE_EVENTS_LEGACY_WRITE`. Fresh installations are unaffected." | markdownify }} + {{- with .Inner }} + {{ . | markdownify }} + {{- end }} +
+
diff --git a/layouts/shortcodes/self-hosting-schema-v2-note.markdown.md b/layouts/shortcodes/self-hosting-schema-v2-note.markdown.md new file mode 100644 index 000000000000..74ed3e5d0ed3 --- /dev/null +++ b/layouts/shortcodes/self-hosting-schema-v2-note.markdown.md @@ -0,0 +1,3 @@ +{{- $inner := trim (printf "%s" .Inner) " \t\n\r" -}} + +> **Warning:** **Upgrading an existing installation?** The current installers enable the V2 engine events database schema (`PULUMI_ENGINE_EVENTS_SCHEMA_V2`). Moving an existing installation onto it requires a database migration that Pulumi performs with you. [Contact Pulumi support](/support/) before pointing an existing install at a current installer version or changing `PULUMI_ENGINE_EVENTS_SCHEMA_V2` or `PULUMI_ENGINE_EVENTS_LEGACY_WRITE`. Fresh installations are unaffected.{{ with $inner }} {{ . }}{{ end }} From cf3a80cc8a1ebe16b3d6028a6b198a78076d57f0 Mon Sep 17 00:00:00 2001 From: Joe Duffy Date: Tue, 11 Aug 2026 17:33:40 -0700 Subject: [PATCH 05/12] Rebuild the self-hosted product page on template-partials The page was a bespoke 2022 layout that predated the section system every other product page uses. It called the platform a "Cloud Engineering Platform", offered "Azure Active Directory" as an identity option, omitted ECS entirely though it is the most complete installer we ship, and routed every docs link through the retired /docs/pulumi-cloud/self-hosted/ path so each click was a redirect. Moving it to type: page + layout: template-page deletes the one-off layout and keeps the URL. The identity copy was wrong on substance, not just naming: self-hosted has no Azure AD OAuth connector. Entra ID reaches it through SAML, which is what the page now says. Deployment targets are Phosphor icons rather than cloud logos. Every logo the old page used lives only under static/, and template partials resolve images through assets/fingerprinted/, where a missing file panics the build. Icons avoid copying six assets to say something an icon says just as well. The VMware tile is gone. It linked to a contact form with no documentation behind it and implied a vSphere installer that does not exist. A "Something else?" card does the same job honestly -- the images run on any OCI-compatible orchestrator -- and eight cards fill two rows of four cleanly. Compliance gets a three-column section where the third column is headed "No FedRAMP authorization" and carries the same weight as the SOC 2 column. A security reviewer who can see immediately what we do not hold will trust what we do claim; burying the non-claim in a footnote produces the opposite. All three columns get a CTA so the negative one does not read as a dead end. FIPS is deliberately absent: nothing in this repo, pulumi/pulumi, or the installers substantiates a claim about our own use of it. Rendering a HubSpot form needed a new section type, since none existed. The #self-hosted-trial anchor is a contract, not decoration -- the self-hosting-trial-note shortcode, the pricing FAQ, and the enterprise page all deep-link to it -- so the partial documents that. The meta image is generated with the site's own Satori renderer using the same "title" template as /what-is/ and /migrate/, because generate-meta-images.mjs does not cover product/. Co-Authored-By: Claude Opus 5 (1M context) --- content/product/self-hosted.md | 261 ++++++++++++++---- layouts/partials/template-page-content.html | 1 + .../template-hubspot-form.html | 38 +++ layouts/product/self-hosted.html | 146 ---------- .../product/self-hosted/self-hosted-meta.png | Bin 0 -> 38120 bytes 5 files changed, 242 insertions(+), 204 deletions(-) create mode 100644 layouts/partials/template-partials/template-hubspot-form.html delete mode 100644 layouts/product/self-hosted.html create mode 100644 static/images/product/self-hosted/self-hosted-meta.png diff --git a/content/product/self-hosted.md b/content/product/self-hosted.md index e51737873f1f..1e0876665603 100644 --- a/content/product/self-hosted.md +++ b/content/product/self-hosted.md @@ -1,66 +1,211 @@ --- title: Self-Hosted Pulumi Cloud -layout: self-hosted +meta_desc: Run the full Pulumi Cloud platform in your own AWS, Azure, Google Cloud, or on-premises environment, including fully air-gapped networks. +meta_image: /images/product/self-hosted/self-hosted-meta.png +type: page +layout: template-page +include_floqer: true -meta_desc: Learn how to operate Pulumi Cloud in your own cloud account or data center. +sections: + - type: hero + title_primary: Pulumi Cloud, + title_secondary: running inside your network. + description: | + Install the Pulumi Cloud API and console into your own AWS, Azure, Google Cloud, or on-premises environment. State, secrets, and audit history live in a database and object store you own, and the installation can run with no route to the public internet. + cta_primary_text: Request a proof of concept + cta_primary_link: "#self-hosted-trial" + cta_secondary_text: Read the install guide + cta_secondary_link: /docs/administration/self-hosting/install/ + anchor: hero -overview: - title: Try Self-Hosted Pulumi - descriptionTop: | - Maintain complete control over your hosting, network isolation, identity, and data ownership to satisfy compliance requirements. [Request a Proof of Concept](#self-hosted-trial) to evaluate self-hosted Pulumi. - descriptionBottom: | - Want Pulumi Cloud delivered as SaaS? [Start Using Pulumi Cloud for free](https://app.pulumi.com/signin). -trial: - title: Request a Proof of Concept + - type: feature_split + heading: For teams that can't hand infrastructure state to a vendor description: | - Fill out the form to connect with a solutions architect and start your evaluation. - hubspot_form_id: b6ff58c0-2b40-4202-9a7f-d6d8aca4414a -capabilities: - title: Capabilities of Self-Hosted Pulumi - items: - - title: Cloud Engineering Platform - icon: rocketship - icon_color: violet - description: | - All the capabilities of Pulumi Cloud: state management, role-based access controls, policy and compliance guardrails. - - title: Full Control of Data - icon: gear - icon_color: violet - description: | - All data in Self-Hosted Pulumi is stored in a MySQL database and an encrypted object store within your own network. - - title: Air-gapped Communications - icon: abstract-shapes - icon_color: blue - description: | - No communication outside of your private network, eliminating all communication over the public internet. - - title: Federated Identity & Group Management - icon: shield - icon_color: yellow - description: | - Integrate with your preferred identity provider and manage permissions across your organization. - items: - - image: /logos/pkg/azuread.svg - text: Azure Active Directory - - image: /logos/pkg/github.svg - text: GitHub - - image: /logos/pkg/gitlab.svg - text: GitLab - - image: /images/self-hosted/bitbucket.svg - text: Bitbucket - - image: /images/self-hosted/samlsso.svg - text: SAML SSO -deployment: - title: Hosting Options - descriptionTop: | - [Install Self-Hosted Pulumi Cloud](/docs/pulumi-cloud/self-hosted/) in any on-premises or cloud provider environment or run in air-gapped environments, including those requiring FedRAMP. - descriptionBottom: | - [Talk to a Pulumi team member](/contact/) if you don't see your desired deployment option. -pricing: - title: Pricing + Most Pulumi customers run on the hosted service at app.pulumi.com, and most should. Self-hosting exists for the organizations that can't: regulators who dictate where data lives, programs that operate with no internet route, and contracts that name a country. + cta_text: Compare hosted and self-hosted + cta_link: /docs/administration/onboarding-guide/choose-edition/ + cards: + - icon: bank + title: Regulated industries + description: | + Financial services, insurance, and healthcare teams that keep infrastructure metadata inside an audited boundary and have to produce evidence for it on demand. + - icon: wall + title: Air-gapped networks + description: | + Installations with no egress at all. Mirror the container images and provider plugins into your environment and run from there — see the [air-gapped guide](/docs/administration/self-hosting/airgapped/). + - icon: globe + title: Data sovereignty + description: | + Statutory or contractual requirements that stack state, secrets, and audit logs never leave a named region or cloud account. + anchor: audience + + - type: testimonial + quote: | + We gave our auditors access to our policy packs because it's far easier to understand and prove controls in code than in docs and diagrams. With Pulumi's Policy as Code approach, that manual review process has gone away. We've reduced our Authority to Operate (ATO) timeline from a year and a half to expecting approval in three months. + author: Michael Hunter + title: CEO + company: Spear AI + anchor: testimonial + + - type: section_header + title: The whole platform, not a state backend + description: | + A self-hosted installation runs the Pulumi Cloud API and console as container images you pull and operate, backed by a MySQL 8.0 database, object storage, and an OpenSearch cluster you provide. Everything below is part of it. + cards_cols: 3 + cards: + - icon: custom/pulumi-iac + title: Pulumi IaC + description: | + Encrypted state, stack history, role-based access control, and audit logs, stored in your own database and object store. + - icon: custom/pulumi-secrets + title: Pulumi ESC + description: | + Environments, secrets, and configuration ship with the install — no separate deployment. + - icon: custom/pulumi-insights + title: Discovery and Policies + description: | + Run Discovery scans and policy evaluations on [customer-managed runners](/docs/insights/self-hosted/) inside your network, so cloud credentials never leave it. + - icon: custom/pulumi-neo + title: Pulumi Neo + description: | + Pulumi's infrastructure agent works against a self-hosted installation, so teams keep AI-assisted infrastructure work inside their own boundary. + - icon: identification-card + title: Your identity provider + description: | + SAML 2.0 SSO against any IdP — Okta, Microsoft Entra ID, Ping — plus GitHub, GitLab, and Bitbucket OAuth, or email and password. SCIM keeps users and groups in sync. + - icon: magnifying-glass + title: Resource search + description: | + Point the API at an OpenSearch cluster you run and resource search indexes across every stack in the installation. + anchor: capabilities + + - type: card_grid + title: Seven supported installations description: | - Self-Hosted Pulumi is available as an additional license for the Business Critical Edition of Pulumi and provided as part of a guided Proof of Concept. -questions: - title: Talk to a Human + Every option below ships as a Pulumi program in [pulumi-self-hosted-installers](https://github.com/pulumi/pulumi-self-hosted-installers). Run them as they are, or treat them as reference architectures and fold the resources into your own pipeline — plenty of customers do. + small_cards_cols: 4 + small_cards: + - icon: cube + title: Docker Compose + description: | + Evaluation only. Brings up the API, console, database, and search on one host so you can try the product before designing a production topology. + cta_text: Docker Compose guide + cta_link: /docs/administration/self-hosting/deployment-options/quickstart-docker-compose/ + - icon: cloud + title: AWS ECS + description: | + Fargate services behind a load balancer with Aurora MySQL, S3, ACM, and Route 53. TypeScript and Go installers. + cta_text: ECS guide + cta_link: /docs/administration/self-hosting/deployment-options/ecs-hosted/ + - icon: tree-structure + title: AWS EKS + description: | + Nine composable Pulumi projects on Kubernetes. Bring your own IAM, VPC, or state buckets when another team owns them. + cta_text: EKS guide + cta_link: /docs/administration/self-hosting/deployment-options/eks-hosted/ + - icon: tree-structure + title: Azure AKS + description: | + Azure Kubernetes Service with Azure Database for MySQL and Blob Storage, behind an NGINX ingress. + cta_text: AKS guide + cta_link: /docs/administration/self-hosting/deployment-options/aks-hosted/ + - icon: tree-structure + title: Google GKE + description: | + Google Kubernetes Engine with Cloud SQL for MySQL and Cloud Storage buckets. + cta_text: GKE guide + cta_link: /docs/administration/self-hosting/deployment-options/gke-hosted/ + - icon: wrench + title: Bring your own Kubernetes + description: | + Any conformant cluster plus MySQL 8.0 and S3-compatible object storage. This is the path for on-premises clusters and air-gapped networks. + cta_text: BYO infrastructure guide + cta_link: /docs/administration/self-hosting/deployment-options/byo-infra-hosted/ + - icon: hard-drives + title: Docker on your own hosts + description: | + For data centers with no Kubernetes platform: run the container images directly against an external MySQL and object store. + cta_text: Docker Engine guide + cta_link: /docs/administration/self-hosting/deployment-options/local-docker/ + - icon: chats-circle + title: Something else? + description: | + The images run on any OCI-compatible orchestrator. Tell us what you operate and a solutions architect will size the installation. + cta_text: Talk to a solutions architect + cta_link: /contact/?form=sales + anchor: deploy + + - type: section_header + tag_line: Day 2 + title: You own uptime. We document the job. + description: | + The [operations guide](/docs/administration/self-hosting/operations/) covers architecture, compute sizing, database and object storage configuration, network layout, and security hardening. These are the four things platform teams ask about first. + cards_cols: 4 + cards: + - icon: pulse + title: High availability + description: | + Stateless API and console services across availability zones, in front of a managed MySQL cluster and replicated object storage. + - icon: floppy-disk + title: Recovery targets + description: | + Under 5 minutes for an availability zone failure, under 1 minute for an Aurora failover, and 1 to 4 hours to rebuild a region from cross-region backups. + - icon: arrows-clockwise + title: Upgrades + description: | + Pin the image tag, run migrations before rolling services, stage through a test environment. Every release lands in the [changelog](/docs/administration/self-hosting/changelog/). + - icon: chart-line-up + title: Observability + description: | + The API exposes Prometheus metrics and OpenTelemetry traces. The [monitoring guide](/docs/administration/self-hosting/operations/monitoring/) gives a three-tier alerting strategy and the metrics worth paging on. + anchor: operations + + - type: three_column + tag_line: Compliance + title: What we claim, and what we don't + subtitle: Security reviews move faster when the vendor is precise. Here is the posture in plain terms. + icon_layout: above + columns: + - icon: certificate + title: SOC 2 Type II + description: | + Pulumi Cloud is covered by an annual SOC 2 Type II audit performed by an independent CPA firm. The report is available under NDA. Architecture, key hierarchy, and operational controls are documented in the security whitepaper. + cta_text: Read the whitepaper + cta_link: /security/pulumi-cloud-security-whitepaper/ + - icon: wall + title: Inside a boundary you already authorized + description: | + Because you install and operate it, the assessment surface is your own infrastructure under your own controls, rather than a third-party service your assessor has to scope separately. + cta_text: Air-gapped deployment guide + cta_link: /docs/administration/self-hosting/airgapped/ + - icon: warning + title: No FedRAMP authorization + description: | + Pulumi holds no FedRAMP authorization. There is no Pulumi ATO and no FedRAMP Marketplace listing. If your program requires a FedRAMP-authorized service, Pulumi Cloud does not meet that requirement today, and self-hosting does not change it — it changes who owns the boundary. + cta_text: Talk to us about your program + cta_link: /contact/?form=sales + anchor: compliance + + - type: two_column + highlight_first_card: true + columns: + - label: Business Critical + title: How self-hosting is licensed + description: | + Self-hosting is part of [Pulumi Business Critical](/pricing/), along with self-hosted Pulumi ESC and self-hosted Discovery scans and policy evaluations. Pricing is custom, and evaluations run as a guided proof of concept with a solutions architect. + cta_text: See pricing + cta_link: /pricing/ + - title: Would the hosted service do? + description: | + For most teams, yes, and it is a great deal less work. Pulumi Cloud at app.pulumi.com gives you high availability, disaster recovery, and upgrades without operating anything, and it is free to start. + cta_text: Compare editions + cta_link: /docs/administration/onboarding-guide/choose-edition/ + anchor: pricing + + - type: hubspot_form + anchor: self-hosted-trial + title: Request a proof of concept description: | - If you have any questions about Self-Hosted Pulumi, please contact us or visit the self-hosted docs. + A solutions architect will walk through your target environment, size the installation, and get you the installer package and an evaluation license key. If you would rather ask a question first, [contact us](/contact/). + hubspot_form_id: b6ff58c0-2b40-4202-9a7f-d6d8aca4414a --- diff --git a/layouts/partials/template-page-content.html b/layouts/partials/template-page-content.html index f7736f770237..f2e32b359923 100644 --- a/layouts/partials/template-page-content.html +++ b/layouts/partials/template-page-content.html @@ -25,6 +25,7 @@ latest_posts — template-latest-posts.html (fields: title, description, ctas[{text, link}], count, show_event, anchor) video_embed — template-video-embed.html (fields: youtube_id, title, poster_image, poster_alt, anchor) feature_callout — template-feature-callout.html (fields: tag_line, title, lead, description, cta_primary_text/link, cta_secondary_text/link, background, anchor) + hubspot_form — template-hubspot-form.html (fields: title, description, hubspot_form_id, anchor) promo_banner — template-promo-banner.html (fields: title, description, cta_text, bg_image, anchor) location — template-location.html (fields: tag_line, title, location, description, map_embed, cta_text, cta_link, anchor) diff --git a/layouts/partials/template-partials/template-hubspot-form.html b/layouts/partials/template-partials/template-hubspot-form.html new file mode 100644 index 000000000000..d106a85dd066 --- /dev/null +++ b/layouts/partials/template-partials/template-hubspot-form.html @@ -0,0 +1,38 @@ +{{/* + Template HubSpot Form Partial + + A centered HubSpot form block for template-driven pages. Wraps the shared + element, which handles lazy loading and styling. + + The anchor is part of the contract, not decoration: /product/self-hosted/ + #self-hosted-trial is linked from the self-hosting-trial-note shortcode + (which fans out across the self-hosting docs), the pricing FAQ, and the + enterprise page. Renaming it breaks all of them. + + Parameters: + - title: Section heading. + - description: Optional body copy above the form (markdown supported). + - hubspot_form_id: HubSpot form GUID. + - anchor: Anchor for the section id. Required when the form is deep-linked. +*/}} + +{{ $title := .title }} +{{ $description := .description }} +{{ $formID := .hubspot_form_id }} +{{ $anchor := .anchor }} + +
+
+ {{ with $title }} +

{{ . }}

+ {{ end }} + {{ with $description }} +

{{ . | markdownify }}

+ {{ end }} +
+
+
+ +
+
+
diff --git a/layouts/product/self-hosted.html b/layouts/product/self-hosted.html deleted file mode 100644 index 54b98ebff1ca..000000000000 --- a/layouts/product/self-hosted.html +++ /dev/null @@ -1,146 +0,0 @@ -{{ define "hero" }} - {{ partial "hero" (dict "title" .Params.title) }} -{{ end }} - -{{ define "main" }} - {{ $pageContext := . }} - -
-
- {{ with .Params.overview }} -

{{ .title }}

-
-

{{ .descriptionTop | markdownify }}

-

{{ .descriptionBottom | markdownify }}

-
- {{ end }} -
-
- -
- {{ with .Params.deployment }} -

{{ .title }}

-
-

{{ .descriptionTop | markdownify }}

-

{{ .descriptionBottom | markdownify }}

-
-
-
- AWS -
AWS
- AWS Docs -
- -
- Azure -
Azure
- Azure Docs -
- -
- Docker -
Docker
- Docker Docs -
-
-
-
-
- Google Cloud -
-
Google Cloud
- Google Docs -
- -
-
- Kubernetes -
-
Kubernetes
- Kubernetes Docs -
- -
- VMware -
VMware
- Talk to a human -
-
- {{ end }} -
- -
-
- {{ with .Params.capabilities }} -

{{ .title }}

-
- {{ range $item := .items }} -
-
-
- {{ partial "color-icon.html" (dict "icon" $item.icon "icon_color" $item.icon_color) }} -
-
{{ $item.title }}
-

{{ $item.description | markdownify }}

- - {{ if $item.items }} - - -

Identity providers include Azure Active Directory, Bitbucket, GitHub, GitLab, and SAML SSO.

- {{ end }} -
-
- {{ end }} -
- {{ end }} -
-
- -
-
-
- {{ with .Params.pricing }} -

{{ .title }}

-

{{ .description | markdownify }}

-
- Pricing -
- {{ end }} -
-
-
- -
-
- {{ with .Params.trial }} -

{{ .title }}

-

{{ .description | markdownify }}

-
- -
- {{ end }} -
-
- -
- {{ with .Params.questions }} -
-
-

{{ .title }}

-

{{ .description }}

- -
-
- {{ end }} -
-{{ end }} diff --git a/static/images/product/self-hosted/self-hosted-meta.png b/static/images/product/self-hosted/self-hosted-meta.png new file mode 100644 index 0000000000000000000000000000000000000000..3f13a0ef3463ca49e277cb90b6ca308ba26e1879 GIT binary patch literal 38120 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 literal 0 HcmV?d00001 From 2b8470626bb27a34f638eb87b35993a9a838708b Mon Sep 17 00:00:00 2001 From: Joe Duffy Date: Tue, 11 Aug 2026 17:36:43 -0700 Subject: [PATCH 06/12] Say what we certify, and what we don't, on /security/ The page claimed one thing -- SOC 2 Type II -- in a single sentence, and the 527-line whitepaper behind it names no certifications at all. That combination undersells a real posture and leaves a security reviewer with nowhere to land, so they email an account rep instead. The most useful sentence on a trust page is the negative one. Stating plainly that we do not hold ISO 27001, HITRUST, or PCI DSS lets a reviewer stop looking rather than assume we are hiding it, and it makes the SOC 2 claim more credible, not less. The same logic drives the FedRAMP section: no authorization, no ATO, no Marketplace listing, said outright, followed by what self-hosting actually changes -- who owns the boundary. Two distinctions the old page blurred. Our pre-built CIS/NIST/PCI policy packs help customers assess their own infrastructure; they say nothing about Pulumi's certification status, and a procurement reader could easily conflate the two. And per our own /what-is/what-is-soc-2/, SOC 2 is an attestation rather than a certification -- worth being precise about here even though the marketing shorthand elsewhere is fine. The whitepaper now gets a paragraph describing what is actually in it, drawn from its real section headings, so the strongest asset we have is no longer sitting behind a bare link. /trust/ and /trust-center/ alias here rather than becoming a second page. Whichever surface a reviewer guesses, they land on the authoritative one, and there is no seam for the two to drift across -- which is how the whitepaper and this page diverged in the first place. Co-Authored-By: Claude Opus 5 (1M context) --- content/security/_index.md | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/content/security/_index.md b/content/security/_index.md index 655734b3d65b..391d95ae39aa 100644 --- a/content/security/_index.md +++ b/content/security/_index.md @@ -1,15 +1,34 @@ --- title: Pulumi Security -meta_desc: A summary of security topics and how they relate to the Pulumi platform. +meta_desc: Pulumi's security posture — SOC 2 Type II attestation, what we do and don't certify, platform architecture, and how to report a vulnerability. +aliases: + - /trust/ + - /trust-center/ --- Pulumi takes security and privacy matters very seriously. We appreciate that our customers and users place a high degree of confidence and trust in our products and services and we strive to meet those expectations. -## Pulumi Platform Security +## Certifications and attestations -The Pulumi platform employs industry best practices for security and is SOC 2 Type II certified. +Pulumi Cloud is covered by an annual **SOC 2 Type II** audit performed by an independent CPA firm against the AICPA Trust Services Criteria. The report is shared under NDA — request it from your account team or email [security@pulumi.com](mailto:security@pulumi.com). -For more details, see our [security whitepaper](/security/pulumi-cloud-security-whitepaper). +Pulumi does not currently hold ISO 27001, HITRUST, or PCI DSS certification. Customers in regulated industries do run Pulumi under those frameworks, because Pulumi Cloud never receives your cloud credentials and never has standing access to your cloud accounts — the architecture that makes this true is described in the [security whitepaper](/security/pulumi-cloud-security-whitepaper/). + +Pulumi also publishes [pre-built policy packs](/docs/insights/policy/policy-packs/pre-built-packs/) for CIS, ISO/IEC 27001, NIST SP 800-53, CMMC, HITRUST, and PCI DSS. Those help you assess *your* infrastructure against a framework; they are not a statement about Pulumi's own certification status. + +## Government and federal programs + +Pulumi holds **no FedRAMP authorization**. There is no Pulumi ATO and no listing in the FedRAMP Marketplace. A program that requires a FedRAMP-authorized service cannot use hosted Pulumi Cloud to satisfy that requirement. + +[Self-hosted Pulumi Cloud](/product/self-hosted/) changes who owns the boundary. Because you install and operate it in your own environment, it is a software component in your inventory, and the controls that apply to it are yours. It can run fully [air-gapped](/docs/administration/self-hosting/airgapped/), with no egress to the public internet. + +## Architecture and controls + +The [security whitepaper](/security/pulumi-cloud-security-whitepaper/) is the technical reference for how Pulumi Cloud is built and operated. It covers the service architecture and data storage model, the three-tier encryption key hierarchy and its KMS integration, organizational key isolation and key rotation, transport security, how secrets are handled in stack state, diagnostic log protection, audit logging, monitoring, incident detection and response, vulnerability management, and backup, recovery, and business continuity. + +## Data processing + +Pulumi's [Privacy Statement](/privacy/) describes what personal data we collect and how it is handled, including transfers out of the EEA under standard contractual clauses. For a Data Processing Addendum, or for questions about data processing in a procurement review, contact [privacy@pulumi.com](mailto:privacy@pulumi.com). ## Vulnerability Reporting From a40561358d5f9d135dc1165ecca96894f003dd3e Mon Sep 17 00:00:00 2001 From: Joe Duffy Date: Tue, 11 Aug 2026 17:39:30 -0700 Subject: [PATCH 07/12] Rename the stale self-hosting menu identifiers Every menu identifier and parent in the tree still read administration-security-compliance-self-hosted-*, left over from a prior move out of a Security & Compliance section that no longer contains these pages. The names were functional but actively misleading to anyone editing frontmatter here, since the section they name is a sibling. Identifiers are not URLs and nothing outside this content directory references them -- verified across templates, data files, SCSS, and scripts before renaming -- so this is a pure legibility fix. The rendered nav tree is unchanged: all 29 entries still resolve under Self-Hosting. Co-Authored-By: Claude Opus 5 (1M context) --- content/docs/administration/self-hosting/airgapped.md | 2 +- content/docs/administration/self-hosting/changelog.md | 2 +- content/docs/administration/self-hosting/components/_index.md | 2 +- content/docs/administration/self-hosting/components/api.md | 4 ++-- .../docs/administration/self-hosting/components/console.md | 4 ++-- .../administration/self-hosting/components/deployments.md | 4 ++-- content/docs/administration/self-hosting/components/search.md | 4 ++-- .../administration/self-hosting/deployment-options/_index.md | 2 +- .../self-hosting/deployment-options/aks-hosted.md | 4 ++-- .../self-hosting/deployment-options/byo-infra-hosted.md | 4 ++-- .../self-hosting/deployment-options/ecs-hosted.md | 4 ++-- .../self-hosting/deployment-options/eks-hosted.md | 4 ++-- .../self-hosting/deployment-options/gke-hosted.md | 4 ++-- .../self-hosting/deployment-options/local-docker.md | 4 ++-- .../deployment-options/quickstart-docker-compose.md | 4 ++-- content/docs/administration/self-hosting/network.md | 2 +- content/docs/administration/self-hosting/operations/_index.md | 2 +- .../administration/self-hosting/operations/architecture.md | 4 ++-- .../administration/self-hosting/operations/backup-recovery.md | 4 ++-- .../administration/self-hosting/operations/compute-sizing.md | 4 ++-- .../docs/administration/self-hosting/operations/database.md | 4 ++-- .../docs/administration/self-hosting/operations/monitoring.md | 4 ++-- .../docs/administration/self-hosting/operations/networking.md | 4 ++-- .../administration/self-hosting/operations/object-storage.md | 4 ++-- .../self-hosting/operations/security-hardening.md | 4 ++-- .../docs/administration/self-hosting/operations/upgrades.md | 4 ++-- content/docs/administration/self-hosting/saml-sso.md | 2 +- 27 files changed, 47 insertions(+), 47 deletions(-) diff --git a/content/docs/administration/self-hosting/airgapped.md b/content/docs/administration/self-hosting/airgapped.md index d1368bef0f58..b58d281704a3 100644 --- a/content/docs/administration/self-hosting/airgapped.md +++ b/content/docs/administration/self-hosting/airgapped.md @@ -8,7 +8,7 @@ menu: name: Air-Gapped parent: administration-self-hosting weight: 5 - identifier: administration-security-compliance-self-hosted-airgapped + identifier: administration-self-hosting-airgapped aliases: - /docs/administration/self-hosting/airgapped/ - /docs/pulumi-cloud/admin/self-hosted/airgapped/ diff --git a/content/docs/administration/self-hosting/changelog.md b/content/docs/administration/self-hosting/changelog.md index 53ed1e215414..ebefec94b386 100644 --- a/content/docs/administration/self-hosting/changelog.md +++ b/content/docs/administration/self-hosting/changelog.md @@ -8,7 +8,7 @@ menu: name: Changelog parent: administration-self-hosting weight: 7 - identifier: administration-security-compliance-self-hosted-changelog + identifier: administration-self-hosting-changelog aliases: - /docs/pulumi-cloud/self-hosted/changelog/ - /docs/administration/self-hosting/pulumi-cloud/changelog/ diff --git a/content/docs/administration/self-hosting/components/_index.md b/content/docs/administration/self-hosting/components/_index.md index c154eb9d1c6e..95ce9f902d28 100644 --- a/content/docs/administration/self-hosting/components/_index.md +++ b/content/docs/administration/self-hosting/components/_index.md @@ -7,7 +7,7 @@ menu: administration: parent: administration-self-hosting weight: 2 - identifier: administration-security-compliance-self-hosted-components + identifier: administration-self-hosting-components aliases: - /docs/guides/self-hosted/console/ - /docs/guides/self-hosted/components/ diff --git a/content/docs/administration/self-hosting/components/api.md b/content/docs/administration/self-hosting/components/api.md index db082c91d184..123673533483 100644 --- a/content/docs/administration/self-hosting/components/api.md +++ b/content/docs/administration/self-hosting/components/api.md @@ -6,9 +6,9 @@ h1: Pulumi Cloud self-hosted API menu: administration: name: Pulumi API - parent: administration-security-compliance-self-hosted-components + parent: administration-self-hosting-components weight: 1 - identifier: administration-security-compliance-self-hosted-components-api + identifier: administration-self-hosting-components-api aliases: - /docs/guides/self-hosted/components/api/ - /docs/pulumi-cloud/self-hosted/components/api/ diff --git a/content/docs/administration/self-hosting/components/console.md b/content/docs/administration/self-hosting/components/console.md index 01b3e69fc9e6..c4f48b53d294 100644 --- a/content/docs/administration/self-hosting/components/console.md +++ b/content/docs/administration/self-hosting/components/console.md @@ -6,9 +6,9 @@ meta_desc: Pulumi console is one of the components required for self-hosting Pul menu: administration: name: Pulumi console - parent: administration-security-compliance-self-hosted-components + parent: administration-self-hosting-components weight: 2 - identifier: administration-security-compliance-self-hosted-components-console + identifier: administration-self-hosting-components-console aliases: - /docs/guides/self-hosted/components/console/ - /docs/pulumi-cloud/self-hosted/components/console/ diff --git a/content/docs/administration/self-hosting/components/deployments.md b/content/docs/administration/self-hosting/components/deployments.md index 95b991b8946f..2e38afb6d846 100644 --- a/content/docs/administration/self-hosting/components/deployments.md +++ b/content/docs/administration/self-hosting/components/deployments.md @@ -6,9 +6,9 @@ h1: Pulumi Cloud self-hosted Deployments menu: administration: name: Pulumi Deployments - parent: administration-security-compliance-self-hosted-components + parent: administration-self-hosting-components weight: 4 - identifier: administration-security-compliance-self-hosted-components-deployments + identifier: administration-self-hosting-components-deployments aliases: - /docs/guides/self-hosted/components/deployments/ - /docs/pulumi-cloud/self-hosted/components/deployments/ diff --git a/content/docs/administration/self-hosting/components/search.md b/content/docs/administration/self-hosting/components/search.md index 04cbda6dbe4b..73734047679f 100644 --- a/content/docs/administration/self-hosting/components/search.md +++ b/content/docs/administration/self-hosting/components/search.md @@ -6,9 +6,9 @@ h1: Pulumi Cloud self-hosted OpenSearch cluster menu: administration: name: OpenSearch cluster - parent: administration-security-compliance-self-hosted-components + parent: administration-self-hosting-components weight: 3 - identifier: administration-security-compliance-self-hosted-components-search + identifier: administration-self-hosting-components-search aliases: - /docs/guides/self-hosted/components/search/ - /docs/pulumi-cloud/self-hosted/components/search/ diff --git a/content/docs/administration/self-hosting/deployment-options/_index.md b/content/docs/administration/self-hosting/deployment-options/_index.md index ca4cc391aed0..d474c6cf7d50 100644 --- a/content/docs/administration/self-hosting/deployment-options/_index.md +++ b/content/docs/administration/self-hosting/deployment-options/_index.md @@ -7,7 +7,7 @@ menu: administration: parent: administration-self-hosting weight: 1 - identifier: administration-security-compliance-self-hosted-deployment-options + identifier: administration-self-hosting-deployment-options aliases: - /docs/pulumi-cloud/self-hosted/deployment-options/ - /docs/administration/self-hosting/pulumi-cloud/deployment-options/ diff --git a/content/docs/administration/self-hosting/deployment-options/aks-hosted.md b/content/docs/administration/self-hosting/deployment-options/aks-hosted.md index e86e9ac0a9ed..a70b7f36c510 100644 --- a/content/docs/administration/self-hosting/deployment-options/aks-hosted.md +++ b/content/docs/administration/self-hosting/deployment-options/aks-hosted.md @@ -6,9 +6,9 @@ h1: Pulumi Cloud self-hosted AKS install menu: administration: name: AKS - parent: administration-security-compliance-self-hosted-deployment-options + parent: administration-self-hosting-deployment-options weight: 4 - identifier: administration-security-compliance-self-hosted-deployment-options-aks + identifier: administration-self-hosting-deployment-options-aks aliases: - /docs/guides/self-hosted/aks-hosted/ - /docs/pulumi-cloud/self-hosted/deployment-options/aks-hosted/ diff --git a/content/docs/administration/self-hosting/deployment-options/byo-infra-hosted.md b/content/docs/administration/self-hosting/deployment-options/byo-infra-hosted.md index c2d41d539375..503d5bab8fc3 100644 --- a/content/docs/administration/self-hosting/deployment-options/byo-infra-hosted.md +++ b/content/docs/administration/self-hosting/deployment-options/byo-infra-hosted.md @@ -6,9 +6,9 @@ h1: Pulumi Cloud self-hosted BYO-infra install menu: administration: name: Bring-your-own infra - parent: administration-security-compliance-self-hosted-deployment-options + parent: administration-self-hosting-deployment-options weight: 7 - identifier: administration-security-compliance-self-hosted-deployment-options-byo-infra-hosted + identifier: administration-self-hosting-deployment-options-byo-infra-hosted aliases: - /docs/guides/self-hosted/byo-infra-hosted/ - /docs/pulumi-cloud/self-hosted/deployment-options/byo-infra-hosted/ diff --git a/content/docs/administration/self-hosting/deployment-options/ecs-hosted.md b/content/docs/administration/self-hosting/deployment-options/ecs-hosted.md index 65466c80569f..525dbe2a9bab 100644 --- a/content/docs/administration/self-hosting/deployment-options/ecs-hosted.md +++ b/content/docs/administration/self-hosting/deployment-options/ecs-hosted.md @@ -6,9 +6,9 @@ h1: Pulumi Cloud self-hosted ECS install menu: administration: name: ECS - parent: administration-security-compliance-self-hosted-deployment-options + parent: administration-self-hosting-deployment-options weight: 2 - identifier: administration-security-compliance-self-hosted-deployment-options-ecs + identifier: administration-self-hosting-deployment-options-ecs aliases: - /docs/guides/self-hosted/ecs-hosted/ - /docs/pulumi-cloud/self-hosted/deployment-options/ecs-hosted/ diff --git a/content/docs/administration/self-hosting/deployment-options/eks-hosted.md b/content/docs/administration/self-hosting/deployment-options/eks-hosted.md index 9f5a2c3529af..5d7cc885158f 100644 --- a/content/docs/administration/self-hosting/deployment-options/eks-hosted.md +++ b/content/docs/administration/self-hosting/deployment-options/eks-hosted.md @@ -6,9 +6,9 @@ h1: Pulumi Cloud self-hosted EKS install menu: administration: name: EKS - parent: administration-security-compliance-self-hosted-deployment-options + parent: administration-self-hosting-deployment-options weight: 3 - identifier: administration-security-compliance-self-hosted-deployment-options-eks + identifier: administration-self-hosting-deployment-options-eks aliases: - /docs/guides/self-hosted/eks-hosted/ - /docs/pulumi-cloud/self-hosted/deployment-options/eks-hosted/ diff --git a/content/docs/administration/self-hosting/deployment-options/gke-hosted.md b/content/docs/administration/self-hosting/deployment-options/gke-hosted.md index 8375366e56c1..318875ca991e 100644 --- a/content/docs/administration/self-hosting/deployment-options/gke-hosted.md +++ b/content/docs/administration/self-hosting/deployment-options/gke-hosted.md @@ -6,9 +6,9 @@ h1: Pulumi Cloud self-hosted GKE install menu: administration: name: GKE - parent: administration-security-compliance-self-hosted-deployment-options + parent: administration-self-hosting-deployment-options weight: 5 - identifier: administration-security-compliance-self-hosted-deployment-options-gke + identifier: administration-self-hosting-deployment-options-gke aliases: - /docs/guides/self-hosted/gke-hosted/ - /docs/pulumi-cloud/self-hosted/deployment-options/gke-hosted/ diff --git a/content/docs/administration/self-hosting/deployment-options/local-docker.md b/content/docs/administration/self-hosting/deployment-options/local-docker.md index 8c1b2c174816..e228785953cc 100644 --- a/content/docs/administration/self-hosting/deployment-options/local-docker.md +++ b/content/docs/administration/self-hosting/deployment-options/local-docker.md @@ -6,9 +6,9 @@ h1: Pulumi Cloud self-hosted local-Docker install menu: administration: name: Local-Docker - parent: administration-security-compliance-self-hosted-deployment-options + parent: administration-self-hosting-deployment-options weight: 6 - identifier: administration-security-compliance-self-hosted-deployment-options-local-docker + identifier: administration-self-hosting-deployment-options-local-docker aliases: - /docs/guides/self-hosted/local-docker/ - /docs/pulumi-cloud/self-hosted/deployment-options/local-docker/ diff --git a/content/docs/administration/self-hosting/deployment-options/quickstart-docker-compose.md b/content/docs/administration/self-hosting/deployment-options/quickstart-docker-compose.md index df9412999fe1..0223a4034924 100644 --- a/content/docs/administration/self-hosting/deployment-options/quickstart-docker-compose.md +++ b/content/docs/administration/self-hosting/deployment-options/quickstart-docker-compose.md @@ -6,9 +6,9 @@ h1: Try Self-Hosted Pulumi Cloud with Docker Compose menu: administration: name: Docker Compose - parent: administration-security-compliance-self-hosted-deployment-options + parent: administration-self-hosting-deployment-options weight: 1 - identifier: administration-security-compliance-self-hosted-deployment-options-quickstart-docker-compose + identifier: administration-self-hosting-deployment-options-quickstart-docker-compose aliases: - /docs/guides/self-hosted/quickstart-docker-compose/ - /docs/pulumi-cloud/self-hosted/deployment-options/quickstart-docker-compose/ diff --git a/content/docs/administration/self-hosting/network.md b/content/docs/administration/self-hosting/network.md index 0d19703d3efd..3a3c9c166ad4 100644 --- a/content/docs/administration/self-hosting/network.md +++ b/content/docs/administration/self-hosting/network.md @@ -8,7 +8,7 @@ menu: name: Network reqs parent: administration-self-hosting weight: 4 - identifier: administration-security-compliance-self-hosted-network + identifier: administration-self-hosting-network aliases: - /docs/guides/self-hosted/requirements/ - /docs/guides/self-hosted/requirements/network/ diff --git a/content/docs/administration/self-hosting/operations/_index.md b/content/docs/administration/self-hosting/operations/_index.md index 24d515f83ff6..31d129a363cc 100644 --- a/content/docs/administration/self-hosting/operations/_index.md +++ b/content/docs/administration/self-hosting/operations/_index.md @@ -8,7 +8,7 @@ menu: name: Operations parent: administration-self-hosting weight: 6 - identifier: administration-security-compliance-self-hosted-operations + identifier: administration-self-hosting-operations pulumi_cloud_feature: self-hosting --- diff --git a/content/docs/administration/self-hosting/operations/architecture.md b/content/docs/administration/self-hosting/operations/architecture.md index 1553ac8d2975..db80755ef7bd 100644 --- a/content/docs/administration/self-hosting/operations/architecture.md +++ b/content/docs/administration/self-hosting/operations/architecture.md @@ -6,9 +6,9 @@ h1: Self-Hosted Architecture Overview menu: administration: name: Architecture - parent: administration-security-compliance-self-hosted-operations + parent: administration-self-hosting-operations weight: 1 - identifier: administration-security-compliance-self-hosted-operations-architecture + identifier: administration-self-hosting-operations-architecture pulumi_cloud_feature: self-hosting --- diff --git a/content/docs/administration/self-hosting/operations/backup-recovery.md b/content/docs/administration/self-hosting/operations/backup-recovery.md index d8be2973ca0c..d9f5762001f0 100644 --- a/content/docs/administration/self-hosting/operations/backup-recovery.md +++ b/content/docs/administration/self-hosting/operations/backup-recovery.md @@ -6,9 +6,9 @@ h1: Backup and Recovery menu: administration: name: Backup and Recovery - parent: administration-security-compliance-self-hosted-operations + parent: administration-self-hosting-operations weight: 7 - identifier: administration-security-compliance-self-hosted-operations-backup-recovery + identifier: administration-self-hosting-operations-backup-recovery pulumi_cloud_feature: self-hosting --- diff --git a/content/docs/administration/self-hosting/operations/compute-sizing.md b/content/docs/administration/self-hosting/operations/compute-sizing.md index ff3a4a553794..928036d1687f 100644 --- a/content/docs/administration/self-hosting/operations/compute-sizing.md +++ b/content/docs/administration/self-hosting/operations/compute-sizing.md @@ -6,9 +6,9 @@ h1: Compute Sizing menu: administration: name: Compute Sizing - parent: administration-security-compliance-self-hosted-operations + parent: administration-self-hosting-operations weight: 3 - identifier: administration-security-compliance-self-hosted-operations-compute-sizing + identifier: administration-self-hosting-operations-compute-sizing pulumi_cloud_feature: self-hosting --- diff --git a/content/docs/administration/self-hosting/operations/database.md b/content/docs/administration/self-hosting/operations/database.md index 8d48beb78141..8f5e343e9805 100644 --- a/content/docs/administration/self-hosting/operations/database.md +++ b/content/docs/administration/self-hosting/operations/database.md @@ -6,9 +6,9 @@ h1: Database Best Practices menu: administration: name: Database - parent: administration-security-compliance-self-hosted-operations + parent: administration-self-hosting-operations weight: 2 - identifier: administration-security-compliance-self-hosted-operations-database + identifier: administration-self-hosting-operations-database pulumi_cloud_feature: self-hosting --- diff --git a/content/docs/administration/self-hosting/operations/monitoring.md b/content/docs/administration/self-hosting/operations/monitoring.md index c93eb185919a..1d73d24b3cdb 100644 --- a/content/docs/administration/self-hosting/operations/monitoring.md +++ b/content/docs/administration/self-hosting/operations/monitoring.md @@ -6,9 +6,9 @@ h1: Monitoring and Alerting menu: administration: name: Monitoring - parent: administration-security-compliance-self-hosted-operations + parent: administration-self-hosting-operations weight: 6 - identifier: administration-security-compliance-self-hosted-operations-monitoring + identifier: administration-self-hosting-operations-monitoring pulumi_cloud_feature: self-hosting --- diff --git a/content/docs/administration/self-hosting/operations/networking.md b/content/docs/administration/self-hosting/operations/networking.md index 851e43835b8e..33a4ed80f8d5 100644 --- a/content/docs/administration/self-hosting/operations/networking.md +++ b/content/docs/administration/self-hosting/operations/networking.md @@ -6,9 +6,9 @@ h1: Networking and Load Balancing menu: administration: name: Networking - parent: administration-security-compliance-self-hosted-operations + parent: administration-self-hosting-operations weight: 5 - identifier: administration-security-compliance-self-hosted-operations-networking + identifier: administration-self-hosting-operations-networking pulumi_cloud_feature: self-hosting --- diff --git a/content/docs/administration/self-hosting/operations/object-storage.md b/content/docs/administration/self-hosting/operations/object-storage.md index 11cc3788eccf..99590e88a94f 100644 --- a/content/docs/administration/self-hosting/operations/object-storage.md +++ b/content/docs/administration/self-hosting/operations/object-storage.md @@ -6,9 +6,9 @@ h1: Object Storage Best Practices menu: administration: name: Object Storage - parent: administration-security-compliance-self-hosted-operations + parent: administration-self-hosting-operations weight: 4 - identifier: administration-security-compliance-self-hosted-operations-object-storage + identifier: administration-self-hosting-operations-object-storage pulumi_cloud_feature: self-hosting --- diff --git a/content/docs/administration/self-hosting/operations/security-hardening.md b/content/docs/administration/self-hosting/operations/security-hardening.md index 4d124e52b1e2..abdbef5ce60f 100644 --- a/content/docs/administration/self-hosting/operations/security-hardening.md +++ b/content/docs/administration/self-hosting/operations/security-hardening.md @@ -6,9 +6,9 @@ h1: Security Hardening menu: administration: name: Security Hardening - parent: administration-security-compliance-self-hosted-operations + parent: administration-self-hosting-operations weight: 9 - identifier: administration-security-compliance-self-hosted-operations-security-hardening + identifier: administration-self-hosting-operations-security-hardening pulumi_cloud_feature: self-hosting --- diff --git a/content/docs/administration/self-hosting/operations/upgrades.md b/content/docs/administration/self-hosting/operations/upgrades.md index 34194023cdd3..9cd630400f31 100644 --- a/content/docs/administration/self-hosting/operations/upgrades.md +++ b/content/docs/administration/self-hosting/operations/upgrades.md @@ -6,9 +6,9 @@ h1: Upgrade Pipeline menu: administration: name: Upgrades - parent: administration-security-compliance-self-hosted-operations + parent: administration-self-hosting-operations weight: 8 - identifier: administration-security-compliance-self-hosted-operations-upgrades + identifier: administration-self-hosting-operations-upgrades pulumi_cloud_feature: self-hosting --- diff --git a/content/docs/administration/self-hosting/saml-sso.md b/content/docs/administration/self-hosting/saml-sso.md index a60ae3f6c9da..cdd92f40d390 100644 --- a/content/docs/administration/self-hosting/saml-sso.md +++ b/content/docs/administration/self-hosting/saml-sso.md @@ -8,7 +8,7 @@ menu: name: SAML SSO parent: administration-self-hosting weight: 3 - identifier: administration-security-compliance-self-hosted-saml-sso + identifier: administration-self-hosting-saml-sso aliases: - /docs/guides/self-hosted/saml-sso/ - /docs/pulumi-cloud/self-hosted/saml-sso/ From b1748533c3bb47566f1e56a14b81ec2b2e4189d3 Mon Sep 17 00:00:00 2001 From: Joe Duffy Date: Tue, 11 Aug 2026 17:43:40 -0700 Subject: [PATCH 08/12] Add consolidated system requirements and a troubleshooting page Two pages built entirely from facts that already existed but were scattered. System requirements collects what an installation needs -- licenses, compute, MySQL, object storage, OpenSearch, Kubernetes, DNS, TLS, network -- from four component pages, the operations guide, and the installer READMEs. Three of those facts were only ever documented upstream and appeared nowhere on the site: the `pulumi` database must exist before you install, the application user needs two specific GRANTs, and the MySQL server must accept inbound ICMP or the installer's connectivity check fails. Troubleshooting exists mostly for its first entry. The error string `ALGORITHM=INPLACE is not supported` is what a failed migration actually prints, and until now it appeared only inside the operations database page, where nobody searching that text would land. The other eight entries have the same property: each is a failure someone hits during a real install, indexed by the symptom rather than by the subsystem that causes it. Not done here, and worth a decision: the api, console, and search component pages each still carry their own minimum-requirements table. Collapsing them into this page is the obvious follow-up, except console's table says 1 CPU core and 1 GB while operations/compute-sizing says 0.5 vCPU and 512 Mi. Those may be measuring different things -- host minimum versus container request -- so they need an answer rather than a guess before anything gets deleted. Co-Authored-By: Claude Opus 5 (1M context) --- .../self-hosting/system-requirements.md | 106 ++++++++++++++++++ .../self-hosting/troubleshooting.md | 93 +++++++++++++++ 2 files changed, 199 insertions(+) create mode 100644 content/docs/administration/self-hosting/system-requirements.md create mode 100644 content/docs/administration/self-hosting/troubleshooting.md diff --git a/content/docs/administration/self-hosting/system-requirements.md b/content/docs/administration/self-hosting/system-requirements.md new file mode 100644 index 000000000000..08536e16806c --- /dev/null +++ b/content/docs/administration/self-hosting/system-requirements.md @@ -0,0 +1,106 @@ +--- +title_tag: "System Requirements | Self-Hosting Pulumi" +meta_desc: Everything a self-hosted Pulumi Cloud installation needs — compute, MySQL, object storage, OpenSearch, DNS, TLS, and license keys. +title: System requirements +h1: Self-Hosted Pulumi Cloud System Requirements +menu: + administration: + name: System requirements + parent: administration-self-hosting + weight: 2 + identifier: administration-self-hosting-system-requirements +pulumi_cloud_feature: self-hosting +--- + +{{< self-hosting-trial-note />}} + +Every deployment option needs the same set of things: somewhere to run three containers, a MySQL database, an object store, and DNS and TLS for two endpoints. The managed-platform installers provision most of this for you. The [bring-your-own-infrastructure](/docs/administration/self-hosting/deployment-options/byo-infra-hosted/) and [Docker Engine](/docs/administration/self-hosting/deployment-options/local-docker/) options expect you to supply it. + +## Licenses + +| Key | Required | Notes | +| :-- | :-- | :-- | +| `PULUMI_LICENSE_KEY` | Yes | A JWT issued by Pulumi. The service will not start without it. | +| `AG_GRID_LICENSE_KEY` | Yes | Set on the console container. | + +You receive both as part of a [proof of concept](/product/self-hosted/#self-hosted-trial). + +## Compute + +Three containers make up an installation: the [API](/docs/administration/self-hosting/components/api/), the [console](/docs/administration/self-hosting/components/console/), and a migrations job that runs once per upgrade. + +| Service | CPU | Memory | +| :-- | :-- | :-- | +| API | 2 vCPU | 4 GB | +| Console | 0.5 vCPU | 512 MB | +| Migrations | 128m | 128 MB | + +The API and console are stateless, so scale the API horizontally rather than vertically. A single-host evaluation needs at least **2 CPU cores and 8 GB of memory**. + +For production sizing, high availability, and per-installer configuration, see [Compute sizing](/docs/administration/self-hosting/operations/compute-sizing/). + +## Database + +| Requirement | Value | +| :-- | :-- | +| Engine | MySQL 8.0.x | +| Storage | 20 GB SSD minimum | +| `sql_mode` | Must include `STRICT_TRANS_TABLES` | + +If you are supplying your own server rather than letting an installer provision one: + +- Create a database named `pulumi` before installing. The installers do not create it. +- Grant the application user the privileges it needs: + + ```sql + GRANT ALL PRIVILEGES ON `pulumi`.* TO 'pulumi'@'%'; + GRANT CREATE USER ON *.* TO 'pulumi'@'%' WITH GRANT OPTION; + ``` + +- Enable inbound ICMP (ping) on the MySQL server. The installer's connectivity check depends on it. + +{{% notes type="warning" %}} +`STRICT_TRANS_TABLES` is not a suggestion. Without it, schema migrations fail with `ALGORITHM=INPLACE is not supported. Try ALGORITHM=COPY`. Aurora MySQL 8.0 does not set it by default — see [Required sql_mode settings](/docs/administration/self-hosting/operations/database/#required-sql_mode-settings) for how to set it per engine. +{{% /notes %}} + +## Object storage + +| Requirement | Value | +| :-- | :-- | +| Type | S3-compatible, Azure Blob Storage, or Google Cloud Storage | +| Storage | 200 GB SSD minimum | + +An installation uses separate buckets for checkpoints, policy packs, engine events, and service metadata. See [Object storage](/docs/administration/self-hosting/operations/object-storage/) for the full inventory and replication guidance. + +Two requirements catch people out with non-AWS S3-compatible stores: + +- Pass `endpoint=IP:PORT` and `s3ForcePathStyle=true` as query parameters on the storage endpoint. +- The store, and any proxy or ingress in front of it, must preserve the `Content-Encoding: gzip` header on responses. Stripping it returns garbled state to clients. + +## Search + +| Requirement | Value | +| :-- | :-- | +| Engine | OpenSearch 2.x | +| Tested versions | 2.9 and 2.11 | + +Resource search needs an OpenSearch cluster, but it is not in the critical path — if the cluster is unreachable, stack updates still work and the console reports search as unavailable. See [Search](/docs/administration/self-hosting/components/search/). + +## Kubernetes + +The EKS, AKS, GKE, and bring-your-own-infrastructure options need a conformant Kubernetes cluster. Each installer pins the version it was validated against; see the deployment guide for the option you are using. The ECS, Docker Compose, and Docker Engine options need no Kubernetes. + +## DNS and TLS + +Every installation serves two endpoints from a domain you control: + +- `api.` — the API, which the CLI and console call. +- `app.` — the console. + +Each needs a TLS certificate. The managed-platform installers can request these for you; the others expect you to supply them. + +## Network access + +Ingress on 443 (and 80 redirecting to it) from CLI users and browsers, plus 8080 from the console to the API. Egress to your database on 3306, your object store, and — unless you are running [air-gapped](/docs/administration/self-hosting/airgapped/) — Docker Hub to pull images. SMTP on 25, 465, or 587 is optional and only needed for invitations and password resets. + +See [Network requirements](/docs/administration/self-hosting/network/) for the full list. diff --git a/content/docs/administration/self-hosting/troubleshooting.md b/content/docs/administration/self-hosting/troubleshooting.md new file mode 100644 index 000000000000..c477cfc5de78 --- /dev/null +++ b/content/docs/administration/self-hosting/troubleshooting.md @@ -0,0 +1,93 @@ +--- +title_tag: "Troubleshooting | Self-Hosting Pulumi" +meta_desc: Symptoms, causes, and fixes for common self-hosted Pulumi Cloud problems — failed migrations, garbled state, TLS errors, and search issues. +title: Troubleshooting +h1: Troubleshooting Self-Hosted Pulumi Cloud +menu: + administration: + name: Troubleshooting + parent: administration-self-hosting + weight: 9 + identifier: administration-self-hosting-troubleshooting +pulumi_cloud_feature: self-hosting +--- + +{{< self-hosting-trial-note />}} + +Problems that come up often enough to be worth naming, with the symptom first so you can find yours by searching the error text. + +## Migrations fail with `ALGORITHM=INPLACE is not supported` + +**Symptom.** The migrations container exits with an error containing `ALGORITHM=INPLACE is not supported. Try ALGORITHM=COPY`. + +**Cause.** The database's `sql_mode` does not include `STRICT_TRANS_TABLES`. Aurora MySQL 8.0 does not set it by default. + +**Fix.** Set `STRICT_TRANS_TABLES` in the parameter group or server configuration and restart, then re-run migrations. See [Required sql_mode settings](/docs/administration/self-hosting/operations/database/#required-sql_mode-settings). + +## The Docker Compose stack exits immediately + +**Symptom.** `run-ee.sh` prints a message about contacting sales and exits before any container starts. + +**Cause.** `PULUMI_LICENSE_KEY` is unset. The script hard-fails rather than starting a service that cannot run. + +**Fix.** Export the license key before running the script. See the [Docker Compose quickstart](/docs/administration/self-hosting/deployment-options/quickstart-docker-compose/). + +## Stack state or policy packs download garbled + +**Symptom.** The CLI reports corrupt or unreadable state, or policy packs fail to load, against an S3-compatible object store. + +**Cause.** The API stores objects gzip-compressed. Something between the store and the client — the store itself, a reverse proxy, or an ingress controller — is stripping the `Content-Encoding: gzip` response header. + +**Fix.** Configure the store and every intermediary to preserve that header. + +## Connection failures to a bring-your-own MySQL server + +**Symptom.** The installer cannot reach a MySQL server that is otherwise up and accepting connections. + +**Cause.** Inbound ICMP is disabled on the database server. The installer's connectivity check uses it. + +**Fix.** Allow inbound ICMP from the cluster to the database server. + +## S3-compatible object storage is not reachable + +**Symptom.** The API fails to read or write objects against a non-AWS S3-compatible store. + +**Cause.** The endpoint is missing the query parameters the storage client needs to address a non-AWS endpoint. + +**Fix.** Append `endpoint=IP:PORT` and `s3ForcePathStyle=true` to the storage endpoint. See [System requirements](/docs/administration/self-hosting/system-requirements/#object-storage). + +## TLS verification fails when connecting to MySQL + +**Symptom.** The API or migrations container fails TLS verification against the database. + +**Cause.** `DATABASE_CA_CERTIFICATE` is set to a file path rather than the PEM contents, or the certificate does not match the hostname the service connects to. + +**Fix.** Set the variable to the PEM value itself and connect using a hostname the certificate covers. See [Encrypting connections with TLS](/docs/administration/self-hosting/operations/database/#encrypting-connections-with-tls). + +## Duplicate or failed migrations across multiple Docker hosts + +**Symptom.** Running the containers on more than one host produces migration errors or repeated migration attempts. + +**Cause.** Every host is trying to run migrations against the shared database. + +**Fix.** Set `disableDbMigrations` on every host except the one that owns migrations. See the [Docker Engine guide](/docs/administration/self-hosting/deployment-options/local-docker/). + +## An unexpected account owns SAML administration + +**Symptom.** After enabling SAML SSO, the administrator is an account nobody intended. + +**Cause.** On a fresh installation the first user to sign up becomes the administrator, and setting `samlEnabled: true` does not by itself block email and password signup. + +**Fix.** Create the intended administrator account first, before sharing the console URL. To stop further email signups, set `PULUMI_DISABLE_EMAIL_SIGNUP` on the API container — hiding the option on the console with `PULUMI_HIDE_EMAIL_SIGNUP` does not disable the underlying handler. + +## Stacks are missing from the Resources page + +**Symptom.** Resource search returns nothing, or is missing recently updated stacks. + +**Cause.** The OpenSearch index is stale or was built while the cluster was unavailable. + +**Fix.** Reindex from **Settings → Self-hosted** in the console. Search reindexes automatically each week, and search is never in the critical path for stack updates. See [Search](/docs/administration/self-hosting/components/search/). + +## Still stuck? + +Contact [Pulumi support](/support/) with your installer, its version, and the failing container's logs. From 51102b257c3b896987e0fa72db222f63411fa3ee Mon Sep 17 00:00:00 2001 From: Joe Duffy Date: Tue, 11 Aug 2026 17:47:00 -0700 Subject: [PATCH 09/12] Surface self-hosting on the docs landing pages Self-hosting had no entry at the docs root at all -- the only pointer was the word "self-hosting" inside the Administration card's description -- and on the Administration index it was the fifth card in a block headed "Getting started", which is not what it is. It now has its own section there and its own card at the root. Co-Authored-By: Claude Opus 5 (1M context) --- content/docs/_index.md | 4 ++++ content/docs/administration/_index.md | 7 +++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/content/docs/_index.md b/content/docs/_index.md index 3cb0ee355327..da880bd738ca 100644 --- a/content/docs/_index.md +++ b/content/docs/_index.md @@ -69,6 +69,10 @@ sections: heading: Administration description: Manage organizations, access, security, and self-hosting. link: /docs/administration/ + - icon: hard-drives + heading: Self-Hosting + description: Run the full Pulumi Cloud platform in your own cloud account or data center. + link: /docs/administration/self-hosting/ - icon: package heading: Registry ↗ description: Browse and search Pulumi packages for 150+ cloud providers and services. diff --git a/content/docs/administration/_index.md b/content/docs/administration/_index.md index 765007bf9082..c785e88bb534 100644 --- a/content/docs/administration/_index.md +++ b/content/docs/administration/_index.md @@ -46,10 +46,13 @@ sections: link: /docs/administration/security-compliance/ description: Set up audit logs and customer managed encryption keys. +- type: full-width-cards + heading: Self-hosting + cards: - icon: buildings - heading: Self-Hosting + heading: Run Pulumi Cloud in your own infrastructure link: /docs/administration/self-hosting/ - description: Deploy Pulumi Cloud in your own infrastructure with the Business Critical edition. + description: Install and operate the full platform on AWS, Azure, Google Cloud, Kubernetes, or your own hardware, including fully air-gapped networks. Available with the Business Critical edition. - type: flat heading: Have questions? From 8c521a2f2f79a71b03495444c827a678b29dc381 Mon Sep 17 00:00:00 2001 From: Joe Duffy Date: Tue, 11 Aug 2026 17:52:47 -0700 Subject: [PATCH 10/12] Split telemetry setup out of the API component reference The API reference had grown to 510 lines, and 147 of them -- nearly a third -- were an operator runbook rather than container reference: collector configuration, the metrics endpoint, and two full Prometheus setups including sixty lines of collector YAML. That material belongs next to the monitoring guide, which until now told you what to alert on without telling you how to get metrics out of the service in the first place. The four environment variables stay in the API reference, under the same #opentelemetry anchor, so the variable reference remains complete in one place and the inbound link from security-hardening and the installer READMEs keeps working. Only monitoring.md needed repointing. Deliberately not splitting further. This is a reference, and references are more useful when one search finds everything; sharding it by storage backend or identity provider would multiply cross-links and force anyone comparing two options to open two pages. The remaining ~370 lines all answer the same question -- what do I set on the API container for this subsystem. Unrelated and pre-existing, noted while checking anchors: the 2024 post self-hosted-search-and-deploy links to components/api#deployments, but that heading has always anchored as #pulumi-deployments. Co-Authored-By: Claude Opus 5 (1M context) --- .../self-hosting/components/api.md | 140 +-------------- .../self-hosting/operations/monitoring.md | 2 +- .../self-hosting/operations/telemetry.md | 165 ++++++++++++++++++ 3 files changed, 169 insertions(+), 138 deletions(-) create mode 100644 content/docs/administration/self-hosting/operations/telemetry.md diff --git a/content/docs/administration/self-hosting/components/api.md b/content/docs/administration/self-hosting/components/api.md index 123673533483..6e5e9cdabda9 100644 --- a/content/docs/administration/self-hosting/components/api.md +++ b/content/docs/administration/self-hosting/components/api.md @@ -316,153 +316,19 @@ To use [AWS DynamoDB](https://aws.amazon.com/dynamodb) to persist Audit Logs, sp ], ``` -## OpenTelemetry +## OpenTelemetry {#opentelemetry} -The API service is configured to export OpenTelemetry metrics and traces to the vendor of your choice via the OpenTelemetry collector. You will need to manage your own OpenTelemetry collector. - -The following environment variables are needed to configure OpenTelemetry in the service: +The API service exports OpenTelemetry metrics and traces to a collector you run, and exposes a `/metrics` endpoint for Prometheus. These are the variables the API container reads; for collector configuration, the metrics endpoint, and both Prometheus options, see [Telemetry](/docs/administration/self-hosting/operations/telemetry/). | Variable name | Description | | --- | --- | | OTEL_EXPORTER_OTLP_ENDPOINT | (Required) Used to configure the OTLP exporter. The base URL to which all telemetry will be sent. If not set, the API service will use no-op metrics and traces. | | OTEL_EXPORTER_OTLP_PROTOCOL | (Optional) Used to configure the OTLP exporter. Valid values are `http` or `grpc`. Defaults to `grpc`. | | PULUMI_ENABLE_DEPRECATED_METRICS | (Optional) Whether to continue emitting API service metrics in a log-based format. Defaults to `true`. | -| METRICS_WEBHOOK_SECRET | Required to successfully authenticate to the `/metrics` endpoint. The Authorization header should be set as follows: `Authorization: webhook-token `. | +| METRICS_WEBHOOK_SECRET | Required to successfully authenticate to the `/metrics` endpoint. | OpenTelemetry is not yet available for the [console service](/docs/administration/self-hosting/components/console/). -### Metrics endpoint - -The API service exposes a metrics endpoint (`https://api.pulumi.com/metrics`) that is secured by a bearer token. This token is configured using the environment variable `METRICS_WEBHOOK_SECRET`. - -{{% notes type="info" %}} -The token type is `webhook-token`, not `Bearer`. -{{% /notes %}} - -```sh -curl -s GET https://api.pulumi.com/metrics -H 'Authorization: webhook-token -``` - -### Prometheus - -The API service provides two options to get metrics into Prometheus: - -1. From the OpenTelemetry collector via a [Prometheus remote write exporter](#prometheus-remote-write-exporter). This is a push-based exporter. -1. From a [Prometheus exporter](#prometheus-exporter) by scraping the `/metrics` endpoint. This is a pull-based exporter. - -#### Prometheus remote write exporter - -This option does not use the `/metrics` endpoint. Instead, it exports metrics from the collector to a [Prometheus remote write compatible backend](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/exporter/prometheusremotewriteexporter/README.md). - -Example OpenTelemetry collector configuration for a service using AWS and the AWS Distro for OpenTelemetry Collector: - -```yaml -extensions: - sigv4auth: - -receivers: - otlp: - protocols: - grpc: - endpoint: localhost:4317 - -processors: - memory_limiter: - - batch: - -exporters: - logging: - - prometheusremotewrite: - endpoint: https://aws-managed-prometheus-endpoint/v1/api/remote_write - auth: - authenticator: sigv4auth - -service: - telemetry: - logs: - - pipelines: - traces: - receivers: [otlp] - processors: [memory_limiter, batch] - exporters: [logging] - - metrics: - receivers: [otlp] - processors: [memory_limiter, batch] - exporters: [prometheusremotewrite] - - extensions: [sigv4auth] -``` - -#### Prometheus exporter - -This option requires configuring the environment variable `METRICS_WEBHOOK_SECRET` to successfully authenticate to the [`/metrics` endpoint](#metrics-endpoint). - -Example OpenTelemetry collector configuration: - -```yaml -extensions: - bearertokenauth: - scheme: webhook-token - token: ${env:METRICS_WEBHOOK_SECRET} - -receivers: - otlp: - protocols: - grpc: - endpoint: localhost:4317 - -processors: - memory_limiter: - - batch: - -exporters: - debug: - - prometheus: - endpoint: api.pulumi.com:443 - auth: - authenticator: bearertokenauth - namespace: pulumi - resource_to_telemetry_conversion: - enabled: true - -service: - telemetry: - logs: - - pipelines: - traces: - receivers: [otlp] - processors: [memory_limiter, batch] - exporters: [debug] - - metrics: - receivers: [otlp] - processors: [memory_limiter, batch] - exporters: [prometheus] - - extensions: [bearertokenauth] -``` - -The bearer token also needs to be included in the Prometheus server configuration: - -```yaml -scrape_configs: - - job_name: pulumi - scrape_interval: 15s - authorization: - type: webhook-token - credentials: - scheme: https - static_configs: - - targets: ["api.pulumi.com"] -``` - ## Pulumi Deployments In order to enable [Pulumi Deployments](/docs/pulumi-cloud/deployments), the following must be configured: diff --git a/content/docs/administration/self-hosting/operations/monitoring.md b/content/docs/administration/self-hosting/operations/monitoring.md index 1d73d24b3cdb..4c09d30f1024 100644 --- a/content/docs/administration/self-hosting/operations/monitoring.md +++ b/content/docs/administration/self-hosting/operations/monitoring.md @@ -16,7 +16,7 @@ pulumi_cloud_feature: self-hosting Effective monitoring is critical for maintaining a reliable self-hosted Pulumi Cloud deployment. This page covers a recommended alerting strategy and the key metrics to watch. -The API service exposes Prometheus metrics and supports OpenTelemetry for tracing. See [OpenTelemetry configuration](/docs/administration/self-hosting/components/api/#opentelemetry) for setup details. +The API service exposes Prometheus metrics and supports OpenTelemetry for tracing. See [Telemetry](/docs/administration/self-hosting/operations/telemetry/) for setup details. ## Three-tier alerting strategy diff --git a/content/docs/administration/self-hosting/operations/telemetry.md b/content/docs/administration/self-hosting/operations/telemetry.md new file mode 100644 index 000000000000..e290c96c8b00 --- /dev/null +++ b/content/docs/administration/self-hosting/operations/telemetry.md @@ -0,0 +1,165 @@ +--- +title_tag: "Telemetry | Self-Hosting Pulumi" +meta_desc: Export metrics and traces from a self-hosted Pulumi Cloud installation via OpenTelemetry, and scrape or remote-write them into Prometheus. +title: Telemetry +h1: Self-Hosted Pulumi Cloud Telemetry +menu: + administration: + name: Telemetry + parent: administration-self-hosting-operations + weight: 7 + identifier: administration-self-hosting-operations-telemetry +pulumi_cloud_feature: self-hosting +--- + +{{< self-hosting-trial-note />}} + +Getting metrics and traces out of a self-hosted installation. For what to alert +on once they are flowing, see [Monitoring](/docs/administration/self-hosting/operations/monitoring/). + +## Configuring the exporter + +The API service is configured to export OpenTelemetry metrics and traces to the vendor of your choice via the OpenTelemetry collector. You will need to manage your own OpenTelemetry collector. + +The following environment variables are needed to configure OpenTelemetry in the service: + +| Variable name | Description | +| --- | --- | +| OTEL_EXPORTER_OTLP_ENDPOINT | (Required) Used to configure the OTLP exporter. The base URL to which all telemetry will be sent. If not set, the API service will use no-op metrics and traces. | +| OTEL_EXPORTER_OTLP_PROTOCOL | (Optional) Used to configure the OTLP exporter. Valid values are `http` or `grpc`. Defaults to `grpc`. | +| PULUMI_ENABLE_DEPRECATED_METRICS | (Optional) Whether to continue emitting API service metrics in a log-based format. Defaults to `true`. | +| METRICS_WEBHOOK_SECRET | Required to successfully authenticate to the `/metrics` endpoint. The Authorization header should be set as follows: `Authorization: webhook-token `. | + +OpenTelemetry is not yet available for the [console service](/docs/administration/self-hosting/components/console/). + +### Metrics endpoint + +The API service exposes a metrics endpoint (`https://api.pulumi.com/metrics`) that is secured by a bearer token. This token is configured using the environment variable `METRICS_WEBHOOK_SECRET`. + +{{% notes type="info" %}} +The token type is `webhook-token`, not `Bearer`. +{{% /notes %}} + +```sh +curl -s GET https://api.pulumi.com/metrics -H 'Authorization: webhook-token +``` + +### Prometheus + +The API service provides two options to get metrics into Prometheus: + +1. From the OpenTelemetry collector via a [Prometheus remote write exporter](#prometheus-remote-write-exporter). This is a push-based exporter. +1. From a [Prometheus exporter](#prometheus-exporter) by scraping the `/metrics` endpoint. This is a pull-based exporter. + +#### Prometheus remote write exporter + +This option does not use the `/metrics` endpoint. Instead, it exports metrics from the collector to a [Prometheus remote write compatible backend](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/exporter/prometheusremotewriteexporter/README.md). + +Example OpenTelemetry collector configuration for a service using AWS and the AWS Distro for OpenTelemetry Collector: + +```yaml +extensions: + sigv4auth: + +receivers: + otlp: + protocols: + grpc: + endpoint: localhost:4317 + +processors: + memory_limiter: + + batch: + +exporters: + logging: + + prometheusremotewrite: + endpoint: https://aws-managed-prometheus-endpoint/v1/api/remote_write + auth: + authenticator: sigv4auth + +service: + telemetry: + logs: + + pipelines: + traces: + receivers: [otlp] + processors: [memory_limiter, batch] + exporters: [logging] + + metrics: + receivers: [otlp] + processors: [memory_limiter, batch] + exporters: [prometheusremotewrite] + + extensions: [sigv4auth] +``` + +#### Prometheus exporter + +This option requires configuring the environment variable `METRICS_WEBHOOK_SECRET` to successfully authenticate to the [`/metrics` endpoint](#metrics-endpoint). + +Example OpenTelemetry collector configuration: + +```yaml +extensions: + bearertokenauth: + scheme: webhook-token + token: ${env:METRICS_WEBHOOK_SECRET} + +receivers: + otlp: + protocols: + grpc: + endpoint: localhost:4317 + +processors: + memory_limiter: + + batch: + +exporters: + debug: + + prometheus: + endpoint: api.pulumi.com:443 + auth: + authenticator: bearertokenauth + namespace: pulumi + resource_to_telemetry_conversion: + enabled: true + +service: + telemetry: + logs: + + pipelines: + traces: + receivers: [otlp] + processors: [memory_limiter, batch] + exporters: [debug] + + metrics: + receivers: [otlp] + processors: [memory_limiter, batch] + exporters: [prometheus] + + extensions: [bearertokenauth] +``` + +The bearer token also needs to be included in the Prometheus server configuration: + +```yaml +scrape_configs: + - job_name: pulumi + scrape_interval: 15s + authorization: + type: webhook-token + credentials: + scheme: https + static_configs: + - targets: ["api.pulumi.com"] +``` From f9aaa0fad68eff12e6644f005247773bcdc84815 Mon Sep 17 00:00:00 2001 From: Joe Duffy Date: Sat, 15 Aug 2026 18:51:03 -0700 Subject: [PATCH 11/12] Bring the ECS install instructions on-site The page described what the installer creates and then sent the reader to a README on GitHub for every actual step. It now carries the steps: prerequisites split by what you must supply, the three projects in deployment order with real commands, a configuration reference as tables rather than a wall of `pulumi config set` lines, and a verification sequence. Verification is the part that was missing everywhere and is worth stating plainly: hit /api/status, `pulumi login`, `pulumi whoami`, then a throwaway `pulumi new` / `up` / `destroy`. That sequence is what the quickstart's own Go integration tests do, so it is a real check rather than a plausible-looking one. Two facts that only existed upstream now appear here. The ECS installer defaults `dbInstanceType` to db.t3.small, a burstable instance that should not carry production traffic unnoticed, so defaults are called out under Sizing rather than left implicit. And hiding email login in the console does not disable the API handler behind it -- a reader configuring SSO would reasonably assume it does. The first-signup-becomes-administrator warning is now a shortcode. It applies to all seven deployment options but was documented only in the AKS installer's README, and it is the kind of thing you can only fix once. This page is the pattern for the remaining six; the others still hand off to their READMEs. Co-Authored-By: Claude Opus 5 (1M context) --- .../deployment-options/ecs-hosted.md | 257 ++++++++++++++---- .../self-hosted-first-admin-note.html | 15 + .../self-hosted-first-admin-note.markdown.md | 3 + 3 files changed, 227 insertions(+), 48 deletions(-) create mode 100644 layouts/shortcodes/self-hosted-first-admin-note.html create mode 100644 layouts/shortcodes/self-hosted-first-admin-note.markdown.md diff --git a/content/docs/administration/self-hosting/deployment-options/ecs-hosted.md b/content/docs/administration/self-hosting/deployment-options/ecs-hosted.md index 525dbe2a9bab..cfa56693c8ee 100644 --- a/content/docs/administration/self-hosting/deployment-options/ecs-hosted.md +++ b/content/docs/administration/self-hosting/deployment-options/ecs-hosted.md @@ -1,8 +1,8 @@ --- -title_tag: ECS-Hosted Install | Self-Hosting Pulumi -meta_desc: Installer and installation instructions for deploying the self-hosted Pulumi Cloud in ECS. +title_tag: ECS Install | Self-Hosting Pulumi +meta_desc: Install self-hosted Pulumi Cloud on Amazon ECS Fargate — prerequisites, the three Pulumi projects, configuration reference, and how to verify the installation. title: ECS -h1: Pulumi Cloud self-hosted ECS install +h1: Install Self-Hosted Pulumi Cloud on Amazon ECS menu: administration: name: ECS @@ -18,72 +18,233 @@ pulumi_cloud_feature: self-hosting {{< self-hosting-trial-note />}} -The [ECS-Hosted Installer](https://github.com/pulumi/pulumi-self-hosted-installers/tree/master/ecs-hosted) is used to deploy the self-hosted Pulumi Cloud in Amazon Elastic Container Service. You can choose between using a TypeScript or Golang installer. +The [ECS installer](https://github.com/pulumi/pulumi-self-hosted-installers/tree/master/ecs-hosted) runs the Pulumi API and console as Fargate services behind Application Load Balancers, backed by Aurora MySQL and S3. Pick this option when you want a production installation on AWS without operating Kubernetes. -## Prerequisites +The installer ships in TypeScript and Go. The commands below use the TypeScript version; the Go version lives in `ecs-hosted/go` and takes the same configuration. + +## What gets deployed -The customer is required to provide and manage the following: +| Service | Purpose | +| :-- | :-- | +| ECS on Fargate | Runs the API and console containers | +| Aurora MySQL | Persistent state, with automated replication and snapshots | +| S3 | Checkpoints, policy packs, and service metadata | +| OpenSearch | Resource search (optional) | +| Application Load Balancer | Traffic routing and TLS termination | +| Route 53 | DNS records for the API and console | +| VPC endpoints | Private connectivity to AWS services | -* AWS VPC with - * At least 2 public subnets available. - * At least 2 private subnets available. - * At least 2 isolated subnets available. - * An "isolated" subnet means it can only route traffic within the subnet. So there is no NAT gateway. -* Route53 hosted zone. -* ACM Certificate that covers FQDNs of the following form, where `{subdomain}` is optional: - * `{subdomain}.{zoneDomainName}` - * `api.{subdomain}.{zoneDomainName}` - * `app.{subdomain}.{zoneDomainName}` -* KMS key to be used the self-hosted Pulumi Cloud for encryption/decryption purposes. +## Prerequisites -## ECS-Hosted Deployment +You provide the network, DNS, certificate, and key material. The installer builds everything else. -The ECS-hosted installation of Pulumi deploys the following services: +**AWS access.** `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` in the environment, plus `AWS_SESSION_TOKEN` if you use temporary credentials. -* ECS - Managed ECS Cluster -* Fargate - Managed Container Service -* RDS Aurora - Managed MySQL DB for persistent state and automated replication and snapshotting. -* S3 - Object storage for checkpoints and policy packs. -* CloudWatch Logs - Centralized logging for all cluster pods. -* Route53 - Managed DNS records. -* NLB - Managed L4/application traffic and TLS termination. -* ACM - Managed Public TLS certificates. +**Networking.** An existing VPC with at least two public, two private, and two isolated subnets. -### Pulumi deploying Pulumi +**DNS and TLS.** A Route 53 hosted zone, and an ACM certificate covering the base domain plus `app.{sub}.example.com` and `api.{sub}.example.com`. -This installer uses Pulumi to deploy the Pulumi Cloud. In this case, one uses the pulumi CLI with a self-managed backend (e.g., S3) to deploy all services listed above to stand up the self-hosted Pulumi Cloud. The installation package includes the Pulumi project code so you can deploy the service by running `pulumi up`. +**Encryption.** A KMS key for the service to encrypt and decrypt secrets. -To this end, you need to set up the following: +**Images.** ECR repositories holding the Pulumi API, console, and migrations images. -* [Download and install the Pulumi CLI](/docs/install/) on your workstation -* [Login to S3-compatible backend](/docs/concepts/state#aws-s3) +**License.** A `PULUMI_LICENSE_KEY` and an AG Grid license key. -### Deployment Steps +See [System requirements](/docs/administration/self-hosting/system-requirements/) for database, storage, and sizing details that apply to every installation. -See the [README](https://github.com/pulumi/pulumi-self-hosted-installers/tree/master/ecs-hosted) file provided with the installer package for detailed deployment steps. +## Sizing -## ECS-Hosted System Management and Maintenance +Defaults are deliberately small so a first deployment comes up quickly. Raise them before running production workloads. -### Pulumi Cloud Updates +| Setting | Default | +| :-- | :-- | +| `dbInstanceType` | `db.t3.small` — burstable; see [Database](/docs/administration/self-hosting/operations/database/) | +| `apiTaskCpu` / `apiTaskMemory` | 512 / 1024 MB | +| `consoleTaskCpu` / `consoleTaskMemory` | 256 / 512 MB | +| `apiDesiredNumberTasks` | 1 — raise to at least 2 for high availability | + +## Install + +The installer is itself a set of Pulumi programs, so you need a state backend for them. These use an S3 bucket, which keeps the installer's own state independent of the installation it creates. + +Deploy the three projects in order. Each consumes outputs from the one before it. + +### 1. Get the installer + +```bash +git clone https://github.com/pulumi/pulumi-self-hosted-installers.git +cd pulumi-self-hosted-installers/ecs-hosted/ts +pulumi login s3:// +``` + +### 2. Deploy base infrastructure + +Creates the Aurora cluster, VPC endpoints, and security groups. + +```bash +cd infrastructure +npm install +pulumi stack init +pulumi config set aws:region us-west-2 +pulumi config set vpcId vpc-0123456789abcdef0 +pulumi config set publicSubnetIds '["subnet-aaa","subnet-bbb"]' +pulumi config set privateSubnetIds '["subnet-ccc","subnet-ddd"]' +pulumi config set isolatedSubnetIds '["subnet-eee","subnet-fff"]' +pulumi up +``` + +### 3. Deploy the application + +Creates the ECS clusters and the API and console services. + +```bash +cd ../application +npm install +pulumi stack init +pulumi config set aws:region us-west-2 +pulumi config set imageTag +pulumi config set acmCertificateArn +pulumi config set kmsServiceKeyId +pulumi config set licenseKey --secret +pulumi config set route53ZoneName example.com +pulumi config set route53Subdomain pulumi +pulumi up +``` + +The database, security group, and OpenSearch values come from the previous stack's outputs. Set them with `pulumi config set` as shown in the [configuration reference](#configuration-reference) below. + +{{% notes type="info" %}} +Pin `imageTag` to a specific version rather than `latest`, so an unrelated `pulumi up` cannot roll the service forward unintentionally. Tags are listed on [Docker Hub](https://hub.docker.com/r/pulumi/service/tags). +{{% /notes %}} + +### 4. Create DNS records + +```bash +cd ../dns +npm install +pulumi stack init +pulumi config set aws:region us-west-2 +pulumi config set route53ZoneName example.com +pulumi config set route53Subdomain pulumi +pulumi config set apiLoadBalancerDnsName +pulumi config set apiLoadBalancerZoneId +pulumi config set consoleLoadBalancerDnsName +pulumi config set consoleLoadBalancerZoneId +pulumi up +``` + +## Configuration reference + +### Base infrastructure + +| Key | Required | Default | Description | +| :-- | :-- | :-- | :-- | +| `aws:region` | Yes | | AWS region | +| `vpcId` | Yes | | Existing VPC | +| `publicSubnetIds` | Yes | | At least two public subnet IDs | +| `privateSubnetIds` | Yes | | At least two private subnet IDs | +| `isolatedSubnetIds` | Yes | | At least two isolated subnet IDs | +| `dbInstanceType` | No | `db.t3.small` | RDS instance type | +| `enableOpenSearch` | No | | Deploy an OpenSearch domain for resource search | +| `openSearchInstanceType` | No | `t3.medium.search` | OpenSearch instance type | +| `openSearchInstanceCount` | No | `2` | Cannot be lower than 2 | +| `openSearchDomainName` | No | `pulumi` | OpenSearch domain name | +| `openSearchDedicatedMasterCount` | No | none | Dedicated master nodes | + +### Application + +| Key | Required | Default | Description | +| :-- | :-- | :-- | :-- | +| `aws:region` | Yes | | AWS region | +| `vpcId` | Yes | | Existing VPC | +| `publicSubnetIds` / `privateSubnetIds` / `isolatedSubnetIds` | Yes | | Subnet IDs, as above | +| `imageTag` | Yes | | Pulumi container image tag | +| `licenseKey` | Yes | | Set with `--secret` | +| `acmCertificateArn` | Yes | | Covers the Route 53 domain | +| `kmsServiceKeyId` | Yes | | KMS key securing secrets | +| `route53ZoneName` | Yes | | Hosted zone name | +| `route53Subdomain` | Yes | | Subdomain for DNS records | +| `dbClusterEndpoint` | Yes | | Aurora cluster endpoint | +| `dbPort` | Yes | `3306` | MySQL port | +| `dbName` | Yes | | Database name | +| `dbUsername` / `dbPassword` | Yes | | Database credentials | +| `dbSecurityGroupId` | Yes | | Database security group | +| `endpointSecurityGroupId` | Yes | | Security group for VPC endpoints | +| `openSearchUser` / `openSearchPassword` | Yes | | OpenSearch credentials | +| `openSearchEndpoint` / `openSearchDomain` | Yes | | OpenSearch endpoint and domain | +| `apiDesiredNumberTasks` | No | `1` | API task count | +| `apiTaskCpu` / `apiTaskMemory` | No | `512` / `1024` | API task-level CPU and memory | +| `apiContainerCpu` | No | task CPU | CPU for the API container | +| `apiContainerMemoryReservation` | No | task memory | Memory reserved for the API container | +| `apiDisabledEmailLogin` / `apiDisabledEmailSignup` | No | | Disable the email login and signup handlers | +| `consoleDesiredNumberTasks` | No | `1` | Console task count | +| `consoleTaskCpu` / `consoleTaskMemory` | No | `256` / `512` | Console task-level CPU and memory | +| `consoleContainerCpu` | No | task CPU | CPU for the console container | +| `consoleContainerMemoryReservation` | No | task memory | Memory reserved for the console container | +| `consoleHideEmailLogin` / `consoleHideEmailSignup` | No | | Hide email login and signup in the UI | +| `smtpServer` | No | | Fully qualified SMTP address | +| `smtpUsername` / `smtpPassword` | No | | SMTP credentials | +| `smtpGenericSender` | No | | From address for outgoing email | +| `logType` | No | none | Log driver, for example `awslogs` | +| `logArgs` | No | | Log driver arguments | +| `agGridLicenseKey` | No | | AG Grid license key for the console | + +Hiding email login in the console does not disable the API handler behind it. To turn the handler off, set `apiDisabledEmailLogin` and `apiDisabledEmailSignup` as well. + +### DNS + +| Key | Required | Description | +| :-- | :-- | :-- | +| `aws:region` | Yes | AWS region | +| `route53ZoneName` | Yes | Route 53 zone name | +| `route53Subdomain` | Yes | Subdomain | +| `apiLoadBalancerDnsName` / `apiLoadBalancerZoneId` | Yes | API load balancer | +| `consoleLoadBalancerDnsName` / `consoleLoadBalancerZoneId` | Yes | Console load balancer | + +## Verify the installation + +```bash +curl -fsS https://api.{sub}.example.com/api/status +pulumi login https://api.{sub}.example.com +pulumi whoami +``` + +Then open `https://app.{sub}.example.com` and create the first account. + +{{< self-hosted-first-admin-note />}} + +Confirm an end-to-end update works: + +```bash +pulumi new aws-typescript --stack dev --yes +pulumi up --yes +pulumi destroy --yes +``` + +## Upgrade {{< self-hosting-schema-v2-note />}} -When deploying the Pulumi Cloud, it is recommended to pin the image tag to a specific version. See the [installer's README](https://github.com/pulumi/pulumi-self-hosted-installers/tree/master/ecs-hosted) file to set the `imageTag` configuration property for the installer to use. +```bash +pulumi login s3:// +cd pulumi-self-hosted-installers/ecs-hosted/ts/application +pulumi config set imageTag +pulumi up +``` + +Migrations run before the services roll. See [Upgrades](/docs/administration/self-hosting/operations/upgrades/) for staged rollouts and ordering. -When ready to update the Pulumi Cloud containers to use a different version, do the following: +## Uninstall -* `pulumi login` to the self-managed (not self-hosted) backend as chosen above when installing the self-hosted service. -* `pulumi config set imageTag {image tag}` to set the version you want to use. -* `pulumi up` to deploy the updates. +Destroy the projects in reverse order — `dns`, then `application`, then `infrastructure`. Aurora and S3 carry deletion protection, so remove that first if you intend to delete the data. -### Database Maintenance +## Maintenance -The installer configures the RDS backend database for replication and checkpointing. So no additional maintenance is needed by the customer. +The installer configures Aurora for replication and automated snapshots, so no routine database work is needed. For S3, consider enabling AWS Backup on the buckets the installer creates, which are named `pulumi-checkpoint-*` and `pulumi-policy-*`. -### Blob Storage Maintenance +## Troubleshooting -The service automatically creates backups of checkpoint (i.e. state) files. However the customer may want to enable AWS Backup to periodically backup the S3 buckets created by the installer. -The buckets will have names of the form: +- Migrations failing with `ALGORITHM=INPLACE is not supported` means `sql_mode` is missing `STRICT_TRANS_TABLES`. Aurora MySQL 8.0 does not set it by default. +- The API cannot start without `licenseKey`. -* `pulumi-checkpoint-XXX` -* `pulumi-policy-XXX` +See [Troubleshooting](/docs/administration/self-hosting/troubleshooting/) for the full list. diff --git a/layouts/shortcodes/self-hosted-first-admin-note.html b/layouts/shortcodes/self-hosted-first-admin-note.html new file mode 100644 index 000000000000..b4c4d3c36846 --- /dev/null +++ b/layouts/shortcodes/self-hosted-first-admin-note.html @@ -0,0 +1,15 @@ +{{- /* Applies to every deployment option, so it lives here rather than being + restated per page. Sourced from the AKS installer README, which is the + only place upstream that spells it out. */ -}} +
+
+ {{ partial "icon.html" (dict "name" "warning" "weight" "fill") }} +
+
+
+ {{ printf "On a fresh installation the **first user to sign up becomes the administrator**, including the SAML administrator. Create the account you intend to own the organization before sharing the console URL. Enabling SAML does not by itself close email and password signup — set `PULUMI_DISABLE_EMAIL_SIGNUP` on the API container to do that, since hiding the option in the console leaves the underlying handler active." | markdownify }} + {{- with .Inner }} + {{ . | markdownify }} + {{- end }} +
+
diff --git a/layouts/shortcodes/self-hosted-first-admin-note.markdown.md b/layouts/shortcodes/self-hosted-first-admin-note.markdown.md new file mode 100644 index 000000000000..ef2c85f3ed28 --- /dev/null +++ b/layouts/shortcodes/self-hosted-first-admin-note.markdown.md @@ -0,0 +1,3 @@ +{{- $inner := trim (printf "%s" .Inner) " \t\n\r" -}} + +> **Warning:** On a fresh installation the **first user to sign up becomes the administrator**, including the SAML administrator. Create the account you intend to own the organization before sharing the console URL. Enabling SAML does not by itself close email and password signup — set `PULUMI_DISABLE_EMAIL_SIGNUP` on the API container to do that, since hiding the option in the console leaves the underlying handler active.{{ with $inner }} {{ . }}{{ end }} From a0f043dba567457a04e8d848c9aac6cfdb61f78b Mon Sep 17 00:00:00 2001 From: Joe Duffy Date: Sat, 15 Aug 2026 18:53:35 -0700 Subject: [PATCH 12/12] Warn about the first-signup administrator on every deployment page Whoever signs up first on a fresh installation becomes the administrator, and turning on SAML does not close email and password signup on its own. That is true of all seven deployment options and was documented in exactly one place: the AKS installer's README on GitHub. It is also unrecoverable in the way that matters -- by the time you notice, someone else owns the organization -- so it belongs next to the install steps rather than in a security page nobody reads first. Co-Authored-By: Claude Opus 5 (1M context) --- .../self-hosting/deployment-options/aks-hosted.md | 2 ++ .../self-hosting/deployment-options/byo-infra-hosted.md | 2 ++ .../self-hosting/deployment-options/eks-hosted.md | 2 ++ .../self-hosting/deployment-options/gke-hosted.md | 2 ++ .../self-hosting/deployment-options/local-docker.md | 2 ++ 5 files changed, 10 insertions(+) diff --git a/content/docs/administration/self-hosting/deployment-options/aks-hosted.md b/content/docs/administration/self-hosting/deployment-options/aks-hosted.md index a70b7f36c510..9cb715418d9b 100644 --- a/content/docs/administration/self-hosting/deployment-options/aks-hosted.md +++ b/content/docs/administration/self-hosting/deployment-options/aks-hosted.md @@ -42,6 +42,8 @@ To this end, you need to set up the following: See the [README](https://github.com/pulumi/pulumi-self-hosted-installers/tree/master/aks-hosted/README.md) file provided with the installer package for detailed deployment steps. +{{< self-hosted-first-admin-note />}} + ## AKS-Hosted System Management and Maintenance ### Pulumi Cloud Updates diff --git a/content/docs/administration/self-hosting/deployment-options/byo-infra-hosted.md b/content/docs/administration/self-hosting/deployment-options/byo-infra-hosted.md index 503d5bab8fc3..f313da9616b9 100644 --- a/content/docs/administration/self-hosting/deployment-options/byo-infra-hosted.md +++ b/content/docs/administration/self-hosting/deployment-options/byo-infra-hosted.md @@ -42,6 +42,8 @@ To this end, you need to set up the following: See the [README](https://github.com/pulumi/pulumi-self-hosted-installers/tree/master/byo-infra/README.md) file provided with the installer package for detailed deployment steps. +{{< self-hosted-first-admin-note />}} + ## BYO Infrastructure Hosted System Management and Maintenance ### Pulumi Cloud Updates diff --git a/content/docs/administration/self-hosting/deployment-options/eks-hosted.md b/content/docs/administration/self-hosting/deployment-options/eks-hosted.md index 5d7cc885158f..8ebc13c79d47 100644 --- a/content/docs/administration/self-hosting/deployment-options/eks-hosted.md +++ b/content/docs/administration/self-hosting/deployment-options/eks-hosted.md @@ -51,6 +51,8 @@ To this end, you need to set up the following: See the [README](https://github.com/pulumi/pulumi-self-hosted-installers/tree/master/eks-hosted/README.md) file provided with the installer package for detailed deployment steps. +{{< self-hosted-first-admin-note />}} + ## EKS-Hosted System Management and Maintenance ### Pulumi Cloud Updates diff --git a/content/docs/administration/self-hosting/deployment-options/gke-hosted.md b/content/docs/administration/self-hosting/deployment-options/gke-hosted.md index 318875ca991e..48227ae5df66 100644 --- a/content/docs/administration/self-hosting/deployment-options/gke-hosted.md +++ b/content/docs/administration/self-hosting/deployment-options/gke-hosted.md @@ -41,6 +41,8 @@ To this end, you need to set up the following: See the [README](https://github.com/pulumi/pulumi-self-hosted-installers/tree/master/gke-hosted/README.md) file provided with the installer package for detailed deployment steps. +{{< self-hosted-first-admin-note />}} + ## GKE-Hosted System Management and Maintenance ### Pulumi Cloud Updates diff --git a/content/docs/administration/self-hosting/deployment-options/local-docker.md b/content/docs/administration/self-hosting/deployment-options/local-docker.md index e228785953cc..f3c44797b3eb 100644 --- a/content/docs/administration/self-hosting/deployment-options/local-docker.md +++ b/content/docs/administration/self-hosting/deployment-options/local-docker.md @@ -53,6 +53,8 @@ To this end, you need to set up the following: See the [README](https://github.com/pulumi/pulumi-self-hosted-installers/tree/master/local-docker/README.md) file provided with the installer package for detailed deployment steps. +{{< self-hosted-first-admin-note />}} + ## Local-Docker System Management and Maintenance ### Pulumi Cloud Updates