Quick tour

A short walkthrough of Circloud® NEST.

Download

Download the installer, a zip for Windows, from the official download page:

nest.circloud.net/download

Plans and Licence

A Circloud® NEST licence is for one plan. The plan sets how many servers one cluster may have and how many clusters the licence runs. Every plan includes every feature. The prices are on the download page.

PlanServers per clusterClusters on serversVirtual cluster
Mist™1 Desktop ComputerNot included1, up to 3 virtual nodes
Cirrus™Up to 32 included, more in your profile1, as many virtual nodes as the desktop’s memory holds
Nimbus™Up to 82 included, more in your profile1, as many virtual nodes as the desktop’s memory holds
Anvil™Up to 252 included, more in your profile1, as many virtual nodes as the desktop’s memory holds
Supercell™Up to 1002 included, more in your profile1, as many virtual nodes as the desktop’s memory holds
  • The virtual cluster: every plan has one, on one Desktop Computer, which counts as one server however many virtual nodes it runs: up to 3 on Mist™, and on the other plans as many as the desktop’s memory holds.
  • Clusters on servers: Cirrus™, Nimbus™, Anvil™ and Supercell™ each include 2, and every server of a cluster counts, the control server included. More are bought in your profile. Mist™ includes none: upgrade the plan to add clusters on servers.
  • Upgrade plan: in your profile. Your clusters keep running and nothing is reinstalled: the installer and your clusters pick up the new plan by themselves.

Your profile

nest.circloud.net/account, signed in with the Google account the licence was bought with, shows your plan, the clusters of each kind in use, every cluster with its status and version, and your orders with their receipts. The installer is downloaded there, and your licence key is shown there when you ask for it. Anyone with the key can install clusters of your plan: keep it private.

When every cluster is in use

The installer asks Circloud before it builds a cluster or adds to one. When every cluster of your plan is in use, Add cluster says so, with one button: Upgrade plan on Mist™, or Profile on the other plans, to buy another cluster or release one that no longer runs. When only one kind is full, the installer locks that choice and says why.

What a cluster sends

Every cluster checks in with Circloud about every 15 minutes. It sends its nodes (each one’s name, role and readiness, its CPU and memory, the label of the computer a virtual cluster runs on, and a hash of its machine’s id), the counts of its tenants, VPCs and pods, the addresses of the platform’s own portals, the platform version and a fingerprint of the cluster. It never sends a tenant’s name or domains, a log or the contents of your apps.

The connection it needs

Each cluster needs outbound HTTPS to licence.circloud.net at least once every 30 days: allow it in your firewall. While Circloud cannot be reached nothing changes for 30 days, and the admin portal shows a warning after 36 hours.

Beyond the plan

Running apps never stop. A cluster beyond its plan — more clusters of one kind than the licence includes, more servers in one cluster than the plan allows, or a copy of a cluster — shows a notice in its admin portal and in your profile, with what to do. Left as it is, changes on it can pause: at the earliest after 14 days over the plan within 30 days, and never sooner than 72 hours after the cluster was told. While changes pause, new resources and edits to running apps are refused; everything else keeps working: sign-in, security rules, deletes, stop, start and restart, Shrink, Destroy, updates and the console.

If the licence service ever ends

If Circloud ever stops the licence service, it publishes a final platform release in which nothing pauses for the licence.

Cloudflare Cloudflare Setup

Before you download the installer, add your Cloudflare account to your Circloud profile. The account needs a domain. Cloudflare's free plan is enough.

1. Copy your Account ID

Go to dash.cloudflare.com, select your domain, and copy the Account ID from the right side of the Overview page.

2. Create the API token

  1. Click your profile icon (top right) → My Profile → API Tokens, then Create Token
  2. Click Get started next to Create Custom Token, and give it a name (e.g. "Circloud NEST")
  3. Add one permission: Account → API Tokens → Edit. It has to be the one under Account, not User → API Tokens
  4. Under Account Resources, select Include > your account
  5. Click Continue to summary: it reads your account – API Tokens: Edit (All accounts – API Tokens: Edit if you included all of them). Click Create Token and copy the token — it is only shown once

3. Add them to your profile

On your profile, nest.circloud.net/account, open Cloudflare, paste the Account ID and the token, and click Add account.

Installation

Circloud® NEST provisions its own cluster and private networking stack on your hardware. The installer handles everything: cluster deployment, GUI/API setup and VPC/subnet routing. It asks for one of the Cloudflare accounts on your Circloud profile and a default domain (Cloudflare Setup).

Prerequisites

There are two ways to run Circloud® NEST, and they do not need the same hardware. Pick the one that matches yours — the numbers below are per path, and one set does not stand in for the other.

Your Desktop Computer · virtual cluster cp control node image registry 4 vCPU · 8 GB RAM 150 GB disk w1 worker node 4 vCPU · 8 GB RAM 150 GB disk virtual switch outbound the internet
The default install is two nodes on the one desktop. The control node also carries the private image registry, so nothing else has to be stood up for it.

What the desktop needs

  • Windows: Windows 10 or 11 Pro, Enterprise or Education with Hyper-V, which a virtual cluster requires on every plan. Home does not offer Hyper-V.
  • Administrator: the installer is run elevated. It creates the virtual cluster’s nodes and their networking on this desktop, and stops early without it.
  • Virtualization: Hyper-V, and VT-x / AMD-V enabled in the firmware. If Hyper-V is off the installer offers to turn it on and restart.
  • CPU: 8 logical cores or more. Three quarters of them go to the cluster, split across the nodes; each node defaults to 4 vCPU.
  • RAM: 32 GB recommended. The two default nodes ask for 8 GB each, and a quarter of the machine's memory (never less than 4 GB) is left to Windows itself.
  • Disk: 200 GB free or more. Node disks default to 150 GB each and are thin-provisioned; the installer scales them down to fit the space you have, never below 50 GB a node. Preparing the node image needs about 25 GB of working room on top of that.
Two nodes is the default, not the floor of what is useful. Add more nodes in the wizard before you install, or add them later with Extend — the cluster grows without a rebuild. The Mist™ plan’s virtual cluster runs up to 3 nodes.
Installer machine a Windows computer never joins the cluster stays on for the run SSH Your servers server 1 · control carries the image registry server 2 · worker these two are the minimum more workers added later with Extend internet
The machine you run the installer from is not one of the servers. It drives the install over SSH and can be the laptop on your desk.

The machine you run the installer from

This machine has requirements of its own, and they are not the servers' requirements. It never becomes part of the cluster — it connects to the servers over SSH, builds them, and can be shut down afterwards.

  • Windows: the installer .exe from the zip you download, run as Administrator, on a computer that reaches the servers over SSH. Hyper-V is not needed on this path; only a virtual cluster requires it.
  • Resources: modest — the work happens on the servers. It only has to stay on and connected until the install finishes.

The servers

  • How many: two or more — one control server and one worker. Add workers whenever you like with Extend, up to your plan’s servers per cluster: 3 on Cirrus™, 8 on Nimbus™, 25 on Anvil™ and 100 on Supercell™.
  • Per server: Ubuntu 22.04 or newer, 2+ CPU cores, 4+ GB RAM, and at least 50 GB of disk — 150 GB is what the platform is sized around.
  • Access: SSH enabled, and a user with sudo.
  • Network: all servers on the same network, each with internet access.
No fixed four-server layout. Control plus one worker is a real, complete cluster; every server past that is capacity you choose to add.

How far it scales

A single cluster scales to your plan’s servers per cluster, up to 100 servers on Supercell™ — one private cloud, on your own hardware. Start with one machine and add servers as you grow; each new server joins the same cluster and the same networking, with no rebuild and no migration.

  • Start: one machine — a virtual cluster on a 64 GB Desktop Computer carries 2.5K concurrent users, and a Xeon 5 server (256 GB RAM) 10K
  • Grow: add servers at any time with Extend
  • Shrink: remove a worker with Shrink, Extend's pair in the installer
  • Scale: up to your plan’s servers per cluster (3 on Cirrus™, 8 on Nimbus™, 25 on Anvil™ and 100 on Supercell™); beyond that, run a second cluster

Shrink removes one node. Choose it and the installer shows what happens before anything does: the node's pods move to the other nodes first, one at a time — a pod's persistent data is copied before it starts on its new node — then the node leaves the cluster and its machine is deleted (a physical server is reset). A VPC whose chosen nodes include it keeps the others as its nodes, even when none of its pods ran on it. You type the node's name to confirm. Only a worker can be removed, and never the node holding the platform database or the cluster's last worker; the control node and the machine that holds the Harbor registry are not removed either. For those the installer says why instead.

A server that no longer exists cannot be reset. When a physical server does not answer and the cluster no longer hears from it, Shrink offers one more confirmation: type the server's name and the node is removed without resetting it. Leave it empty if the server is only switched off: switch it on first. If a server you confirmed gone ever comes back, it joins the cluster again: wipe it before you switch it on. A server that held a VPC's persistent data cannot be removed this way: that data cannot be copied off a server that is gone, so Shrink says so and asks for no confirmation.

GPU Support (Optional)

To enable GPU workloads, mark specific worker nodes with gpu: true in the installer wizard before you install. The installer automatically installs NVIDIA drivers and configures the container runtime. Pods can then request GPU access by setting gpu_access: true.

Install on Windows

Step 1: Download

Download the installer zip from nest.circloud.net/download. Its name carries two versions: the installer's own, and the latest platform version when you download it. For example: circloud-nest-installer-1.5.22-platform-1.7.47.zip. So two different installers never share a name. The folder and the .exe inside it carry the same name. When it runs, the installer installs the latest platform version. The download needs a Cloudflare account with a domain on your Circloud profile first (Cloudflare Setup).

Step 2: Run as Administrator

Unzip it, right-click the .exe inside and select Run as Administrator. The graphical setup wizard will open and guide you through:

  1. System Check — verifies Administrator privileges and shows this computer's resources
  2. Install Mode — choose Virtual Cluster on Desktop Computer or Physical Servers. Hyper-V is checked here, and only for the virtual cluster, which requires it
  3. Configuration — the cluster's name and the admin username, the Cloudflare account and the default domain (two lists from your Circloud profile), then the nodes: CPU cores, memory, number of nodes and network switches
  4. Review & Install — confirm and start deployment
The installer's System Check: Administrator privileges and this computer's resources
System Check

The cluster's addresses. The cluster's name gives the label in every address of the cluster: lowercase letters, digits and hyphens, at most 54 characters (MyCluster gives mycluster). The Configuration step shows the label and the addresses under the name — admin-<label>.<domain>, user-<label>.<domain> and api-<label>.<domain>; the container registry and the email service follow the same rule, registry-<label> and email-<label>. So one domain carries many clusters, and two of your clusters cannot have the same label: Circloud refuses the second at the install, before anything is built, and the step says so under the name (Another of your clusters is called mycluster; pick another name.).

The two Cloudflare lists are read from your profile when the step opens; Refresh reads them again. An account the installer cannot use is listed greyed out, with why (no domain yet, a token that no longer works or lacks the permission). With no account it can use, the step says so and offers Profile, to add one. Once the install has started, press Approve: it opens your Circloud profile in your browser to approve the new cluster. Its addresses come online a few minutes after you approve it.

The installer's Configuration step: the cluster's name with its label and addresses, and the Cloudflare account and default domain from the Circloud profile
Configuration: the cluster's addresses and Cloudflare
Administrator required: The installer needs Administrator privileges to create the virtual cluster’s nodes and configure networking. It will fail without elevation.

The installer handles everything: base image preparation, node provisioning, cluster deployment and CloudManager GUI/API/DB. If a reboot is needed (to turn on Hyper-V, which the virtual cluster requires), it saves progress and resumes automatically.

What the installer tells Circloud: after each install, Extend, node removal, Upgrade or Destroy, and when you adopt or import a cluster, it sends Circloud a short description of that cluster, under your licence: its name, status, installer and platform versions, its network ranges, and each node's name, role, size and private address. Each time it starts, it also sends any cluster on this computer that Circloud has not heard about yet, including clusters installed before this reporting existed. It never sends passwords, SSH keys, tokens or public addresses. If it cannot reach Circloud, it sends the description the next time it starts.

Step 3: Access the Platform

When the install finishes, the installer shows:

  • Addresses — the admin portal, the user portal and the API on your domain: https://admin-<label>.<domain>, https://user-<label>.<domain> and https://api-<label>.<domain>. They come online a few minutes after you approve the cluster. Until then the finish screen keeps Approve, while its link is valid.
  • Access — the same three at their direct addresses on the control node, which answer at once. Your browser warns about the certificate on these, because it is the cluster's own; the addresses on your domain carry a trusted one.
  • Admin sign-in — the admin username you chose and the password the installer generated, with Show and Copy. Your first tenant has the same name and password, the whole cluster's CPU, memory and disk, and every active domain of your Cloudflare account.

The installer keeps the sign-in, with the admin API token, in a file of your Windows account, %LOCALAPPDATA%\Circloud\clusters\<cluster id>\credentials.json, and names it at the end of its log: open it any time to read them again.

Keep this file safe. It holds the admin password and the admin API token, which reaches every tenant.

Access URLs

Direct Access (on the control node)

API: https://<control node>:8080
Admin GUI: https://<control node>:8443
User GUI: https://<control node>:8444

Public Access (via Cloudflare)

API: https://api-<cluster>.<your-domain>
Admin GUI: https://admin-<cluster>.<your-domain>
User GUI: https://user-<cluster>.<your-domain>

<cluster> is the cluster's label, its name as an address: lowercase letters, digits and hyphens, so one domain carries many clusters. A cluster installed before addresses carried its name keeps api.<your-domain>, admin.<your-domain> and user.<your-domain>.

Upgrades. A newer release is installed from the admin portal's Version card, or with the installer's Upgrade: see Upgrading the Platform.

Getting Started

Welcome to Circloud! This guide will help you get started with deploying and managing your cloud infrastructure. Create Virtual Private Clouds (VPCs), subnets, pods, and Cloudflare tunnels to expose your services.

Your Resources: You can manage VPCs, subnets, pods, tunnels, and registry credentials from your dashboard. All resources are isolated within your environment.

VPCs

Create isolated virtual networks with optional internet access. Each VPC is completely isolated from other tenants.

Subnets

Divide your VPC into logical network segments with custom CIDR blocks.

Pods

Deploy containerized applications with auto-scaling replicas and load balancing.

Tunnels

Expose your services securely to the internet via Cloudflare tunnels.

Customizing Table Views

Every table in the dashboard has a View section with column toggles. Switch a column on or off to show or hide it. This lets you focus on the information that matters most for your current task. Your choice is saved in this browser.

Admin Login

After installation, the first thing to do is log in to the CloudManager admin dashboard. This is where you manage tenants, configure the platform, monitor infrastructure, and control Cloudflare tunnels.

Getting Your Admin Credentials

The installer generates a random admin password during installation and shows the sign-in when it finishes (Admin sign-in, with Show and Copy). It also keeps it, with the admin API token, in a file of your Windows account, %LOCALAPPDATA%\Circloud\clusters\<cluster id>\credentials.json, which the end of the installer's log names. Its cloudmanager_admin section holds your username and password.

Keep this file safe. It holds the admin password and the admin API token. Do not commit it to version control.

To change the admin password, use Change password on the admin portal's Config → Admin Authentication card (below). The file keeps the password the installer generated: once you change it, the file's copy no longer signs in.

Accessing the Admin Dashboard

Open the CloudManager admin dashboard at https://admin-<cluster>.<your-domain> (or at its direct address on the control node, https://<control node>:8443, which the installer shows) and log in with your admin username and password. admin-<cluster> is the admin portal's subdomain unless you chose another one on the Domains card (admin on a cluster installed before addresses carried its name).

Admin API Token

The same file also holds the admin API token (the cloudmanager_admin.api_token field), which the admin portal's Admin Authentication card shows too. This token is used for privileged API endpoints that require the X-Admin-Token header — such as creating tenants, managing service tunnels, and configuring global settings.

There are two types of authentication in the API:

HeaderWho uses itPurpose
X-Auth-Token Tenants Manage VPCs, subnets, pods, tunnels within the tenant's scope
X-Admin-Token Platform admin Create/delete tenants, manage service tunnels, approve domains, configure provider settings

AI Agent Integration

Skip the manual setup entirely. Point your AI coding agent — Claude Code, Cursor, Copilot Workspace, or anything else that speaks HTTP — at Circloud® NEST and it can provision tenants, VPCs, subnets, pods, and Cloudflare tunnels by calling the REST API directly. No clicking through dashboards, no hand-rolled infrastructure commands. The agent reads your code, builds the image, pushes it, then creates everything else automatically.

Put your credentials.json file into your project, at its root next to your README.md. It is a small JSON file — api_url, tenant_id and token, and default_docker_registry: the server, username and password of your default registry, the one the agent pushes your images to (see Your Default Registry; without one it holds ADD_YOUR_DOCKER_REGISTRY_URL_HERE and its two siblings, and the agent asks you for a registry), then db_clusters: each of your DB clusters' write and read addresses, database and login (see DB Clusters) — and the portal makes it for you: Config → Authentication → Download credentials. Use it as it downloads, credentials.json, and keep it out of version control. (The admin portal's Admin Authentication card gives the administrator's file the same way: api_url and admin_token, for an agent that manages the platform itself.) The API reference itself lives on your cluster: the agent reads api_url from the file and fetches <api_url>/openapi.json, the complete, machine-readable reference the API generates from its own code — every route, who may call it, every status it answers and why. <api_url>/docs shows the same reference in a browser, and neither needs a token to read. Every route there lists the token header it takes; Authorize takes your token once and sends it with every request you try from the page. Creating a VPC, a subnet, a pod or a topology takes the token in the body instead. With the file and the reference, the agent has everything it needs to provision the infrastructure your app needs and put it on the public internet, end to end, in under a minute.

⬇ Download deployable app template (.zip)

Prefer to skip the boilerplate? The deployable app template is a working starter project — a Node.js HTTP service backed by a PostgreSQL pod, plus deploy.sh / upgrade.sh / destroy.sh that talk to the Circloud Nest API and a topology.json that wires VPC, subnets, pods, and a public Cloudflare tunnel. Its CLOUD_README.md tells the agent to read credentials.json at the root and to fetch the reference from api_url; credentials.example.json shows the shape (a project set up before may have the file as .credentials: the scripts read that too). Tell your agent: "unzip this template, put my credentials.json at its root, adapt demo-app/ and cloud/topology.json to build my project, then run cloud/deploy.sh." That's the shortest path from an empty repo to a Nest-deployed application running on the public internet.

AI Agent
1
Generate Code
Analyzes requirements and writes application code
2
Build Image
Builds Docker image and pushes to registry
3
Deploy to Circloud® NEST

Example prompt

Build a gaming website with online payments
that auto-heals and auto-scales, then deploy
it on Circloud Nest with the credentials.json file
in this folder (the API reference is at
<api_url>/openapi.json), and expose it
under the subdomain games.
Want infrastructure as code? The same API also accepts a topology JSON document — see the Topology section. Your agent can produce that JSON, version-control it alongside your code, and re-apply it on every deploy.

Create Account

Circloud® NEST is multi-tenant. Each tenant gets isolated VPCs, subnets, pods, and tunnels. Before tenants can use the platform, you need to create their accounts. You can optionally set resource limits (max pods, VPCs, subnets, CPU, RAM, storage) per tenant.

In the CloudManager admin dashboard, go to the Tenants tab and click Create Tenant. Enter a tenant name and password. You can also set resource limits. The platform generates a Tenant ID and API Token that the tenant uses to log in and interact with the API.

Create Tenant from Admin Dashboard
Creating a tenant from the CloudManager admin dashboard

Self-Service Signup

When self-service signup is enabled in the admin settings, tenants can register directly from the User GUI login page. They choose a name and password, and receive their credentials immediately.

Self-service tenant registration
Self-service tenant registration from the User GUI login page

User Login

Tenants log in to the User GUI at https://user-<cluster>.<your-domain> (or at its direct address on the control node, https://<control node>:8444) using the tenant name and password created by the admin or via self-service signup. The installer makes the first one for you: a tenant with the administrator's username (the one you chose in the installer), signing in with the administrator's password, made once at the install — an update never makes one, and one you delete stays deleted. Its password and the administrator's are separate from then on. A tenant changes its own password with Change password on Config → Authentication (see Change Password).

User GUI login screen
User GUI Login

Setup & API Access

Each tenant has a Tenant ID and API Token for authenticating with the Circloud® NEST API. These are shown on the dashboard after logging in.

Step 1: Get Your Credentials

1

Log into the Dashboard

Visit the Circloud portal and log in with your tenant credentials.

2

Copy Your Tenant ID and API Token

Open Config → Authentication: the card shows your API URL, tenant ID and API token, each with a copy button.

3

Or Download credentials

Download credentials, at the foot of the same card beside Change password, hands you all three — the API URL, your tenant ID and your token — with your default registry and your DB clusters' logins, as the JSON file a project reads, credentials.json: put it at the root of your project as it is, and the app template's scripts and your AI agent find the API from it. See AI Agent Integration.

CloudUser Authentication card with the API URL, tenant ID, API token and the Download credentials control
Tenant Authentication (API URL, ID, API Token, Download credentials)

Change Password

Change password on Config → Authentication opens a form under the card: your current password, the new one, and the new one again. The new password needs at least 8 characters (at most 128), with an uppercase letter, a lowercase letter and a digit — the rule account creation uses — and cannot be the current one. Click Save: the old password stops working at once.

  • Every other browser where you are signed in is signed out: it can read and change nothing more, and its next page load asks it to sign in. The one you changed it in stays signed in. If someone else has signed in as you, changing the password ends their session.
  • Your API token does not change, and neither does a credentials.json file: rotate the token on the same card if you think someone else has it.
  • Five attempts a minute (twenty an hour) are allowed; a wrong current password counts. Every change, and every refused one, is in the Ops Log, never with a password.

Virtual Private Clouds (VPCs)

A VPC is an isolated virtual network where you deploy your resources. Each VPC has its own routing table and is completely isolated from other VPCs.

CloudUser VPCs tab
VPCs Tab

Names

Every name you choose — tenant, VPC, subnet, pod, tunnel and subdomain — uses lowercase letters, digits and hyphens, starting and ending with a letter or digit, at most 63 characters. The API answers a name outside the rule with 400 and that sentence.

The platform builds the names of the cluster objects behind a VPC, subnet, pod or tunnel from your tenant name, a short id and the names you chose (for example team-a-469e-shop-web), so a name that fits the rule on its own but pushes one of those past 63 characters is refused too, with a 400 that names the object, its limit and the name it would have had.

Creating a VPC

Navigate to the VPCs tab and click "Create VPC". Enter a name and choose whether to enable internet access.

Create VPC form
Create VPC

Deleting a VPC

Click the delete button (×) on any VPC card to remove it. This is a cascade delete — all subnets, pods, tunnels, DNS records, and persistent storage within the VPC are permanently removed. This action cannot be undone. The cloud storages that only this VPC's pods use go with it too: the dialog says how many and names them, and its switch (on to start with) keeps them when switched off — over the API, delete_cloud_storage=false. See Cloud Storage.

Warning: Deleting a VPC destroys all resources inside it, including running pods and their data. Make sure to back up any important data before deleting.

A delete that fails part way keeps the VPC in your VPC list, marked Failed: delete it, and says what failed — a pod whose data could not be removed from its node in time, for example — and what was deleted before it. Nothing new can be added to it; delete it again to carry on where it stopped.

Migrate External: Another Cluster

Migrate external moves a VPC to another cluster of the platform, into an existing tenant of that cluster. The target is one of the other clusters on this cluster's Cloudflare account, of the same Circloud profile, chosen from a list: nobody types the target's address. A cluster is listed once it is approved on the Circloud profile. The migration also needs the target tenant's ID and its API token: both are on the target tenant's Config → Authentication card, in the target cluster's user portal. No administrator of either cluster takes part. The target cluster checks the token before anything moves, and the platform keeps it, encrypted, only until the migration ends.

The Migrate external button is on the VPC's card (the administrator has it on every VPC, beside Migrate internal, which moves a VPC to other nodes of the same cluster), and opens its card in a pop-up, as +Pod does. The card asks for the Target cluster, chosen in its list — each cluster by its name and API address — the Target tenant ID and the Target tenant API token. With no other cluster on this cluster's Cloudflare account, the list says so.

Press Check to preview the migration: what is created on the target cluster, how much data is copied and how long that takes at the uplink last measured on this cluster, which addresses move, how long the VPC is split between the two clusters and what is down during the migration — or, in one sentence, why it cannot start (a wrong token, a pod name already taken, an older platform version on the target cluster). Then press Start and confirm. The card follows the migration step by step.

Domains first. The target cluster creates an address only on a domain the target tenant holds. When the target tenant does not hold the domain of one of the VPC's addresses, Check says which domains and which addresses, and asks whether to migrate without them. Confirm, and the migration goes on without those addresses: they are not created on the target cluster, and they stop working when the VPC is deleted from this cluster. Cancel, add the domain to the target tenant (its administrator adds it, or the tenant requests it in its user portal), then check again.

A VPC with a pod that has both persistent storage and a cloud storage cannot be migrated to another cluster yet: the pod's persistent folder would not be copied, so the migration is refused, naming the pod, and nothing moves.

The migration runs in the platform, step by step:

  1. the VPC is found on the target cluster by name, or created with the same internet setting, then its subnets with the same names and ranges;
  2. every pod is created stopped — the same image, replicas, port, environment and options; a pod's cloud storage is attached by its UUID (both clusters use the same Cloudflare account; nothing is copied); the registry credentials its images need are copied first;
  3. the firewall rules are copied before any pod starts;
  4. each pod with persistent storage and no cloud storage, one at a time, is stopped on this cluster (its application gets to stop cleanly), its data is copied and checked on both sides, and the pod starts on the target cluster;
  5. each pod with cloud storage, then each stateless pod, starts on the target cluster while it still runs on this cluster;
  6. a check that every pod runs on the target cluster as it ran on this cluster;
  7. each address is stopped on this cluster and created on the target cluster with the same hostname — except the addresses left out for a missing domain;
  8. the VPC is deleted from this cluster. Its cloud storages are kept.

From when the first pod with persistent storage stops until the migration finishes, the VPC is split: its pods on one cluster cannot reach those on the other. The VPC, its subnets and its pods get new IDs on the target cluster; their names stay, and so do the names pods reach each other by. Its pods reach the internet from the target cluster's addresses.

A failure before a pod runs on the target cluster puts the pod back on this cluster, unchanged, and stops the migration; a pod whose data already moved runs on the target cluster and stays stopped on this cluster, and the failure says what runs where. Starting the migration again continues where it stopped.

Platform Services

Every VPC comes with the services it needs, created and maintained by Circloud:

  • its own DNS (2 replicas) for internal name resolution
  • tunnel connectors, when you create tunnels
  • stable VIP addresses used by DNS records

Internet Access

When you enable internet access on a VPC, Circloud configures external routing so pods can be granted outbound or inbound connectivity. Internet access is controlled at the VPC level and refined per pod.

Setting Scope Effect
enable_internet VPC Enables external routing so EIP, SNAT, and FIP can be allocated
external_access Pod Allocates an EIP and SNAT for outbound internet
external_inbound Pod Creates a FIP for bidirectional inbound/outbound access
Note: external_inbound requires external_access=true. For HTTP/HTTPS services, Cloudflare tunnels are often simpler than direct inbound IPs.

Subnets

Subnets divide your VPC into smaller network segments. Each subnet has its own CIDR block and can host multiple pods.

CloudUser Subnets tab
Subnets Tab

Creating a Subnet

Navigate to the Subnets tab and click "Create Subnet". Select a VPC, enter a name, CIDR block, and gateway IP.

Create Subnet form
Create Subnet

Deleting a Subnet

Click the delete button (×) on any subnet to remove it. All pods within the subnet are deleted along with their tunnels and persistent storage — and the cloud storages that only those pods use, unless the dialog's switch is off (over the API, delete_cloud_storage=false). A subnet listed without a delete button is the platform's own and cannot be deleted.

The pods go one at a time. If one cannot be deleted — its data not removed from its node in time, for example — the delete stops there and says which pod, why, and which pods were deleted before it. The rest of the subnet stays as it was; delete the subnet again to carry on.

CIDR Planning: Plan your CIDR blocks carefully. Subnets within the same VPC should not overlap. Common patterns include /24 subnets (254 usable IPs) for most workloads.

Security Rules

Security rules are a per-VPC firewall for your workloads. Each rule allows or denies ingress or egress traffic between a remote (an IPv4 CIDR — 0.0.0.0/0 is the internet, i.e. every address — or this VPC) and a target inside the VPC (the whole VPC, one subnet, or specific pods), for a protocol and optional ports. Every VPC gets its own rule set, managed from the Security tab inside the VPC.

VPC Security tab with priority-ordered firewall rules
Security Tab (per-VPC firewall rules)

How Rules Are Evaluated

  • Lowest priority wins — rules are evaluated in priority order (1–2000), lowest number first, and the first match decides.
  • Deny beats allow — at the same priority, a deny rule is evaluated before an allow.
  • Implied baseline — three fixed implied rules frame everything you write: always allow the platform's own services in the VPC (its DNS, tunnels and load balancers, in both directions — no rule can block them, so a deny never takes out your own DNS), and beneath your rules allow all outbound and deny all other inbound. They cannot be edited, reordered, or deleted, and the panel shows them as a static note.
  • The gateway check — before a pod starts, the network pings its subnet's gateway, and the pod cannot start without the reply. That ping and its reply are always allowed, whatever your rules say, so narrowing or deleting Allow internal traffic, or denying all outbound traffic, never stops your pods from starting. Nothing else is let through: a pod's ping to its own subnet's gateway is the only traffic it adds.
  • Seeded rule — every new VPC starts with one ordinary rule, Allow internal traffic (priority 2000), so pods in the VPC can reach each other. It is editable, disableable, and deletable like any other rule; deleting it leaves you with exactly the implied baseline.

Managing Rules

Open the VPCs tab, select a VPC, and switch to its Security tab. Click +Rule to add a rule — pick a direction, action, priority, protocol and ports, remote, and target. Use the pencil to edit a rule, the × to delete it, and the Enabled switch to keep a rule while pausing its enforcement. To reorder rules, edit their priorities — the lowest number is evaluated first. The direction dropdown filters the table to ingress or egress rules.

ColumnMeaning
PriorityEvaluation order (1–2000). The lowest number is checked first; the first matching rule wins.
Directioningress (traffic into your pods) or egress (traffic out of your pods)
Actionallow or deny the matched traffic
Protocol / Portstcp, udp, icmp, or all. Ports (e.g. 443, 8000-9000, or a comma list) apply only to tcp and udp; blank means all ports.
RemoteThe other end of the connection: an IPv4 CIDR (0.0.0.0/0 is the internet) or this VPC, which covers traffic between its own subnets
TargetWhat the rule protects inside the VPC: all pods in the VPC, one subnet, or specific pods
EnabledA disabled rule is kept but not enforced

Admin Read-Only View

Admins get the same table as a support view: in the CloudManager dashboard, open Tenants, select a tenant, open one of its VPCs, and switch to the Security tab. The view is read-only — no add, edit, or toggle — and is rendered from the same payload the tenant sees, so admin and tenant can never disagree about what is enforced.

CloudManager read-only firewall rules support view
Admin support view (Firewall Rules, read-only)

DNS & Service Discovery

Each VPC includes a dedicated DNS service (dnsmasq), run by the platform. The platform configures pod DNS settings so service names resolve inside the VPC, while external domains are forwarded to the provider DNS servers.

Resolution Flow

pod -> the VPC's DNS -> external DNS forwarder

Record Format

Pods and VIP services are registered automatically. Names are stable even when pods restart.

web.my-tenant
web

HA for DNS

DNS runs two replicas. Pods are configured with both DNS IPs when available, providing resilience if one replica is unavailable.

Provider DNS Settings

External DNS servers and the ndots setting come from provider configuration. For self-hosted labs, these map to pod_dns_nameservers and pod_dns_ndots in your configuration.

Registry Credentials

Registry credentials let your pods pull private images. Credentials are stored in the tenant database and synchronized to a platform credential named <tenant>-registry-creds, which is attached to your pods automatically. The platform registry is in it already, after yours (see The Platform Registry).

When do you need this? If your container images are hosted on public Docker Hub (e.g. nginx:latest, postgres:16), or on the platform registry, no registry credentials are needed. You only need to add registry credentials when pulling from private registries like GitHub Container Registry (ghcr.io), AWS ECR, or private Docker Hub repositories.
CloudUser Registry tab
Registry Credentials

Adding Registry Credentials

Navigate to the Registry tab and click "Add Registry". Enter a name, server URL, username, and password or token.

Add Registry form
Add Registry Credentials

Reusing a credential name updates the existing entry. Listing credentials hides passwords in responses. Pods use these credentials when use_registry_credentials is true (default). The name platform is the platform registry's, and the registries the platform itself uses cannot be added: the API refuses them.

Your Default Registry

One of your registries is your default: the one your credentials.json download carries as default_docker_registry, with its server, username and password, for the app template and your AI agent to push your images to. No other registry's password is in the file. Deleting your default leaves you with none.

"default_docker_registry": {"server": "https://index.docker.io/v1/", "username": "myuser", "password": "mytoken"}

Without a default the file carries placeholders, so the agent knows to ask you for a registry before it pushes anything:

"default_docker_registry": {"server": "ADD_YOUR_DOCKER_REGISTRY_URL_HERE",
                            "username": "ADD_YOUR_DOCKER_REGISTRY_USERNAME_HERE",
                            "password": "ADD_YOUR_DOCKER_REGISTRY_PASSWORD_HERE"}

Press Set default on its row of the Registry card (it is badged Default from then on), then download the file again.

The Platform Registry

Your images can live on the platform itself, before you have a registry anywhere else: the platform registry, at registry-<cluster>.<your-domain> once your administrator publishes it. It is a registry of its own for tenants — not where the platform keeps its own images — and each tenant has its own space in it, registry-<cluster>.<your-domain>/<tenant name>/, with its own login. Nobody else can read, pull or overwrite your images, and you cannot see anyone else's.

  • Your login — the username is your tenant's name; the password is on the Registry card, on its last row, platform (its copy button). It is not in your credentials.json download, which carries your default registry only. It changes when your API token is rotated: log in again.
  • Push — tag your image with your space and push it:
docker login registry.example.com -u TENANT_NAME        # the password from the Registry card
docker tag web:1 registry.example.com/TENANT_NAME/web:1
docker push registry.example.com/TENANT_NAME/web:1
  • Run — create a pod (or a topology) with "container_image": "registry.example.com/TENANT_NAME/web:1". Your pods pull it with the login they already have; an image in someone else's space is refused. Every pod pulls its image again whenever it starts.
  • The app template pushes to your default registry (default_docker_registry); without one, its deploy.sh asks for a registry — the platform registry among them — keeps it in the file and makes it your default.
Limits. A push goes through the platform's public address: a layer over 100 MB, or one that takes more than about 100 seconds to upload, is refused. While the registry's disk is nearly full, pushes are refused and pulls go on. Deleting a tenant deletes its images.

Pods

Pods are the deployable units that run your containerized applications. Each pod can have multiple replicas for high availability and automatic load balancing.

CloudUser Pods tab
Pods Tab

Pod Features

When creating a pod, you can configure these capabilities:

  • Auto-healing — When enabled, Circloud automatically restarts pods that crash or become unresponsive. The platform monitors pod health and recreates failed containers without manual intervention.
  • Auto-scaling — Pods can scale horizontally based on CPU or memory usage. Set minimum and maximum replica counts, and the platform adjusts automatically based on load.
  • Persistent storage — Pods can request node-local persistent storage. Storage is created under /storage/<tenant-id>/<pod-id> and mounted into the container. Persistent pods are pinned to a single worker node.
  • Cloud storage — A pod with persistent storage can also have a cloud storage: files kept off-site under a UUID that any of your pods can use, for exports, shared files and backups on your own schedule. See Cloud Storage.
  • Replicas — Run multiple identical copies of a pod for redundancy and load distribution. Traffic is automatically balanced across replicas via the internal load balancer.
  • Internet access — Controlled at pod level. external_access enables outbound internet, external_inbound enables bidirectional access with a floating IP.
  • GPU access — Pods can request GPU resources on nodes that have GPUs configured. Set gpu_access: true to schedule the pod on a GPU-enabled worker.

Creating a Pod

Navigate to the Pods tab and click "Create Pod". Select a subnet, enter a name and an image, set the replicas and the service port, then switch on what the pod needs: outbound or inbound internet access, persistent storage — and cloud storage, which needs it — auto-healing, auto-scaling, and a tunnel. Every option is a switch; a switch that cannot be used yet is greyed out, and hovering it says why (Enable Cloud Storage stays greyed out until Enable Persistent Storage is on).

Create Pod form with persistent storage, cloud storage and a tunnel switched on
Create Pod — persistent storage, cloud storage (a new storage) and a tunnel switched on

Pod Actions (Actions Column)

Actions appear on the first row of each pod group.

Icon Action
▶ Start a stopped pod workload, or recreate a missing pod (A Missing Pod)
■ Stop the pod workload
↻ Restart the pod workload
+ Add a replica (up to 10)
× Remove a replica (minimum 1)
📋 View pod logs with colorized output, copy, and download
🗑 Delete the pod and all its resources (tunnels and persistent storage are removed in cascade). Its cloud storage goes with it when no other pod uses it — switch off Also delete its cloud storage in the dialog to keep it; see Cloud Storage

The amber × is for replica removal; the red × is for deleting the pod.

When autoscaling is enabled, manual replica changes are ignored and the platform controls scaling.

Viewing Logs

Click the logs button on any pod to open the colorized logs viewer. You can copy logs to clipboard or download them as a text file. Logs are fetched in real-time from the running container.

Service VIPs and Replicas

Circloud creates a VIP service for each pod group. For single pods, the VIP provides a stable IP. For replicas, one VIP load-balances traffic across all replicas.

The Service IP column in the GUI shows this VIP address.

replica pods: api-0, api-1, api-2
VIP service: api -> 10.x.x.x (stable VIP)

Automatic Scaling

Enable auto_scaling to have the platform add and remove replicas automatically, based on average CPU usage. Auto-healing is implied (the platform manages the replica set for you), and manual replica changes are disabled. The replica_count is treated as the initial value and clamped to the autoscale min/max. When autoscaling is enabled, the minimum replica count is always 2.

Edit Pod Configuration

You can modify pod settings after creation by clicking the edit icon in the flags column. This opens the Pod Configuration modal where you can toggle auto-healing, persistent storage, auto-scaling and cloud storage (and choose which storage) without recreating the pod. Cloud storage needs persistent storage: its switch opens once persistent storage is on, and persistent storage cannot be turned off while cloud storage is on — turn cloud storage off first.

Edit Pod Configuration dialog of a pod with cloud storage
Edit Pod Configuration — a pod with cloud storage: persistent storage stays on under it
Note: Enabling auto-scaling automatically enables auto-healing. Disabling auto-healing also disables auto-scaling. There is brief downtime during the workload recreation.

When a Pod Would Go Over Your Quota

Your administrator gives your account a quota — CPU, memory, storage, pods, VPCs and subnets; the strip at the top of the Monitoring tab shows where you stand. A request that would start a pod past your CPU or memory quota — creating one, starting, restarting or scaling it, changing its configuration, a tunnel or cloud storage — is refused with one sentence that counts the whole request, every replica included, and a pod the request had begun to create is removed again:

This would go over your quota: memory requests 928 MiB used of 1 GiB, and this needs 256 MiB more. Stop or delete a pod, or ask the administrator for more.

When the request alone needs more than your whole quota, it says that instead: This needs more than your whole quota: … Ask the administrator for more. Over the API the answer is 409 with detail.code QUOTA_EXCEEDED, the sentence in detail.message, the clause it is built around in detail.usage, and the figures — what was asked for, in use and allowed, per resource — in detail.quota. A change that had already stopped the pod when it was refused says so and leaves the pod stopped, and its probe says which request stopped it: start it once there is room. A pod with auto-healing or auto-scaling is started after the answer, so the request succeeds and a replica over your quota stays not started. The administrator sees the same refusal naming your account and the limit to raise (Max CPU or Max RAM).

The Create Pod form asking for ten replicas, and the error that refuses it with the quota sentence
A create the quota has no room for — ten replicas — refused with the API's own sentence; nothing is left behind

A Missing Pod

A pod can stop running without anyone stopping it — the server it ran on restarted, for example. When the platform has not seen a pod running for ten minutes, and the pod was not stopped, it marks the pod Missing (⭕) and says since when. It can be started again or deleted:

  • Start recreates it from its record: its image, environment, storage and network, its name in the VPC and its tunnels, and the address it had in its subnet if no other pod has taken it. Its tunnels come back once their VPC's internet path is confirmed, as for any tunnel started (Tunnels): when it cannot be, the pod is not made again and the Start says so — start it again in a minute.
  • Delete removes it, as for any pod.

The pod's row reads Missing, its probe says since when, and Start and Delete are on the row.

Until it runs again, a missing pod cannot be stopped, and its settings and replicas cannot be changed: start it first, or delete it.

Each missing pod raises one Pod missing alert that says since when; it clears as soon as the pod runs again or is deleted. A pod is never marked missing while it is being created, started, stopped, restarted, changed, scaled, migrated or deleted, nor when a migration that did not finish left it for the next migration of its VPC to start again — until the pod runs again.

A pod the cluster refuses to create — over your quota, for example — is not missing: it reads Failed, and its probe gives the reason.

A Stuck Update

A restart of a pod with auto-healing or auto-scaling, on a new image or not, is an update, and so is a migration that moves it: a new copy of the pod is made beside the one that runs, and the old copy is retired once the new one is ready. While the update is under way, the pod shows the new copy. When the new copy has made no progress for ten minutes, the update is stuck: the pod shows the old copy, which keeps serving and reads Ready, and the update is marked stuck, with since when, why, and what to do:

  • Cannot download image — no image has that name and tag, or the registry refuses the registry credentials. Once the image can be downloaded, the update finishes by itself.
  • Cannot be created — the quota has no room for the new copy, for example; the probe gives the figures. It is created once there is room.
  • No node can take it — it is placed once a node has room for it.
  • Keeps stopping, or did not become ready in time.

The Update stuck mark beside the pod's name opens since when, why, and what to do, and its probe names the previous image when it was another one. Restart in the portals keeps the pod's image: to undo the update, or to try another image, use the API.

A pod with persistent storage is updated the other way round: its copy stops first, and the new copy starts once it has stopped, so two copies never use its data at the same time. The pod is down while it stops and starts again, and an update that cannot finish leaves it down: its status says why, and the update is undone the same way.

Each stuck update raises one Pod update stuck alert, dated by when it began; it clears as soon as the update completes or is undone. An update in progress is never marked: a copy still downloading its image or starting, and a download that failed once, are not stuck — only ten minutes without progress is.

Cloud Storage

Cloud storage keeps your pod's files off-site: exports, uploads, and copies of what the pod keeps on its persistent storage — its backups. Each storage has a UUID. It outlives the pod that created it, any of your pods can use it by that UUID, and a pod reads and writes it over standard S3, at https://cloud-storage, with a key pair the platform gives the pod: no account to manage.

What it needs

  • Persistent storage on the pod. A pod gets cloud storage only together with persistent storage, and persistent storage cannot be turned off while cloud storage is on.
  • Internet access on the pod's VPC.
  • Cloud storage enabled by your administrator — see When cloud storage is not available.

Turning both off in one change is fine: the pod is detached and the storage and its files are kept.

Enable Cloud Storage stays greyed out until Enable Persistent Storage is on — hover it to see why.

Turning it on

On the create-pod form, switch on Enable Persistent Storage, then Enable Cloud Storage, and leave Storage on New storage — or pick one of yours.

Create Pod form: Enable Persistent Storage, then Enable Cloud Storage and the Storage choice
Persistent storage on, then cloud storage — the Storage choice left on New storage

The Storage tab has two tables. Persistent Storage lists each of your pods with persistent storage: how much its folder holds, the cluster, its VPC and subnet, the node the folder is kept on, and its cloud storage. Cloud Storage (S3) lists your storages with their UUIDs (each with a copy button), the pods using each one, the DB clusters whose backups are in it, and how much it holds. Assign on a storage gives it to one of your pods with persistent storage, which restarts with it; a storage no pod uses has a × to delete it. Both tables list your own storages and pods only. A storage marked Temporary was made to carry a pod's persistent storage to another cluster while its VPC migrates to it: no pod is given it, it cannot be deleted while the migration runs, and it goes when the migration ends. A VPC's Cloud Storage tab lists the storages its pods use and yours that no pod uses yet. A pod with cloud storage carries a C chip in the Flags column of the Pods table, and its storage is named in the table's Cloud Storage column.

The Storage tab: Persistent Storage, then Cloud Storage (S3) with each storage's UUID and the pods using it
The Storage tab: your pods with persistent storage, then each cloud storage's UUID and the pods using it
A VPC's Cloud Storage tab: the storage its pod uses, with its UUID and the pod
A VPC's Cloud Storage tab: the storages its pods use

Reading and writing files

Your container gets standard S3 settings: any S3 client works with them, and current AWS SDKs and the AWS CLI need nothing else — they read AWS_ENDPOINT_URL_S3 (boto3 1.28, AWS CLI 1.29 and 2.13, or newer). Give an older one the endpoint yourself: --endpoint-url "$S3_URL".

Variable Value
S3_URL https://cloud-storage — your VPC's cloud storage, the same name in every VPC.
STORAGE_UUID The storage's UUID: S3 clients address the storage by it (s3://$STORAGE_UUID/<key>).
S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY This pod's key pair. It reaches this pod's storage and nothing else.
S3_REGION auto
S3_CA_BUNDLE /etc/cloud-storage/ca.crt — the certificate authority https://cloud-storage is checked against.
AWS_ENDPOINT_URL_S3, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION, AWS_DEFAULT_REGION, AWS_CA_BUNDLE The same, for the AWS SDKs and the AWS CLI. Given only when your own variables name no AWS_ variable, so a pod that talks to AWS keeps its own.
NODE_EXTRA_CA_CERTS The same certificate file, for Node.js — unless you set it.
# Store a file, list what you have, fetch it back, remove it.
aws s3 cp june.csv "s3://$STORAGE_UUID/reports/june.csv"
aws s3 ls "s3://$STORAGE_UUID/reports/"
aws s3 cp "s3://$STORAGE_UUID/reports/june.csv" june.csv
aws s3 rm "s3://$STORAGE_UUID/reports/june.csv"

# The same from Python: boto3 reads the variables by itself.
python3 -c 'import boto3, os; boto3.client("s3").upload_file("june.csv", os.environ["STORAGE_UUID"], "reports/june.csv")'

A client you give S3_URL yourself uses path-style requests (https://cloud-storage/<UUID>/<key>; boto3 does on its own) and the certificate in S3_CA_BUNDLE. The key pair is never among the pod's environment variables as the dashboard and the API show them. A presigned URL works inside the VPC only.

Keys, operations and refusals

  • One storage per key pair: S3 clients address the storage by its UUID, and the pod's key pair reaches that storage alone — naming another is 403 AccessDenied. Refusals are S3 error documents, as any S3 client reads them.
  • A key is a path you choose — reports/june.csv, at most 900 characters. It must not start with /, contain \, a . or .. segment, an empty segment or a control character, and it is refused rather than tidied up (400 InvalidArgument). A trailing / (a folder marker) is fine.
  • What works: get (ranges and conditions included), head, put, copy within the storage, delete and the multi-object delete, listings, multipart uploads and presigned URLs. Anything else — ACLs, tagging, versions, object locks, encryption with your own keys — is 501 NotImplemented.
  • Checksums CRC32, SHA-1 and SHA-256 are checked as the bytes arrive: a file that fails one is not stored (400 BadDigest). CRC32C and CRC64NVME are refused, and so is a checksum of a whole multipart upload: each part's is checked instead.
  • Sizes: up to 5 GiB in one upload, larger as a multipart upload whose parts — all but the last — are the same size, at least 5 MiB.
  • A wrong key pair is 403, and so is the key pair of a storage removed from you; a key you have not stored is 404 NoSuchKey.
  • When a node fails, https://cloud-storage keeps its address and answers again within seconds. A request in flight at that moment fails, and S3 clients retry on their own.

Sharing a storage between pods

A storage is yours, not the pod's. Give another pod the same storage and both pods read and write the same objects — for handing files from one service to another, a shared download cache, a replacement pod picking up where the old one stopped, or anything else. The pods can be in any of your VPCs, and there is no limit on how many share one storage.

Pick the storage in the Storage choice under Enable Cloud Storage; leaving it on New storage gives the pod one of its own. To change an existing pod, open its configuration (the pencil in the Flags column) and turn cloud storage on, off, or choose another storage.

A UUID is a capability: one you do not hold yet is looked for on the same Cloudflare account — a storage made by another cluster connected to it, an earlier install or a tenant deleted since — and, when found, is assigned to you on the spot and marked Assigned on your Storage tab. A UUID found nowhere is refused with 404. Giving one of your storages to another tenant of the same cluster is not available, to keep tenants isolated (such a UUID is refused as that tenant's). A tenant of another cluster uses it by its UUID, or once that cluster's administrator assigns it (below). Each pod has its own key pair: a pod reaches the storage it is attached to and nothing else.

Turning cloud storage off detaches the pod and keeps the storage and its objects. Changing a pod's storage, or turning it on or off, restarts the pod, because the S3 variables reach the container through its environment.

Using a storage on another cluster

A storage's UUID works on another cluster connected to the same Cloudflare account too. Pass it as cloud_storage_id when you create a pod on that cluster (or change one): the platform finds it on the account and assigns it to you on the spot — or the administrator of that cluster assigns it to you from the UUID on your Storage tab. Either way a storage is found once it holds at least one file (an empty one cannot be found). It then appears on your Storage tab on that cluster, marked Assigned (its date is when it was assigned), and in the Storage choice of the pod form. You use it exactly like a storage of your own: pick it, or pass its UUID as cloud_storage_id, in any of your VPCs, and your pods read and write the same files the pods of the other cluster do. It needs persistent storage on the pod, like every cloud storage. Migrate external attaches the pods' cloud storages on the target cluster this way.

Right after such a storage is attached, a request can be answered 503 with a Retry-After header while the storage is being connected: wait the seconds it says and send it again.

A cluster never deletes the files of a storage it did not create. Deleting an assigned storage (from its row, over the API, or with its last pod: Deleting) removes it from that cluster only — its files are kept, and the dialog and the answer ("files": "kept") say so. To empty it, delete its files from a pod that uses it before you remove it. Deleting it on the cluster that created it (if that cluster still exists) deletes its files for every cluster using it, so check that none still needs it first.

Once a storage is removed from you — you remove it, or the administrator gives it to another tenant — none of your pods can reach it any more, even one that still has its key pair.

Backing up with cloud storage

There is no separate backup feature: a backup is a copy your pod puts into its cloud storage, when and as often as you decide — after every export, once a night, before a risky migration. Your application knows when its data is consistent, so it is the one to make the copy. Write it to the pod's persistent storage first, then upload it under a name that says when it was taken:

#!/bin/sh
# backup.sh — runs inside the pod: from a cron job, after an export, or by hand.
set -e
STAMP=$(date -u +%Y%m%dT%H%M%SZ)
mkdir -p /storage/backups

# 1. A consistent copy on the pod's persistent storage (here, a PostgreSQL dump).
pg_dump -Fc -f /storage/backups/app.dump app

# 2. Keep it off-site, named by when it was taken.
aws s3 cp /storage/backups/app.dump "s3://$STORAGE_UUID/backups/app-$STAMP.dump"
# The copies you have:
aws s3 ls "s3://$STORAGE_UUID/backups/"

# Restore one — in this pod, or in any pod with the same cloud_storage_id:
aws s3 cp "s3://$STORAGE_UUID/backups/app-20260930T020000Z.dump" /storage/backups/restore.dump
pg_restore --clean -d app /storage/backups/restore.dump

# Retire one you no longer need:
aws s3 rm "s3://$STORAGE_UUID/backups/app-20260901T020000Z.dump"
  • The schedule is yours. Run the script from a cron job in the pod, from your application's own timer, or at the end of the job that changes the data.
  • So is retention. Nothing is deleted for you: list backups/ and delete the copies you no longer want.
  • Restore anywhere. The copies belong to the storage, not to the pod: the pod that made them, a replacement for it, or a pod in another of your VPCs reads them with the same cloud_storage_id.

Deleting

A storage goes with the delete of its last pod. Deleting a pod, a subnet, a VPC or a tenant deletes every storage that no other pod uses any more — unless you say otherwise. A storage that another of your pods still uses — in any of your VPCs — is kept until that pod goes. A stopped pod counts as using its storage, and so does a pod whose own delete failed half-way. A storage no pod uses stays until you delete it, and cannot be deleted while any pod is attached.

Every delete dialog carries Also delete its cloud storage, switched on to start with: it says how many storages go and names them, and switching it off keeps them all. When a pod still uses a storage, the dialog says it stays. A storage no pod uses is deleted from the Storage tab, with the × on its row.

Deleting a storage this cluster created deletes every file in it and cannot be undone — also when a tenant of another cluster has it assigned: the cluster that made a storage is the one that deletes its files, on its own or with the last pod on that cluster that uses it, so check that no other cluster still needs it first. An assigned one keeps its files (above). The operations log entry of every delete says what happened to the storages.

A delete takes effect at once: the storage leaves the Storage tab and no pod can be given it any more. For a storage this cluster created, its files are removed right after, in the background, and that is retried until none is left — a storage with many files can take a few minutes to empty, and nothing needs to be done while it does.

A pod's key pair is for the storage it was given and does not expire. When a pod moves to another storage it is restarted with a new key pair; a copy of the OLD pair made before that (logged, pasted into another system) still reaches the old storage. Treat the key pair like a password and do not copy it out of the pod.

When cloud storage is not available

Cloud storage needs your administrator to have set it up on the cluster.

Until then Enable Cloud Storage and the Storage choice are greyed out — hover one to see why.

DB Clusters

A DB cluster is a PostgreSQL service in one of your VPCs, made in one step: a primary that takes reads and writes, standbys that follow it and take over when it fails — each instance on a node of its own, with a volume of its own — and continuous backups into a cloud storage of yours from the moment it is created. Every VPC card reads Pods · DB Clusters · Cloud Storage: open a VPC, then its DB Clusters tab. Each row shows the DB cluster's status, its primary, how many of its instances are ready, its write and read addresses, its latest backup and the window a restore can reach.

A VPC's DB Clusters tab: a DB cluster's status, primary, instances, write and read addresses, latest backup and restorable window
A VPC's DB Clusters tab

Creating a DB cluster

On the VPC's DB Clusters tab, click +DB cluster and fill in the form:

  • Name — follows the name rule. Applications reach the DB cluster as <name>-rw and <name>-ro.
  • Subnet — one of the VPC's subnets: its instances get their addresses there. Applications anywhere in the VPC reach it by its names.
  • Instances — 2 to 5: one primary, the rest standbys. Each runs on a node of its own, so the VPC needs as many usable nodes as instances.
  • Size per instance (GiB) — each instance's volume, 1 to 1024. It can grow later, never shrink.
  • Backups — on to start with, into the chosen Cloud storage: a new one, or one of yours (each DB cluster writes under a folder of its own). Schedule (cron, UTC) sets when base backups are taken (five cron fields, at most one an hour; empty: every day at 02:MM UTC) and Retention (days) how long they are kept (1 to 365; empty: 14). Backups need cloud storage set up by your administrator and internet access on the VPC.
  • Restore from — left on None for a new, empty database (see Backups and restore).

Create makes it: its status reads Creating, then Ready, about a minute later, and a first base backup is taken as soon as the primary is up.

The Create DB cluster form: name, subnet, instances, size per instance, backups with their cloud storage, schedule and retention, and Restore from
Creating a DB cluster

The instances and one more pod, the DB cluster's manager, count against your quota. They are in the VPC's Pods table, managed by the DB cluster: a pod's row names its role (Primary, Standby or Manager) and opens its DB cluster, and stop, restart, change and delete are the DB cluster's own, never a single pod's. An instance's Logs button shows its database log: PostgreSQL's own lines, each with its time and severity. A subnet that holds a DB cluster cannot be deleted on its own, and a VPC that holds one cannot be migrated yet.

Connecting

Applications in the VPC connect on port 5432, with TLS (sslmode=require), to two names:

  • <name>-rw — writes and reads, on the primary. It follows the primary through a failover and a switchover.
  • <name>-ro — reads, on the standbys.

The login lives with the DB cluster: the platform keeps the password, so it is there whenever you need it. A new password is taken by the database within seconds, and the previous one still works meanwhile; then only the new one does. Open connections stay open; new ones need the new password, so update your applications' configuration.

Details on its row opens its Connection: the write and read addresses, the database, the username and the password — hidden until you show it — each with a copy button, and a ready-made connection string. The credentials.json download (Config → Authentication) lists every DB cluster's login after your default registry.

Rotate gives the login a new password; Password state reads Applying until the database has taken it.

A DB cluster's details: its connection with the password hidden, its settings and its instances
A DB cluster's details: connection, settings and instances

When the primary fails

A standby becomes the primary on its own, and <name>-rw follows it; the write address answers nothing for the moment that takes.

Replication is asynchronous. The primary acknowledges a commit without waiting for a standby, so a failover loses the commits no standby had received yet. Applications reconnect, retry, and treat a commit that was in flight as unknown.

The Instances table shows each standby's replication: how far behind the primary it is, measured about every minute — what a failover at that moment would lose. The Operation section names the last change of primary: when, from which instance to which, and whether it was a failover or a switchover.

Changing a running DB cluster

One operation runs at a time, on a ready DB cluster, and the Ops Log records it.

The details' Operation section follows an operation until it is done.

  • Switchover, on a standby's row — that standby becomes the primary. The primary stops cleanly first, so nothing is lost; writes pause for a few seconds, and applications reconnect. The old primary goes on as a standby.
  • Rebuild, on a standby's row — the instance and its volume are deleted and a new one is copied from the primary, on a node with no other instance of the DB cluster: for a damaged volume, or an instance whose node will not come back. Never the primary: switch over first. The DB cluster has one standby fewer until the new one is ready.
  • Size per instance and Apply — every instance's volume grows: the instances are replaced one at a time at the new size, the standbys first, then a switchover, then the old primary. Writes pause for a few seconds once. A size never shrinks.
  • Instances and Apply — adds standbys, each on a node of its own, or removes the newest ones with their volumes; never the primary.
  • Backups — the switch turns backups off (the backups already taken stay restorable, and so does the storage) or on again; Save, at the section's foot, keeps a new schedule and retention.

Backups and restore

A DB cluster backs up continuously to its cloud storage, with base backups on a schedule. When backups have failed for a few minutes, the DB cluster reads Degraded and an alert says so. A point in time can be restored up to the last transaction the backups hold. A DB cluster nobody has written to since its first base backup has no restorable window yet: its backups restore as they were taken.

A restore always makes a new DB cluster: the source is only read. It can come from one of your DB clusters here — restored to the latest its backups hold, as a backup was taken, or to a point in time inside its restorable window — or from the backups of a DB cluster made on another installation connected to the same Cloudflare account, or of one deleted since, by its cloud storage's UUID and its DB cluster ID.

The details' Backups section shows the cloud storage the backups go to, with its UUID; whether the continuous backup is working; the schedule and the retention; the restorable window (the points in time a restore can reach); the DB cluster's ID; and every base backup, with when it was taken, its size and whether it can be restored. Back up takes a base backup now.

A DB cluster's backups: its cloud storage and UUID, the continuous backup working, the restorable window, its base backups and its operations log
A DB cluster's backups and operations log

Restore on the Backups section opens the create form with this DB cluster as the source and the last moment its backups reach as the point in time; Restore on a backup's row opens it with that backup chosen. Give the new DB cluster a name and a subnet, and Create. In the form, Restore from takes:

  • This installation — one of your DB clusters here, restored to the Latest its backups hold, as A backup was taken, or to A point in time (UTC) inside its restorable window.
  • Another installation — the backups of a DB cluster made on another installation connected to the same Cloudflare account, or of one deleted since: its cloud storage's UUID and its DB cluster ID, both shown on its Backups section.

The restored DB cluster backs up into a folder of its own of the same storage, so it can be restored in turn, and its details say what it was restored from. A restore its backups cannot reach — no such backup, a time outside the window — fails the new DB cluster with a sentence that says so: delete it and restore again.

Deleting

Deleting a DB cluster removes its instances and their volumes: the database is gone, and it cannot be undone.

The cloud storage is kept. Unlike a pod's, a DB cluster's cloud storage stays when it is deleted: it holds the backups, to restore from later by its UUID.

Delete is in the details. Switch on Also delete its cloud storage in the dialog to delete the storage too, when nothing else uses it.

A kept storage goes on naming the deleted DB cluster in its DB clusters column, on the Storage tab and each VPC's Cloud Storage tab: when it was deleted, its ID, its backups as last read and its restorable window, and for a restored DB cluster which backup it came from. To restore them, choose Restore from Another installation with the storage's UUID and that ID.

Deleting a VPC or a tenant deletes its DB clusters with it, and that delete's own switch decides for their storages too: left on, as it starts, it deletes them and their backups.

Email

Mail for your own domains. The platform receives the mail of the addresses you add, keeps it in a database of yours, and sends from those addresses, signed with your domain's own key. The Email tab, after VPCs, has your email domains on the left with +Email domain; a domain selected shows its addresses with +Address, and an address selected shows its mail, in Inbox and Sent.

Email domains

+Email domain opens the form: choose one of your domains (Config → Domains). Your first email domain also asks for the VPC and the subnet of the DB cluster the platform makes to keep your mail (Where your mail is kept). Add sets the domain up at Cloudflare, all at once:

  • Email Routing, turned on when it was off: Cloudflare adds the domain's MX and SPF records and locks them.
  • One rule for the whole domain, its catch-all: every address's mail goes to the platform. Rules the domain already has for single addresses keep working as they did.
  • A DKIM key of the domain's own, its record at <selector>._domainkey.<domain>: everything sent from the domain is signed with it.
  • A DMARC record, v=DMARC1; p=none, only when the domain has none.

The domain's card shows its status (Setting up, Active, Failed or Removing), the records the platform added — Catch-all, DKIM, DMARC — and the DB cluster that keeps your mail.

No SPF change. The platform adds nothing to your domain's SPF record: every tenant sends from the cluster's one internet address, so that address in the record would let any tenant send as your domain. Your mail is signed with the domain's own DKIM key instead, and DMARC passes on that signature.

An email domain is the domain itself, not a subdomain, and its DNS is on the platform's Cloudflare account. A domain whose mail goes to another provider cannot be an email domain too. A received message is at most 25 MiB. Mail is read in the portal or through the API: there is no access for mail apps.

Where your mail is kept

In a DB cluster of yours named mail, made with your first email domain in the VPC and subnet you chose: two instances on two nodes of the VPC, with backups into a new cloud storage of yours. Each message as it arrived and each attachment are kept in that DB cluster's cloud storage too, under email/. Your later email domains keep their mail in the same DB cluster.

Mail is taken once the DB cluster is ready, about a minute after the first email domain is added; until then senders are asked to try again later, as mail servers do. A message a sending server delivers twice is kept once. On its VPC's DB Clusters tab the DB cluster carries an Email badge, and it cannot be deleted while an email domain uses it.

Addresses

An address is the part before the @ — lowercase letters, digits, dots, hyphens and underscores, starting and ending with a letter or a digit, at most 64 characters — with, optionally, a name: the name its mail is sent with. It takes mail at once; adding one changes nothing at Cloudflare. Mail to name+anything@ your domain arrives at name@. Mail to an address you have not added is refused to its sender: Address does not exist.

An address can be turned off — its senders are told it does not exist, and it sends nothing; its mail is kept — and on again. Removing an address deletes it with all its mail, received and sent.

+Address adds one. Each address shows how many messages it holds and how many are unread; its switch turns it off or on, and removing it asks first.

Inbox, Sent and the reader

An address's mail is in two folders, Inbox and Sent, newest first. Deleting a message deletes it with its attachments.

Each folder lists who sent a message (in Sent, who it went to), the subject, the date, the size and an attachment mark; unread mail is in bold. Opening a message marks it read, and Unread marks it unread again. The tab checks for new mail every half minute, and its refresh button checks at once. Delete asks first.

The reader shows the message's headers, then the message itself:

  • text as text;
  • HTML cleaned first — no scripts, forms, frames or event handlers — and shown in a sandboxed frame that runs no script and loads nothing by itself;
  • images inside the message, from its own attachments, are shown; images from the internet stay hidden until Show images, and then only over https;
  • links open in a new tab, without telling the site where they came from;
  • attachments download: the browser never opens one in place.

Writing, replying and forwarding

A message goes to at most 50 recipients, To, Cc and Bcc together, and carries at most 20 attachments and 15 MiB of them; as it goes out it is at most 25 MiB. Bcc recipients get the message and are never shown to the others.

New, Reply, Reply all and Forward open the same form: From (the address, with its name), To, Cc, Bcc, Subject, the message and its attachments. Reply goes to the sender, or to its Reply-To when it has one, and quotes the message; Reply all adds everyone else it went to, never your own address. A reply threads with the message it answers in every mail program. Forward carries the message's attachments, with a switch to leave them out. The portal writes text.

Delivery

Send keeps the message in Sent and queues it. The platform signs it with the domain's DKIM key and delivers it straight to each recipient's mail servers, encrypted whenever the server offers it. In Sent its state reads Queued, Sending or Retrying while it is on its way, then Sent, Partly sent or Not delivered; Not sent means it could not be queued, and it is kept to send again. Opened, it shows each recipient — On its way, Delivered or Not delivered — with the receiving server's answer.

A server that asks to try later — a greylisting, a timeout, a server away — is tried again after 1, 4, 10, 20 and 40 minutes, then after 1, 2 and 4 hours and every 4 hours after that, until 24 hours have passed. A server that refuses the message ends that recipient at once, with the server's words. Nothing is dropped silently: how each recipient's delivery ended is written into the message in Sent. Deleting a message still on its way stops whatever has not gone out yet.

Daily limits

Every tenant sends from the cluster's one internet address, so sending has daily limits that keep that address in good standing: your tenant sends at most 200 emails a day and each address 100, unless your administrator set other limits. Each recipient counts as one email, and the day is the UTC day. The form says how many the address has left today. A send that would pass a limit is refused, with nothing sent and nothing counted, and the sentence says which limit and when sending opens again, for example: [email protected] reached its limit of 100 emails today (each recipient counts as one). Your other addresses can still send. Sending opens again at 00:00 UTC (in 3 h 12 min). Over the API the answer is 409 with EMAIL_DAILY_LIMIT.

Removing an email domain

All its mail is deleted. Removing an email domain deletes its addresses and all their mail, and it cannot be undone.

Exactly what the platform added at Cloudflare is taken away: the domain's rule (the one it had before is put back), Email Routing when the platform turned it on, the DKIM key and its record, and the DMARC record it added. The DB cluster mail stays: delete it on its VPC's DB Clusters tab once you have no email domain left. A removal that stops part-way leaves the domain Removing, taking no mail; removing it again carries on.

The × on the domain's card removes it, and asks first.

Console Access

You can access a terminal inside your running pods using the console feature. Click the green terminal icon (>_) next to any running pod to open a web-based terminal. Console access is only available when the pod is in a Ready state.

Console button highlighted on a pod row
Click the green terminal icon on the pod row
Console modal
Pod Console (web terminal)

The terminal opens an interactive /bin/sh session via a WebSocket connection. If your image does not include /bin/sh, use a base image that provides a shell.

# Example commands inside the console
whoami
df -h
ls -la /storage

Pod Logs

A pod's logs are its container's output, the latest lines first to read: for debugging an application, following a startup, or looking at what a pod did. A DB cluster's instance shows its database log: PostgreSQL's own lines, each with its time and severity.

Click the logs icon (document icon) next to a pod in the Pods table. The logs panel opens and streams the container's output as it is written; scroll back to read earlier lines.

Logs button highlighted on a pod row
Click the logs icon on the pod row to open the panel
Pod Logs panel
Real-time pod log viewer

Monitoring

Pod status is refreshed by a monitoring service that polls the cluster and writes status records to the CloudManager database. The dashboard displays per-replica status, IP address, and restart count.

The top of the Monitoring tab stays in view whatever you open below it: a status line (live, when the figures last updated, and an Internet summary of every VPC that opens the Internet sub-tab when clicked), then one strip of tiles, each a large figure against your quota. CPU and memory show what your pods have reserved and a line of the last hour (5-minute averages); storage shows a meter; pods, VPCs and subnets show a dot for each one in its state: green running, amber not all running or stopped, red failed, and an empty ring for a VPC or subnet without pods. The worst state is named beside the figure (1 failed), and pointing at the dots lists them all. A figure at 75% of its quota or more is marked ▲, and at 90% or more ⚠; the line turns amber and red past the same marks. Below the strip are three sub-tabs: Internet (Internet and DNS with its timeline, beside the speed test), Pods (every pod with its live usage) and Trends. The tab reopens on the sub-tab you last chose in that browser.

CloudUser Monitoring tab, Internet sub-tab: Internet and DNS, the timeline under it over the last hour, and the speed test
Monitoring — Internet and DNS, its timeline over the last hour, and the speed test

Live Metrics

The Pods sub-tab lists every pod — when it was created, its VPC and subnet — with its real-time usage, sorted by the figure you choose under Sort by:

  • CPU — usage in millicores, beside what the pod reserved, with a bar
  • RAM — memory in use, beside what the pod reserved, with a bar
  • Storage — the disk the pod uses
  • Network — what it receives and sends right now, with the totals under it

Metrics are collected by the resource monitor service running inside the cluster and updated every few seconds in the dashboard.

CloudUser Monitoring tab, Pods sub-tab
Monitoring — Pods sub-tab

Internet and DNS

Each VPC has a small monitor that checks, every minute, that the VPC's own DNS answers and that the internet can be reached. The Internet sub-tab shows the last verdict per VPC, one line each: whether the internet is reachable and its round-trip time, whether DNS is resolving, and in the Loss column when the internet was last lost and for how long — or that the loss is still going on. VPCs with a problem are listed first. The line above the table says how many VPCs need attention and how long ago they were checked; hover a verdict for its details — the address probed, the nameserver and name looked up, and when that VPC was checked. A VPC created without internet access shows Not monitored for the internet, and a verdict older than about twenty minutes reads as unknown rather than being repeated. A new VPC's first verdicts reach the page within about fifteen minutes; until then its DNS reads Not checked and its timeline no data.

Internet Over Time

Under the table, Internet over time draws each VPC as two lanes: its internet (the thick lane) and its DNS (the thin lane under it), as the VPC's monitor reported them — up, down, or no data; a VPC without internet access reads internet off. A loss is a stretch of the lane as long as the loss lasted, so an outage shows how long it was, not only that it happened. Choose the window under Range — the last hour, 6, 12 or 24 hours, 7 or 30 days; the choice is remembered in that browser. The line above the chart sums up the window. Hover a stretch, or focus the chart and walk the stretches with the arrow keys, to read when each one began and how long it lasted.

Speed Test

Pick a VPC under From and press GO in the middle of the dial to measure the cluster's own connection. A short-lived platform pod in that VPC measures the round trip to speed.cloudflare.com, then downloads from it and uploads to it, each for at least 5 seconds and at most 10: past 5 seconds it stops once it has moved its budget — 250 MB down, 100 MB up — and it never moves more than 1 GB down or 500 MB up, in requests of at most 25 MB, so only a link faster than 1.6 Gbps down or 800 Mbps up is measured over less. The rate is what it moved over the time it spent moving it, not counting the round trip each request's answer takes to come back. That is the path your workloads in that VPC actually get, through the VPC's own resolvers and its internet routing, not your browser's. The dial is live while it measures: it says Starting the test… until the pod reports, then names the phase it is in — Ping, Download, Upload — with the rate measured so far in Mbps (megabits per second; Kbps below one, Gbps above a thousand), and the needle follows it. When the run ends the needle settles on the Downlink; press the Downlink or Uplink figure to put that one on the needle. A run that stops reporting is said to have stopped rather than shown as still live. Beside the figures:

  • Ping — the network round trip to the test server, in milliseconds, as measured on the test's own connection. It leaves out the time the test server spends preparing its answer, so it is close to what a ping from the same network reports.
  • Jitter — how much that round trip varies from one request to the next.
The speed test dial while it measures
The speed test while it measures — the phase, the rate so far, and the needle

A run that did not record its round trip — one from before Ping was measured this way — shows a dash for Ping and Jitter; hover it for the figure it did record and why that is not a round trip. One run at a time in the whole cluster — every VPC reaches the internet through the cluster's one address, so two runs at once would each measure part of it — and three minutes between the end of one run and the start of the next, whichever VPCs ran them, since Cloudflare refuses bursts from one address: until then GO waits on every VPC and says A speed test ran from this cluster a moment ago and until when; the last ten runs of each VPC are shown, drawn as a small chart once there are three and listed in a table, and a run that could not complete is listed with its reason. Administrators can run it on any VPC from the admin dashboard.

Limited. Cloudflare's test server limits the internet address a test comes from once it has served it enough, and every VPC of the cluster comes from the same one. When it refuses a request (it answers 429 Too Many Requests), that phase reads Limited — on the dial, in the figures and in the table, in words, never as a number — and the test stops there. Until the time the server asked for (15 minutes when it named none), the whole cluster starts no new run: GO waits on every VPC, and the panel and the refusal say Try again after that time, in UTC. A phase that could not be measured for another reason — another answer from the server, a broken connection, or a transfer the server ended before it could be a measurement — reads Failed, and a phase the test did not reach reads Not run; what it measured before that is still shown. Over the API the same is in the operations log entry of the run: latency_state, down_state and up_state in its parameters.

The Trends sub-tab charts CPU, memory and network traffic (received and sent, in Kbps or Mbps) per VPC over the last hour, 6 hours, 12 hours, 24 hours, 7 days, 30 days or year. The charts are drawn on black; a chart with four or more series draws lines only, so they stay apart. Every line is solid and unbroken: where a sample is missing, the line is drawn straight across it. Hover a chart to read every series at that instant. The scale beside a chart is marked in round steps, each with its exact value; a network chart's reaches 1 Kbps at least, so a nearly idle VPC's traffic runs along its bottom. Only the VPCs that exist are drawn: a deleted VPC leaves the charts with it, in both portals, even while its readings are still kept.

CloudUser Monitoring tab, Trends sub-tab
Monitoring — Trends sub-tab

Node Monitoring

The admin dashboard's Nodes sub-tab shows node-level metrics including CPU, RAM, and disk usage per node, and how many tenants' pods each node runs. Node status probes indicate whether the monitoring data is fresh, stale, or offline.

Status Probes

Probes are shown as colored indicators in the Pods and Nodes tables. Click a probe to see detailed status information including phase, IP, reason, and error messages.

Pod status probe popover
Click a probe to see status details

ProbeMeaning
🟢Ready / Fresh (healthy)
🟡Pending / Not Ready / Stale
🔴Failed / Offline
🟥Stopped
⭕Missing: no longer running, although it was not stopped (what to do)
⚪Unknown (no data yet)

Node probes are based on the last metrics update time: ≤30s = Fresh (green), ≤60s = Stale (yellow), >60s = Offline (red).

Pod Status States

StatusMeaning
readyPod is running and Ready condition is true
not_readyPod is running but not Ready
pendingPod is being scheduled or pulling images
failedPod has failed or is in an Unknown phase
unknownStatus has not been observed yet

These are the states of each replica. The pod itself reads Stopped while it is stopped, and Missing — lifecycle_status "missing" — when it is no longer running although it was not stopped: Start recreates it, Delete removes it (A Missing Pod). A pod whose update cannot finish keeps serving from its previous copy and carries the Update stuck mark (A Stuck Update).

Auto-Healing & Auto-Scaling

When auto_healing is enabled, the platform manages your pods as a supervised workload, so they are automatically recreated on failure. Restart counts in the UI help identify unstable workloads.

When auto_scaling is enabled, the platform manages the replica count for you. The dashboard shows the live replica count as it scales up and down based on CPU usage.

High Availability

For pods with replica_count greater than 1, a VIP service load-balances across replicas. DNS points to the VIP, so clients are insulated from individual pod restarts.

Alerts

The Alerts tab lists what the platform found wrong, for you to fix or to know about: an attack being tried, a VPC’s internet or DNS down, a pod that keeps restarting, a quota nearly used, something the platform set up that has drifted, something stuck being deleted. You see the alerts about your own VPCs and pods; the administrator sees every tenant’s, and the platform-wide ones besides. The same tab, with the same chips and the same order, is in both portals, and every VPC card has an Alerts sub-tab with that VPC’s own.

One alert per condition

An alert is one condition — this resolver not answering, this source address scanning, this node’s disk filling up — never one line per occurrence. Its last seen is the newest sign of the condition itself: for an attack, the time of the newest request, so a scan at 01:00 still reads 01:00 in the afternoon. Its count is how many of the platform’s checks found the condition happening: a check counts once, and only when it found something newer than the alert already had — the number of requests or failures is in the alert’s detail. A condition seen again never adds a row.

The platform resolves an alert once the condition has not been seen for a while: half an hour for a steady condition (a pod, a disk, a quota), a day for a network condition that comes and goes (a resolver that stops answering for a few seconds once a day stays one open alert instead of blinking open and shut), and a day after the last sign of an attack, so a scan in the night is still there in the morning. If the condition comes back, the same alert opens again. An alert about a condition on a VPC or a tenant that has been deleted is resolved too, since nothing will observe it clear; an attack alert is not — it stays its day, as evidence.

Reading an alert

An alert has a severity — critical, high, medium, low or info — and a kind, the condition in words (“DNS not answering”, “Endpoint scan”), of a family: attacks, the network, workloads, capacity, the platform’s own parts, or drift. The list is ordered for action: open alerts first (unread before acknowledged), then by severity, then the most recent activity.

Each row carries two chips. The severity says how urgent it is, in a pill filled with its level's gradient: crimson for critical, orange for high, amber for medium, blue for low, slate for info. The kind is a quieter tag whose mark is coloured by its family: red for attacks, blue for the network, violet for workloads, amber for capacity, grey for the platform’s own parts, pink for drift. Open the title for the detail, the evidence, where it is (tenant, VPC, subnet, pod, each a link) and who acknowledged it. The Alerts tab’s badge is the number of open alerts.

Acknowledge, dismiss, resolved

  • Acknowledge — “I see it, keep tracking it”. The alert stays open and keeps counting. If the platform then resolves it and the same condition returns within a day of your acknowledgement, it reopens as acknowledged rather than as new, so a condition that comes and goes does not keep paging you.
  • Dismiss — “not this time”. A dismissed alert stays hidden, and keeps counting, while the condition goes on; if the condition is not seen for a day and then comes back, that is a new occurrence and the alert opens again. An alert the platform raises once for something it did — an internet path it put back, a pod restarted while it took its VPC’s node rule — opens again at the next one, even after a dismissal. A dismissal never silences a source or a name for good. A tenant cannot dismiss an attack alert about its own resources: it is the administrator’s evidence too — acknowledge it instead.
  • Resolved — the platform saw the condition clear. Resolved and dismissed alerts stay in the archive.

Ack and Dismiss are on an open alert's row and in its detail; Dismiss asks first, and is not offered where you cannot dismiss. The status filter shows the archive.

The kinds

FamilyKindWhat it meansSeverityClears
AttacksNew administrator accountAn administrator account exists that was not there at the last approved baseline.criticalwhen acknowledged into the baseline, or gone
Repeated failed sign-insEight or more failed sign-ins for one name within an hour, in the last six hours.higha day after the last sign of it
Failed sign-ins for many namesMore names than the scanner lists one by one failed to sign in.criticala day after the last sign of it
Sign-in burstFive or more failed sign-ins for one name inside a minute.higha day after the last sign of it
Sign-in bursts for many namesMore names than the scanner lists one by one had a sign-in burst.criticala day after the last sign of it
Platform-wide sign-in failuresFifteen or more failed sign-ins across every name in five minutes: a spray.high (critical from 40 failures in five minutes)a day after the last sign of it
Sign-ins to names that do not existThree or more failed sign-ins to a name no account has.higha day after the last sign of it
Administrator name guessedA sign-in tried a name from the usual attacker word list (admin, root...).criticala day after the last sign of it
Another tenant's resources probedA tenant's requests were refused three or more times on another tenant's resources.higha day after the last sign of it
Many deletes in a minuteFive or more successful deletes by one actor inside a minute.higha day after the last sign of it
Many changes in a minuteTen or more successful changes by one actor inside a minute.mediuma day after the last sign of it
Administrator operation tried with a tenant tokenA tenant token was used on an administrator-only operation.higha day after the last sign of it
Path traversal attemptA request carried a path-traversal payload (such as ../) in the last day.criticala day after the last sign of it
Injection attemptA request carried an injection payload in the last day.higha day after the last sign of it
Injection attempts from many sourcesMore sources than the scanner lists one by one sent such payloads.criticala day after the last sign of it
Endpoint scanTwelve or more refused requests over five or more paths from one source in an hour.medium (high from 30 probes in an hour)a day after the last sign of it
Endpoint scans from many sourcesMore scanning sources than the scanner lists one by one.higha day after the last sign of it
Path traversal request at a portalA path-traversal request reached one of the portals. One alert per portal and path, whichever replica answered it.high (critical when the request was answered 200)a day after the last sign of it
NetworkInternet path missingA VPC's or subnet's internet path is not in the network's own table, and the platform could not put it back on its own yet.highhalf an hour after it was last seen
Internet path put backA VPC's or subnet's internet path had gone missing and the platform put it back. The tenant's copy is low: it is for knowing, not for doing.mediuma day after the last sign of it
Internet path repair failedThe platform tried to put a missing internet path back and the network still does not show it.highas soon as its check finds it in order
Firewall rules put backThe firewall rules on a VPC's subnets no longer matched its security rules, and the platform wrote them again. The tenant's copy is low: it is for knowing, not for doing.mediuma day after the last sign of it
Internet lost in every VPCEvery VPC that reported lost the internet in the same minutes: the site's own connection was down. The VPCs' own internet alerts are not raised for those minutes.higha day after it was last seen
Tunnel downA tunnel is failed or inactive, so its public address does not reach its service.high (medium when the tunnel is only inactive)half an hour after it was last seen
DNS not answeringOne of the VPC's resolvers did not answer the name check three times in a row.higha day after it was last seen
DNS answer hijackedA public name resolved to a private address inside the VPC.criticala day after it was last seen
DNS replicas disagreeThe VPC's two resolvers gave different answers for the same name.higha day after it was last seen
Address changed hardware identityAn address on the VPC's network answered from a different hardware identity.criticala day after the last sign of it
Unknown neighbour on the networkAn address from outside the VPC answered on its network.higha day after the last sign of it
Platform service unreachableOne of the VPC's own platform services did not answer three times in a row.higha day after it was last seen
Internet unreachableThe VPC's monitor could not reach the internet three checks in a row.mediuma day after it was last seen
DNS upstreams unreachableNone of the public resolvers the VPC's resolvers forward to answered, three checks in a row. Names already in use keep answering from the resolvers' memory.mediuma day after it was last seen
Internet reachable where it should not beA VPC created without internet access can reach the internet.mediuma day after it was last seen
Monitor errorThe VPC's monitor hit an error in one of its checks.mediuma day after the last sign of it
Monitor floodingThe VPC's monitor reported more distinct findings in one pass than it can honestly.higha day after the last sign of it
Monitor silentThe VPC's monitor has not reported in; nothing is watching that VPC's network.mediumhalf an hour after it was last seen
Monitor missingThe VPC's monitor is gone although the platform expects it.highhalf an hour after it was last seen
WorkloadsPod unhealthyA pod is not ready, keeps restarting, cannot pull its image, or cannot be created at all (over the quota, for example).medium (high for a crash loop, an out-of-memory kill or a failed pod)half an hour after it was last seen
Pod missingA pod is no longer running, although it was not stopped. Start recreates it from its record; Delete removes it.highas soon as the pod runs again or is deleted
Pod update stuckA pod's update cannot finish while its previous copy still serves: the new copy cannot download its image, cannot be created or placed on a node, keeps stopping, or did not become ready in time. The alert says why and what to do.mediumas soon as the update completes or is undone
Pod stuck deletingA pod has been deleting for more than an hour; its name and quota slot are held.mediumhalf an hour after it was last seen
Pods outside the VPC's nodesPods of a VPC run on nodes that are not the VPC's. The platform does not move them by itself: Migrate internal with the same nodes moves only them.mediumhalf an hour after it was last seen
DB instance unreachableA PostgreSQL instance of a DB cluster runs without its address in the VPC, so applications cannot reach it. The platform recreates it on the same volume.highas soon as the instance has its address again, or is gone
DB cluster backups failingA DB cluster's write-ahead log has not reached its cloud storage for several minutes: its backups stop at that moment, and a restore cannot reach past it.highas soon as the write-ahead log reaches the cloud storage again
CapacityNode disk filling upA node's disk is 80% full or more.high (critical from 90%)half an hour after it was last seen
Quota nearly usedA tenant is at 80% or more of a quota.low (medium from 90%, high at 100%)half an hour after it was last seen
PlatformNode readings staleNo fresh usage readings for a node in five minutes: the figures shown for it are old.medium (high after an hour, critical after a day)half an hour after it was last seen
NAT rule stuck deletingA NAT rule has been deleting for longer than the platform allows. The tenant's copy is low: it is for knowing, not for doing.highwhen the object is gone
Address stuck deletingAn external address has been deleting for longer than the platform allows. The tenant's copy is informational.mediumwhen the object is gone
Address left in placeAn external address could not be freed when its NAT rule went, because a router still carried it or could not be read, and has waited longer than the platform allows. The platform frees it on its own once nothing carries it.mediumwhen the object is gone
Licence noticeThe cluster's licence needs attention: more servers or clusters than the plan allows, no confirmation from Circloud for 36 hours, a licence about to run out, or none at all. Running apps are never affected.medium (high while changes are paused)as soon as its check finds it in order
Cloud storage not servedPods of a VPC use cloud storage, but no storage service is on record for that VPC, or the one on record does not answer: their storage calls fail.highhalf an hour after it was last seen
Cloud storage on one proxyA VPC's cloud storage answers through one proxy only, because another has not answered for ten minutes (its node is down, it waits for a node, or it keeps restarting). If the remaining one or its node fails too, the VPC's storage calls fail until a proxy answers again.mediumhalf an hour after it was last seen
Cloud storage CA missingThe certificate authority the platform made for cloud storage is gone while a storage service still uses a certificate it issued. It is never made again: until it is put back, a pod with cloud storage that is started, made again or changed starts without its storage settings, and creating one is refused.highhalf an hour after it was last seen
VPC placement needs attentionNew pods of a VPC cannot be kept on its chosen nodes as they should: the platform lacks a permission on the cluster's nodes or could not set them, none of the VPC's nodes takes new pods, or a pod is held while it takes its VPC's node rule. A pod restarted while it took that rule keeps the alert open until it is dismissed; until then no other pod takes the rule in place.highas soon as its check finds it in order
Router tables unreadableThe platform cannot read the network's own table of internet paths, so it neither checks nor repairs them. Running apps are not affected by this alone.mediumas soon as its check finds it in order
Network update haltedA network change the platform rolls out one VPC at a time failed its checks on a VPC, was undone there, and stopped. Acknowledging the alert lets it try that VPC once more.highas soon as its check finds it in order
Network update waiting on a VPCA network change has skipped a VPC for a day because the VPC was not healthy, was being moved, or was running a speed test.lowas soon as its check finds it in order
Network updates pausedThe platform's network changes that roll out one VPC at a time have been paused for an hour or more by an update of the platform or by the administrator. Repairs still run. It clears when the pause ends.lowas soon as its check finds it in order
Firewall update haltedA new way of writing firewall rules failed its health check on the first VPC; that VPC's previous rules were put back and no other VPC was changed.criticalas soon as its check finds it in order
Platform repairs pausedThe platform's self-repairing checks have not run for ten minutes, because an update of the platform is still in progress or cannot be read.highas soon as its check finds it in order
Platform update refused or rolled backAn update of the platform was refused before it changed anything, or was undone because tenant traffic got worse during it.highas soon as its check finds it in order
Platform update not verifiedAn update of the platform stopped before its last steps because the site's own internet was down, so tenant traffic could not be checked; nothing was undone. It clears on the next update that passes its checks.mediumas soon as its check finds it in order
Cloudflare tokens not deletedThe platform could not delete some of its Cloudflare API tokens. The alert names them and their account: delete them in the Cloudflare dashboard, then dismiss it.lowwhen the platform deletes them after all
Cloudflare renewal failedThis version of the platform needs its Cloudflare access renewed, and the renewal failed. The alert says why and when it runs again; until then, the features that need it do not work.mediumas soon as a renewal succeeds
Cloudflare token on your profile not workingThe Cloudflare token on your Circloud profile for this cluster's account does not work for this cluster. The alert says why: replace the token on your profile, or save a working one on the Cloudflare card.mediumas soon as a working token is saved, on your profile or on the Cloudflare card
Tunnel name taken on CloudflareOn the Cloudflare account, a tunnel this cluster did not create carries the name the platform gives one of its tenants' addresses. It is never used: a new address is not published, and an existing one keeps the name it had and keeps working. The alert names the tunnel: if nothing uses it, delete it in the Cloudflare dashboard.mediumwhen no tunnel the cluster did not create carries the name
Address on a shared tunnelOne Cloudflare tunnel carries two addresses: two of this cluster's, or one of this cluster's and one of another cluster on the same account. Only one of them is served, and its visitors can reach the other's connector. The alert names both: delete the address that should not use the tunnel and publish it again; it gets a tunnel of its own, and the other address is left as it is.highwhen the tunnel carries one address
DriftUnexpected namespaceA namespace the platform did not create and the baseline does not know.mediumwhen acknowledged into the baseline, or gone
Unexpected service accountA service account the platform did not create and the baseline does not know.mediumwhen acknowledged into the baseline, or gone
Unexpected cluster roleA cluster role that was not there at the last approved baseline.highwhen acknowledged into the baseline, or gone
Unexpected cluster role bindingA cluster role binding that was not there at the last approved baseline.highwhen acknowledged into the baseline, or gone
Tenant not created by the platformA tenant exists with no record of the platform creating it.lowwhen acknowledged into the baseline, or gone
Unexpected platform secretA secret in the platform's own namespace that no record of the platform accounts for.highwhen acknowledged into the baseline, or gone

Three checks of the per-VPC monitor are no longer alerts, because what they measured was never a problem: the router reachability check, which no router answers (it failed on every VPC every minute); the internal name check, which asked the VPC’s resolver for a name it is built not to know; and the large-packet check, whose answer was never large. The monitor asks for one public name now, and calls the internet unreachable only after three failed checks in a row. Alerts of retired kinds, and alerts that were once raised one per hour or per replica, are resolved by the platform and stay readable in the archive.

Operations Log

Every mutating operation on the platform is recorded in the Ops Log — creating, deleting, starting, stopping, restarting pods, VPCs, subnets, tunnels, and configuration changes. The log tracks the source (GUI, API, or System), actor (admin or tenant), status (success or failed), and error details for failed operations. A VPC's migration and each of its steps read Migrate internal or Migrate external, and a step of a Migrate external names the step too (Migrate external: Verify); hover one for the operation id the API filters on (vpc_placement, vpc_placement_move).

Global Ops Log tab
Global Ops Log with server-side filters and cursor-based pagination

The Ops Log is available at three levels:

  • Global — all operations across all VPCs (main Ops Log tab)
  • VPC-level — operations within a specific VPC (Ops Log tab inside each VPC)
  • Tenant-level — all operations for a tenant (admin dashboard only)

Use the filter dropdowns (Source, Status, Resource Type, Operation) to narrow results. Filters are applied server-side for fast queries even with thousands of entries. Click Load More to fetch the next page of results.

Issues

The Issues tab is where you tell your administrator that something is wrong. Press +Ticket, say what you expected, what happened instead and when it started, and press Report to admin. You do not have to gather anything yourself, and you do not have to describe the problem in technical terms: the diagnostics of what the ticket is about go with it.

Writing a ticket

+Ticket opens the ticket card. Pick what the ticket is about, in three optional steps; each step narrows the next, and decides how much is collected:

  • VPC — or leave it on None for your whole account
  • Subnet — only once a VPC is chosen; None covers the whole VPC
  • Pod — only once a subnet is chosen; None covers the whole subnet

Then write what is wrong and press Report to admin, at the card’s bottom right. Your tickets are listed under +Ticket, so you can see that yours arrived.

Report to Circloud

Your administrator reads the tickets in the admin portal’s Issues tab; a click on a ticket opens it with everything that was collected alongside it. Each ticket’s row has a Report to Circloud button, which sends it on to Circloud for help, and a Circloud column with what Circloud answered: Sent with Circloud’s reference, the one to quote when writing to support, or the reason it did not take the ticket.

What is collected with a ticket

  • What you picked — its settings and current state, so the ticket still says what it was about even after the pod is gone
  • Pod state — ready or not, restart counts, and the reason a container last stopped
  • Recent usage — CPU, memory and network for the last few hours, because a problem that has already passed is invisible in a live reading
  • Your recent operations — the Ops Log entries for that scope, which is usually where “it worked yesterday” is answered
  • Your open alerts — in case the platform already noticed
  • The pod’s last log lines — only when you pick a pod, and only that pod’s own output
  • Whether the platform was watching — how many nodes were reporting and how fresh their readings were, so a stale reading is not mistaken for an idle pod. Counts only: no node names and no addresses

Only your own VPCs, subnets and pods can be chosen or collected, and the platform’s own parts of a VPC are never included. Your API token, pod environment variables and registry credentials are never collected. Everything gathered is size-capped, and the ticket records anything that had to be trimmed.

What goes to Circloud

With Report to Circloud, the ticket goes as you sent it, with the cluster’s health at that moment — its nodes and VPCs, the internet and name-service checks, speed-test results, the state of every pod and of the platform’s own services, the tunnels, open alerts, the operations log around the time of the ticket, and the platform’s versions — together with the cluster’s licence, so Circloud knows whose cluster it is. The same rule holds as for the ticket itself: no API token, no environment variables, no tunnel tokens and no registry credentials ever go. Reporting it again later updates the copy Circloud has, under the same reference.

Cloudflare Tunnels

Tunnels provide secure external access to your pods without opening inbound ports. Traffic is routed through Cloudflare's global network, providing DDoS protection, automatic SSL/TLS, and zero-trust access.

When you create a tunnel, Circloud deploys a cloudflared connector pod in the VPC, allocates outbound access, and registers DNS records in Cloudflare. The tunnel origin targets the pod DNS name or VIP service.

Tunnel status is tracked as active, inactive, or failed in the dashboard.

CloudUser Tunnels tab
Tunnels Tab

Creating a Tunnel

Navigate to the Tunnels tab and click "Create Tunnel". Select a pod and configure the tunnel hostname and port settings.

Create Tunnel form
Create Tunnel

Using Custom Domains

If custom domains have been assigned, you can use them:

CloudUser Domains tab
Custom Domains (Tenant Domains)
Add Domain form
Add Custom Domain
Protocol Use Cases:
  • HTTP: Websites, REST APIs, webhooks, microservices, admin panels
  • HTTPS: Services with internal SSL, legacy apps, mTLS requirements
  • SSH: Remote administration, SFTP file transfers, Git over SSH, dev access
  • TCP: Databases (PostgreSQL, MySQL, MongoDB, Redis), RDP, custom protocols
  • UDP: Game servers (Source, Minecraft), VoIP (SIP), DNS, QUIC, media streaming
Note: You can only create tunnels using domains that have been approved for your tenant. Contact your administrator to add new custom domains.

Managing Tunnels

The Tunnels tab on your dashboard lists your tunnels. Click the delete button (×) on a tunnel row to remove it.

Deleting a Tunnel

Deleting a tunnel cleans up its Cloudflare tunnel, DNS record, and access policy automatically. The cloudflared pod running the tunnel is also removed from the cluster.

A tunnel reaches the internet through its VPC's own internet path, so creating or deleting one never touches that path: the VPC keeps its DNS and internet whatever happens to its tunnels. Before a tunnel is created or started, the platform confirms the VPC's internet path; if it cannot, the request changes nothing and says so, and the administrator is alerted. Tunnels made before this each had a NAT rule of their own; the platform tidies those away one VPC at a time, checking the VPC's internet after every step, and each step is in your operations log. A NAT rule or an address that stays stuck being deleted is on the Alerts tab instead of going unnoticed; an alert raised earlier for one names the tunnel and what it means for your VPC, for example Tunnel web: NAT rule left behind or Tunnel web: NAT rule stuck deleting. There is nothing for you to do — the administrator gets an alert of their own — and both alerts clear themselves once it is gone. A NAT rule whose VPC is already gone can never finish deleting on its own, so the platform releases it itself, without an alert. Dismissing yours hides only yours.

Custom Domains

A tunnel needs a domain of your own. Your domains are yours alone — the platform's default domain carries the platform's portals and is never used for your addresses. There are two ways to get one: request it from the Domains tab (Config → Domains) and the administrator approves it, or the administrator adds it to your tenant. The first domain you get becomes your default: new tunnels go on it unless you pick another of your domains in the tunnel form. Until you have one, the tunnel forms say so and Create Tunnel is disabled: Request a domain first (Config → Domains), or ask your administrator to add one. The API answers the same sentence (409, DOMAIN_NOT_CONFIGURED).

Domain Workflow

  1. Request — the tenant submits a domain request from the Domains tab in the User GUI
  2. Pending — the request appears in the admin dashboard awaiting approval
  3. Approval — the admin approves the domain from the CloudManager Tenants section
  4. Active — the tenant can now create tunnels using the approved domain; the first one approved is the default

A domain is assigned to one tenant only. The administrator approves a request only when the domain is on the platform's Cloudflare account, active there (a domain still pending at Cloudflare waits until its nameservers are switched), and no other tenant holds it, and may reject a request. A rejected request reads Rejected, with the administrator's reason under the domain's name when one was given. Remove it with ×, or request the domain again: the new request replaces the rejected one.

Set default on another of your domains makes it the default for new tunnels and moves the addresses on the previous default domain to it; addresses on your other domains stay where they are. Adding a later domain changes nothing until you set it.

To delete a domain, click the × next to it. Deleting your default domain makes another of your domains the default — the one most of your addresses sit on, else your oldest — so you always have one while you have any; no address moves. Addresses already on the deleted domain keep working until they are deleted. Deleting your only domain leaves you with none: Create Tunnel is disabled until you have another, and the next domain you get becomes your default.

Tunnels made before this rule keep their address: a tunnel published on the platform's domain before your tenant had a domain of its own keeps working unchanged. New tunnels need a domain of your own.

Topology (Infrastructure-as-Code)

The Topology feature allows you to define your entire infrastructure in JSON and deploy it with a single API call. This is ideal for version control, reproducible deployments, and automation.

The Topology tab displays a visual diagram of your infrastructure and lets you export or import your entire setup as JSON.

CloudUser Topology tab
Topology Tab

Exporting Your Topology

From the Topology tab, you can view your current infrastructure as JSON and download it for backup or version control.

Tip: Use the visual topology diagram in the Topology tab to understand your infrastructure at a glance. The diagram updates in real-time as you make changes.

CloudManager (Admin Portal)

The CloudManager GUI is the admin control plane for the entire cluster. It provides global configuration, tenant lifecycle management, monitoring, and system visibility across every tenant.

Access the Admin GUI at its direct address on the control node, https://<control node>:8443, or publicly at the admin portal's address: https://admin-<cluster>.<default domain> (https://admin.<default domain> on a cluster installed before addresses carried its name), or the subdomain you gave it on the Domains card.

The Config tab holds the platform's settings as cards, in this order: Admin Authentication, Licence and Tenant Defaults; Cloudflare, Domains and Service Tunnels; then the Version. Each card is as wide as its content, and a row holds as many cards as the screen allows; a card's Save is always its last line, at its bottom right, in every card of both portals. On a narrow screen each row of the Domains and Service Tunnels tables is a block of labelled lines, and on a phone the cards are one column. The tenant portal's Config page lays its cards out the same way. The provider's network settings are not a card: they are the Provider strip under the page's header, on every tab.

Admin Authentication Card

Displays the admin username and the admin API token used for privileged endpoints. Use this token as the X-Admin-Token header when creating tenants or managing global settings. Once the API is published (the Domains card), the card shows its address, the API URL, too. At the card's foot:

  • Download credentials — the administrator's credentials.json for a script or an AI agent that manages the platform: JSON with api_url and admin_token (the tenant's file carries api_url, tenant_id and token). Keep it out of version control — the admin token reaches every tenant. Until the API is published there is no address to put in it, and the card says so.
  • Change password — the same form and rules as a tenant's (Change Password), for the password you sign in to this portal with. The installer's copy of the first password, in its credentials.json, no longer signs in after a change.

Click Change password at the card's foot: your current password, the new one, and the new one again, then Save.

CloudManager Admin Authentication card
Admin Auth

Cloudflare Card

Shows the Cloudflare account the platform uses and the portals' addresses: admin-<cluster>.<default domain>, user-<cluster>.<default domain> and api-<cluster>.<default domain> (on a cluster installed before addresses carried its name, admin.<default domain> and so on), then the container registry's and the email service's, or not published; while you change the Domains card they follow as a preview, and after a save they show what was saved. A cluster installed with an account from your Circloud profile needs nothing entered here once you approve it; until then the card says Waiting for your approval on your Circloud profile. To change its token, replace the token on your profile.

On a cluster installed without an account from the profile, enter the Account ID and the token here (Cloudflare Setup) and save. The token is not shown again once saved. The domains are on the Domains card below, where the default is chosen. Moving the platform to another Cloudflare account is confirmed first, and every domain in use has to be on the new account too; when the new account does not have the default domain, the card lists its domains and asks which one becomes the default. While cloud storage uses the account, a token for another account is refused.

CloudManager Cloudflare card
Cloudflare Configuration

Domains Card

Every domain on the Cloudflare account, as last fetched from Cloudflare — the page opens without asking Cloudflare. The platform fetches the list by itself every 5 minutes; click Refresh to fetch it at once, for example right after adding a domain to the account. When a fetch fails, the line above the table says when and why, and the list stays as the last good fetch left it. A domain that disappears from the account is marked Missing rather than dropped while a tenant or a tunnel still uses it; hover a domain's name to see what uses it.

  • Tenant — the tenant the domain is assigned to; a dash when no tenant holds it. A domain is assigned to one tenant only. On a cluster installed before this rule, a domain may still be assigned to more than one tenant: the card names them in the warning colour, and nothing is taken from any of them until you remove the domain from all but one (Tenants, Config → Domains). The platform's own addresses are not a tenant's: the default domain, and the portals and API published on it, may be a domain a tenant holds; an address already in use is refused, whichever side asks for it.
  • Default — the platform's default domain: where the platform's own addresses are published. It is the platform's alone. Tenants' domains are independent of it: setting or changing the default touches no tenant's domains and no tenant address. A tenant gets its domains by requesting them (you approve) or from its card, Config → Domains, and its first one becomes its default; a tenant with no domain cannot publish an address, and tunnels published on the platform's domain before this keep their address. Only a domain that is active on the account can become the default.
  • Admin portal, User portal, API — the platform's own three portal addresses, published on the default domain. Switch a service on to publish it and set its subdomain (admin-<cluster>, user-<cluster> and api-<cluster> unless you change them, where <cluster> is the cluster's label; admin, user and api on a cluster installed before addresses carried its name). A box left empty stands for that default, which it shows as its placeholder. Every control is greyed out except on the default's row, and a subdomain box stays greyed out until its service is switched on.
  • Container registry — the platform registry tenants push their images to (registry-<cluster> unless you change it, registry on an older cluster; see The Platform Registry). It is published only with the API, which checks its logins. On a cluster installed before it, it shows switched on beside a published API, with a ! until the next Save publishes it.
  • Email — the email service, where every message of the tenants' email domains reaches the platform (email-<cluster> unless you change it, email on an older cluster). The platform publishes it by itself with the cluster's first email domain, unless you switched it off on this card. While an email domain exists, switching it off is refused: Email cannot be unpublished: the mail of … arrives through it. Those email domains are removed first, by their tenants.

Nothing changes until you click Save. A save publishes what is switched on and not published yet, removes what is switched off, and moves what changed address — a new subdomain, or a new default domain. A move or a removal is confirmed first, in a dialog that says exactly which addresses change. While the admin portal's own address moves, the page is locked and shows each portal moving in turn (the admin portal last, because it serves the page), then sends you to the new admin address once it answers. A ! beside a service means an earlier save did not complete for it; hover it for what is left, and save again to finish.

The admin portal cannot be left without an address. Switching it off is refused while its address is the only working one it has, because you would lose access to this page. To take it off the default domain, first add a second admin address (below). Once that address answers, switching it off is allowed: the platform checks, through Cloudflare, that the second address answers before it removes anything, and the page takes you there.

The card publishes one address for each portal. A second address for the admin portal is added over the API (the API tab); it then shows on the Service Tunnels card, below, with a remove button (×).

CloudManager Domains card
Domains

Service Tunnels Card

Under the Domains card: the tunnels the platform's own portals are published through, the container registry's and the email service's among them (the tenants' tunnels are on the Tunnels tab, below). Each row shows the service, the tunnel name, the protocol, the public hostname and a status probe. A tunnel published by a save appears straight away with an orange Starting probe, which turns green Active once its connector answers; click a probe for its detail. A probe reads Unknown when the monitor has not reported the connector for a couple of minutes. An older tunnel that shares a connector with the one a service is published through now reads Not managed, and saves leave it alone.

The Domains card's own tunnels are removed by switching them off there. Every other row — an older tunnel, a second address added through the API — has a remove button (×) at the end of its public hostname. Removing one never stops a connector another tunnel still uses, never deletes a Cloudflare tunnel that is not this platform's alone or that sits on a domain it does not use (only the row goes then), and never takes the admin portal's last working address.

CloudManager Service Tunnels card
Service Tunnels

Provider Strip

Under the page's header, on every tab, one compact line shows the provider's networking settings: its name, the external subnet CIDR, its gateway, the management network and the excluded IP ranges. These values define how external access is allocated for pods. On a narrow screen the line wraps.

CloudManager Provider strip
Provider Networking

Tenant Defaults Card

Sets default resource limits for new tenants (pods, storage, VPCs, subnets, CPU, RAM). These defaults are applied when a tenant is created without explicit resource caps. Click Save to update.

CloudManager Tenant Defaults card
Tenant Defaults

Version Card: Upgrading the Platform

Beside the Licence card, the Version card shows the platform version the cluster runs, and upgrades it from this page: no installer, and no sign-in to a node. Circloud names its newest release at each of the cluster's check-ins, about every 15 minutes; the Licence card's Check now asks within a minute.

What the card shows:

  • Up to date — <version> · Up to date, and when the cluster last checked with Circloud.
  • A newer release — <version> · <newer> is available, and Upgrade. It asks once, Upgrade to <newer>: the portals restart during the upgrade, which takes 10 to 20 minutes, and tenants' workloads keep running.
  • Upgrading — Upgrading to <newer> · started 14:02 UTC by the administrator who asked, the step in flight under it, and six steps, each Done, Running or Waiting: Download, Registry, Images, Services, Finish and Checks. The portals restart halfway: the page keeps asking, and shows the progress again once they are back.
  • Done — Upgraded to <newer> at 14:19 UTC, with how many of the platform's checks passed, and Reload while the page itself is still the old version.
  • Stopped — a warning with the reason and its code, followed by Every step is safe to run again. Upgrade is offered again. An upgrade that stops reporting for 10 minutes, because the control node restarted for example, is shown as stopped: The upgrade stopped reporting at 14:10 UTC.

The upgrade runs on the control node by itself — the same upgrade the installer runs — so neither the portals' restart nor a closed page stops it. One operation changes the platform at a time: an upgrade, from either side, the installer's Extend or a node's removal. One started while another runs stops at once, nothing changed, with Another platform operation is running on this cluster (E506): upgrade again once the other has ended. A finished upgrade checks in with Circloud at once, so your profile shows the new version within a minute.

A cluster on platform 1.7.54 or an earlier release is upgraded once with the installer; from then on, from this card. If the card says The control node needs one upgrade from the installer first, run the installer's Upgrade once.

The other way: the installer. On the cluster's card in the installer, click Upgrade: it checks for the newest release and runs the same upgrade over SSH. The card reads the version from the cluster when it connects, so an upgrade made from the admin portal shows there too.

Monitoring Tab

Cluster overview for tenants, VPCs, pods, and node utilization. A status line stays in view on every sub-tab: live, last update, the monitor's state and the node it runs on, and an Internet summary of every VPC that opens the Internet sub-tab. Three sub-tabs sit below it:

  • Nodes — in two columns. First the cluster's tiles, each a large figure — CPU and memory in use against capacity, each with what pods have reserved against what the nodes can allocate and a line of the last hour; storage; network traffic received and sent by all nodes with its last 60 seconds; and the number of tenants, VPCs and pods, each with a dot for each one in its state and the worst of them named — beside per-node metrics with how many tenants' pods each node runs. Under them, the highest-usage pods with the node each runs on, to find hotspots, beside each tenant's quota with what its pods have reserved and what they actually use. On a narrower screen the four stack in that order.
  • Internet — the Internet and DNS verdict of every VPC on the cluster, each named with its tenant, and every VPC's internet and DNS over time, beside the in-cluster speed test (runnable on any tenant's VPC).
  • Trends — resource trends per node and per VPC, from the last hour up to a year, on the same black charts as the tenant's.

The board shows the tenants' workloads, not the services the platform runs on: a VPC's cloud storage service is listed with the VPC's own services, on its Core Services tab.

The tab reopens on the sub-tab last chosen in that browser.

CloudManager Monitoring tab, Internet sub-tab
Monitoring — Internet sub-tab
CloudManager Monitoring tab, Trends sub-tab: black trend charts per node and per VPC
Monitoring — Trends sub-tab, per node and per VPC

Nodes Sub-tab

On the Monitoring tab, and the one it opens on. The cluster's tiles beside the health and utilization of every node, including CPU, RAM, storage, GPU metrics, and network traffic; then the highest-usage pods beside each tenant's quota. Use this to confirm node capacity, detect failures and see who is near a limit.

  • Pods (nodes table) — how many tenants' pods the node runs. Every running replica counts (one still starting, failed or finished does not); the platform's own services are not counted.
  • Node (top pods table) — the node the pod runs on; a pod with replicas on several nodes lists each of them.
CloudManager Monitoring tab, Nodes sub-tab
Nodes

Tenants Tab

Create, search, and delete tenants. The Allow tenant self-signup toggle controls whether the CloudUser login page shows the Create Account option.

  • Create Tenant: Provide name + password, optionally set resource caps.
  • Delete Tenant: Click the × on a tenant card to remove the tenant and all resources — its cloud storages and its whole off-site space too, unless the dialog's switch is off (see the Storage tab, below).
  • Resources: Set per-tenant limits (pods, storage, VPCs, subnets, CPU, RAM), and the two daily email limits (below).
  • Domains: Add domains to a tenant and approve or reject its requests; its first domain becomes its default for new tunnels, and deleting its default makes another of its domains the default (the one most of its addresses sit on, else its oldest). A tenant with none cannot publish an address: its card's tunnel form says so and opens the moment you add or approve its first domain. A domain is assigned to one tenant only: adding a domain another tenant holds is refused, naming that tenant. Approve is available only when the requested domain is on the Cloudflare account, active there, and no other tenant holds it — otherwise it is greyed out, and the reason shows under the domain. Adding a domain follows the same rule, with the same sentence. A domain still pending at Cloudflare (its nameservers not switched yet) waits until it is active: the domain list refreshes every 5 minutes and shows when it is. Reject asks for confirmation and an optional reason, which the tenant sees beside the rejected request.
  • Registry: Manage tenant registry credentials.
  • Topology: View or apply tenant topology JSON.
  • VPCs / Pods: Admin view of tenant networks and workloads, including pod actions, and each VPC's Migrate internal and Migrate external (below).
  • Email: the tenant's email, read-only (below).
CloudManager Tenants tab
Tenants
Create Tenant form
Create Tenant (with Resource Limits)

A Tenant's DB Clusters

A tenant's VPC card reads Pods · DB Clusters · Cloud Storage here too. The DB Clusters tab lists the VPC's DB clusters as the tenant sees them, read-only: no create form, no operation, and never a password — the connection shows the addresses, the database and the username. Details shows its settings, instances, operation, backups and operations log, and its open Alerts:

  • DB instance unreachable — an instance runs without its address in the VPC, so applications cannot reach it. The platform recreates it on the same volume.
  • DB cluster backups failing — its write-ahead log has not reached its cloud storage for several minutes: its backups stop at that moment, and a restore cannot reach past it.

Both are on the Alerts tab too, and the tenant has its own copy. The changes are the tenant's to make, from its portal or the API.

The admin portal's DB Clusters tab of a tenant's VPC: a DB cluster's details, read-only, with its connection without a password and its alerts
A tenant's DB cluster, read-only, in the admin portal

A Tenant's Email

A tenant's card has an Email tab, read-only: the tenant's email domains, each with its status and the records the platform added at Cloudflare (Catch-all, DKIM, DMARC), their addresses, on or off, and what each address sent and received today. Never what the mail says. The line above the table gives the day's total against the tenant's limit, and the DB cluster that keeps its mail.

Every tenant sends from the cluster's one internet address, which the receiving mail servers judge for all of them, so sending has two daily limits: the tenant's (200 emails a UTC day) and each of its addresses' (100), each recipient counting as one. An address's limit is never more than its tenant's.

Set them under Resources → Set resources: Emails a day and Emails a day per address, empty for the defaults. The Resources cards show Emails today against the tenant's limit.

A tenant's Email tab in the admin portal: its email domain, active, with the records the platform added, its address, and what it sent and received today against the tenant's limit
A tenant's email, read-only, in the admin portal

Migrate Internal: Other Nodes of This Cluster

Every VPC on a tenant's VPC list has two buttons: Migrate internal, to other nodes of this cluster, and Migrate external, to another cluster (the tenant has the second one on its own VPC).

Migrate internal opens its card in a pop-up, with the cluster's nodes as switches, on the Nodes: line. The ones switched on are the nodes chosen for the VPC the last time it was migrated — or, for a VPC never migrated, the nodes it runs on now. A node pods cannot be moved to (not ready, not taking new pods, or taking no tenant pods) is greyed out with the reason beside it, and the control node is labelled as such. Switch on the nodes the VPC should run on and switch off the ones it should leave: the card shows What would move — only the tenant's pods that have to move, each with its steps, where it is now and the nodes it goes to — or, in one sentence, why it cannot. Each node in the table has a bar for its CPU and one for its RAM, showing what the node's pods reserve of what it can allocate (what decides whether a pod fits on it), with a mark inside for what is in use, and a bar for its disk in use of its size; a line under the table says so, and hovering a node gives the figures. A pod already on one of the chosen nodes is not touched, not even restarted. With the nodes recorded for the VPC, the table is empty, says so, and Start stays greyed out; for a VPC whose nodes were never chosen, Start records them: nothing moves, the table says that from then on the VPC stays on those nodes, and a warning above it says what that means — its new pods start only on those nodes, and wait while none of them can take one. What the platform runs for the VPC itself (its name service, its monitor, its cloud storage access and its addresses' connectors) follows it and is not listed. Nothing moves until you press Start and confirm; the confirmation says which pods move and what is interrupted during the migration — cloud storage access pausing for a moment, or the VPC's public addresses reconnecting, included.

The migration runs in the platform, one pod at a time, each running again before the next one goes. A pod with persistent storage is stopped while its data is copied to the new node and checked; it starts on that node, and its old copy is removed only once it is ready. Stopped pods and tunnels stay stopped. If a step fails before its pod has switched over, that pod is put back where it was and the migration stops; pods that had already moved stay on their new nodes. Only when nothing had moved does the VPC go back to its previous nodes. The table stays on the card and follows the migration step by step, a bar under each step's state showing how far it is; the card cannot be closed until the migration has finished. A step that does not finish says which pod is not ready on which node, and why. Once the migration has set the nodes — the first thing it does — every new pod of the VPC (a copy its autoscaling adds, one that replaces a copy on a failed node, a pod started) goes to the chosen nodes, and pods that stay are not restarted. Of a pod with several copies, only the copies on other nodes move. The one exception is a pod with auto-healing or autoscaling last started or restarted before the platform's current version: until it is started or restarted again, a new copy of it may start outside the nodes (the administrator is told: Pods outside the VPC's nodes), and the first time one of its copies has to move, all of its copies may restart onto the nodes, once, one at a time. Removing a node from the cluster (the installer's Shrink) moves its pods with this same migration.

Migrate external, the second button, opens the card that migrates the VPC to another cluster of the platform, into an existing tenant of that cluster: the target cluster, from the list of the other clusters on this cluster's Cloudflare account, the target tenant ID and the target tenant API token, Check, Start — the same card a tenant has on its own VPC (see Migrate External). No administrator of either cluster takes part, and when the migration finishes the VPC is deleted from this cluster.

A VPC's Migrate internal card: the nodes as switches and what would move
Migrate internal — choose the nodes, see what would move before anything does

Tunnels Tab

Every tenant's tunnels in one table — tenant, VPC, pod, hostname, protocol, status and when it was created — with a filter by tenant above it; the table refreshes with the page, and the filter stays as you set it. A tunnel is stopped, started or deleted on its tenant's card (Tenants → the VPC's Tunnels tab); the platform's own addresses are the Config page's Service Tunnels card.

The admin Tunnels tab: every tenant's tunnels with a tenant filter
The Tunnels tab — every tenant's tunnels, filtered by tenant

Storage Tab

Two tables, as on a tenant's Storage tab, for every tenant and with a Tenant column. Persistent Storage lists every pod with persistent storage: how much its folder holds, the cluster, its tenant, VPC and subnet, the node the folder is kept on, and its cloud storage. Cloud Storage (S3) lists every cloud storage of every tenant, with its UUID, the pods using it, its DB clusters, how much it holds and when it was made (or assigned), and every one on the Cloudflare account that no tenant of this cluster holds: made by another cluster connected to the same account, by an earlier install, or by a tenant deleted since. Those show No tenant. A space on the account that the platform did not make is one cloud storage too, marked External. A storage shows once it holds at least one file. The platform looks at the account every 15 minutes and every time the Cloudflare card is saved.

CloudManager Storage tab: Persistent Storage and Cloud Storage (S3), every tenant's
Storage — every tenant's persistent storage and cloud storages

Refresh, in the Cloud Storage table's title bar, looks at the account at once. A storage no tenant holds has Assign: a pop-up with the cluster — this one, or another cluster on the same Cloudflare account — that cluster's tenants, and the name the tenant sees it by. A storage is deleted with the × on its row; while cloud storage is not configured the delete of a storage this cluster created is greyed out, and hovering it says what to do: save a token with API Tokens: Edit under Account in Config → Cloudflare, and the platform sets cloud storage up from it. An assigned storage has Take over on its row.

Only a storage no pod uses can be deleted, and one this cluster created goes with every file in it. An assigned storage keeps its UUID and its files, appears on that tenant's Storage tab and in their pod form, marked Assigned, and their pods use it in any of their VPCs. This cluster never deletes an assigned storage's files: deleting it removes it from this cluster, keeps its files, and from then on none of that tenant's pods can reach it. One that holds files of a current tenant of this cluster (its record on this cluster lost) can only go back to that tenant, and is then its own again. An external one is assigned like any other, is never deleted by the platform, never taken over, and given to no pod. Deleting a storage no tenant holds deletes it from the Cloudflare account, with every file in it: this cluster cannot tell whether another cluster on the same account still uses those files, so delete only what you know is left over.

Given to a tenant of another cluster on the same Cloudflare account, the storage is handed to that cluster, which assigns it to its tenant within a minute, with its own rules. Until then its row says Requested and that tenant; once assigned, the Tenant column shows that tenant and its cluster, and the storage is neither assigned nor deleted on this cluster again — it is that cluster's. A cluster that refuses it says why, on the row's Refused, and the storage is offered again. The other clusters are your clusters connected to the same Cloudflare account and approved on your Circloud profile; one is offered in the pop-up once it has listed its tenants on the account, a few minutes after it is connected.

A storage marked Temporary carries a pod's persistent storage to another cluster while its VPC migrates to it: it is never assigned, taken over or given to a pod, no delete takes it while the migration runs, and the migration deletes it when it ends.

Take over is for a storage whose cluster is gone (an earlier install, a deleted tenant): this cluster then manages it as its own, and deleting it, or its last pod, deletes its files. A storage that went to another cluster with a migrated VPC cannot be taken over: that cluster uses its files. Files another cluster wrote before cloud storages had a UUID show as Unidentified and a short id; they cannot be assigned. The cluster that wrote them may still use them: delete them only when you know it does not. Take over and every delete from the account ask you to type the name shown, and all of them are recorded in the Ops Log.

Deleting a tenant takes its cloud storages with it, emptied before the delete answers — unless the delete dialog's Also delete its cloud storages is switched off (over the API, delete_cloud_storage=false), which keeps the storages' files on the account for the next Refresh to list and assign to another tenant. One delete removes up to 10,000 files: a tenant with more is refused with a sentence that says how many went, and each repeat of the delete removes the next batch.

A VPC's cloud storage answers through two proxies on different nodes, sharing its address, https://cloud-storage: when the node of one fails, the other answers within seconds. When one has not answered for ten minutes — its node is down, it waits for a node, or it keeps restarting — the alert Cloud storage on one proxy names the VPC: if the remaining one or its node fails too, the VPC's storage calls fail until a proxy answers again. The alert is yours alone: the tenant's storage still answers, and nothing in it is the tenant's to do. A VPC with a single node runs on one proxy by design, and raises no alert.