Pulumi Cloud self-hosted API
The Pulumi API is one of the components required for self-hosting Pulumi Cloud in your organization’s environment. It provides the necessary APIs for both the CLI and the Console.
Prerequisites
- 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.)
- 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, setPULUMI_LOCAL_DATABASE_HOSTandPULUMI_LOCAL_DATABASE_PORTaccordingly (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.
- The default DB endpoint is
- Provide an external load balancer with TLS termination.
Minimum System Requirements
| Type | Properties | Notes |
|---|---|---|
| Compute | 2 CPU cores w/ 8 GB memory | |
| Storage | 20GB SSD | For MySQL data. Note: By default, the installation uses a single data path via PULUMI_DATA_PATH to map both the SQL data volume and the object storage path. Specify a volume for the db container as required. |
| Storage | 200GB SSD | For Object Storage. Note: By default, the installation uses a single data path via PULUMI_DATA_PATH to map both the SQL data volume and the object storage path. A dedicated path can be set via env var PULUMI_LOCAL_OBJECTS for the api container. |
Note: The storage recommendations for the Object Storage can be lesser than 200GB depending on your organization size and the expected usage.
What’s In The Container?
The API service is a Go-based application. This is a single binary application that has all of the dependencies it needs in order to run.
Server
This container runs an HTTP server which provides the APIs needed by the Console and the CLI. By default, this container will serve using port 8080 over standard HTTP. If TLS is configured the server will instead serve over port 8443 using HTTPS.
Function Mode
It’s possible to split apart the HTTP Server from the Background Jobs functionality to distribute responsibility across multiple instances. The function mode determines the mode in which the server runs based upon the env variable PULUMI_API_CONTAINER_MODE. If this value is not defined, or doesn’t match a valid option, then it defaults to FULL.
| Variable Name | Description |
|---|---|
| FULL | Pulumi API & Background Jobs (Default) |
| API | Only Pulumi API |
| JOBS | Only Background Jobs |
Environment Variables for Core Infrastructure
The core infrastructure components to successfully run the API service are the database, object storage, and encryption services. Depending on your requirements, you can configure additional (optional) identity services as well as enhanced security between the API and the database. The API also supports exporting OpenTelemetry metrics and traces via the OpenTelemetry collector.
| Variable Name | Description |
|---|---|
| PULUMI_LICENSE_KEY | The license key value. A JWT string. Note: Be sure to enclose the value in single-quotes. |
| PULUMI_DATABASE_ENDPOINT | The database server endpoint in the format host:port. This should be a MySQL 8.0 server. |
| PULUMI_DATABASE_NAME | The name of the database on the database server. |
| PULUMI_API_DOMAIN | The internet or network-local domain using which the API service can be reached, e.g. pulumiapi.acmecorp.com. Default is localhost:8080. |
| PULUMI_CONSOLE_DOMAIN | The internet or network-local domain using which the Console can be reached, e.g. pulumiconsole.acmecorp.com. Default is localhost:3000. |
| PULUMI_ENGINE_EVENTS_SCHEMA_V2 | Set this environment variable to true for fresh installs. If you have an existing installation and the environment variable is currently not set or set to false, contact Pulumi support before setting it to true. |
| PULUMI_ENGINE_EVENTS_LEGACY_WRITE | Set this environment variable to false for fresh installs. If you have an existing installation and the environment variable is currently not set or set to true in your installation, contact Pulumi support before setting it to false. |
Object storage
The service saves the state of every stack, that uses it as the backend, to a persistent object storage. If your org uses policy packs, then anytime a user publishes a policy pack, it gets uploaded to the same object storage service as well. Both the state (checkpoint) and the policy pack must use different buckets on the same object storage service.
Content-Encoding: gzip header on responses. If this header is stripped or missing, clients will receive garbled content instead of valid data.Local storage
| Variable Name | Description |
|---|---|
| PULUMI_LOCAL_OBJECTS | Folder path for persisting state for stacks. Ensure that this path is highly available, and backed-up regularly. Only use this if you want the service to persist objects to a local path. |
| PULUMI_POLICY_PACK_LOCAL_HTTP_OBJECTS | Folder path for persisting published policy packs. Ensure that this path is highly available, and backed-up regularly. Only use this if you want the service to persist policy packs to a local path. |
AWS S3
AWS_REGION with
any valid AWS region name. For example, us-west-2.| Variable Name | Description |
|---|---|
| PULUMI_CHECKPOINT_BLOB_STORAGE_ENDPOINT | The storage endpoint for persisting stack state/checkpoint. The value takes the format: s3://<bucket-name>. The s3:// scheme also supports query-params. See the GoCloud docs for an example of the query-params. |
| PULUMI_POLICY_PACK_BLOB_STORAGE_ENDPOINT | The storage endpoint for persisting published policy packs. The value takes the format: s3://<bucket-name>. Similar to PULUMI_CHECKPOINT_BLOB_STORAGE_ENDPOINT, this also supports query-params. |
| PULUMI_ENGINE_EVENTS_BLOB_STORAGE_ENDPOINT | The storage endpoint for persisting large engine events. We recommend configuring this value to improve performance and reduce the size of the MySQL database. The value takes the format: s3://<bucket-name>. Similar to PULUMI_CHECKPOINT_BLOB_STORAGE_ENDPOINT, this also supports query-params. |
| PULUMI_SERVICE_METADATA_BLOB_STORAGE_ENDPOINT | The storage endpoint for persisting authorization policies and large config values. We recommend configuring this value to enable OIDC trust or if your programs use configuration values exceeding 64kb. The value takes the format: s3://<bucket-name>. Similar to PULUMI_CHECKPOINT_BLOB_STORAGE_ENDPOINT, this also supports query-params. |
Azure Storage
| Variable Name | Description |
|---|---|
| PULUMI_CHECKPOINT_BLOB_STORAGE_ENDPOINT | The storage endpoint for persisting stack state/checkpoint. The value takes the format: azblob://<blob-container>. |
| PULUMI_POLICY_PACK_BLOB_STORAGE_ENDPOINT | The storage endpoint for persisting published policy packs. The value takes the format: azblob://<blob-container>. |
| PULUMI_ENGINE_EVENTS_BLOB_STORAGE_ENDPOINT | The storage endpoint for persisting large engine events. We recommend configuring this value to improve performance and reduce the size of the MySQL database. The value takes the format: azblob://<blob-container>. |
| PULUMI_SERVICE_METADATA_BLOB_STORAGE_ENDPOINT | The storage endpoint for persisting authorization policies and large config values. We recommend configuring this value to enable OIDC trust or if your programs use configuration values exceeding 64kb. The value takes the format: azblob://<bucket-name>. |
| AZURE_STORAGE_ACCOUNT | The name of the Azure storage account where the blob containers for checkpoint and policy pack have been created. See Cloud Provider Authentication for additional configuration options for Azure. |
| AZURE_STORAGE_KEY | (Optional) The primary or secondary storage key for the storage account. You only need to specify this if you are not using Azure MSI. |
Encryption services
The service supports using a master key available in a local-path or in a remote key management service. You only need to configure one of the support services.
Local keys
| Variable Name | Description |
|---|---|
| PULUMI_LOCAL_KEYS | Path to a file that contains a random 32-byte key. Ensure that this path is highly available, and backed-up regularly. |
AWS KMS
Mandatory key actions
Define the following actions in the key’s key policy in AWS KMS. Otherwise, the service will fail to start or will not be able to run crypto operations:
kms:Encryptkms:Decryptkms:GenerateDataKeykms:GenerateDataKeyWithoutPlaintext
| Variable Name | Description |
|---|---|
| PULUMI_KMS_KEY | ARN for the AWS KMS customer master key resource. |
Azure KeyVault
Mandatory key operations or permissions
Configure the key in Azure KeyVault to support and allow the following operations. Otherwise, the service will fail to start or will not be able to run crypto operations:
EncryptDecryptSignVerify
| Variable Name | Description |
|---|---|
| PULUMI_AZURE_KV_URI | Azure KeyVault URI. For example, https://<vault-name>.vault.azure.net. |
| PULUMI_AZURE_KV_KEY_NAME | The name of the key in KeyVault. The key must be an RSA key type. We recommend a key size of 2048 for most cases. |
Cloud Provider Authentication
These settings are required if you are running Pulumi Cloud on one of these clouds or using one of their services.
AWS
For more information about authenticating with AWS services, see the AWS SDK docs.
| Variable Name | Description |
|---|---|
| AWS_REGION | The region where the dependent AWS services used by Pulumi Cloud have been created. For example, the KMS key must exist in this region. Similarly, if you are using RDS, then there must be a writable cluster in this region. |
| AWS_ACCESS_KEY_ID | The AWS access key ID. |
| AWS_SECRET_ACCESS_KEY | The AWS secret key. |
| AWS_PROFILE | The AWS profile. |
| AWS_ROLE_ARN | The AWS role ARN to assume using the base access keys. |
Azure
AZURE_STORAGE_KEY env var.| Variable Name | Description |
|---|---|
| AZURE_CLIENT_ID | Client ID of the Azure Managed System Identity or the self-managed Service Principal (SP) that should be used for both Azure KeyVault and Storage. The MSI or the SP must have access to Key Management operations (Get, Encrypt and Decrypt) of the KeyVault you plan to use. |
| AZURE_CLIENT_SECRET | (Optional) Client secret of the Azure SP. |
| AZURE_TENANT_ID | (Optional) Tenant ID of the Azure SP. |
| AZURE_SUBSCRIPTION_ID | (Optional) Subscription ID of the Azure AP. |
| AZURE_STORAGE_DOMAIN | (Optional) The custom domain for your storage domain, if any. If this is not provided, the default Azure public domain “blob.core.windows.net” will be used. |
GitLab OAuth
Only required if using GitLab as the backing identity provider for your organization.
| Variable Name | Description |
|---|---|
| GITLAB_OAUTH_ID | GitLab OAuth app client ID. It is used for GitLab OAuth sign in. Create a new GitLab OAuth app. |
| GITLAB_OAUTH_SECRET | GitLab OAuth app client secret. See above to create a new GitLab OAuth app. |
| GITLAB_OAUTH_ENDPOINT | The domain for your GitLab instance. It defaults to https://gitlab.com, which should be used unless you are running GitLab on a custom domain. |
Sending Emails
| Variable Name | Description |
|---|---|
| SMTP_SERVER | Location of the SMTP server to use for sending notification emails. (must be in <host>:<port> format, e.g. smtp.domain.com:465) |
| SMTP_USERNAME | Name of the SMTP user Pulumi Cloud connects as. |
| SMTP_PASSWORD | Password of the SMTP user Pulumi Cloud connects as. |
| SMTP_GENERIC_SENDER | Sender information used as FROM: for outgoing emails. |
Other Environment Variables
| Variable Name | Description |
|---|---|
| GITHUB_OAUTH_ENDPOINT | Used for GitHub API calls. |
| PULUMI_DATABASE_USER_NAME | Name of the database user Pulumi Cloud connects as. Leave default unless you are having trouble connecting to your database. |
| PULUMI_DATABASE_USER_PASSWORD | Password of the database user Pulumi Cloud connects as. Leave default unless you are having trouble connecting to your database. |
| PULUMI_CORS_ALLOWED_ORIGINS | Comma-separated list of browser origins allowed to call the API cross-origin, each written as <scheme>://<host>[:<port>] with no path and no default port (https://pulumiconsole.acmecorp.com, not https://pulumiconsole.acmecorp.com:443). Two keywords are accepted: * allows every origin, and localhost allows any http or https origin on a loopback host regardless of port. Default is *, which will answer every cross-origin request. Set it to the origin of your Console (the PULUMI_CONSOLE_DOMAIN value with its scheme) to reject other sites’ browser requests; add further entries only for other web apps you run that call the API from a browser. Requests that carry no Origin header, such as the pulumi CLI and server-to-server callers, are unaffected. Each rejected request is logged as CORS origin mismatch and counted by the cors.origin_mismatch metric. |
| PULUMI_CORS_ENFORCE | When false, requests whose Origin is not in PULUMI_CORS_ALLOWED_ORIGINS are still logged and counted but are answered as if the list were *. Use it to audit a candidate allowlist without affecting users, then unset it (or set true, the default) to enforce. |
| PULUMI_DISABLE_EMAIL_LOGIN | When true the API will disallow logins using the email/password identity. To hide the email login option from the Console refer to the email identity configuration for the Console. |
| PULUMI_DISABLE_EMAIL_SIGNUP | When true the API will disallow signups using the email/password identity. To hide the email signup option from the Console refer to the email identity configuration for the Console. |
| PULUMI_DISABLE_SSRF_PROTECTION | Comma-separated list of features whose SSRF protection is switched off: ESC, AGENTS_BYOK, OIDC_ISSUER, VCS, WEBHOOKS. Unset by default, which keeps the protection on for every feature. See SSRF protection. |
| PULUMI_DISABLE_ESC_SSRF_PROTECTION | Deprecated. When true, treated as ESC in PULUMI_DISABLE_SSRF_PROTECTION. Use PULUMI_DISABLE_SSRF_PROTECTION=ESC instead. |
| PULUMI_PASSKEY_CEREMONY_KEY | Signs the state token that links a passkey registration or sign-in attempt’s start and finish steps. Must be the standard-base64 encoding of exactly 32 random bytes (44 characters including padding); generate one with openssl rand -base64 32. The API service validates this at startup and fails to boot if the value is the wrong length or isn’t valid base64. Leaving it unset disables the passkey routes entirely. Passkeys are also gated by a platform-level setting outside this variable’s control, so if the routes still return 404 once this is set, contact Pulumi support to confirm passkeys are enabled for your deployment. Rotating the key invalidates any passkey ceremony in progress (each has a five-minute window to complete), but does not affect passkeys your users have already registered. |
| RECAPTCHA_SECRET_KEY | Used for password reset requests by users. Create a Cloudflare Turnstile Widget to generate the Secret Key. See also Console Component. |
| SAML_CERTIFICATE_PUBLIC_KEY | Public key used by the IdP to sign SAML assertions. Learn how to set SAML_CERTIFICATE_PUBLIC_KEY. |
| SAML_CERTIFICATE_PRIVATE_KEY | Private key used by Pulumi to validate the SAML assertions sent by the IdP. Learn how to set SAML_CERTIFICATE_PRIVATE_KEY. |
SSRF protection
To protect against server-side request forgery (SSRF), the API service refuses outbound requests to URLs that users supply when the destination resolves to a loopback, private, link-local, carrier-grade NAT (RFC 6598), or other reserved address. This includes the cloud metadata endpoint 169.254.169.254. The address is checked when the connection is made, so a hostname that resolves to a public address when it’s saved and to a private one later is still refused.
If a feature needs to reach a service on the same host or private network as your installation, such as a secret store that a Pulumi ESC provider reads from, switch the protection off for that feature only by listing it in PULUMI_DISABLE_SSRF_PROTECTION. Names are case-insensitive and unknown names are ignored with a warning in the API service logs.
| Scope | Outbound requests it covers |
|---|---|
ESC | Pulumi ESC providers and rotators that call a URL you configure: Vault, Infisical, Terraform state, GitHub login, and external providers and rotators. |
AGENTS_BYOK | Pulumi Neo requests to a custom model provider. |
OIDC_ISSUER | Registering an OIDC issuer and fetching its signing keys. |
VCS | Refreshing a member’s GitHub Enterprise Server token when individual user authentication is enabled. |
WEBHOOKS | Webhook delivery. |
For example, to let ESC providers and Neo reach services on your private network:
PULUMI_DISABLE_SSRF_PROTECTION=ESC,AGENTS_BYOK
The API service logs a warning once for each scope that is switched off. PULUMI_DISABLE_ESC_SSRF_PROTECTION=true is still honored as ESC, but it’s deprecated and no longer switches off the protection for any other feature.
Outbound proxies
Requests covered by SSRF protection honor the standard HTTPS_PROXY, HTTP_PROXY, and NO_PROXY environment variables. The proxy itself may be on a private address. The API service checks the destination before handing the request to the proxy, so a blocked destination never reaches the proxy, and a request sent directly to the proxy’s own address is refused.
Two limitations apply when a proxy is configured:
- The API service must be able to resolve the destination’s hostname itself. If only the proxy can resolve external names, protected requests fail. Switch off the protection for the affected feature if that applies to your network.
- The proxy resolves the hostname again after the API service has checked it. To guard against DNS rebinding behind a proxy, restrict private destinations with an egress policy on the proxy.
TLS Environment Variables
API Service
The service is configurable to serve the API using TLS. The following environment variables are all required in order to enable TLS. The values of the environment variables may either be a filepath or the actual value of the entity. If these variables are set, the service will be served over HTTPS (i.e using TLS) using port 8443. If the following variables are not set the service will default to serving over HTTP using port 8080.
| Variable Name | Description |
|---|---|
| API_TLS_CERTIFICATE | The TLS certificate. The certificate must be supplied in X.509 format and must be PEM encoded. |
| API_TLS_PRIVATE_KEY | The private key associated with the TLS certificate. The private key must be PEM encoded. |
| API_MIN_TLS_VERSION | The minimum version of TLS to use when serving the API (must be in <major>.<minor> format, e.g. 1.2). |
Note: Self-signed certificates may be used to configure TLS in the event the need for a trusted entity is not necessary. A self-signed cert and private key may be generated using OpenSSL. The following command uses OpenSSL to generate a self-signed certificate. This example will output two files, the certificate (cert.pem) and the private key (key.pem) used to sign it.
openssl \
req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem \
-days { days_until_expiration } -nodes -subj "/CN={ common_name }"
Database Connections
API Service
The service is configurable to enable connections to the backend SQL database over TLS. The following environment variables are all required to connect to the database using TLS. If these variables are set the service will establish connections to the database using TLS, otherwise the service will default to connecting without TLS. The same ports will be used for communication to the database regardless of whether TLS is configured or not.
| Variable Name | Description |
|---|---|
| DATABASE_CA_CERTIFICATE | The CA certificate used to establish TLS connections with the database. This certificate must be PEM encoded. This must be set to the value of the certificate itself and not a filepath to the location of the certificate file. |
| DATABASE_MIN_TLS_VERSION | The minimum TLS version to use for database connections (must be in <major>.<minor> format, e.g. 1.2). |
Migrations
The database migrations container is configurable to enable connections to the database over TLS. To use TLS, the following environment variable must be set. The default is to not use TLS.
| Variable Name | Description |
|---|---|
| DATABASE_CA_CERTIFICATE | The CA certificate used to establish TLS connections with the database. This certificate must be PEM encoded. This must be set to the value of the certificate itself and not a filepath to the location of the certificate file. |
| MYSQL_ROOT_USERNAME | The root username to log in to the MySQL database. Defaults to root. |
| MYSQL_ROOT_PASSWORD | The root user password to log in to the MySQL database. |
| MYSQL_ALLOW_EMPTY_PASSWORD | Set to true to allow the container to be started with a blank password for the root user. |
| PULUMI_DATABASE_ENDPOINT | The database server endpoint in the format host:port. This should be a MySQL 8.0 server. |
| PULUMI_DATABASE_PING_ENDPOINT | The database server endpoint to ping for availability before login. |
| RUN_MIGRATIONS_EXTERNALLY | Request for migrations to be run against an external database. |
Audit Logs
Audit Logs are persisted in MySQL by default. Alternative backends can be configured to support a higher volume of writes without scaling out MySQL.
DynamoDB
To use AWS DynamoDB to persist Audit Logs, specify the name of the table in the environment variable PULUMI_AUDIT_LOGS_DYNAMO_TABLE. The table provided must be configured with following attributes:
hashKey: "org_id",
rangeKey: "timestamp_id",
globalSecondaryIndexes: [
{
hashKey: "org_user_id",
projectionType: "ALL",
name: "org_user",
rangeKey: "timestamp_id",
},
],
attributes: [
{
name: "org_id",
type: "S",
},
{
name: "org_user_id",
type: "S",
},
{
name: "timestamp_id",
type: "S",
},
],
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:
| 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>. |
OpenTelemetry is not yet available for the console service.
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.
webhook-token, not Bearer.curl -s GET https://api.pulumi.com/metrics -H 'Authorization: webhook-token <METRICS_WEBHOOK_SECRET>
Prometheus
The API service provides two options to get metrics into Prometheus:
- From the OpenTelemetry collector via a Prometheus remote write exporter. This is a push-based exporter.
- From a Prometheus exporter by scraping the
/metricsendpoint. 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.
Example OpenTelemetry collector configuration for a service using AWS and the AWS Distro for OpenTelemetry Collector:
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.
Example OpenTelemetry collector configuration:
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:
scrape_configs:
- job_name: pulumi
scrape_interval: 15s
authorization:
type: webhook-token
credentials: <METRICS_WEBHOOK_SECRET>
scheme: https
static_configs:
- targets: ["api.pulumi.com"]
Pulumi Deployments
To enable Pulumi Deployments, the following must be configured:
PULUMI_SERVICE_METADATA_BLOB_STORAGE_ENDPOINTorPULUMI_LOCAL_OBJECTSobject storageCustomer-managed runners - You also need to update the
pulumi-workflow-agent.yamlconfiguration file by settingservice_urlto<PULUMI_API_DOMAIN>. Example:token: pul-d2d2…. version: v0.0.5 service_url: https://pulumiapi.acmecorp.com
Pulumi ESC
In order to enable Pulumi ESC, the following must be configured:
PULUMI_SERVICE_METADATA_BLOB_STORAGE_ENDPOINTorPULUMI_LOCAL_OBJECTSobject storageOne of the encryption services
Pulumi IDP Registry
In order to enable the Pulumi IDP Registry, the following must be configured:
- Environment variables for where to store public and private artifacts in a remote object store (see below).
- Cloud provider authentication where the remote object store lives.
AWS S3
| Variable Name | Description |
|---|---|
| PULUMI_REGISTRY_PUBLIC_BLOB_STORAGE_ENDPOINT | The storage endpoint for persisting public registry artifacts. The value takes the format: s3://<bucket-name>. Similar to PULUMI_CHECKPOINT_BLOB_STORAGE_ENDPOINT, this also supports query-params. |
| PULUMI_REGISTRY_PRIVATE_BLOB_STORAGE_ENDPOINT | The storage endpoint for persisting private registry artifacts. The value takes the format: s3://<bucket-name>. Similar to PULUMI_CHECKPOINT_BLOB_STORAGE_ENDPOINT, this also supports query-params. |
Azure Storage
| Variable Name | Description |
|---|---|
| PULUMI_REGISTRY_PUBLIC_BLOB_STORAGE_ENDPOINT | The storage endpoint for persisting public registry artifacts. The value takes the format: azblob://<blob-container>. |
| PULUMI_REGISTRY_PRIVATE_BLOB_STORAGE_ENDPOINT | The storage endpoint for persisting private registry artifacts. The value takes the format: azblob://<blob-container>. |
Terraform state backend
To let Terraform and OpenTofu use your self-hosted Pulumi Cloud as a state backend, set the following environment variable on the API service:
| Variable Name | Description |
|---|---|
| PULUMI_TFE_DOMAIN | The domain that serves the Terraform-compatible API, for example tf.pulumiapi.acmecorp.com. When unset, the Terraform-compatible API is disabled and its routes aren’t registered. |
Point the DNS record for this domain at the same host that serves PULUMI_API_DOMAIN. A separate domain keeps the Terraform-compatible API distinct from the Pulumi API, but it isn’t required: you can set PULUMI_TFE_DOMAIN to the same value as PULUMI_API_DOMAIN if you don’t want a second DNS record.
In the Terraform or OpenTofu configuration, the terraform login or tofu login command, and the TF_TOKEN_* variable name, use the PULUMI_TFE_DOMAIN value wherever the state backend guide uses tf.pulumi.com.
Operations guide
For production deployment best practices including compute sizing, high-availability configuration, monitoring, backup and recovery, and security hardening, see the Self-hosted operations guide.