Skip to main content

Production Best Practices

When properly configured, a self-hosted GrowthBook deployment can scale to billions of requests per month.

The default settings in the docker-compose file are meant to get you up and running quickly on a local dev machine. There are a few things to keep in mind when deploying GrowthBook securely at scale in production.

Security

There are a number of best practices to keep your GrowthBook deployment secure.

Encryption Keys and Secrets

First, make sure you pick long, random strings for your encryption keys and secrets. Specifically, there are 3 environment variables that need to be configured:

  • NODE_ENV - Set to production to turn on additional security checks and logging
  • JWT_SECRET - Auth signing key (use a long random string)
  • ENCRYPTION_KEY - Data source credential encryption key (use a long random string)

If you change the ENCRYPTION_KEY, you will need to migrate any existing data sources using the following script:

# If you didn't have an ENCRYPTION_KEY before, leave OLD_KEY blank below
docker-compose run growthbook yarn migrate-encryption-key OLD_KEY

Networking

The most secure thing you can do is to put your entire GrowthBook deployment behind a firewall and/or corporate VPN. This way, you can restrict access to only those who need to sign into the GrowthBook platform. This can drastically reduce the attack vector and serves as an important first layer of security.

If you are using GrowthBook to serve feature flags to client-side apps, you will need some way for your end users to download the feature flag payload outside of the firewall or VPN. There are a few secure approaches for this:

  1. Use a GrowthBook Proxy server. This way, your main GrowthBook instance can remain on a private subnet and only the Proxy needs to be exposed to the internet. The Proxy has a very small attack surface compared to the full GrowthBook app.
  2. Use a CDN. If you go this route, it's very important to only allow requests to the /api/features/* endpoint in your CDN. If you allow access to other endpoints (e.g. /auth/* or other API routes) you lose many of the benefits of a Firewall or VPN.
  3. Use SDK Webhooks to send your feature payload to a publically accessible place (e.g. a public S3 bucket). This switches GrowthBook from a "pull" model to a "push" model and you no longer need to allow any incoming requests from users at all.

Authentication and Permissions

For our Enterprise customers, we recommend using SSO and SCIM to authenticate with GrowthBook and manage permissions. This offloads access control and management to your existing identity management infrastructure and further reduces the possible attack surface.

No matter which authentication method you use, it's best to follow the least access principle. Admins can invite other users and grant permissions, so restrict this role to only the people who really need it. Read more about permissions.

When using our REST API, it's best to use readonly API keys when possible. When you need write access, using Personal Access Tokens is best since it inherits the permissions of the user who created it. Only use admin Secret Access Tokens as a last resort.

MongoDB

Securing MongoDB in production is its own topic entirely and outside the scope of GrowthBook. We recommend using a hosted solution such as MongoDB Atlas, which is secure by default.

If you do want to host MongoDB yourself in production, they have a detailed guide on their docs.

Email SMTP Settings

Configuring email is required in order to send experiment alerts, team member invites, and reset password emails.

  • EMAIL_ENABLED ("true" or "false")
  • EMAIL_HOST
  • EMAIL_PORT
  • EMAIL_HOST_USER
  • EMAIL_HOST_PASSWORD
  • EMAIL_FROM

File Uploads

GrowthBook lets users add Markdown comments throughout the app and these support image uploads.

The UPLOAD_METHOD environment variable controls where to store uploaded files and screenshots. The supported values are local, s3, and google-cloud.

local

This is the default value. Uploads are stored in the GrowthBook docker container at /usr/local/src/app/packages/back-end/uploads. In production, you should mount a shared volume here to persist uploads across container restarts and ensure your horizontally scaled GrowthBook instances all share the same uploads directory.

s3

Store uploads in an AWS S3 bucket.

  • S3_BUCKET
  • S3_REGION (defaults to us-east-1)
  • S3_DOMAIN (defaults to https://${S3_BUCKET}.s3.amazonaws.com/)
  • AWS_ACCESS_KEY_ID (not required when deployed to AWS with an instance role)
  • AWS_SECRET_ACCESS_KEY (not required when deployed to AWS with an instance role)
  • USE_FILE_PROXY set this to true for access to uploads to proxy through your self hosted server allowing you to keep the bucket private.

google-cloud

Store uploads in a Google Cloud Storage bucket.

  • GCS_BUCKET_NAME
  • GCS_DOMAIN (defaults to https://storage.googleapis.com/${GCS_BUCKET_NAME}/)
  • GOOGLE_APPLICATION_CREDENTIALS (not required when deployed to GCP with an instance service account)
  • USE_FILE_PROXY set this to true for access to uploads to proxy through your self hosted server allowing you to keep the bucket private.

Scaling

GrowthBook instances are stateless and can be horizontally scaled behind a load balancer. We recommend each instance have at least 2GB of RAM and 1vCPU. You should run at least 3 instances at a time for maximum fault tolerance.

Serving Feature Flags

Hitting the GrowthBook instance directly from our SDKs can work fine at a small scale, but we recommend an additional layer for added scalability and fault tolerance. There are a few options for this:

  1. Use a GrowthBook Proxy server. Each Proxy Server instance can easily handle thousands of requests per second. We recommend horizontally scaling these instances and configuring Redis to keep them in sync.

  2. Use a CDN in front of the /api/features/* endpoints. The response from GrowthBook contains cache headers by default that most CDNs will recognize without any custom configuration. You can tweak these cache settings with the following environment variables (all in seconds):

    • CACHE_CONTROL_MAX_AGE (default 30)
    • CACHE_CONTROL_STALE_WHILE_REVALIDATE (default 3600 = 1 hour)
    • CACHE_CONTROL_STALE_IF_ERROR (default 36000 = 10 hours)
  3. Use SDK Webhooks to send your feature payload to a publically accessible place (e.g. an S3 bucket) and point the SDKs there instead. This bypasses the issue by switching GrowthBook from a "pull" model to a "push" model.

Observability and Logging

The GrowthBook API is instrumented with OpenTelemetry to publish observability metrics, traces, and logs.

To enable, you must change the Docker CMD from the default yarn start to yarn start:with-tracing.

The standard OTEL_* Environment Variables are supported, such as OTEL_SERVICE_NAME and OTEL_EXPORTER_OTLP_ENDPOINT.

In addition to this, make sure to configure the EXPRESS_TRUST_PROXY_OPTS environment variable. It supports boolean (true/false), string values, and integer values for trusting the nth hop from the front-facing proxy server as the client. Leavy empty or specify false to use Express' default behavior. If you are running GrowthBook behind a proxy or load balancer, this is required to track the correct user IP for audit log events. Read more about this setting in Express' documentation.