Skip to content

Deploy Streamlit with the streamlit template

Deployment

Deploy Streamlit with the streamlit template

Stand up Streamlit, a Python framework for data apps and interactive demos, on a single Quake AI instance using the validated OpenTofu template streamlit. You apply the template, open the sample app over the floating IP, replace it with your own Python code, and put a reverse proxy in front so the app runs over HTTPS.

Streamlit hosts internal dashboards and model demos on infrastructure you own. You run it yourself; this is a self-hosted tool you operate, not a managed service.

YouYour domain(DNS A record)Floating IPUbuntu instanceCaddyreverse proxyStreamlitPython appBlock volume/opt/streamlit proxies 443 to 8501reads code + dataHTTPS app
Click to zoom
What you'll build: a Streamlit data app on a single instance, with Python code and data on a block volume, served over HTTPS through a Caddy reverse proxy

Monthly cost estimate

Pricing calculator ↗

Sized as a custom package on shared vCPU.

Starting template$15.50/mo

Monthly total for the required template above. Use the configurator below to add optional pieces and see the total update.

What each resource is for

Streamlit data-app host

s1a.small · 2 shared vCPU, 2 GiB RAM, 0.5 Gbps

Runs a Streamlit app in Docker with Python code and data files on an attached volume.

A single Streamlit app runs on 2 vCPU and 2 GiB RAM. Size up for heavier pandas workloads or larger in-memory datasets.

$16.50/mo

Compute shown per role at custom-package rates ($29/dedicated vCPU, $7.25/shared vCPU, $1/GiB RAM). The headline above is the billed total: the cheaper of a named plan and the custom package, plus add-ons.

Included in baseline

s1a.small

2 shared vCPU, 2 GiB RAM, 0.5 Gbps

$16.50

Compute + RAM rate basis

2 vCPU + 2 GiB RAM at $29/dedicated vCPU, $7.25/shared vCPU, $1/GiB RAM (regular). Totals apply the flat −$5/mo package promotion.

—

Block storage (50 GiB)

50 GiB at $0.08/GiB/mo

$4.00

Public IP (included)

1 included with the custom package

$0.00

Package promotional discount

Flat −$5.00/mo on the custom package (same promotion as named plans).

$-5.00

Included at no charge

These line items are zero on Quake AI. Many other providers meter them separately.

Data transfer (inbound and outbound)

Unlimited data transfer on every plan; Quake AI does not meter per-GB egress.

AWS, GCP, and Azure meter outbound transfer per GB. DigitalOcean and Hetzner include an allowance on compute plans, then charge overage.

Learn more
$0.00

Private networking

Private networks, subnets, Neutron routers, and security groups are included with the plan.

VPC objects are usually free to create elsewhere, but NAT gateways bill hourly plus per-GB processed. Quake AI uses router SNAT with no separate NAT line item.

$0.00

Control-plane API requests

OpenStack API calls for provisioning and management are included.

Some managed services on other clouds meter API calls or charge for premium control-plane features.

$0.00

Pricing data last validated: . For current rates, check quake.ai/pricing.

Prerequisites#

You need:

  • OpenTofu 1.6.0 or later (or Terraform 1.6.0 or later) installed locally.
  • Your OpenStack credentials sourced into the shell (source openrc.sh). See the OpenStack CLI guide.
  • An SSH keypair that already exists in your project. Record its name for the key_name variable.
  • A copy of the streamlit template directory from the template reference page.
  • Your workstation's public IP address, so you can open port 8501 to it for first-boot setup. Find it with curl -sS https://api.ipify.org.

A domain is optional for first boot. You add it in step 3 to serve the app over HTTPS.

Step 1: Set the variables and apply the template#

The app listens on port 8501 over plain HTTP. The template's security group restricts port 8501 to app_allowed_cidr, which defaults to the private network only, so the raw port stays off the public internet. To reach the app from your workstation for first-boot setup, set app_allowed_cidr to your own address.

Copy the template's example variables file and open it:

bash
cp terraform.tfvars.example terraform.tfvars

Set key_name to the SSH keypair already in your project, and app_allowed_cidr to your workstation's public IP with a /32 suffix:

HCL
key_name           = "YOUR_KEY_NAME"
app_allowed_cidr   = "YOUR_IP/32"

Initialize the working directory, preview the plan, and apply:

bash
tofu init
tofu plan
tofu apply

OpenTofu provisions a private network, a router, a security group, a block volume mounted at /opt/streamlit, an instance, and a floating IP. On first boot, cloud-init mounts the data volume, installs Docker Engine, and starts Streamlit from a compose file on port 8501.

When the apply finishes, read the outputs:

bash
tofu output

Record floating_ip and app_url.

Step 2: Open the sample app and deploy your own code#

cloud-init takes a few minutes after the instance reaches ACTIVE. Open app_url (for example http://YOUR_FLOATING_IP:8501) in your browser. If the page does not load yet, wait and retry; you can watch the container start over SSH:

bash
ssh ubuntu@YOUR_FLOATING_IP "sudo docker ps --filter name=streamlit"

The sample app shows a slider widget. Replace it with your own project:

  1. On your workstation, create a directory with main.py and requirements.txt for your app.
  2. Copy the files to the instance:
bash
scp -r ./my-app/* ubuntu@YOUR_FLOATING_IP:/opt/streamlit/app/
  1. Restart the container:
bash
ssh ubuntu@YOUR_FLOATING_IP "cd /opt/streamlit && sudo docker compose up -d"

Store datasets under /opt/streamlit/data on the instance. Quake AI flavors are CPU-only; keep in-memory workloads within the instance RAM or read larger files from Object Storage.

Step 3: Serve the app over HTTPS with Caddy#

The template leaves ports 80 and 443 open for a reverse proxy. Caddy obtains and renews a TLS certificate automatically once a domain resolves to the instance.

  1. Create a DNS A record for your domain (for example data.example.com) pointing at YOUR_FLOATING_IP. Follow How to point a domain at a Quake AI resource. Wait until the record resolves:
bash
dig +short data.example.com

The command returns your floating IP once the record propagates.

  1. SSH to the instance and add a Caddy service that proxies HTTPS to Streamlit on port 8501. Create /opt/streamlit/Caddyfile:
data.example.com {
  reverse_proxy 127.0.0.1:8501
}
  1. Add Caddy to the compose file at /opt/streamlit/docker-compose.yml so it runs alongside Streamlit:
YAML
services:
  caddy:
    image: caddy:2
    restart: unless-stopped
    network_mode: host
    volumes:
      - /opt/streamlit/Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
volumes:
  caddy_data:
  1. Apply the changes and confirm both containers run:
bash
cd /opt/streamlit
sudo docker compose up -d
sudo docker compose ps

Open https://data.example.com and confirm the padlock. Streamlit does not ship authentication; add auth at the reverse proxy or in your app if the dashboard should not be public. Once HTTPS works, close direct access to port 8501 by setting app_allowed_cidr back to the private network in terraform.tfvars and running tofu apply.

What you built#

  • Applied the streamlit template to provision a network, security group, data volume, instance, and floating IP, and let cloud-init install Docker and start Streamlit
  • Replaced the sample app with your own Python code and dependencies on the attached volume
  • Served the app over HTTPS by pointing a domain at the floating IP and routing it through a Caddy reverse proxy

Scope of this deployment#

This template runs a single-VM Streamlit host, not a managed app platform. The instance is CPU-only and runs in one region. You operate the instance, Docker, your Python code, and the data volume yourself: back them up, patch them, and watch resource use as datasets grow. Gradio fits the same host shape if your team prefers Gradio widgets: swap the container image and entrypoint while keeping the volume layout.

Next steps#

Clean up#

When you no longer need the deployment, destroy everything the template created:

bash
tofu destroy

Then remove the DNS A record you created in step 3. Because your app code and data live on the instance and its attached volume, tofu destroy removes them along with the infrastructure. Copy anything you want to keep off the volume before you destroy.

Before this
Was this page helpful?