Outline team knowledge base
Outline team knowledge base
This pattern composes Compute, Network, and Block Storage into a self-hosted team wiki you run on infrastructure you control.
What this template does#
Provisions a single instance running Outline, an open-source team knowledge base (a self-hosted alternative to Notion or Confluence). Your team keeps runbooks, decisions, onboarding, and project notes on infrastructure you own:
- Compute instance that runs Outline in Docker alongside a bundled PostgreSQL and Redis (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, so the database, Redis, and local file uploads live on a volume you can grow rather than on the boot disk - cloud-init installs Docker Engine, brings up PostgreSQL and Redis, and prepares Outline to start once you finish configuration
Outline's secret keys and the database password are generated on first boot and written to /opt/outline/.env; no credential ships with this template.
Outline requires an auth provider#
Outline has no built-in email-and-password login. It authenticates users through an external identity provider and does not serve the wiki until you configure at least one. Supported providers include OIDC (any standards-compliant identity provider), Google, Slack, and Azure AD. You set the provider, and the public URL, in /opt/outline/.env before you start the app. This is a hard requirement.
For a lighter knowledge base without the auth-provider and Redis dependencies, BookStack (PHP plus MySQL, with built-in local accounts) and Docmost are simpler self-hosted options. This template leads with Outline because it is the closest self-hosted match for a Notion or Confluence workspace.
Parameters#
| Parameter | Description | Default |
|---|---|---|
key_name | SSH keypair name (must already exist) | No default |
flavor_name | Instance size (Outline plus PostgreSQL and Redis runs on 4 vCPU / 4 GiB) | s1a.medium |
image_name | Operating system image | Ubuntu-24.04 |
app_name | Display name prefix for resources | outline |
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.46.0.0/24 |
app_allowed_cidr | CIDR allowed to reach Outline on port 3000 | 10.46.0.0/24 |
file_storage | Upload storage: local or s3 | local |
s3_endpoint | S3-compatible endpoint (when file_storage is s3) | "" |
s3_region | S3 region (when file_storage is s3) | us-east-1 |
s3_bucket | S3 bucket name (when file_storage is s3) | "" |
Finish setup after apply#
cloud-init starts PostgreSQL and Redis and writes the generated secrets to /opt/outline/.env. Complete the setup over SSH:
- Point a domain's DNS A record at the floating IP and put a reverse proxy (Caddy or Nginx) in front for HTTPS on 443.
- Edit
/opt/outline/.env: setURLto your public HTTPS address and fill in your auth provider (for example theOIDC_*block). - Run the database migration and start Outline:
cd /opt/outline
sudo docker compose run --rm outline yarn db:migrate
sudo docker compose up -dAccess and security#
Outline listens on port 3000 over plain HTTP. The security group restricts 3000 to app_allowed_cidr, which defaults to the private network only. Because Outline needs a public URL and an auth provider, the normal access path is a domain with HTTPS on 443 behind a reverse proxy. Ports 80 and 443 stay open for that proxy; they carry no traffic until you add one.
File storage#
The file_storage parameter selects where uploads go:
local(default): uploads live on the data volume. No external service is needed.s3: uploads go to an S3-compatible bucket, such as Quake AI Object Storage. Sets3_endpoint,s3_region, ands3_bucket, then addAWS_ACCESS_KEY_IDandAWS_SECRET_ACCESS_KEYto/opt/outline/.envon the instance. The keys stay out of tfvars and the repo.
When to use this pattern#
Run a shared team wiki with a rich editor, collections, and search on a host you operate. Outline suits a team that already has an identity provider and wants its documentation on its own infrastructure. The bundled PostgreSQL and Redis suit a single-team knowledge base; to run them separately, point DATABASE_URL and REDIS_URL at a self-managed PostgreSQL instance and a Redis instance.
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
Outline knowledge-base host
s1a.medium · 4 shared vCPU, 4 GiB RAM, 0.5 Gbps
Runs Outline in Docker (the team wiki and document editor) alongside its bundled PostgreSQL and Redis, with the database and local uploads on an attached volume.
Outline plus its bundled PostgreSQL and Redis runs on 4 vCPU and 4 GiB RAM. Size up for large teams or heavy document 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" "outline" {
name = "${var.app_name}-sg"
description = "SSH and HTTP/HTTPS for a reverse proxy; app port 3000 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.outline.id
}
# 80 and 443 carry Outline when it is served over a domain with automatic TLS
# through a reverse proxy (Caddy or Nginx). Outline needs a stable public URL
# and an auth provider to operate, so the domain path is the expected way to
# reach it; see the reference page.
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.outline.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.outline.id
}
# Raw app HTTP on 3000 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 = 3000
port_range_max = 3000
remote_ip_prefix = var.app_allowed_cidr
security_group_id = openstack_networking_secgroup_v2.outline.id
}
resource "openstack_networking_port_v2" "outline" {
name = "${var.app_name}-port"
network_id = openstack_networking_network_v2.private.id
security_group_ids = [openstack_networking_secgroup_v2.outline.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" "outline" {
name = var.app_name
flavor_name = var.flavor_name
key_pair = var.key_name
user_data = templatefile("${path.module}/cloud-init/outline.yaml.tftpl", {
app_name = var.app_name
file_storage = var.file_storage
s3_endpoint = var.s3_endpoint
s3_region = var.s3_region
s3_bucket = var.s3_bucket
})
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.outline.id
}
}
resource "openstack_compute_volume_attach_v2" "data" {
instance_id = openstack_compute_instance_v2.outline.id
volume_id = openstack_blockstorage_volume_v3.data.id
}
resource "openstack_networking_floatingip_v2" "outline" {
pool = var.external_network
}
resource "openstack_networking_floatingip_associate_v2" "outline" {
floating_ip = openstack_networking_floatingip_v2.outline.address
port_id = openstack_networking_port_v2.outline.id
}
variable "key_name" {
description = "SSH keypair name (must already exist in your project)"
type = string
}
variable "flavor_name" {
description = "Instance size. Outline plus its bundled PostgreSQL and Redis runs comfortably on 4 vCPU and 4 GiB RAM (s1a.medium). Size up for large teams or heavy document volume."
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 = "outline"
}
variable "volume_size" {
description = "Block volume size in GiB, mounted at /var/lib/docker so the knowledge-base data (the PostgreSQL database, Redis, and local file uploads) 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.46.0.0/24"
}
variable "app_allowed_cidr" {
description = "CIDR allowed to reach Outline on port 3000. Defaults to the private network only, so the app is not exposed to the public internet on its raw port. Outline needs a stable public URL and an auth provider to operate, so serve it over a domain with HTTPS on 443 behind a reverse proxy. To reach port 3000 directly from your workstation during setup, set this to YOUR_IP/32."
type = string
default = "10.46.0.0/24"
}
variable "file_storage" {
description = "Where Outline stores uploaded files. 'local' (default) keeps uploads on the data volume. 's3' stores them in an S3-compatible bucket (for example Quake AI Object Storage); set the s3_* variables and add the access keys to /opt/outline/.env on the instance (never in tfvars)."
type = string
default = "local"
validation {
condition = contains(["local", "s3"], var.file_storage)
error_message = "file_storage must be either \"local\" or \"s3\"."
}
}
variable "s3_endpoint" {
description = "S3-compatible endpoint URL for file_storage = \"s3\" (for example https://object.us-east-1.rumble.cloud). Ignored when file_storage is local."
type = string
default = ""
}
variable "s3_region" {
description = "S3 region for file_storage = \"s3\". Ignored when file_storage is local."
type = string
default = "us-east-1"
}
variable "s3_bucket" {
description = "S3 bucket name for file_storage = \"s3\". Ignored when file_storage is local. The access keys are never set here: add them to /opt/outline/.env on the instance."
type = string
default = ""
}
output "instance_id" {
description = "ID of the compute instance running Outline"
value = openstack_compute_instance_v2.outline.id
}
output "floating_ip" {
description = "Public floating IP address of the Outline host"
value = openstack_networking_floatingip_v2.outline.address
}
output "private_ip" {
description = "Private IP address of the instance"
value = openstack_compute_instance_v2.outline.access_ip_v4
}
output "app_url" {
description = "Outline app URL on port 3000. Reachable from app_allowed_cidr (the private network by default). Outline needs a stable public URL and an auth provider before it serves the wiki; put a reverse proxy in front and use HTTPS on 443, then set the URL and auth provider in /opt/outline/.env."
value = "http://${openstack_networking_floatingip_v2.outline.address}:3000"
}
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 (3000) to your workstation IP for setup.
# Leave unset to keep 3000 reachable only from the private network and tunnel
# over SSH. Outline needs a public URL and an auth provider to operate, so the
# normal access path is a domain with HTTPS on 443 behind a reverse proxy.
# app_allowed_cidr = "203.0.113.10/32"
# File storage: local (default, on the data volume) or s3 (S3-compatible
# bucket). For s3, set the endpoint, region, and bucket, then add the access
# keys to /opt/outline/.env on the instance.
# file_storage = "s3"
# s3_endpoint = "https://object.us-east-1.rumble.cloud"
# s3_region = "us-east-1"
# s3_bucket = "my-outline-uploads"
# flavor_name = "s1a.medium"
# image_name = "Ubuntu-24.04"
# app_name = "outline"
# volume_size = 20
# external_network = "PublicStatic"
# private_cidr = "10.46.0.0/24"
#cloud-config
package_update: true
packages:
- ca-certificates
- curl
write_files:
- path: /opt/outline/docker-compose.yml
permissions: "0644"
content: |
# Outline knowledge base for ${app_name}. The app listens on port 3000.
# Outline needs a stable public URL and at least one auth provider (OIDC,
# Google, Slack, or Azure) before it serves the wiki: set URL and the auth
# provider in /opt/outline/.env, then start the app. No credential ships
# with this template: the app secret keys and the database password are
# generated on first boot. cloud-init starts PostgreSQL and Redis; bring
# up Outline after you finish configuring /opt/outline/.env.
services:
outline:
image: docker.getoutline.com/outlinewiki/outline:latest
restart: unless-stopped
ports:
- "3000:3000"
env_file:
- /opt/outline/.env
depends_on:
- postgres
- redis
volumes:
- outline_uploads:/var/lib/outline/data
postgres:
image: postgres:16-alpine
restart: unless-stopped
env_file:
- /opt/outline/.env
volumes:
- outline_pg:/var/lib/postgresql/data
redis:
image: redis:7-alpine
restart: unless-stopped
volumes:
- outline_redis:/data
volumes:
outline_uploads:
outline_pg:
outline_redis:
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 so the PostgreSQL
# data, Redis, and local file uploads live 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 outlinedata "$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
# Install Docker Engine plus the compose plugin from Docker's convenience
# script.
curl -fsSL https://get.docker.com | sh
# Generate Outline's secret keys and the bundled database password on first
# boot. These never leave this instance.
SECRET_KEY=$(openssl rand -hex 32)
UTILS_SECRET=$(openssl rand -hex 32)
PGPASS=$(openssl rand -hex 24)
umask 077
{
echo "NODE_ENV=production"
echo "SECRET_KEY=$SECRET_KEY"
echo "UTILS_SECRET=$UTILS_SECRET"
echo "DATABASE_URL=postgres://outline:$PGPASS@postgres:5432/outline"
echo "PGSSLMODE=disable"
echo "POSTGRES_USER=outline"
echo "POSTGRES_PASSWORD=$PGPASS"
echo "POSTGRES_DB=outline"
echo "REDIS_URL=redis://redis:6379"
echo "PORT=3000"
%{ if file_storage == "s3" ~}
echo "FILE_STORAGE=s3"
echo "AWS_REGION=${s3_region}"
echo "AWS_S3_UPLOAD_BUCKET_URL=${s3_endpoint}"
echo "AWS_S3_UPLOAD_BUCKET_NAME=${s3_bucket}"
echo "AWS_S3_FORCE_PATH_STYLE=true"
echo "AWS_S3_ACL=private"
echo "# Add the S3 access keys here, then start Outline:"
echo "# AWS_ACCESS_KEY_ID="
echo "# AWS_SECRET_ACCESS_KEY="
%{ else ~}
echo "FILE_STORAGE=local"
echo "FILE_STORAGE_LOCAL_ROOT_DIR=/var/lib/outline/data"
echo "FILE_STORAGE_UPLOAD_MAX_SIZE=26214400"
%{ endif ~}
echo "# Set URL to your public HTTPS address before starting Outline:"
echo "# URL=https://docs.example.com"
echo "# Configure at least one auth provider, for example OIDC:"
echo "# OIDC_CLIENT_ID="
echo "# OIDC_CLIENT_SECRET="
echo "# OIDC_AUTH_URI="
echo "# OIDC_TOKEN_URI="
echo "# OIDC_USERINFO_URI="
echo "# OIDC_DISPLAY_NAME=SSO"
} > /opt/outline/.env
chmod 600 /opt/outline/.env
# Bring up the datastores. Outline starts after you set URL and an auth
# provider in /opt/outline/.env and run:
# cd /opt/outline && docker compose run --rm outline yarn db:migrate
# cd /opt/outline && docker compose up -d
cd /opt/outline
docker compose up -d postgres redis
# Outline team knowledge base
Single compute instance running [Outline](https://www.getoutline.com), a self-hosted team wiki and knowledge base (a self-hosted alternative to Notion or Confluence) on infrastructure you control. After apply, you set a public URL and an auth provider, run the database migration, start the app, sign in through your identity provider, and create your first collection of documents.
**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 knowledge-base data lives on a resizable volume. cloud-init installs Docker Engine, brings up the bundled PostgreSQL and Redis, and prepares the Outline service to start once you finish configuration.
## Where this fits
Outline is the team's shared documentation home: runbooks, decisions, onboarding, and project notes, kept on infrastructure you own rather than on a third-party SaaS. It is the heaviest of the self-hosted ops tools because it needs PostgreSQL, Redis, and an external auth provider.
## Outline requires an auth provider
Outline has no built-in email-and-password login. It authenticates users through an external identity provider, and it will not serve the wiki until you configure at least one. Supported providers include OIDC (any standards-compliant identity provider), Google, Slack, and Azure AD. Configure the provider in `/opt/outline/.env` before you start the app. This is a hard requirement, not an optional hardening step.
If you want a lighter knowledge base without the auth-provider and Redis dependencies, [BookStack](https://www.bookstackapp.com) (PHP plus MySQL, with built-in local accounts) and [Docmost](https://docmost.com) are simpler self-hosted options. This template leads with Outline because it is the closest self-hosted match for a Notion or Confluence workspace.
## 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)
- An identity provider you can configure for OIDC, Google, Slack, or Azure AD
- A domain you can point at the instance (Outline needs a stable public URL)
## Resource baseline
Outline plus its bundled PostgreSQL and Redis runs on 4 vCPU and 4 GiB RAM. The default `s1a.medium` flavor leaves headroom for the three containers. Size up for large teams or heavy document 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 Outline's secret keys and the database password into `/opt/outline/.env`, and starts PostgreSQL and Redis. Finish the configuration over SSH:
1. Point a domain's DNS A record at `floating_ip` and put a reverse proxy (Caddy or Nginx) in front for HTTPS on 443.
2. Edit `/opt/outline/.env`: set `URL` to your public HTTPS address and fill in your auth provider (for example the `OIDC_*` block).
3. Run the database migration and start Outline:
```bash
cd /opt/outline
sudo docker compose run --rm outline yarn db:migrate
sudo docker compose up -d
```
No credential ships with this template: the `SECRET_KEY`, `UTILS_SECRET`, and database password are generated on first boot.
## Access and security
Outline listens on port 3000 over plain HTTP. The security group restricts 3000 to `app_allowed_cidr`, which defaults to the private network only. Because Outline needs a public URL and an auth provider, the normal access path is a domain with HTTPS on 443 behind a reverse proxy. Point the domain's DNS A record at `floating_ip`. Ports 80 and 443 stay open for that reverse proxy; they carry no traffic until you add one.
## File storage
`file_storage` selects where uploads go:
- `local` (default): uploads live on the data volume at `/var/lib/outline/data`. No external service is needed.
- `s3`: uploads go to an S3-compatible bucket, such as Quake AI Object Storage. Set `s3_endpoint`, `s3_region`, and `s3_bucket`, then add `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` to `/opt/outline/.env` on the instance. The keys stay out of tfvars and the repo.
## Datastores
This template bundles PostgreSQL and Redis as containers on the same instance, which suits a single-team knowledge base. To run them as separate services, point `DATABASE_URL` and `REDIS_URL` in `/opt/outline/.env` at a [self-managed PostgreSQL](/resources/iac-templates/self-managed-postgres) instance and a [Redis](/resources/iac-templates/redis-cache) instance, and remove the bundled services from the compose file.
## 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 (Outline plus PostgreSQL and Redis runs on 4 vCPU / 4 GiB) |
| `image_name` | string | no | `Ubuntu-24.04` | Operating system image |
| `app_name` | string | no | `outline` | 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.46.0.0/24` | CIDR for the private subnet |
| `app_allowed_cidr` | string | no | `10.46.0.0/24` | CIDR allowed to reach Outline on port 3000 |
| `file_storage` | string | no | `local` | Upload storage: `local` or `s3` |
| `s3_endpoint` | string | no | `""` | S3-compatible endpoint (file_storage = s3) |
| `s3_region` | string | no | `us-east-1` | S3 region (file_storage = s3) |
| `s3_bucket` | string | no | `""` | S3 bucket name (file_storage = s3) |
## Outputs
| Name | Description |
| --- | --- |
| `floating_ip` | Public floating IP assigned to the instance |
| `private_ip` | Private IP address of the instance |
| `app_url` | Outline app URL on port 3000 |
| `instance_id` | Compute instance ID |
## Scope
This is a single-VM Outline host that you operate, not a managed knowledge-base cloud. It is CPU-only and runs in one region. You operate the instance, Docker, Outline, PostgreSQL, Redis, and the data volume yourself: back them up, patch them, and watch resource use as the wiki grows. For larger teams, move PostgreSQL and Redis onto their own instances and size the app host up.
## Documentation
See also: [self-managed PostgreSQL](/resources/iac-templates/self-managed-postgres), [Redis](/resources/iac-templates/redis-cache), [S3 object storage](/resources/iac-templates/s3-storage-acl)
Resources, parameters, and variables
key_namerequiredflavor_name="s1a.medium"image_name="Ubuntu-24.04"app_name="outline"volume_size=20external_network="PublicStatic"private_cidr="10.46.0.0/24"app_allowed_cidr="10.46.0.0/24"file_storage="local" validation {s3_endpoint=""s3_region="us-east-1"s3_bucket=""
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