# retool-onpremise: running Retool yourself with Docker Compose

> This repository is a deployment bundle for self-hosted Retool: a Compose file, an install script that writes environment files, and a Dockerfile whose version argument decides which images run. The hard parts are secrets management and upgrades, not the container startup.

**tryretool/retool-onpremise** — Deploying Retool On Prem

- Repository: https://github.com/tryretool/retool-onpremise
- Stars: 685 · Forks: 224
- Language: Shell
- License: not declared
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/tryretool-retool-onpremise

## A deployment bundle, not the Retool product

The first thing to understand is what this repository is not. It contains no application code. The top-level entries are a Dockerfile, a compose.yaml, an install.sh, an upgrade.sh, a temporal.yaml, Kubernetes and CloudFormation directories, some seccomp profiles and a scripts directory. The running software comes from images published by the vendor on Dockerhub.

That is stated in the Dockerfile itself, which builds from tagged images and takes the tag as a build argument:

```
ARG VERSION=X.Y.Z-stable

FROM tryretool/agent-sandbox-service:${VERSION} AS agent-sandbox
```

and finally:

```
FROM tryretool/backend:${VERSION}

CMD ./docker_scripts/start_api.sh
```

So this is the part of self-hosting you would otherwise have to reconstruct: the topology, the environment variables, the order of operations and the upgrade path. The README points at the documentation for the more specific variants, including deploying with Kubernetes or Helm, and it directs anyone who needs older instructions to a separate deprecated-onpremise repository.

## install.sh writes the two env files everything else reads

The install sequence is three steps. Clone the repository, then run the script:

```
git clone https://github.com/tryretool/retool-onpremise retool && cd retool
```

```
./install.sh
```

The script is described as attempting to set up Docker and to initialize the `.env` files, and it creates `docker.env` and `retooldb.env` on success, otherwise calling out the issues to address before rerunning. Everything in compose.yaml then reads from those generated files, so the script is the step that creates the secrets, the license key and the randomized keys.

One assumption is baked in and it bites on non-Ubuntu hosts. The README says the project tests and supports running on Ubuntu, and that on a different platform you may need to install requirements such as Docker manually. The docs also warn that Compose v2 is assumed, accessed through `docker compose`, with the legacy v1 `docker-compose` syntax no longer used.

## Blob storage defaults to a bundled MinIO you are meant to replace

The generated defaults ship a MinIO instance inside the deployment, selected with `RR_BLOB_STORAGE_PROVIDER=s3` and the `RR_DEFAULT_S3_*` variables. The instruction for production is to replace those defaults with external object store credentials.

The two cases are handled differently and it is easy to get wrong. For AWS S3 you remove `RR_DEFAULT_S3_ENDPOINT` and `AWS_ENDPOINT_URL`. For S3-compatible providers such as MinIO, you set both endpoint variables to the provider endpoint. In other words the internal MinIO is a convenience for evaluation, and the switch to a real bucket is a configuration change rather than a redeployment of a different stack.

A second secret deserves more attention than the blob settings. The README asks you to save off the `ENCRYPTION_KEY` value, since it is needed to encrypt and decrypt values saved into the Postgres database the Retool instance runs on. Losing that key does not just lose configuration, it makes stored encrypted values unreadable, which is why it sits in the manual checklist rather than in the script.

## The service topology comes from one Compose file

compose.yaml defines the shape of the deployment, and the api service is the anchor. It reads `docker.env`, declares its role through `SERVICE_TYPE=MAIN_BACKEND,DB_CONNECTOR,DB_SSH_CONNECTOR,RR_GIT_SERVER`, and waits for Postgres to start and for the minio-init job to complete successfully before it starts:

```
services:
  api:
    build:
      context: .
    env_file: docker.env
    environment:
      - SERVICE_TYPE=MAIN_BACKEND,DB_CONNECTOR,DB_SSH_CONNECTOR,RR_GIT_SERVER
    ports:
      - 3000:3000
```

The rest follows the same pattern. There is a jobs-runner with `SERVICE_TYPE=JOBS_RUNNER`, a workflows-backend, a workflows-worker that also sets `NODE_OPTIONS=--max_old_space_size=1024`, and an agent-worker whose task queue is set to `agent`. Services join named networks, with the api sitting on frontend, backend, code-executor and js-executor, and the executor networks are what let the platform run user code and JavaScript in separate processes.

The practical takeaway is that the `SERVICE_TYPE` variable is how one image becomes several roles, and the network list is the security boundary. Editing either in compose.yaml is how you change what a container can reach.

## HTTPS depends on a domain, a STAGE flag and a free certificate

Serving over TLS is described as a domain problem first. Your domain has to point at the server IP address, `DOMAINS` has to be correct in `docker.env`, and then `STAGE=production` is set in compose.yaml so the `https-portal` container attempts to obtain and use a free `Let's Encrypt` certificate for that domain on startup.

The escape hatch is explicit about its cost. To log in without HTTPS configured you must set `COOKIE_INSECURE=true` in `docker.env`, and the README marks that as not recommended. The implication is that a production deployment without a working domain has no clean path: either the certificate works or the session cookies are unsecured.

A fresh instance is initialized from the browser by opening the domain or IP and clicking `Sign up`, which is the point at which the license key and the first admin account come into play.

## Temporal and MCP are switches you flip in the same file

Two optional subsystems are configured by editing the deployment, and both are off by default in the sense that you have to remove something to disable them.

The Temporal container for Workflows is included by default through an include block at the top of compose.yaml:

```
include:
  - temporal.yaml
```

An Enterprise licence holder who prefers Retool's managed Temporal cluster comments that block out and removes the `WORKFLOW_TEMPORAL_...` variables from `docker.env`.

The `mcp` service serves Retool's MCP server at `/mcp` so external MCP clients can connect to the instance. It needs HTTPS and three variables, `OAUTH_MAIN_DOMAIN`, `MCP_SERVICE_EXTERNAL_URL` and `OAUTH_INTROSPECTION_AUTH_TOKEN`, all written by `install.sh`. The `https-portal` container routes `/mcp` to it through `CUSTOM_NGINX_SERVER_CONFIG_BLOCK`, the OAuth metadata and introspection endpoints are served by the `api` service, and the client points at `https://<your-domain>/mcp`. Disabling it means removing the `mcp` service and that nginx block from compose.yaml.

## An upgrade is a version bump, a rebuild and a prune

Upgrades are described as a version change plus three commands, and the version lives in the Dockerfile as the `X.Y.Z-stable` placeholder that you replace with a version listed on the vendor Dockerhub, with the latest patch of the most recent stable release recommended. After editing it, you build the new images, bring up the new containers, and remove the old ones:

```
docker compose build
```

```
docker compose up -d
```

```
docker image prune -a -f
```

A `./upgrade.sh` script is provided as an alternative to running those steps by hand.

The sharp edge is in a note about the MCP variables. `install.sh` writes `OAUTH_MAIN_DOMAIN`, `MCP_SERVICE_EXTERNAL_URL` and `OAUTH_INTROSPECTION_AUTH_TOKEN` only on a fresh install, so an existing deployment being upgraded has to add them by hand. Without them the `mcp` container still starts, but MCP clients fail to authenticate, which is a quiet failure that will not show up in a container status check.

## Kubernetes and Helm sit in the docs, and the legacy repo is deprecated

Docker Compose is the path this repository documents, but the alternatives are named and partly present. The README links the documentation for deploying with Kubernetes or with Helm, and the repository itself contains kubernetes/ and kubernetes-with-temporal/ directories alongside a cloudformation/ directory, an appArmor/ directory and seccomp profiles named gvisor-seccomp.json and nsjail-seccomp.json. The difference in approach is orchestration: Compose treats the host as the deployment target, while the Kubernetes path expects a cluster, and the seccomp and appArmor assets exist to satisfy the sandboxing requirements of the code execution containers.

For older setups, the README points at a separate deprecated-onpremise repository, which is the place to look if you are running a deployment that predates the current compose layout.

On maintenance, the repository is not archived and the last push was on 2026-10-19, but there are no GitHub releases, so the state of the system is defined by the branch rather than by a version tag. The licence is not identified anywhere in the repository listing, and the README carries the vendor branding rather than a licence grant, so a team that needs a defined licence for the deployment bundle has to ask the vendor rather than infer one.

## Conclusion

This repository fits an engineering team that has decided to host Retool in its own environment and wants the official Compose files, environment templates and upgrade scripts rather than assembling them by hand. It does not fit a team that expects a turnkey installer or a supported product, since the licence is not identified anywhere in the repository listing, there are no GitHub releases, and the documentation says testing and support target Ubuntu. Verify first that you can keep the ENCRYPTION_KEY safe, decide whether the bundled MinIO or an external object store suits production, and read the note about the MCP variables, because install.sh writes them only on a fresh install.

## FAQ

### How do I deploy Retool on my own server with retool-onpremise?

Clone the repository, run ./install.sh to set up Docker and generate docker.env and retooldb.env, replace X.Y.Z-stable in the Dockerfile with the desired Retool version, then run docker compose up -d and open the domain or IP in a browser to sign up and initialize the instance.

### What does the retool-onpremise install script create?

The script attempts to set up Docker and initialize the .env files, creating docker.env and retooldb.env on success. If it cannot complete, it reports the issues to address before rerunning.

### How do I use an external object store instead of the bundled MinIO?

The generated defaults use bundled MinIO with RR_BLOB_STORAGE_PROVIDER=s3 and the RR_DEFAULT_S3_* variables. For AWS S3 you remove RR_DEFAULT_S3_ENDPOINT and AWS_ENDPOINT_URL, and for S3-compatible providers such as MinIO you set both endpoint variables to the provider endpoint.

### What is the ENCRYPTION_KEY used for in a Retool self-hosted deployment?

The README states it is needed to encrypt and decrypt values saved into the Postgres database the Retool instance runs on, and instructs you to save off the value when configuring the deployment.

### Why do MCP clients fail to authenticate after upgrading retool-onpremise?

The mcp service reads OAUTH_MAIN_DOMAIN, MCP_SERVICE_EXTERNAL_URL and OAUTH_INTROSPECTION_AUTH_TOKEN from docker.env, and install.sh only writes them on a fresh install. On an upgraded deployment you add them yourself, otherwise the container still starts but clients cannot authenticate.

## Sources

- [Issues](https://github.com/tryretool/retool-onpremise/issues)
- [README](https://github.com/tryretool/retool-onpremise/blob/master/README.md)
- [tryretool/retool-onpremise on GitHub](https://github.com/tryretool/retool-onpremise)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/tryretool-retool-onpremise
