Early access — The platform is open but still being completed; features and prices may change before general availability.

Projects and providers

What a project holds, per provider, and how networking, storage and destruction behave.

A project is the unit of everything: one provider, one network story, its storage, its components, its runners, its audit trail.

Providers

ProviderDeliveryThe platform creates
Machines (Incus)Ansible over cloud-initVMs/containers, networks, storage pools and volumes
KubernetesHelm releasesNamespace-scoped releases, ingress exposure, monitoring wiring
AWSTerraform + Ansible over user dataEC2 machines, EBS volumes, tags that mark ownership
OpenStackTerraform + Ansible over user dataNova machines, Neutron networks, Cinder volumes, tags that mark ownership

OpenStack prerequisites

The platform deploys into a cloud you run; have these ready before the first deploy:

  1. Reachable APIs — the Keystone auth URL and every public service endpoint it catalogs (Neutron, Nova, Glance, Cinder) must be reachable from the machine your runner runs on.
  2. Admin rights, as one revocable credential. Create an unrestricted application credential from an admin user (openstack application credential create idp-bootstrap --unrestricted) and store its id and shown-once secret in the project's target settings. On the first deploy the platform uses it - server-side, never inside a pipeline - to create a Keystone project named after your IdP project, a dedicated service user, and a restricted project-scoped working credential that every pipeline then runs with. Revoking the bootstrap credential in your cloud takes one command and cuts the platform's admin access instantly; already-deployed projects keep working on their own minimal credentials. (Alternatively, mint a member-scoped credential in a project of your own and paste it as the working credential - the platform then manages only what is inside.)
  3. An external network name (for floating IPs and outbound traffic), at least one image components can run on — a Debian 13 genericcloud image named debian-13 is the default every component's machine shape starts with (or name your own image per component) — the flavor names you want, and quota room.
  4. A runner, before anything deploys. A GitLab runner machine you operate (Debian works well) with Docker, outbound access to gitlab.com and to the cloud's APIs — the runners page hands you the exact commands, and the Deploy button waits until GitLab reports your runner online.
  5. Outbound internet for deployed machines through the external network: each component machine installs its software on first boot.

The dashboard speaks each provider's language: pods, working-set memory and claims on Kubernetes; machines, CPU and network bytes on AWS; the instance view on machines. OpenStack reports machine power state — the platform never invents telemetry a cloud may not run.

Networking

Machine projects declare their network (bridge, addressing) in project settings; Kubernetes components are exposed through the project's ingress controller with per-component hostnames; AWS machines take a subnet and can expose one port with a public IP when the component's shape says so; OpenStack projects get a Neutron network with one subnet, optionally routed to the cloud's external network so machines can take a floating IP.

On OpenStack the network settings default the external network to the one the last inventory refresh observed on the cloud (Neutron's router:external), when there is exactly one; the field stays editable and empty still means isolated. A machine's floating-IP network defaults to the same external network.

Storage

Components that keep data declare persistent paths in the catalog. The platform refuses to deploy such a component until a volume is attached at exactly that path — so data survives redeploys by construction. Components with no persistent path (a bare machine, a toolchain) need no volume. On OpenStack the attachment is done from the machine's side: the component's machine looks the Cinder volume up by name, attaches it, formats it on first use and mounts it at the persistent path before its role runs. Attach from the storage page as on every provider.

The quickest way to give components their data disks is Add disk on the components page: check the components (or open one row's Action menu), give a size in GiB, and one managed volume per component is created, named <role>-data, attached with a conventional device name and mounted at the role's persistent path. A component that already has a disk is skipped and said so. Sizes can differ per component - run Add disk once per size. Deploy then plans the new volumes before the machines; grow a disk later from the storage page (never shrink).

A component reaches Populated - and becomes eligible for its machine - only when four things hold: a machine shape (flavor and image), a ready role interface, validated app settings (open App settings and save, even with the defaults), and, where the role keeps data, a disk attached at its persistent path. The deployment page's component specifications table shows a Readiness badge per component naming whatever is still missing, and Deploy says the same rather than deploying the infrastructure and silently leaving the machines uncreated.

Destroy, honestly

A project destroy tears down everything the platform created, in dependency order, from a single typed confirmation. Storage volumes holding data are the deliberate exception surfaced during the flow. If the browser goes away mid-destroy, a server-side sweeper finishes the job.

© 2026 FMJConsulting. All rights reserved.