Appsmith internal tools
Appsmith internal tools
This pattern composes Compute, Network, and Block Storage into a self-hosted low-code platform for internal tools and admin panels, on infrastructure you control.
What this template does#
Provisions a single instance running Appsmith Community Edition, an open-source low-code platform (a self-hosted alternative to Retool). Your team builds internal tools and admin panels on infrastructure you own:
- Compute instance that runs Appsmith's single fat container: the app server, an embedded MongoDB, and an embedded Redis, all in one image (4 vCPU and 4 GiB RAM)
- Private network, subnet, router, port, and security group; a floating IP for public access
- A block volume mounted at
/var/lib/docker, holding the/appsmith-stacksbind mount where all persistent state lives - cloud-init installs Docker Engine and starts the container automatically; no manual configuration step blocks first login
APPSMITH_ENCRYPTION_PASSWORD and APPSMITH_ENCRYPTION_SALT are generated on first boot and written to /opt/appsmith/.env; no credential ships with this template.
A single fat container, unlike the other multi-container ops tools#
Appsmith Community Edition's documented self-host path is one container that bundles the app server, an embedded MongoDB, and an embedded Redis via a supervisor process, closer in shape to Uptime Kuma's single-container simplicity than to Infisical or Plane's separate datastore containers. This template uses the open-source Community Edition image (appsmith-ce) rather than the Enterprise Edition image the Docker Hub listing recommends by default.
Parameters#
| Parameter | Description | Default |
|---|---|---|
key_name | SSH keypair name (must already exist) | No default |
flavor_name | Instance size (the fat container runs on 4 vCPU / 4 GiB) | s1a.medium |
image_name | Operating system image | Ubuntu-24.04 |
app_name | Display name prefix for resources | appsmith |
volume_size | Block volume size in GiB, mounted at /var/lib/docker | 20 |
external_network | External network for floating IP allocation | PublicStatic |
private_cidr | CIDR for the private subnet | 10.53.0.0/24 |
app_allowed_cidr | CIDR allowed to reach Appsmith on port 8080 | 10.53.0.0/24 |
Finish setup after apply#
cloud-init starts the fat container immediately; no held-back service waits on manual configuration:
- Open the app at
app_url(or tunnel over SSH to port 8080) and sign up the first admin account. - For production use, point a domain's DNS A record at the floating IP, put a reverse proxy (Caddy or Nginx) in front for HTTPS on 443, and route it to port 8080.
Back up the encryption password and salt#
APPSMITH_ENCRYPTION_PASSWORD and APPSMITH_ENCRYPTION_SALT in /opt/appsmith/.env encrypt stored datasource credentials at rest. Losing them makes stored datasource credentials unrecoverable. Copy /opt/appsmith/.env to a secure location outside this instance immediately after first boot, before you connect any real datasource.
Access and security#
Appsmith's internal port 80 is remapped to 8080 so a host-level reverse proxy can own ports 80 and 443 for the public domain. The security group restricts 8080 to app_allowed_cidr, which defaults to the private network only. Ports 80 and 443 stay open for a reverse proxy you add for production use; they carry no traffic until you add one.
When to use this pattern#
Build internal tools, admin panels, and database-backed UIs for a team on a host you operate. All persistent state, including the embedded database, lives under /appsmith-stacks on the attached volume: there is no separate datastore to point elsewhere.
Estimated cost#
Monthly cost estimate
Pricing calculator ↗Sized as a custom package on shared vCPU.
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
Appsmith internal-tools host
s1a.medium · 4 shared vCPU, 4 GiB RAM, 0.5 Gbps
Runs Appsmith Community Edition's single fat container (app server, embedded MongoDB, and embedded Redis in one image), with all persistent state under the /appsmith-stacks bind mount on an attached volume.
Appsmith's fat container runs on 4 vCPU and 4 GiB RAM. Size up for many concurrent users or large datasource query volume.
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.medium
4 shared vCPU, 4 GiB RAM, 0.5 Gbps
Compute + RAM rate basis
4 vCPU + 4 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
Public IP (included)
1 included with the custom package
Package promotional discount
Flat −$5.00/mo on the custom package (same promotion as named plans).
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 morePrivate 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.
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.
Pricing data last validated: . For current rates, check quake.ai/pricing.
Template source#
Show source (7 files)Hide source
data "openstack_images_image_v2" "os" {
name = var.image_name
most_recent = true
}
data "openstack_networking_network_v2" "external" {
name = var.external_network
}
resource "openstack_networking_network_v2" "private" {
name = "${var.app_name}-net"
admin_state_up = true
}
resource "openstack_networking_subnet_v2" "private" {
name = "${var.app_name}-subnet"
network_id = openstack_networking_network_v2.private.id
cidr = var.private_cidr
ip_version = 4
dns_nameservers = ["1.1.1.1", "8.8.8.8"]
}
resource "openstack_networking_router_v2" "main" {
name = "${var.app_name}-router"
external_network_id = data.openstack_networking_network_v2.external.id
}
resource "openstack_networking_router_interface_v2" "private" {
router_id = openstack_networking_router_v2.main.id
subnet_id = openstack_networking_subnet_v2.private.id
}
resource "openstack_networking_secgroup_v2" "appsmith" {
name = "${var.app_name}-sg"
description = "SSH and HTTP/HTTPS for a reverse proxy; app port 8080 restricted"
}
resource "openstack_networking_secgroup_rule_v2" "ssh" {
direction = "ingress"
ethertype = "IPv4"
protocol = "tcp"
port_range_min = 22
port_range_max = 22
remote_ip_prefix = "0.0.0.0/0"
security_group_id = openstack_networking_secgroup_v2.appsmith.id
}
# 80 and 443 carry Appsmith when it is served over a domain with automatic
# TLS through a host-level reverse proxy (Caddy or Nginx), rather than
# Appsmith's own embedded Let's Encrypt integration, so the certificate
# story stays consistent with the rest of this template library.
resource "openstack_networking_secgroup_rule_v2" "http" {
direction = "ingress"
ethertype = "IPv4"
protocol = "tcp"
port_range_min = 80
port_range_max = 80
remote_ip_prefix = "0.0.0.0/0"
security_group_id = openstack_networking_secgroup_v2.appsmith.id
}
resource "openstack_networking_secgroup_rule_v2" "https" {
direction = "ingress"
ethertype = "IPv4"
protocol = "tcp"
port_range_min = 443
port_range_max = 443
remote_ip_prefix = "0.0.0.0/0"
security_group_id = openstack_networking_secgroup_v2.appsmith.id
}
# Raw app HTTP on 8080 is restricted to app_allowed_cidr (the private network
# by default). Use it for setup over an SSH tunnel or a scoped workstation IP;
# put a reverse proxy on 443 in front for routine access.
resource "openstack_networking_secgroup_rule_v2" "app" {
direction = "ingress"
ethertype = "IPv4"
protocol = "tcp"
port_range_min = 8080
port_range_max = 8080
remote_ip_prefix = var.app_allowed_cidr
security_group_id = openstack_networking_secgroup_v2.appsmith.id
}
resource "openstack_networking_port_v2" "appsmith" {
name = "${var.app_name}-port"
network_id = openstack_networking_network_v2.private.id
security_group_ids = [openstack_networking_secgroup_v2.appsmith.id]
fixed_ip {
subnet_id = openstack_networking_subnet_v2.private.id
}
depends_on = [openstack_networking_router_interface_v2.private]
}
resource "openstack_blockstorage_volume_v3" "data" {
name = "${var.app_name}-data"
size = var.volume_size
}
resource "openstack_compute_instance_v2" "appsmith" {
name = var.app_name
flavor_name = var.flavor_name
key_pair = var.key_name
user_data = templatefile("${path.module}/cloud-init/appsmith.yaml.tftpl", {
app_name = var.app_name
})
block_device {
uuid = data.openstack_images_image_v2.os.id
source_type = "image"
destination_type = "volume"
volume_size = 30
boot_index = 0
delete_on_termination = true
}
network {
port = openstack_networking_port_v2.appsmith.id
}
}
resource "openstack_compute_volume_attach_v2" "data" {
instance_id = openstack_compute_instance_v2.appsmith.id
volume_id = openstack_blockstorage_volume_v3.data.id
}
resource "openstack_networking_floatingip_v2" "appsmith" {
pool = var.external_network
}
resource "openstack_networking_floatingip_associate_v2" "appsmith" {
floating_ip = openstack_networking_floatingip_v2.appsmith.address
port_id = openstack_networking_port_v2.appsmith.id
}
variable "key_name" {
description = "SSH keypair name (must already exist in your project)"
type = string
}
variable "flavor_name" {
description = "Instance size. Appsmith's fat container bundles the app server, an embedded MongoDB, and an embedded Redis, so it needs more headroom than a single-process tool. It runs comfortably on 4 vCPU and 4 GiB RAM (s1a.medium)."
type = string
default = "s1a.medium"
}
variable "image_name" {
description = "Operating system image. Ubuntu 24.04 is the recommended base."
type = string
default = "Ubuntu-24.04"
}
variable "app_name" {
description = "Display name prefix for compute and network resources"
type = string
default = "appsmith"
}
variable "volume_size" {
description = "Block volume size in GiB, mounted at /var/lib/docker so the /appsmith-stacks bind mount (the embedded database, uploaded assets, SSL config, and encryption keys) lives on a volume you can grow rather than on the boot disk."
type = number
default = 20
}
variable "external_network" {
description = "Shared external network for router gateway and floating IPs; defaults to PublicStatic (persisted FIP / production pattern). Override with PublicEphemeral for ephemeral demos."
type = string
default = "PublicStatic"
}
variable "private_cidr" {
description = "CIDR for the private tenant network the instance lives in"
type = string
default = "10.53.0.0/24"
}
variable "app_allowed_cidr" {
description = "CIDR allowed to reach Appsmith on port 8080. Defaults to the private network only, so the app is not exposed to the public internet on its raw port. Put a reverse proxy on 443 in front for HTTPS once you point a domain at the instance. To reach port 8080 directly from your workstation during setup, set this to YOUR_IP/32."
type = string
default = "10.53.0.0/24"
}
output "instance_id" {
description = "ID of the compute instance running Appsmith"
value = openstack_compute_instance_v2.appsmith.id
}
output "floating_ip" {
description = "Public floating IP address of the Appsmith host"
value = openstack_networking_floatingip_v2.appsmith.address
}
output "private_ip" {
description = "Private IP address of the instance"
value = openstack_compute_instance_v2.appsmith.access_ip_v4
}
output "app_url" {
description = "Appsmith app URL on port 8080. Reachable from app_allowed_cidr (the private network by default). Appsmith's fat container starts automatically on first boot; sign up the first admin account as soon as it is reachable. Put a reverse proxy in front and use HTTPS on 443 for production use."
value = "http://${openstack_networking_floatingip_v2.appsmith.address}:8080"
}
terraform {
required_version = ">= 1.6.0"
required_providers {
openstack = {
source = "terraform-provider-openstack/openstack"
version = "~> 2.0"
}
}
}
provider "openstack" {}
# Required: SSH keypair must already exist in your project
key_name = "YOUR_KEY_NAME"
# Recommended: restrict the app port (8080) to your workstation IP for setup.
# Leave unset to keep 8080 reachable only from the private network and tunnel
# over SSH. For production use, put a reverse proxy in front on 443.
# app_allowed_cidr = "203.0.113.10/32"
# flavor_name = "s1a.medium"
# image_name = "Ubuntu-24.04"
# app_name = "appsmith"
# volume_size = 20
# external_network = "PublicStatic"
# private_cidr = "10.53.0.0/24"
#cloud-config
package_update: true
packages:
- ca-certificates
- curl
write_files:
- path: /opt/appsmith/docker-compose.yml
permissions: "0644"
content: |
# Appsmith Community Edition for ${app_name}: a single fat container
# bundling the app server, an embedded MongoDB, and an embedded Redis.
# Internal ports 80/443 are remapped to 8080 so a host-level reverse
# proxy can own 80/443 for the public HTTPS domain, matching the
# Infisical/Plane/Unleash pattern in this template library rather than
# relying on Appsmith's own embedded Let's Encrypt integration. All
# persistent state, including the embedded database, lives under the
# /appsmith-stacks bind mount. This template uses the open-source
# Community Edition image (appsmith-ce), not the Enterprise Edition
# image the Docker Hub listing recommends by default.
services:
appsmith:
image: appsmith/appsmith-ce:release
restart: unless-stopped
ports:
- "8080:80"
env_file:
- /opt/appsmith/.env
volumes:
- /opt/appsmith/stacks:/appsmith-stacks
runcmd:
- |
set -e
# The data volume attaches as /dev/sdb on this platform (not /dev/vdb).
# Mount it at /var/lib/docker before Docker is installed, and keep the
# /appsmith-stacks bind mount under /opt so it lives on the resizable
# volume rather than the boot disk.
DEV=/dev/sdb
for i in $(seq 1 30); do [ -b "$DEV" ] && break; sleep 5; done
if ! blkid "$DEV" >/dev/null 2>&1; then mkfs.ext4 -F -L appsmithdata "$DEV"; fi
mkdir -p /var/lib/docker
mount "$DEV" /var/lib/docker
grep -q "$DEV" /etc/fstab || echo "$DEV /var/lib/docker ext4 defaults,nofail 0 2" >> /etc/fstab
mkdir -p /opt/appsmith/stacks
# Install Docker Engine plus the compose plugin from Docker's convenience
# script.
curl -fsSL https://get.docker.com | sh
# Generate Appsmith's encryption password and salt on first boot. These
# encrypt stored datasource credentials and never leave this instance.
# Losing them makes stored datasource credentials unrecoverable: back up
# /opt/appsmith/.env immediately after first boot.
ENC_PASSWORD=$(openssl rand -hex 24)
ENC_SALT=$(openssl rand -hex 12)
umask 077
{
echo "APPSMITH_ENCRYPTION_PASSWORD=$ENC_PASSWORD"
echo "APPSMITH_ENCRYPTION_SALT=$ENC_SALT"
} > /opt/appsmith/.env
chmod 600 /opt/appsmith/.env
# Bring up the fat container. Unlike Infisical or Plane, Appsmith has no
# separate datastore to bring up first and no public-URL-blocking auth
# callback for basic first-run: it is reachable right after boot.
cd /opt/appsmith
docker compose up -d
# Appsmith internal tools
Single compute instance running [Appsmith](https://www.appsmith.com) Community Edition, a self-hosted low-code platform for internal tools and admin panels (a self-hosted alternative to Retool) on infrastructure you control. After apply, the app is reachable immediately: sign up the first admin account and connect a datasource.
**Network class:** production — `external_network` defaults to `PublicStatic` for persisted floating IPs and multi-tier stacks; override with `PublicEphemeral` for ephemeral demos.
The instance provisions a private network, a floating IP, and a block volume mounted at `/var/lib/docker` so the `/appsmith-stacks` bind mount, holding all of Appsmith's persistent state, lives on a resizable volume. cloud-init installs Docker Engine and starts the fat container with no manual steps required before first login.
## Where this fits
Appsmith lets a team build internal tools, admin panels, and database-backed UIs by connecting datasources (REST APIs, PostgreSQL, MongoDB, and more) and dragging in widgets, on infrastructure you own rather than on a third-party SaaS.
## A single fat container, unlike the other multi-container ops tools
Appsmith Community Edition's documented self-host path is one "fat container" image that bundles the app server, an embedded MongoDB, and an embedded Redis inside a single container via a supervisor process. This is architecturally different from [Infisical](/resources/iac-templates/infisical-secrets) or [Plane](/resources/iac-templates/plane-project-management), which wire up separate datastore containers: there is nothing else to start. All persistent state, including the embedded database, lives under the `/appsmith-stacks` directory.
This template uses the open-source Community Edition image (`appsmith-ce`) rather than the Enterprise Edition image the Docker Hub listing recommends by default, matching this library's self-hosted, no-vendor-lock-in framing.
## Prerequisites
- OpenTofu >= 1.6.0 or Terraform >= 1.6.0
- Quake AI account with OpenStack credentials
- An existing SSH keypair in your project (the value of `key_name` must match that keypair)
## Resource baseline
Appsmith's fat container runs on 4 vCPU and 4 GiB RAM. The default `s1a.medium` flavor leaves headroom for the app server, MongoDB, and Redis running inside the same container. Size up for many concurrent users or large datasource query volume.
## Usage
1. Clone or copy this template directory
2. Copy `terraform.tfvars.example` to `terraform.tfvars` and fill in your values
3. Source your OpenStack credentials: `source openrc.sh`
4. Initialize: `tofu init`
5. Preview: `tofu plan`
6. Apply: `tofu apply`
After apply, cloud-init installs Docker, generates `APPSMITH_ENCRYPTION_PASSWORD` and `APPSMITH_ENCRYPTION_SALT` into `/opt/appsmith/.env`, and starts the Appsmith container. No credential ships with this template: both encryption values are generated on first boot.
## Back up the encryption password and salt
`APPSMITH_ENCRYPTION_PASSWORD` and `APPSMITH_ENCRYPTION_SALT` encrypt stored datasource credentials (database passwords, API keys) at rest. Losing them makes stored datasource credentials unrecoverable. Copy `/opt/appsmith/.env` to a secure location outside this instance immediately after first boot, before you connect any real datasource.
## Access and security
Appsmith's internal port 80 is remapped to 8080 so a host-level reverse proxy can own ports 80 and 443 for the public domain, rather than relying on Appsmith's own embedded Let's Encrypt integration. The security group restricts 8080 to `app_allowed_cidr`, which defaults to the private network only. For production use, point a domain's DNS A record at `floating_ip` and add a reverse proxy (Caddy or Nginx) in front for HTTPS on 443.
## Datastores
All persistent state, including the embedded MongoDB, lives inside the `/appsmith-stacks` directory on the attached volume. There is no separate datastore container to point elsewhere: the fat container is self-contained.
## Variables
| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `key_name` | string | yes | n/a | SSH keypair name (must already exist in your project) |
| `flavor_name` | string | no | `s1a.medium` | Instance size (the fat container runs on 4 vCPU / 4 GiB) |
| `image_name` | string | no | `Ubuntu-24.04` | Operating system image |
| `app_name` | string | no | `appsmith` | Display name prefix for resources |
| `volume_size` | number | no | `20` | Block volume size in GiB, mounted at `/var/lib/docker` |
| `external_network` | string | no | `PublicStatic` | Persisted FIP / production default; override with `PublicEphemeral` for demos |
| `private_cidr` | string | no | `10.53.0.0/24` | CIDR for the private subnet |
| `app_allowed_cidr` | string | no | `10.53.0.0/24` | CIDR allowed to reach Appsmith on port 8080 |
## Outputs
| Name | Description |
| --- | --- |
| `floating_ip` | Public floating IP assigned to the instance |
| `private_ip` | Private IP address of the instance |
| `app_url` | Appsmith app URL on port 8080 |
| `instance_id` | Compute instance ID |
## Scope
This is a single-VM Appsmith host that you operate, not a managed low-code cloud. It is CPU-only and runs in one region, and its embedded MongoDB and Redis run inside the same container as the app server. You operate the instance, Docker, Appsmith, and the data volume yourself: back up `/appsmith-stacks` (the encryption keys especially), patch the image, and watch resource use as concurrent users grow.
## Documentation
See also: [self-managed PostgreSQL](/resources/iac-templates/self-managed-postgres), [Infisical secrets management](/resources/iac-templates/infisical-secrets)
Resources, parameters, and variables
key_namerequiredflavor_name="s1a.medium"image_name="Ubuntu-24.04"app_name="appsmith"volume_size=20external_network="PublicStatic"private_cidr="10.53.0.0/24"app_allowed_cidr="10.53.0.0/24"
Customize this pattern#
- Customize a template's image and flavor
- Add a block volume to a template
- Parameterize a template with a tfvars file
See also#
Usage Guidelines
The sample code, software libraries, command line tools, proofs of concept, templates, and other related technology on this page (including any of the foregoing that is provided by Quake AI personnel) is provided to you as Quake AI Content under the Quake AI Customer Agreement, or the relevant written agreement between you and Quake AI (whichever applies). Do not use this Quake AI Content in your production accounts, or on production or other critical data. You are responsible for testing, securing, and optimizing the Quake AI Content (such as sample code) as appropriate for production grade use based on your specific quality control practices and standards. Deploying Quake AI Content may incur Quake AI charges for creating or using Quake AI chargeable resources, such as running Compute instances or storing data in Object Storage. Your use is also subject to the Acceptable Use Policy.
For the full policy, see Usage Guidelines.
See Also
Terraform and OpenTofu on Quake AI
Prerequisite
Networks
Prerequisite
Authoring IaC templates for Quake AI
Shares: Volumes, Security Groups
Deploy an API gateway with the api-gateway template
Shares: Volumes, Security Groups
Deploy a regional edge cache with the edge-cache template
Shares: Volumes, Security Groups