Deploy Self-Hosted Retool on EC2

Deploy a multi-container Retool instance on EC2 using Docker Compose.

Introduction

30 Second Summary

Every enterprise platform you use, from internal dashboards to workflow engines, runs as a set of containers working together behind the scenes.

In this project, you will deploy a self-hosted Retool instance on an AWS EC2 instance using Docker Compose, learning how Docker orchestrates 10+ containers into a single working application.

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 the Retool API server, background job runners, workflow services, a PostgreSQL database, and more.

By the end of this project, you'll have:

  • A running EC2 instance hosting Retool via a Docker Compose stack you understand line by line.
  • A clear mental model of Docker's core architecture: images, containers, Dockerfiles, Compose files, container networking, and volumes.
  • Hands-on experience inspecting, stopping, restarting, and monitoring containers in a real multi-container application.
  • A stretch challenge to codify your EC2 provisioning with Terraform, turning your manual setup into reproducible Infrastructure as Code.

Are there any prerequisites?

You need an AWS account with CLI access, a Retool Enterprise license key, and basic familiarity with SSH and the Linux command line. Docker and Git will be installed on the EC2 instance during the project.

Launch and Connect to Your EC2 Instance

Before you can deploy Retool with Docker, you need a server to run it on. EC2 gives you a virtual machine in the cloud where you'll install Docker, clone the Retool repository, and launch the entire application stack. In this step, you'll provision an EC2 instance that meets Retool's hardware requirements and connect to it via SSH.

In This Step, Get Ready To:
  • Launch an EC2 instance with the right size, storage, and security group rules for Retool.
  • Connect to your instance via SSH and verify its resources.
  • Install Git so you can clone the Retool repository in the next step.
Launch a New EC2 Instance

Retool's self-hosted stack runs 10+ containers simultaneously, so it needs a beefy machine. The minimum requirements are 8 vCPUs, 16 GiB of RAM, and 60 GiB of storage. A c5.2xlarge instance type fits these requirements exactly.

  • Open the AWS Console and navigate to the EC2 dashboard.
  • Click Launch instances.
  • Give your instance a name like retool-docker.
  • Under Application and OS Images, select Ubuntu. Choose Ubuntu Server 22.04 LTS (HVM), SSD Volume Type with the 64-bit (x86) architecture.
  • Under Instance type, select c5.2xlarge.
  • Under Key pair, create a new key pair or select an existing one. If creating a new one, name it retool-key and download the .pem file.

Now you need to configure the security group. This controls which network traffic can reach your instance.

  • Under Network settings, click Edit.
  • Add four inbound security group rules:

Why port 3000?

Port 3000 is the default port where the Retool API server listens. Without this rule, you wouldn't be able to access Retool in your browser. Ports 80 and 443 are for the HTTPS portal service that handles SSL termination.

  • Under Configure storage, set the root volume to 60 GiB with volume type gp3.
  • Click Launch instance.

Wait for the instance state to show Running and the status checks to pass. This usually takes about a minute.

Cost reminder

A c5.2xlarge instance costs approximately $0.34/hour in us-east-1. Teardown instructions are included in the Before You Go section at the end of this project.

Connect to Your Instance via SSH

Your instance is running, but you need a way to interact with it. SSH gives you a secure terminal session into the machine, just as if you were sitting in front of it.

  • Open a terminal on your local machine.
  • Set the permissions on your key file so SSH will accept it.
chmod 400 [[PEMPATH="path/to/your-key.pem"]]
  • Connect to your instance using SSH.
ssh -i [[PEMPATH="path/to/your-key.pem"]] ubuntu@[[EC2_PUBLIC_IP="your EC2 public IPv4 address"]]

Where do I find my public IP?

In the EC2 Console, select your instance. The public IPv4 address appears in the Instance summary panel. You can also find it under the Networking tab.

Once you're connected, verify that the instance is running the correct operating system and has the resources you expect.

  • Check the Ubuntu version.
lsb_release -a

What should I see?

You should see Ubuntu 22.04 in the output. The exact point release (e.g., 22.04.4) may vary.

  • Confirm the available memory.
free -h
  • Confirm the number of CPUs.
nproc

What should I see?

The free -h command should show approximately 16 GiB of total memory. The nproc command should return 8. These match the c5.2xlarge specs: 8 vCPUs and 16 GiB RAM.

Can't connect via SSH?

If you see Permission denied (publickey), make sure you ran chmod 400 on your key file and that you're using the correct .pem file. If you see Connection timed out, double-check that your security group has an inbound rule for SSH on port 22. Help me troubleshoot my SSH connection.

Install Git on the Instance

In the next step, you'll clone the Retool on-premise repository from GitHub. Git needs to be installed on the instance first.

  • Update the package list and install Git.
sudo apt-get update && sudo apt-get install -y git

What does this command do?

This is actually two commands chained with &&. The first command, sudo apt-get update, refreshes the list of available packages from Ubuntu's repositories. The second command, sudo apt-get install -y git, installs Git. The -y flag automatically confirms the installation prompt.

  • Verify Git is installed.
git --version

I see a version number

Git is installed and ready to go.

I see an error

If you see command not found, try running the install command again. Make sure you include sudo at the beginning. Help me install Git on Ubuntu.

Your EC2 instance is running, you're connected via SSH, and Git is installed. Next up, you'll install Docker and start building your mental model of how images and containers work.

Install Docker and Understand What You Just Installed

Your EC2 instance is running and you can SSH into it. Now you need the engine that will actually run Retool: Docker. Retool's on-premise deployment ships as a set of pre-built Docker images orchestrated by Docker Compose. Before you can launch any of that, you need Docker installed on your instance.

In This Step, Get Ready To:
  • Clone the Retool on-premise repository and run its install script to set up Docker.
  • Verify your Docker installation and understand the client-daemon architecture.
  • Run your first container to see Docker's full lifecycle in action.
Clone the Retool Repository and Run the Install Script

Retool provides an on-premise repository on GitHub that contains everything you need: a Dockerfile, a compose.yaml, and an install script that handles Docker setup for Ubuntu.

  • In your SSH session, clone the repository:
git clone https://github.com/tryretool/retool-onpremise.git
  • Change into the cloned directory:
cd retool-onpremise
  • Run the install script:
./install.sh

What does this script do?

The install.sh script does three things. It installs Docker Engine and Docker Compose if they are not already present. It generates a docker.env file with randomized secrets (including your ENCRYPTION_KEY). It also creates a retooldb.env configuration file for the RetoolDB database.

The script may take a minute or two to complete. Wait until you see your terminal prompt return before continuing.

Verify Docker and Understand the Architecture

Now that Docker is installed, let's confirm it is working and understand what you actually have on your system.

  • Check the Docker Engine version:
docker --version
  • Check the Docker Compose version:
docker compose version

Why docker compose and not docker-compose?

The Retool on-premise repository uses Docker Compose v2, which is a plugin built into the docker CLI. The command is docker compose (with a space). The legacy standalone binary docker-compose (with a hyphen) is a separate tool that is no longer recommended.

I see version numbers

You are good to go. Both Docker Engine and Docker Compose are installed and responding.

Command not found

The install script may not have completed successfully. Try running ./install.sh again and watch for error messages in the output.

Still not working?

Make sure you are running Ubuntu 22.04 LTS. The install script is tested and supported on Ubuntu. Help me troubleshoot my Docker installation.

  • Run docker info to see the Docker daemon's full configuration:
docker info

This command outputs a wall of information. You do not need to memorize it. The important thing is understanding what it reveals about Docker's architecture.

What is Docker's client-server architecture?

Docker Engine is a client-server application with three components. The Docker daemon (dockerd) runs in the background, managing images, containers, networks, and volumes. The docker CLI is the client that sends commands to the daemon. Docker Compose is a plugin that extends the CLI to manage multi-container applications from a single file.

Every time you type a docker command, the CLI sends a request to the daemon, and the daemon does the actual work.

Run Your First Container

Before diving into Retool's complex multi-container stack, let's see Docker's full lifecycle with the simplest possible example.

  • Run the hello-world container:
docker run hello-world

What does this command do?

This single command triggers Docker's entire lifecycle:

  • Docker checks if the hello-world image exists locally. It does not, so Docker pulls it from Docker Hub (a public registry of images).
  • Docker creates a container from that image.
  • Docker runs the container, which prints a message and exits.

This is the core mental model: Registry (where images are stored) to Image (a read-only template) to Container (a running instance of that image).

  • Read the output in your terminal carefully. Docker prints a detailed explanation of exactly what happened during the run.

What should I see?

You should see a message starting with "Hello from Docker!" followed by a numbered list explaining the steps Docker took. If you see this message, your Docker installation is working correctly.

Docker is installed and you have seen its full lifecycle in action. Next, you will read the Retool Dockerfile line by line to understand how Docker images are actually built.

Read the Dockerfile Line by Line

In the previous step, you installed Docker Engine and saw the full image-to-container lifecycle with hello-world. Now it is time to look at how Docker images actually get built.

A Dockerfile is a text file containing instructions that Docker reads to assemble an image. Every line in the file adds a layer to the image. The Retool repository includes a Dockerfile that builds the main application image, and you are going to read every line of it.

In This Step, Get Ready To:
  • Read and understand every line of the Retool Dockerfile.
  • Build the Retool Docker image with a pinned version number.
  • Inspect the images on your system and understand the difference between an image and a container.
Open and Walk Through the Dockerfile

The Dockerfile in the retool-onpremise repository is short, but every line matters. Each instruction tells Docker how to construct the image layer by layer.

  • Make sure you are in the retool-onpremise directory.
  • Run the following command to display the Dockerfile.
cat Dockerfile

You should see output similar to this:

ARG VERSION=X.Y.Z-stable
FROM tryretool/code-executor-service:${VERSION} AS code-executor
FROM tryretool/backend:${VERSION}
CMD ./docker_scripts/start_api.sh

Four lines. Let's break down what each one does.

What does each line do?

  • ARG VERSION=X.Y.Z-stable declares a build-time variable. This value is only available during the image build process, not when a container runs.
  • FROM tryretool/code-executor-service:${VERSION} AS code-executor pulls a specific image from Docker Hub and names it as a build stage called code-executor. This stage is available as a separate build target.
  • FROM tryretool/backend:${VERSION} sets the main base image. The final image inherits everything from tryretool/backend.
  • CMD ./docker_scripts/start_api.sh defines the default command that runs when a container starts from this image.

What is a multi-stage build?

This Dockerfile uses a multi-stage build. The two FROM lines define two separate stages. The final image inherits from tryretool/backend, but the code-executor stage can be targeted independently during the build. This pattern keeps images lean by separating concerns into distinct stages.

Pin the Version and Build the Image

The default VERSION in the Dockerfile is a placeholder. You need to pin it to a specific, known version of Retool so your deployment is reproducible.

  • Open the Dockerfile in a text editor.
nano Dockerfile
  • Replace the X.Y.Z-stable placeholder on the first line with 3.334.7-stable.

The first line should now read:

ARG VERSION=3.334.7-stable
  • Save the file and exit the editor (in nano, press Ctrl+O to save, then Ctrl+X to exit).
  • Run the build command.
sudo docker compose build

What does this command do?

docker compose build reads the compose.yaml file and builds images for every service that has a build directive. It uses the Dockerfile you just edited.

Watch the output as it runs. Each step in the Dockerfile creates a layer. Layers are cached, so if you run the build again without changing anything, it finishes almost instantly. This is why Docker images are efficient.

Pro tip: build time

The first build takes a few minutes because Docker needs to pull the base images from Docker Hub. Subsequent builds will be much faster thanks to layer caching.

Inspect the Built Images

The build is complete, but nothing is running yet. You have created images, not containers. Let's see what is on your system.

  • Run the following command to list all Docker images.
sudo docker images

You should see several images in the output. Look for the retool-onpremise-api image you just built. You should also see the base images that were pulled during the build: tryretool/backend and tryretool/code-executor-service.

Notice the image sizes and tags in the output. Each image has a unique ID, a repository name, and a tag.

What is the difference between an image and a container?

An image is a read-only template. It does not run. It is the blueprint. A container is a running instance of an image. You can create many containers from the same image, each with its own state and configuration.

Think of it like a class and an object in programming. The image is the class definition. The container is the object you instantiate from it.

You now have a custom Retool image sitting on your EC2 instance, ready to be turned into running containers. Next up, you will decode the compose.yaml file that orchestrates all of Retool's services into a single, coordinated stack.

Decode the compose.yaml Architecture

You have a Dockerfile that builds a single image. But Retool is not a single-container application. It is a system of 10+ services that need to talk to each other, share a database, and start in the right order. Docker Compose solves this problem by letting you define your entire application stack in one file: compose.yaml. In this step, you will read that file and understand every layer of the architecture it describes.

In This Step, Get Ready To:
  • Identify all 10 services in the compose file and understand their roles.
  • Map out the three isolated networks that segment container traffic.
  • Understand how volumes persist data and how service dependencies control startup order.
Identify the Services in compose.yaml

The compose.yaml file is the single source of truth for your entire application stack. Every container, network, and volume is declared here.

  • Open the compose file.
cat compose.yaml

This file defines the entire Retool application stack. Take a moment to scroll through it and notice the structure. Each top-level key under services: is a separate container that Docker Compose will create and manage.

Here are the services you should see:

  • api is the main Retool backend server, exposed on port 3000.
  • jobs-runner processes background tasks like scheduled queries.
  • workflows-backend handles workflow logic.
  • workflows-worker executes workflow tasks.
  • agent-worker and agent-eval-worker handle AI agent execution.
  • code-executor runs user-written code in a sandboxed environment.
  • postgres is the primary database, using the postgres:16.8 image.
  • retooldb-postgres provides storage for RetoolDB.
  • https-portal handles TLS/SSL termination for HTTPS access.

Why do so many services share the same Dockerfile?

Notice that every service except postgres, retooldb-postgres, code-executor, and https-portal uses build: context: . to build from the same Dockerfile. They are the same image running with different SERVICE_TYPE environment variables.

This is a key Docker pattern: one image, many containers, different roles. It keeps your images consistent and your builds fast.

Study the Network Segmentation

Containers do not all need to talk to each other. The compose file uses Docker networks to control which services can communicate.

  • Scroll to the networks: section at the bottom of compose.yaml.

The compose file defines three networks:

  • frontend connects the services that need to be reachable from outside, like api and https-portal.
  • backend connects internal services to the database. The postgres service only connects to this network.
  • code-executor isolates the sandboxed code execution service.

The api service connects to all three networks because it needs to serve traffic, reach the database, and communicate with the code executor. The https-portal only connects to frontend. The database is never exposed to the frontend network.

What is network segmentation?

This is the same concept as VPC subnet isolation in AWS, but at the Docker layer. By placing the database on a private network, you prevent any frontend-facing service from directly accessing it. If the https-portal container were compromised, the attacker could not reach postgres because they are on different networks.

Study the Volumes, Dependencies, and Temporal Include

Containers are ephemeral by default. When a container stops, any data written inside it disappears. Docker volumes solve this by storing data outside the container's filesystem.

  • Look at the postgres service definition in compose.yaml.

The postgres service mounts a named volume called data at /var/lib/postgresql/data. Without this volume, stopping the container would destroy your entire database. The retooldb-postgres service has its own volume called retooldb-data.

Now look at the depends_on directives on the application services. These tell Docker Compose to start postgres before the services that need it. This prevents the API server from crashing on startup because the database is not ready yet.

  • Open the Temporal configuration file.
cat temporal.yaml

The include: temporal.yaml line in compose.yaml pulls this file in as part of the stack. Temporal is an orchestration service that manages workflow execution. It uses the image tryretool/one-offs:retool-temporal-1.1.6, exposes port 7233, and connects to the backend and temporal networks.

What is the difference between a volume and a bind mount?

Named volumes like data are managed entirely by Docker. Docker decides where to store the data on the host filesystem. A bind mount maps a specific host directory into the container. Named volumes are preferred for databases because Docker handles permissions and cleanup automatically.

You now have a complete mental map of the compose.yaml architecture: 10+ services, three isolated networks, persistent volumes, and dependency ordering. Next up, you will configure the environment variables that these services need and launch the entire stack.

Configure Environment Variables and Launch Retool

You have a fully built Docker image and a compose file you understand inside and out. The last piece before launch is configuration. Environment variables are how you inject settings into containers at runtime without hardcoding them into images. In this step, you will configure the docker.env file and launch the entire multi-container stack with a single command.

In This Step, Get Ready To:
  • Configure your encryption key, license key, and cookie settings in docker.env.
  • Launch 10+ containers with a single docker compose up command.
  • Access your running Retool instance in the browser and create an admin account.
Configure the docker.env File

The docker.env file contains all the environment variables that get injected into your containers at runtime. In the compose.yaml, each service references this file through the env_file: docker.env directive. This keeps sensitive configuration out of your images and compose file.

  • Open the file to see its contents.
cat docker.env

The install script auto-generated several values here, including an ENCRYPTION_KEY. This key encrypts all of your Retool resources. You need to configure three things in this file:

  • Find the ENCRYPTION_KEY value that was auto-generated. Copy this value and save it somewhere secure outside of Retool (such as a password manager or a local file). If you lose this key, you cannot decrypt your Retool resources.
  • Open the file for editing.
sudo nano docker.env
  • Find the LICENSE_KEY line and replace the placeholder with your actual Retool Enterprise license key.
  • Find the COOKIE_INSECURE line and uncomment it by removing the # at the beginning. Make sure the value is set to true.
  • Save the file with Ctrl+O, press Enter, then exit with Ctrl+X.

Why COOKIE_INSECURE?

By default, Retool expects HTTPS connections. Setting COOKIE_INSECURE=true allows Retool to work over plain HTTP. This is fine for learning and testing, but in a production environment you would configure SSL/TLS instead.

Back up your ENCRYPTION_KEY

The ENCRYPTION_KEY is critical. It encrypts all saved queries, credentials, and resources in Retool. If you lose it and your database is wiped, everything is gone. Save it somewhere safe before moving on.

Launch the Entire Stack

With the configuration in place, one command brings up every service defined in your compose.yaml.

  • Run the following command to start all containers.
sudo docker compose up -d

What does this command do?

docker compose up reads your compose.yaml and starts every service defined in it. The -d flag runs containers in detached mode, meaning they run in the background and you get your terminal back.

Docker Compose handles the entire orchestration for you. It pulls any missing images, creates the networks and volumes, and starts containers in the correct order based on depends_on directives. This single command orchestrates 10+ containers.

Watch the output as Docker pulls images, creates networks, creates volumes, and starts containers in dependency order. This may take a few minutes on the first run.

  • Once the command completes, check the status of all running containers.
sudo docker compose ps

What should I see?

You should see a table listing every service from your compose file. Each row represents a running container. Look for the STATUS column. All containers should show Up. The api container should show port 3000 in the PORTS column.

Containers showing Restarting or Exit?

If any containers are not in the Up state, check their logs with sudo docker compose logs <service-name>. Common causes include a missing or incorrect LICENSE_KEY in docker.env. Help me debug my container startup errors.

Access Retool in Your Browser

Your containers are running. The api service is listening on port 3000. Before opening the browser, confirm the API server has finished starting up by checking its logs.

  • View the API server logs.
sudo docker compose logs api

Look for startup messages indicating the server is ready and listening. Once you see those, the API is accepting connections.

  • Open your browser and navigate to http://:3000.

I see the Retool signup page

You should see the Retool signup page asking you to create an admin account.

  • Fill in your name, email, and password to create your admin account.
  • Complete the onboarding flow.

You now have a running self-hosted Retool instance powered by Docker Compose.

I see an error or blank page

A few things to check:

  • Make sure you are using http:// and not https://. You have not configured SSL.
  • Verify your EC2 security group allows inbound traffic on port 3000 from 0.0.0.0/0.
  • Confirm the api container is still running with sudo docker compose ps.
  • Check the logs with sudo docker compose logs api for error messages.
  • Verify that COOKIE_INSECURE=true is uncommented in docker.env.

If you made changes to docker.env, restart the stack with sudo docker compose down && sudo docker compose up -d to pick up the new values.

Help me troubleshoot why I cannot access Retool in my browser.

You just went from a docker.env file to a fully running enterprise application with a single command. Next up, you will dive inside these containers to inspect, stop, restart, and monitor them like a pro.

Inspect, Explore, and Manage Your Containers

Your Retool instance is live and you have an admin account. Now it is time to look under the hood. In this step, you will use Docker commands to inspect container configurations, test lifecycle management, and monitor resource usage across your entire stack.

In This Step, Get Ready To:
  • Inspect a running container's full runtime configuration and compare it to the compose.yaml blueprint.
  • Stop, start, and restart individual services without affecting the rest of the stack.
  • Monitor real-time resource usage and execute commands inside running containers.
Inspect a Running Container's Configuration

The compose.yaml file is the blueprint for your application. A running container is the live instance built from that blueprint. The docker inspect command lets you see every detail of a container's runtime state, including network settings, mounted volumes, environment variables, and the command it is executing.

  • Run sudo docker compose ps to see all running containers.
sudo docker compose ps

Each row represents a running container. Notice the container names follow the pattern retool-onpremise-<service>-1. The columns show each container's current state, health status, and port mappings.

  • Run docker inspect on the API container to see its full runtime configuration.
sudo docker inspect retool-onpremise-api-1

What does this command do?

This outputs a large JSON document containing everything Docker knows about this container. Scroll through and look for the NetworkSettings section (which networks the container is attached to), the Mounts section (volumes), and the Cmd section (the command the container is running).

Compare what you see to the api service definition in compose.yaml. The compose file declared the desired state. The inspect output shows the actual running state.

Test Container Lifecycle Commands

One of Docker Compose's strengths is the ability to manage individual services independently. You can stop, start, and restart a single container without touching the rest of your stack. Let's prove this by temporarily taking down the Retool API while everything else keeps running.

  • Stop just the API container.
sudo docker compose stop api
  • Switch to your browser and refresh the Retool page at http://your-ec2-public-ip:3000.

Retool is down. The page will not load because the API container is the service that handles web requests on port 3000.

  • Bring the API container back up.
sudo docker compose start api
  • Refresh your browser again.

Retool is back. The other containers (postgres, jobs-runner, workflows-backend, and the rest) stayed running the entire time. Only the API service was affected.

  • Run a restart to cycle the API container in one command.
sudo docker compose restart api

What Is the Difference Between Stop, Start, and Restart?

The stop command gracefully shuts down a container's process. The start command boots it back up using the same configuration. The restart command does both in sequence. All three operate on individual services within your stack, leaving everything else untouched.

Monitor Resources and Execute Commands Inside Containers

Running containers consume CPU, memory, and network bandwidth. Docker provides built-in tools to monitor this in real time. You can also execute commands directly inside a running container, which is useful for debugging and verifying that your data is intact.

  • Run docker stats to see resource usage for every running container.
sudo docker stats --no-stream

What does this command do?

The --no-stream flag captures a single snapshot instead of continuously updating. The output shows CPU percentage, memory usage, memory limit, network I/O, and block I/O for each container. This is how you monitor a containerized application in production.

Notice which services consume the most resources. The API and workflows containers typically use more memory than the database or code executor.

  • Execute a SQL query inside the running PostgreSQL container to verify the database is live and your data persists.
sudo docker compose exec postgres psql -U retool -d hammerhead -c "SELECT count(*) FROM users;"

What does this command do?

The docker compose exec command runs a command inside a running container. Here, you are launching psql (the PostgreSQL client) inside the postgres container, connecting as the retool user to the hammerhead database, and running a query that counts users. This proves three things: the database is running, the data persists in the named volume, and you can interact with containers directly from the host.

Getting a "relation does not exist" error?

The database name and user in this command (retool and hammerhead) are based on the defaults generated by the install script. Your docker.env file may have different values for POSTGRES_USER and POSTGRES_DB. Check your docker.env and update the command accordingly. Help me fix this database connection error.

You should see a count of at least 1 (the admin account you created in the previous step). This is the user record stored in the PostgreSQL container's volume. Even if you restart the container, this data persists because of the named volume defined in compose.yaml.

You have now inspected, managed, and monitored every layer of your containerized Retool deployment. You know how to read a container's runtime state, control individual services, and verify data persistence. These are the same skills you will use with any Docker-based application, whether it is a single container or a hundred.

Secret mission

Codify Your EC2 Setup with Terraform

You just built a running Retool instance by clicking through the AWS Console. But what happens when you need to do it again? Or when a teammate needs the same setup? In this secret mission, you will turn your manual EC2 provisioning into a Terraform configuration, so your infrastructure becomes code you can version, share, and reproduce in seconds.

Before you go

Clean Up Your Resources

This project created AWS resources that cost money while they exist. Decide whether to keep your resources running, pause them to come back later, or delete them entirely.

Cost warning

Your c5.2xlarge EC2 instance costs approximately $0.34/hour ($8.16/day). The 60 GiB gp3 EBS volume costs approximately $4.80/month even when the instance is stopped. If you are not actively using Retool, stop or terminate the instance to avoid unnecessary charges.

Resources you used:

  • EC2 instance (c5.2xlarge) running Ubuntu 22.04 with Docker Compose and the Retool stack.
  • EBS volume (60 GiB gp3) attached to the EC2 instance.
  • Security group with inbound rules for ports 22, 80, 443, and 3000.
  • SSH key pair used to connect to the instance.
  • Terraform-provisioned EC2 instance and security group (Secret Mission only).

Keep everything running

No action needed. Choose this if you are still actively using your Retool instance or plan to continue building with it soon. Your EC2 instance will continue running and you will be charged approximately $0.34/hour.

Pause - I'll come back to this later

Stop the EC2 instance to halt compute charges while keeping your data intact on the EBS volume. You can restart the instance later and your Retool setup will come back up because all data is stored on the persistent EBS volume.

  • Go to the EC2 Console and select your Retool instance.
  • Click Instance State, then select Stop instance.
  • The compute charge stops immediately. The EBS volume charge (~$4.80/month) continues.
  • To resume, select the instance and choose Instance State > Start instance. Note that the public IP address will change after a restart unless you have an Elastic IP.

Delete - I don't want to use this again

Remove all project resources and start fresh. This deletes the EC2 instance, its EBS volume, and all data. This action cannot be undone.

  • Go to the EC2 Console and select your Retool instance.
  • Click Instance State, then select Terminate instance. This deletes the instance and its attached EBS volume.
  • Go to Security Groups in the EC2 Console sidebar. Find the security group you created for this project and delete it.
  • If you no longer need the SSH key pair, go to Key Pairs in the EC2 Console sidebar and delete it. Also delete the .pem file from your local machine.
  • If you completed the Secret Mission, run terraform destroy in your retool-infra directory to clean up any Terraform-provisioned resources.

Mission accomplished

That's a Wrap!

Nice work! You just deployed a self-hosted Retool instance on AWS EC2 using Docker Compose. More importantly, you understand exactly how it works under the hood.

Here's what you learned:

  • Installed Docker Engine and Docker Compose on an EC2 instance, then read a real-world Dockerfile and compose.yaml line by line to understand multi-stage builds, service definitions, container networking, and persistent volumes.
  • Launched a 10+ container application stack with a single docker compose up -d command, then inspected, stopped, restarted, and monitored individual containers to understand Docker's lifecycle management.
  • Configured environment variables via docker.env, understood how they flow into containers at runtime, and accessed a running Retool instance to create an admin account.
  • Codified your EC2 provisioning with Terraform, turning a manual console setup into reproducible Infrastructure as Code that can be created and destroyed in a single command.

Ready to quiz yourself?