Deploy Self-Hosted Retool on EC2
Deploy a multi-container Retool instance on AWS EC2 using Docker Compose.
Introduction
30 Second Summary
Every company eventually needs internal tools, and the teams that build them need to decide whether to trust a cloud provider with their data or run the platform on their own infrastructure.
In this project, you will deploy a self-hosted Retool instance on an EC2 instance using Docker Compose, learning how multi-container applications are configured and launched in real production environments.
What You'll Build
A fully functional self-hosted Retool instance running on AWS EC2, powered by a multi-container Docker Compose stack that includes an API server, jobs runner, workflows worker, database, and more.
By the end of this project, you'll have:
- A properly sized EC2 instance with Docker and Docker Compose installed and ready for container workloads.
- A configured Retool deployment with a license key, encryption key, and environment variables wired across multiple containers.
- A running multi-container application accessible via your EC2 public IP on port 3000, with a completed admin account.
- A custom domain with automatic HTTPS via Let's Encrypt, making your Retool instance production-ready (Secret Mission).
Are there any prerequisites?
You need an AWS account with CLI access and a Retool Enterprise license key. Self-hosted Retool requires an Enterprise plan. If you do not have a license key, contact Retool's sales team to request a trial.
Launch and Connect to Your EC2 Instance
Before you can run any Docker containers, you need a machine to run them on. In this step, you'll launch an EC2 instance in AWS, configure its network access, and connect to it over SSH. This remote Linux server becomes the foundation for your entire Retool deployment.
In This Step, Get Ready To:
- Launch an EC2 instance with the right size, storage, and operating system for Retool.
- Configure a security group to allow SSH, HTTP, HTTPS, and Retool traffic.
- Connect to your instance via SSH and verify you're on a remote Linux server.
Launch the EC2 Instance
Retool's self-hosted deployment has specific hardware requirements. You need an instance with enough CPU, memory, and storage to run multiple Docker containers simultaneously.
- Open the AWS Console and navigate to the EC2 service.
- Click Launch instances.
- Give your instance a name like retool-server.
- Under Application and OS Images, select Ubuntu. Choose Ubuntu Server 22.04 LTS with 64-bit (x86) architecture.
- Under Instance type, select m5.xlarge (4 vCPUs, 16 GiB RAM).
Why m5.xlarge?
Retool's official requirements specify 16 GiB RAM, 8 vCPUs, and 60 GiB storage. The m5.xlarge provides 4 vCPUs and 16 GiB RAM, which is slightly under the vCPU recommendation. For a single-user learning deployment, this is sufficient and keeps costs lower at ~$0.19/hour.
If you experience performance issues, you can stop the instance and change the type to m5.2xlarge (8 vCPUs, 32 GiB RAM) at $0.384/hour.
- Under Key pair (login), click Create new key pair.
- Name it retool-key, keep the type as RSA and format as .pem, then click Create key pair. The .pem file downloads automatically.
Now configure the network settings. The security group acts as a virtual firewall that controls which traffic can reach your instance.
- Under Network settings, click Edit.
- Select Create security group and name it retool-sg.
- Add four inbound rules by clicking Add security group rule for each:
- SSH (port 22) from 0.0.0.0/0 and ::/0.
- HTTP (port 80) from 0.0.0.0/0 and ::/0.
- HTTPS (port 443) from 0.0.0.0/0 and ::/0.
- Custom TCP (port 3000) from 0.0.0.0/0 and ::/0.
Why four ports?
Port 22 lets you SSH into the instance. Port 3000 is where Retool's web interface runs by default. Ports 80 and 443 are for HTTP and HTTPS traffic, which you'll need if you set up a custom domain with SSL in the Secret Mission.
- Under Configure storage, change the root volume to 60 GiB with volume type gp3.
- Click Launch instance.
Your instance begins launching. Wait for the Instance state to show Running and the Status check to show 2/2 checks passed before moving on.
Connect to Your Instance via SSH
SSH lets you open a terminal session on your remote EC2 instance from your local machine. You'll use the .pem key file you downloaded as your authentication credential.
- Copy your instance's Public IPv4 DNS from the EC2 console. You'll find it in the instance details panel.
- Open a terminal on your local machine.
- Navigate to the directory where your .pem file was downloaded (usually ~/Downloads).
- Set the correct permissions on your key file.
chmod 400 retool-key.pem
What does this command do?
The chmod 400 command restricts the file so only you can read it. SSH refuses to use key files that are accessible to other users on your system.
- Connect to your instance with SSH.
ssh -i retool-key.pem ubuntu@[[EC2DNS="your-ec2-public-ipv4-dns"]]
What does this command do?
The -i flag specifies the private key file to use for authentication. The ubuntu part is the default username for Ubuntu EC2 instances.
- When prompted with "Are you sure you want to continue connecting?", type yes and press Enter.
I see a welcome message
You should see a welcome message from Ubuntu and a new command prompt showing ubuntu@ip-.... You're now on the remote server.
I see an error
Having trouble connecting?
- If you see "Permission denied", make sure you ran chmod 400 on your .pem file and that you're using the correct filename.
- If you see "Connection timed out", verify your security group has an inbound rule for SSH (port 22) and that the instance status checks have passed.
- If you see "No such file or directory", make sure your terminal is in the same directory as the .pem file.
Still stuck? Help me troubleshoot my SSH connection.
- Verify you're on the correct operating system by running the following command.
lsb_release -a
You should see output confirming Ubuntu 22.04.
Understand What You Just Built
You now have a remote Linux server running in AWS. This is the machine Docker will run on. Every container you launch in the next steps will share this machine's CPU, RAM, and network.
The security group rules you configured are what allow you (SSH on port 22) and future users (HTTP on port 80, HTTPS on port 443) to reach the instance. Port 3000 is where Retool's web interface will be accessible once you deploy it.
Your remote server is ready and waiting. Next up, you'll install Docker on this machine and explore the Retool deployment files.
Install Docker and Explore the Basics
You have a remote Linux server running in AWS. Now you need the engine that will actually run Retool. Docker lets you package and run applications inside isolated containers, and Docker Compose orchestrates multiple containers from a single configuration file. In this step, you'll install both and start understanding the building blocks of your deployment.
In This Step, Get Ready To:
- Clone the Retool on-premise repository and run the install script to set up Docker.
- Verify Docker and Docker Compose are installed and working.
- Examine the project files that define your entire Retool deployment.
Clone the Retool Repo and Run the Install Script
Retool provides an open-source repository with everything you need to deploy their platform using Docker Compose. The repo includes a handy install script that sets up Docker, Docker Compose, and generates starter configuration files for you.
- In your SSH session on the EC2 instance, run the following command to clone the repository and navigate into it:
git clone https://github.com/tryretool/retool-onpremise retool && cd retool
What does this command do?
This clones Retool's on-premise deployment repository from GitHub into a folder called retool, then moves you into that folder. All the files you need for the deployment live here.
- Run the install script:
sudo ./install.sh
This script does several things automatically. It installs Docker Engine and the Docker Compose plugin if they are not already present. It also generates two environment files: docker.env and retooldb.env. The script creates a random ENCRYPTION_KEY and places a LICENSE_KEY placeholder in docker.env for you to fill in later.
Script failing or hanging?
Make sure you are running the script with sudo. The install script needs root privileges to install Docker packages. If you see permission errors, help me troubleshoot the install script.
Verify Docker Is Installed and Explore Key Concepts
Before moving forward, you need to confirm that Docker and Docker Compose were installed correctly. You'll also take a moment to understand the core concepts you'll be working with for the rest of this project.
- Run the following commands to check the installed versions:
docker --version
docker compose version
What should I see?
You should see version numbers for both Docker Engine and Docker Compose. Note that Retool uses Docker Compose v2 syntax, which means the command is docker compose (with a space), not the older docker-compose (with a hyphen).
- Run docker info to see your Docker daemon's full configuration.
sudo docker info
This output shows you the Docker daemon running on your EC2 instance. It reports how many containers exist, how many are running, the storage driver, and the operating system. This is the engine that will power every container in your Retool deployment.
- Optionally, add your user to the docker group so you don't need sudo for every Docker command going forward:
sudo usermod -aG docker $USER
- Log out and log back in for the group change to take effect:
exit
- SSH back into your instance and navigate to the retool directory:
ssh -i [[PEMPATH="PATH TO YOUR .PEM FILE"]] ubuntu@[[EC2="YOUR PUBLIC IPV4 DNS"]]
cd retool
Now let's make sure the core Docker concepts are clear before you start using them.
What are images, containers, and Docker Compose?
A Docker image is a read-only template that contains everything an application needs to run. Think of it like an AMI for EC2 instances, but for containers.
A container is a running instance of an image. You can run multiple containers from the same image, each isolated from the others.
Docker Compose lets you define and manage multiple containers in a single YAML file. Instead of starting each container manually, you run one command and Compose handles the rest.
Examine the Project Files
The cloned repository contains three critical files that define your entire Retool deployment. Understanding what each file does is essential before you start configuring anything.
- List the directory contents to see all the files:
ls -la
You should see several files, but three are the most important:
- Dockerfile defines which Retool Docker image to use. It points to a specific version of the tryretool/backend image on Docker Hub.
- compose.yaml defines all the containers and how they connect to each other. This is the orchestration file that Docker Compose reads.
- docker.env contains the environment variables that configure the deployment, like your license key and encryption key.
- Open compose.yaml to see how Retool's multi-container architecture is defined:
cat compose.yaml
Take a moment to scroll through this file. You'll notice it defines multiple services: api (the main backend), jobs-runner, workflows-worker, workflows-backend, code-executor, a PostgreSQL database (retool-db), and https-portal for SSL. Each of these services becomes a separate container when you launch the stack.
Why so many containers for one application?
Retool follows a microservice architecture. Instead of running everything in a single process, each responsibility gets its own container. The API server handles user requests. The jobs runner processes background tasks. The workflows worker executes automations. The database stores all the data.
This separation means you can restart one service without affecting the others. It also means each service can be scaled independently. This is exactly how production applications work in the real world.
How do all these containers share the same image?
If you look closely at compose.yaml, you'll notice that multiple services use the same tryretool/backend image. The difference is the SERVICE_TYPE environment variable. Setting SERVICE_TYPE=MAIN_BACKEND makes the container act as the API server, while SERVICE_TYPE=JOBS_RUNNER makes it act as the background jobs processor. One image, many roles.
You now have Docker installed and a solid understanding of the project files that define your Retool deployment. Next up, you'll configure these files with your license key, Retool version, and deployment settings to prepare for launch.
Configure the Retool Deployment
You have Docker installed and the Retool deployment files cloned. Before you can launch anything, Docker needs to know what to run and how to configure it. In this step, you will edit three configuration files that control the entire deployment: the Dockerfile, docker.env, and compose.yaml.
In This Step, Get Ready To:
- Pin the exact Retool image version in the Dockerfile.
- Set your license key and environment variables in docker.env.
- Back up the encryption key and understand how Docker Compose passes configuration to containers.
Set the Retool Version in the Dockerfile
The Dockerfile tells Docker which base image to use when building your containers. Right now it contains a placeholder version. You need to replace it with the exact Retool version you want to deploy.
- Open the Dockerfile with nano.
nano Dockerfile
- Find the FROM line and replace the placeholder version with the stable Retool image.
FROM tryretool/backend:3.334.7-stable
What does this line do?
The FROM instruction is the foundation of every Dockerfile. It tells Docker to pull the tryretool/backend image at version 3.334.7-stable from Docker Hub. Pinning an exact version prevents surprises. Without it, Docker might pull a newer version that introduces breaking changes.
- Save and exit by pressing Ctrl+X, then Y, then Enter.
Configure Environment Variables
The docker.env file holds all the environment variables that configure how Retool behaves. The install script already generated this file with some defaults, but you need to add your license key and enable HTTP access for initial testing.
- Open docker.env in nano.
nano docker.env
- Find the LICENSE_KEY line and replace the placeholder value with your Retool Enterprise license key.
- Verify that the ENCRYPTION_KEY line already has a value. The install script auto-generated this for you.
- Find the COOKIE_INSECURE line. Uncomment it and make sure it is set to true.
Why set COOKIE_INSECURE to true?
By default, Retool requires HTTPS to set login cookies. Since you have not configured SSL yet, setting COOKIE_INSECURE=true allows you to log in over plain HTTP on port 3000. You will set this back to false if you enable HTTPS in the Secret Mission.
- Save and exit by pressing Ctrl+X, then Y, then Enter.
Back Up the Encryption Key and Review Compose Configuration
The ENCRYPTION_KEY is the most critical value in your deployment. It encrypts all the database credentials, API keys, and other secrets that Retool stores. If you lose this key, you will need to reconfigure every resource connected to your Retool instance.
- Copy the ENCRYPTION_KEY value from docker.env and save it to a local file or password manager on your own machine.
Do not skip this backup
If your EC2 instance is terminated or the file is corrupted, the encryption key is gone forever. Store it somewhere outside of the instance right now.
Now take a closer look at how Docker Compose uses this environment file.
- Open compose.yaml to review how services reference the environment file.
cat compose.yaml
Notice how multiple services include an env_file reference pointing to ./docker.env. This is how Docker Compose passes the same set of environment variables to every container in the stack. Instead of duplicating configuration across each service definition, a single .env file acts as the shared configuration source.
How do multiple containers run different services from the same image?
Look at the service definitions in compose.yaml. The API server, jobs runner, and workflows containers all use the same tryretool/backend image. What makes each container behave differently is the SERVICE_TYPE environment variable. One container gets MAIN_BACKEND, another gets JOBS_RUNNER, and so on. The same image, configured differently, becomes a completely different service.
Your configuration is complete. All three files are set up and ready for Docker to build and launch the full Retool stack. Next, you will build the Docker image and bring up every container.
Build and Launch Retool
Your configuration files are set. Now it's time to turn those files into a running application. In this step, you'll use Docker Compose to build a custom Docker image from your Dockerfile, launch all of Retool's containers at once, and verify that everything is running.
In This Step, Get Ready To:
- Build the Retool Docker image from the Dockerfile.
- Launch the full multi-container stack with Docker Compose.
- Verify all containers are running and access the Retool signup page in your browser.
Build the Docker Image
Before any containers can run, Docker needs an image to base them on. Your Dockerfile tells Docker which base image to pull from Docker Hub and how to customize it. The build step reads that Dockerfile and creates a local image on your EC2 instance.
- Make sure you are in the retool directory on your EC2 instance.
- Run the build command.
docker compose build
Watch the output as Docker pulls the tryretool/backend:3.334.7-stable image from Docker Hub and builds your local image. This may take a few minutes depending on your network speed.
What is happening during the build?
Docker's build system works in layers. Each instruction in a Dockerfile creates a new layer on top of the previous one. Docker caches these layers, so if you rebuild later without changing the Dockerfile, the build completes almost instantly.
This is why Docker images are described as "read-only templates." The image itself never changes. When you run a container from it, Docker adds a thin writable layer on top for any runtime changes.
Launch the Containers
With the image built, you can now bring up the entire Retool stack. Docker Compose reads your compose.yaml and starts every service defined in it: the API server, jobs runner, workflows backend, PostgreSQL database, and more.
- Run the following command to start all services in detached mode.
sudo docker compose up -d
What does this command do?
- docker compose up reads compose.yaml and starts all the services defined in it.
- The -d flag runs everything in detached mode (in the background). Without it, closing your terminal would stop all containers.
The first launch takes several minutes as the containers start up and the PostgreSQL database performs its initial setup. Be patient here.
Verify the Deployment and Create Your Admin Account
You need to confirm that every container started successfully before trying to access Retool in your browser.
- Run the following command to check the status of all containers.
docker compose ps
What should I see?
Every container should show "Up" in its status column. You should see services like api, jobs-runner, workflows-worker, retool-db, and others all running.
A container is not showing "Up"?
If any container shows a status other than "Up", check its logs by running docker compose logs <service-name> (replace <service-name> with the name of the failing service). Common issues include an incorrect license key in docker.env or the database still initializing. Wait a minute and run docker compose ps again. Help me troubleshoot my container logs.
Once all containers show "Up" status, it's time to access Retool in your browser.
- Open a browser and navigate to http:// :3000/auth/signup.
- You should see the Retool signup page. Fill in your details to create your admin account.
You now have a fully running self-hosted Retool instance. Every piece of the application is running as a separate Docker container, orchestrated by the single compose.yaml file you configured.
How do all these containers work together?
Multiple containers share the same tryretool/backend image but run different services based on their SERVICE_TYPE environment variable. The API container handles web requests. The jobs runner processes background tasks. The workflows containers manage automations. The PostgreSQL container stores all of Retool's data.
Docker Compose created a virtual network so these containers can talk to each other by service name instead of IP address. This is the foundation of how microservice architectures work in production.
Your Retool instance is live. Next up, you'll use Docker commands to inspect, monitor, and manage the containers you just launched.
Explore and Manage Your Docker Deployment
Your Retool instance is live and you have a working admin account. But deploying containers is only half the story. In a real production environment, you need to know how to inspect, troubleshoot, and manage running containers. In this step, you'll use Docker commands to peek inside your deployment, explore how containers communicate, and practice stopping and starting individual services.
In This Step, Get Ready To:
- Inspect running containers, images, and port mappings with Docker commands.
- Explore container logs and Docker's virtual networking.
- Test container lifecycle management by stopping, starting, and restarting services.
Inspect the Running Containers
Docker gives you two ways to view running containers. docker compose ps shows containers managed by your compose.yaml file. docker ps shows all containers running on the entire Docker daemon, regardless of how they were started.
- Run docker compose ps to see all services defined in your Compose stack.
docker compose ps
You should see every service listed with its status, ports, and name. Every container should show a status of "Up".
- Now run docker ps to see the same containers from Docker's perspective.
docker ps
What's the difference?
docker ps gives you lower-level details like container IDs, image names, port mappings, and uptime. docker compose ps is scoped to just the services in your current Compose project. Both are useful depending on whether you're debugging a specific Compose stack or investigating everything running on the host.
- Run docker images to see all images stored on your system.
docker images
Notice how multiple containers share the same base image (tryretool/backend). Each container runs a different service based on its SERVICE_TYPE environment variable. One image, many roles. This is a common pattern in microservice architectures where the same codebase serves different functions depending on configuration.
Explore Container Logs and Networking
When something goes wrong in a multi-container deployment, logs are your first line of defense. Docker Compose lets you view logs for individual services, which is essential when you need to pinpoint which container is causing an issue.
- Run the following command to view the API server's logs.
docker compose logs api
What does this command do?
This streams the full log output from the api service. In a production scenario, you'd use this to check for startup errors, failed database connections, or request handling issues.
- Run the following command to see just the last 20 lines of the jobs runner's logs.
docker compose logs --tail=20 jobs-runner
Pro tip: tailing logs
The --tail=20 flag limits output to the most recent 20 lines. Without it, you might get thousands of lines dumped to your terminal. You can also add -f to follow logs in real time (press Ctrl+C to stop).
Now let's look at how these containers talk to each other. Docker Compose automatically creates a virtual network for your stack. This network lets containers find each other by service name instead of IP address.
- Run docker network ls to see all Docker networks on your system.
docker network ls
You should see a network created by your Compose project (typically named retool_default or similar). This is the virtual network that connects all your containers.
How do containers find each other?
Inside this virtual network, Docker provides built-in DNS. The API container reaches the database by the hostname retool-db rather than a hardcoded IP address. If you look at compose.yaml, you'll see service names used as hostnames throughout. This is one of the biggest advantages of container networking over traditional server setups.
Test Container Lifecycle Management
In a multi-container deployment, you often need to restart a single service without taking down the entire stack. Docker Compose gives you fine-grained control over individual containers.
- Run the following command to stop just the API container.
docker compose stop api
- Open your browser and visit your Retool URL at http:// followed by your EC2 public IP on port 3000.
The page should fail to load or show an error. The API container is the service that handles web requests, so stopping it makes Retool inaccessible. The other containers (database, jobs runner, etc.) are still running in the background.
- Bring the API container back by running the following command.
docker compose start api
- Refresh your browser. Retool should be accessible again after a few moments.
This demonstrates how individual services in a Compose stack can be managed independently. In a production scenario, you might stop and restart a single service to apply a configuration change without disrupting the entire application.
- Finally, restart all services at once with the following command.
docker compose restart
What Is the Difference Between Restart and Down/Up?
docker compose restart stops and starts containers in place without removing them. docker compose down && docker compose up -d removes containers entirely and recreates them from scratch.
Use restart for quick refreshes. Use down/up when you've changed configuration files like compose.yaml or docker.env.
You now have hands-on experience inspecting, debugging, and managing a live multi-container deployment. These are the same Docker commands you'd use to manage any containerized application in production. Next up, you'll wrap up the project and explore your options for keeping or tearing down your deployment.
Secret mission
Enable HTTPS with a Custom Domain
Your Retool instance is running on a raw IP address over HTTP. That means traffic between your browser and the server is unencrypted. In this secret mission, you'll register a domain in Route 53, point it to your EC2 instance, and configure automatic HTTPS with Let's Encrypt so your deployment is production-ready.
Before you go
Clean Up Your Resources
This project uses cloud resources that cost money while running. Decide whether to keep your resources running, pause them to come back later, or delete them entirely.
Cost warning
Your EC2 instance (m5.xlarge) costs approximately $0.19/hour, which adds up to about $4.61/day. If you are not actively using your Retool deployment, stop or terminate the instance to avoid unnecessary charges.
Resources you used:
- EC2 instance (m5.xlarge) with 60 GiB gp3 EBS storage.
- EC2 key pair (.pem file on your local machine).
- Security group with inbound rules for ports 22, 80, 443, and 3000.
- Docker containers running on the EC2 instance (Retool API, jobs runner, workflows, PostgreSQL, https-portal).
- Route 53 domain registration and hosted zone (if you completed the Secret Mission).
Keep everything running
No action needed. Choose this if you are still actively building with your self-hosted Retool instance.
- Your EC2 instance will continue running at ~$0.19/hour (~$4.61/day).
- EBS storage costs ~$4.80/month for the 60 GiB gp3 volume.
- If you registered a domain, the Route 53 hosted zone costs $0.50/month.
- Your Retool instance remains accessible at your EC2 public IP on port 3000 (or your custom domain if configured).
Pause - I'll come back to this later
Stop the EC2 instance to eliminate compute charges while keeping your data and configuration intact.
- In the EC2 console, select your instance and choose **Instance state**, then **Stop instance**.
- This stops all compute charges immediately. You will still pay for EBS storage (~$4.80/month).
- When you restart the instance, your EC2 public IP will change. Update your Route 53 A record if you configured a custom domain.
- After restarting, SSH back in, navigate to the retool directory, and run docker compose up -d to bring your containers back up.
Delete - I don't want to use this again
Remove all project resources and start fresh. This permanently deletes your Retool data and configuration.
- In the EC2 console, select your instance and choose **Instance state**, then **Terminate instance**. This deletes the instance and its EBS storage.
- Delete the key pair from the EC2 console under **Network & Security**, then **Key Pairs**. Also delete the .pem file from your local machine.
- Delete the security group from the EC2 console under **Network & Security**, then **Security Groups**. You can only delete it after the instance is fully terminated.
- If you registered a domain in Route 53, the domain registration is non-refundable. However, you can delete the hosted zone to stop the $0.50/month charge. Go to Route 53, select **Hosted zones**, select your domain, delete all non-default records (A records you created), then delete the hosted zone.
- Make sure you have saved your ENCRYPTION_KEY somewhere secure before terminating. You will need it if you ever redeploy and want to restore your Retool configuration.
Mission accomplished
That's a Wrap!
Nice work! You just deployed a production-grade internal tools platform on AWS infrastructure you built from scratch, using Docker to orchestrate a multi-container microservice architecture.
You've learned how to:
- Install Docker and Docker Compose on a fresh EC2 instance and configure a multi-service deployment using Dockerfile, compose.yaml, and environment variables.
- Build, launch, and manage a multi-container application with Docker Compose, including inspecting logs, networking, and container lifecycle management.
- Understand core Docker concepts like images, containers, layers, and container networking in the context of a real enterprise deployment.
- Register a domain in Route 53, configure DNS, and enable automatic HTTPS with Let's Encrypt via the https-portal container.
Ready to quiz yourself?