> ## Documentation Index
> Fetch the complete documentation index at: https://docs2.growthbook.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Self-Hosting GrowthBook

> Learn how to set a self-hosted version of GrowthBook

GrowthBook consists of a NextJS front-end, an ExpressJS API, and a Python stats engine. Everything is bundled together in a single [Docker Image](https://hub.docker.com/r/growthbook/growthbook).

In addition to the app itself, you will also need a MongoDB instance (or MongoDB compatible database) to store login credentials, cached experiment results, and metadata.

<Tip>
  **Don't want to install or host the app yourself?**

  <a href="https://app.growthbook.io">GrowthBook Cloud</a> is a fully managed version that's free to get started with.
</Tip>

## Quick Start

You can use **docker compose** to get started quickly:

```yml theme={null}
# docker-compose.yml
services:
  mongo:
    image: "mongo:latest"
    environment:
      - MONGO_INITDB_ROOT_USERNAME=root
      - MONGO_INITDB_ROOT_PASSWORD=password
    volumes:
      - mongodata:/data/db
  growthbook:
    image: "growthbook/growthbook:latest"
    ports:
      - "3000:3000"
      - "3100:3100"
    depends_on:
      - mongo
    environment:
      - MONGODB_URI=mongodb://root:password@mongo:27017/growthbook?authSource=admin
    volumes:
      - uploads:/usr/local/src/app/packages/back-end/uploads
volumes:
  uploads:
  mongodata:
```

Then, just run `docker compose up -d` to start everything and view the app at [http://localhost:3000](http://localhost:3000)

<Warning>
  **Use of mongo image**

  The use of the mongo image within the docker-compose.yml is meant to quickly get a dev or staging environment up and running.
  For production you may want to use a more scalable and stable solution (ie. AWS DocumentDB, Google Cloud MongoDB Atlas, Azure Cosmos DB for Mongo, etc.)
</Warning>

We also offer an official Helm chart for deploying GrowthBook on Kubernetes. See the [Kubernetes Self-Hosting Guide](/self-host/kubernetes) for more details.

## Production

We have a dedicated guide for [Self-Hosting GrowthBook in Production](/self-host/production) that covers best practices for security, scaling, performance, and more.

## Docker Tags

The `latest` tag is updated with every commit to the main branch. We run this tag in GrowthBook Cloud, so it's generally safe for production, but may occasionally have minor bugs.

We periodically create stable release tags (e.g. `4.1.0`) if you prefer to have more control over updates. Check out the [Releases page on GitHub](https://github.com/growthbook/growthbook/releases) for a list of releases with detailed release notes.

Lastly, if you need to reference the image for a specific git commit for any reason, you can use the git shorthash tag (e.g. `git-41278e9`).

## Hardened (non-root, shell-less) image

The GrowthBook runtime image is a distroless [Docker Hardened Image](https://www.docker.com/products/hardened-images): it runs as a **non-root user (uid 1000)** and contains **no shell or package manager**. This removes a recurring class of OS-package CVEs. If you pull the image directly (`docker run`, Docker Compose, or a pinned `latest`/git-sha tag), there are two things to know.

### Local file uploads must be writable by uid 1000

If you use `UPLOAD_METHOD=local`, a volume created by an older (root) GrowthBook image contains root-owned files that the non-root process can't write to. Newly created volumes work automatically; an **existing** volume needs a one-time ownership fix:

```bash theme={null}
# Docker named volume (e.g. the docker-compose "uploads" volume):
docker run --rm -v <volume-name>:/data busybox chown -R 1000:1000 /data

# Host bind-mount:
sudo chown -R 1000:1000 /path/to/uploads
```

Alternatively, keep running as root by setting `user: "0:0"` on the service, or switch to `s3`/`google-cloud` storage (no local volume needed). On Kubernetes, the Helm chart sets `fsGroup: 1000`, which handles this for you.

### Debugging without a shell

`docker exec <container> sh` no longer works. To inspect a running container, attach a throwaway debug container that shares its process namespace:

```bash theme={null}
docker run --rm -it --pid=container:<container-name> --cap-add=SYS_PTRACE busybox sh
# the running container's filesystem is under /proc/1/root/, e.g.:
#   ls /proc/1/root/usr/local/src/app
```

`--cap-add=SYS_PTRACE` is required to read the target process's filesystem. Any image with a shell works (`busybox`, `debian`); the matching `dhi.io/node:<version>-debian12-dev` image gives you the same libraries for running the app's own binaries. On Kubernetes, use `kubectl debug -it <pod> --image=busybox --target=<container>`. One-off admin scripts (e.g. encryption-key migration) are run via `node` directly — see [Environment Variables](/self-host/env).
