Getting started: deploy an existing app
How to take a repo you already have and get it running on gbandit. The steps are short; the work is usually in making your container satisfy the runtime constraints. Every step is covered in full in the deploy contract.
Starting fresh instead? Use the template.
1. Install the CLI
sh
curl -fsSL https://github.com/gbandit/cli/releases/latest/download/install.sh | sh
gbandit logingbandit login signs you in with Google in the browser. You can skip it: gbandit deploy then offers a guest account, which can deploy a frontend.
2. Add gbandit.jsonc
At the repo root, declare your project and its components. The file is JSONC, so comments are allowed:
jsonc
{
"project": "my-app",
"frontend": { "dockerfile": "frontend/Dockerfile", "context": "frontend" },
"backend": { "dockerfile": "backend/Dockerfile", "context": "backend" },
}Declare only what you have: a pure client-side game needs just frontend, an SSR app just backend (it then receives all traffic, not only /api/*). Both paths are relative to the repo root and point wherever your Dockerfiles actually live. Set context to "." if backend and frontend share code. All fields: gbandit.jsonc reference.
The slug becomes your subdomain: https://<project>.gbandit.com (prod) and https://dev-<project>.gbandit.com (dev).
By default deploy never touches git: no commits, no pushes, and a dirty tree deploys as it is. It is safe to point at a repo you already use. See Git behaviour.
3. Make the backend fit the contract
The platform builds your declared Dockerfile as it is, so any language works. The context you declared is the docker build context, so COPY whatever you need from inside it. See Components.
The pitfalls that break ports
Backends run untrusted code, so the runtime is hardened. These are the constraints real ports fail on:
- Listen on
$PORT(currently8080), not your app's default port. - Declare your database.
DATABASE_URLis only set whengbandit.jsoncdeclares one (see step 5). - Read-only root filesystem. Write only to
/tmp, and to/datafor SQLite projects. Caches, lock files and logs must not land anywhere else. - Forced UID 65534. Don't require root, and don't write to
$HOME. - 256Mi memory and 500m CPU (512Mi for SQLite projects), and exactly 1 replica. JVM and .NET images need their heap flags tuned.
The full list, including gVisor and egress rules: Runtime hardening.
4. Frontend
If you declared a frontend, its image must contain the built site. The image is never run; its files are extracted and served. Everything except /api/* goes to the static site, and /api/* goes to your backend. See Static frontend and Routing.
Load the gbandit runtime in your index.html's <head>, before your own scripts:
html
<script defer src="/__gbandit/runtime.js"></script>It gives you the player's token, counts your players for the catalog and sends browser errors to gbandit logs frontend. A deploy without it warns.
5. Database
Give the backend a volume, "backend": { ..., "volume": { "sqlite": true } }, or declare a managed database, "database": { "postgres": true }. Either one needs a backend; omit both for no database. Databases explains which to pick. Removing the declaration later removes the database on the next confirmed deploy; see Removing a database.
DATABASE_URL is set either way. Your app owns its schema and the platform never runs a migrator, so run yours in the container's start command, for example prisma migrate deploy && node server.js. See Migrations.
Other config your app needs: gbandit env set KEY=VALUE.
6. Deploy
sh
gbandit deploy --create--create creates the project on the first deploy without asking. The deploy goes to dev; gbandit promote then points prod at what dev runs. If the app does not come up, check gbandit logs backend and the pitfalls above.
Where to go next
- Deploy contract: the full reference this guide links into.
- Authentication: let players log in with their gbandit account.
- The gbandit runtime: one script tag in your
<head>gives you the player's token, ranking in the games.gbandit.com catalog, andgbandit logs frontend, which stays empty without it.