Skip to content

wess/tower

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Tower

Your own PaaS. Your own metal. Live in seconds.

Tower is a self-hostable, Fly.io-style platform you run on your own bare metal. Push your code and it boots as an isolated Firecracker microVM — a dedicated database, vectors, and a multi-provider AI gateway wired up automatically, with TLS and private networking handled for you. It's invite-only and multi-tenant, so you can host your friends, family, or a team on infrastructure you own. wess.dev runs on it.

Why Tower

  • Git push-to-deploy. Each app is a bare git repo. Push a commit with a root Dockerfile and Tower builds the image, imports it, and ships it — straight from git push, with the build log streamed back to your terminal live.
  • Real microVM isolation. Every app boots its own image as a Firecracker microVM with its own kernel — hardware-isolated, not a shared-kernel container — so you can safely host untrusted code and other people's apps.
  • A database in every app. First deploy provisions a dedicated Postgres role + database, revokes CONNECT from PUBLIC, and injects the connection string as the app's DATABASE_URL. Tenant databases ship with the pgvector extension for embeddings and RAG.
  • One AI gateway, swappable backends. Attach Anthropic, OpenAI, or Ollama to an app and it gets a single endpoint. The app only ever holds an opaque aigw_… key — re-point the provider or model without a redeploy, and the app never holds a raw provider API key.
  • Invite-only, multi-tenant. The first registrant becomes owner; after that, registration requires an invite. Every member gets their own isolated apps and subdomains on hardware you control.
  • Runs on your own hardware. Point a wildcard DNS at the edge, and Tower issues per-host Let's Encrypt certificates on the fly. No cloud bill, no vendor, no servers to babysit — just your box.

Quick start

Tower ships a single CLI binary, wess, that talks to your deployment (the reference deployment is wess.dev).

1. Install

curl -fsSL https://wess.dev/install.sh | sh

This downloads the per-platform binary to wess. Point the CLI at your own deployment with the WESS_API environment variable (default https://wess.dev).

2. Log in

wess login

You'll be prompted for your email and password (password input is hidden on a TTY). You can also pass them directly:

wess login -e you@example.com -p 'your-password'

Your token is saved to ~/.wess/token.

3. Create an app

App names are lowercase letters and digits, 3–31 characters (no hyphens).

wess create myapp

4a. Deploy with git push (build from a Dockerfile)

Scaffold a starter project, commit it, add the wess remote, and push. Your repo needs a root Dockerfile.

wess init myapp                          # scaffolds server.ts, Dockerfile, AGENTS.md
git init && git add -A && git commit -m "init"
wess git myapp                           # adds a `wess` git remote
git push wess main                       # builds, imports, and deploys — log streams live

4b. Deploy a prebuilt image

wess deploy myapp --image ghcr.io/you/myapp:latest --port 8080

Either way, the app's DATABASE_URL (and any secrets) are injected into the VM's environment on every deploy — your dedicated Postgres database is provisioned automatically on first deploy.

5. You're live

wess status myapp        # machines, database, URL
wess open myapp          # opens https://myapp.wess.dev
wess logs myapp -f       # follow logs (-n sets line count, default 200)

Add --json to any command for machine-readable output.

Features

Deploy

Two paths to production: git push to build a root Dockerfile, or wess deploy --image <ref> for a prebuilt image (with a sticky --port). Redeploys are rolling — a new machine boots and the app's image/status update before the previous machine is destroyed. Every app is served at https://<name>.wess.dev, with the edge router pointing the subdomain at the current running machine.

Databases

On an app's first deploy, Tower provisions a dedicated Postgres role and database (app_<name>, owned by that role, CONNECT revoked from PUBLIC), stores the connection string as the app's DATABASE_URL secret, and routes connections through PgBouncer. Tenant databases ship with pgvector for storing embeddings.

AI gateway

wess ai myapp anthropic -m claude-opus-4-8
wess ai myapp openai
wess ai myapp ollama

Attaching a provider mints a gateway key and injects AI_GATEWAY_URL, AI_GATEWAY_KEY, AI_MODEL, and AI_PROVIDER into the VM. The app's single endpoint routes to whichever backend the owner configured — Anthropic, OpenAI, or Ollama (server or cloud), with OpenAI-compatible bases also covering Groq, Together, OpenRouter, and vLLM. The gateway resolves the key to the current provider and model at request time, so the owner can swap providers without a redeploy and the app never holds a real provider API key.

Sandbox

wess sandbox python ./script.py
wess sandbox bun ./task.ts

Runs untrusted python / node / bun / bash code in a throwaway Firecracker microVM, captures stdout, stderr, exit code, and elapsed time, then destroys the VM. Default timeout is 30s, capped at 120s.

Tokens

wess token create ci --scopes read,deploy --app myapp
wess token list
wess token revoke <id>

Mint scoped API tokens from read, deploy, logs, secrets, destroy, and sandbox, optionally bound to a single app with --app — so an agent or CI job can do exactly what you granted and nothing more. App-scoped tokens are rejected from platform-wide resources. The wess token CLI requires an owner session; members create and manage their own tokens in the web console under Settings.

Secrets

wess secrets set myapp STRIPE_KEY sk_live_xxx
wess secrets list myapp
wess secrets unset myapp STRIPE_KEY

Secrets are snapshotted into the VM's environment at deploy time.

Doctor

wess doctor myapp          # structured pass/fail health report
wess doctor myapp -x       # add a one-line AI explanation of failures

Runs ordered health checks — app status, machine running state, TCP reachability of the app's port, database pooler reachability, AI attachment, and recent-log error scanning — and returns a structured report.

More

  • wess apps — list your apps.
  • wess destroy myapp — destroys app, machines, and database (prompts you to retype the app name to confirm).

App names must match ^[a-z][a-z0-9]{2,30}$ (a set of names is reserved), and each app runs one machine.

Multi-tenant & invites

Tower is invite-only and tenant-isolated by design.

  • Bootstrap. The first person to register becomes the platform owner — no invite required. Every registration after that requires a valid invite code, or it's rejected with an invite is required to register.
  • Roles. There are two roles, owner and member. Invites grant member access.
  • Anyone can invite. Every authenticated member — owner included — can mint invite links. Codes are inv_<uuid>, single-use, and can be locked to a specific email. Invite links look like https://wess.dev/admin/register?code=<code>. As the console puts it: anyone you invite can also invite others.
  • Per-member isolation. Members see only their own apps, their own API tokens, and the invites they created. The owner sees everything — all apps, all members, tenant databases, the AI providers card, and the platform events feed.
  • Revoke asymmetry. The owner can revoke any invite, including accepted history. A member can revoke only their own still-pending invites.
  • Member removal. Owner-only; you can't remove yourself. When a member is removed, their apps' ownership is released so the owner can reclaim or destroy them.

Sessions use a one-week tower_session cookie JWT in the console; the API accepts either a session JWT or a wess_-prefixed scoped token. Owner-only actions require a full, non-token owner session.

Architecture

Tower is a Bun + TypeScript control plane. Deploys boot app images as Firecracker microVMs (via firecracker-ctr on the aws.firecracker runtime, each under a transient systemd unit), one machine per app. State and tenant data live in a shared Postgres cluster, with a dedicated database and role provisioned per app and connections pooled through PgBouncer. An edge layer handles wildcard subdomain routing and issues per-host Let's Encrypt certificates on the fly, pointing https://<name>.wess.dev at the app's current running machine. A server-rendered admin console provides the owner/member dashboard, invites, and provider configuration.

License

Licensed under the Apache License, Version 2.0. See LICENSE.

About

Apps on your metal.

Resources

License

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors