Download
Download the latest installer bundle from the official endpoint:
The bundle contains:
circloud-installer(single binary that installs the cluster + platform)lab-config.yaml(template for VM sizing, nodes, and Cloudflare settings)scripts/(PowerShell helpers for Hyper-V VM lifecycle)scripts/setup_image.sh(WSL helper to prep the base VHDX image)state/template_vm-facts.json(template for physical host installs)
Self-Hosting Installation
Circloud provisions its own Kubernetes lab and networking stack on your VMs or physical machines. It includes the GUI, API, VPC/subnet routing, and Cloudflare tunnels so you can expose apps securely using your own domain.
Prerequisites
Hardware
Minimum 4 nodes: 1 control plane + 3 workers. Each node needs 4+ GB RAM, 2+ CPU cores, 50+ GB disk.
Network
All nodes must be on the same network with internet access. Static IPs recommended.
Cloudflare
A Cloudflare account with a domain, Account ID, and API Token with Tunnel and DNS permissions.
Tools
WSL2 (for Windows) or Linux, PowerShell 7 (Hyper-V only), kubectl, git.
C:\Users\YourName\projects\circloud) accessible from both Windows PowerShell
and WSL via /mnt/c/.... Do NOT use a WSL-only path like ~/projects.
Configuration (lab-config.yaml)
Create or edit lab-config.yaml in the project root:
base_vhdx_path: vhdx/ubuntu-22.04-server.vhdx
vm_root_path: 'C:\Hyper-V\circloud'
vswitch_name: LAN-Switch
dataplane_switch_name: K8s-dp-LAN-Switch
dataplane_cidr: 11.0.0.0/24
dataplane_gateway: 11.0.0.1
dataplane_nat_name: K8s-dp-LAN-Switch-nat
pod_dns_nameservers:
- 4.2.2.4
pod_dns_ndots: 1
cpu_count: 4
memory_gb: 12
# Cloudflare Tunnel configuration (REQUIRED)
# Leave blank to be prompted during installation
cloudflare_account_id: your-cloudflare-account-id
cloudflare_api_token: your-cloudflare-api-token
cloudflare_domain: yourdomain.com
nodes:
- name: cp
role: control
- name: w1
role: worker
gpu: true
- name: w2
role: worker
- name: w3
role: worker
- name: w4
role: worker
- name: s1
role: storage
Cloudflare credentials can be added to lab-config.yaml to avoid prompts; otherwise the installer will request them during setup.
Cloudflare Tunnel Configuration (Required)
Cloudflare Tunnel credentials are required for CloudManager deployment. Put them in
lab-config.yaml to avoid prompts; otherwise the installer will ask for them during setup.
Since lab-config.yaml is tracked, avoid committing real secrets.
How to obtain these values
- Cloudflare Account ID: Log in to Cloudflare Dashboard, select your domain, and find the Account ID on the Overview page.
- Cloudflare API Token: Go to API Tokens, click "Create Token", and use the "Edit Cloudflare Zero Trust" template or create a custom token with:
- Account > Cloudflare Tunnel > Edit
- Zone > DNS > Edit
- Cloudflare Domain: Use a domain you own and have added to Cloudflare (example: example.com).
What gets exposed after deployment
https://api.yourdomain.com- CloudManager APIhttps://admin.yourdomain.com- CloudManager Admin GUIhttps://yourdomain.com- CloudUser GUI (tenant portal)
Tenants can also create tunnels for their workloads using either the global domain or custom domains assigned by the admin.
Binary Installer (WSL)
Extract the bundle and run the installer from WSL:
tar -xf circloud-<version>.tar.gz
cd circloud-<version>
./circloud-installer
Step 1: Prepare Base Image (Hyper-V Only)
Skip this step if using physical machines.
# From WSL (using Windows filesystem path):
cd /mnt/c/Users/YourName/projects/circloud
./scripts/setup_image.sh
This downloads Ubuntu cloud image and prepares it for VM creation.
Step 2: Provision VMs (Hyper-V Only)
Skip this step if using physical machines. Instead, create state/vm-facts.json manually.
# From Windows PowerShell (Administrator):
cd C:\path\to\circloud
.\scripts\create-vms.ps1
Creates VMs based on lab-config.yaml and outputs state/vm-facts.json.
Step 3: Configure Cluster
This is the main installation step that deploys Kubernetes and CloudManager.
# From WSL:
# For Hyper-V: use Windows filesystem path
cd /mnt/c/Users/YourName/projects/circloud
# For physical machines: can use any path
cd ~/projects/circloud
./circloud-installer
The script will:
- Prompt for missing Cloudflare credentials if not in
lab-config.yaml - Generate Ansible inventory from
state/vm-facts.json - Deploy Kubernetes cluster using Kubespray
- Deploy Harbor container registry
- Deploy CloudManager API, GUI, and database
- Install GPU drivers on GPU-enabled worker nodes
- Create Cloudflare tunnels for API and GUI access
GPU Support (Optional)
To enable GPU workloads, mark specific worker nodes with gpu: true in lab-config.yaml
before running the installer. The installer installs NVIDIA drivers and configures the GPU runtime
automatically. Pods can then request GPU access using gpu_access: true.
Step 4: Access the Platform
After installation completes, access the platform:
Local Access
API: https://localhost:8080
Admin GUI: https://localhost:8443
User GUI: https://localhost:8444
Public Access (via Cloudflare)
API: https://api.yourdomain.com
Admin GUI: https://admin.yourdomain.com
User GUI: https://yourdomain.com
These public URLs are derived from cloudflare_domain in lab-config.yaml. For example, if
you set cloudflare_domain: circloud.net, you will access the User GUI at
https://circloud.net, the Admin GUI at https://admin.circloud.net, and the API at
https://api.circloud.net.
# Verify installation:
export KUBECONFIG=$PWD/state/kubespray/inventory/mycluster/artifacts/admin.conf
kubectl get nodes -o wide
kubectl get pods -n cloud-manager
Physical Machine Setup
For physical machines, manually create state/vm-facts.json:
{
"s1": {"ipv4": "192.168.1.10", "role": "control", "user": "admin", "password": "yourpass"},
"w1": {"ipv4": "192.168.1.11", "role": "worker", "user": "admin", "password": "yourpass"},
"w2": {"ipv4": "192.168.1.12", "role": "worker", "user": "admin", "password": "yourpass"},
"w3": {"ipv4": "192.168.1.13", "role": "worker", "user": "admin", "password": "yourpass"}
}
Then run ./circloud-installer from WSL or Linux.
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.
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.
Persistent Pods
Pods can request node-local persistent storage by setting persistent: true (and optional
persistent_mount_path). Storage is created under /storage/<tenant-id>/<pod-id>
and mounted into the container (default mount path is /storage).
- Persistent pods are pinned to a single worker node selected by available storage.
- All replicas for a persistent pod stay on the same node (no cross-node replication).
- Storage is deleted when the pod is deleted, including cascade deletes via subnet/VPC/tenant removal.
Login
Use your tenant name and password to access the CloudUser dashboard. Your admin can provide the credentials, or you can create your own account if self-signup is enabled.
Create Account
If self-service signup is enabled by the admin, you can create a tenant directly from the login page. This option is hidden when self-signup is disabled.
Architecture
Circloud combines a FastAPI control plane with Kubernetes and Kube-OVN networking. The GUIs call the CloudManager API, which stores state in PostgreSQL and provisions VPC networking, pods, VIP services, DNS, and tunnels inside the cluster.
It is designed for independent developers, students, and startups who want cloud capabilities without hyperscale costs: run Circloud on local desktops (VMs) or on-prem servers, then expose apps securely through Cloudflare tunnels using a domain you own. For many workloads this is about 5% of the price of cloud infrastructure software on the market, making it practical for smaller teams.
Control Plane
Browser
|
|-- CloudManager GUI (admin)
|-- CloudUser GUI (tenant)
|
v
CloudManager API (FastAPI)
|-- PostgreSQL (state)
|-- Kubernetes + Kube-OVN (VPCs, subnets, pods, VIPs)
|-- Tunnel Manager (Cloudflare API + DNS)
|-- Harbor Registry (optional, internal images)
Tenant Data Plane
Tenant Namespace
VPC
+ Core Subnet (12.0.0.0/16)
- tenant-dns (2 replicas)
- tunnel-service pods (cloudflared)
+ Workload Subnets
- pods (replicas)
- VIP Service (stable IP)
- optional EIP + SNAT/FIP for internet
Setup & API Access
To use Circloud, you need your Tenant ID and API Token. These are available from your dashboard after logging in.
Step 1: Get Your Credentials
Log into the Dashboard
Visit the Circloud portal and log in with your tenant credentials.
Copy Your Tenant ID and API Token
Your credentials are displayed at the top of the dashboard. Click to copy them.
Step 2: Configure API Access
Use your API token with any HTTP client (curl, Postman, Python requests, etc.):
# Set your credentials
export TENANT_ID="your-tenant-id"
export API_TOKEN="your-api-token"
export API_URL="https://api.circloud.net"
# Test API access
curl -k -X GET "$API_URL/tenants/$TENANT_ID/vpcs" \
-H "X-Auth-Token: $API_TOKEN"
API Roles and Tokens
Circloud exposes two authentication scopes:
| Scope | Header | Used For |
|---|---|---|
| Admin | X-Admin-Token |
Tenant lifecycle, domains, provider config, service tunnels |
| Tenant | X-Auth-Token |
VPCs, subnets, pods, tunnels, topology |
Many create endpoints also expect the token field in the JSON body. The header is still required
and is the primary authentication check.
Step 3: Deploy Using Topology JSON
Create a topology.json file to define your infrastructure:
{
"token": "YOUR_API_TOKEN",
"vpcs": [
{
"name": "my-vpc",
"description": "My VPC",
"enable_internet": true
}
],
"subnets": [
{
"name": "my-subnet",
"vpc_name": "my-vpc",
"cidr": "10.100.1.0/24",
"gateway_ip": "10.100.1.1"
}
],
"pods": [
{
"name": "my-app",
"vpc_name": "my-vpc",
"subnet_name": "my-subnet",
"container_image": "nginx:latest",
"replica_count": 2,
"service_port": 80,
"external_access": true,
"auto_scaling": true,
"autoscale_max_replicas": 6,
"autoscale_cpu_target_millicores": 250
}
]
}
Deploy with a single command:
curl -k -X POST "$API_URL/tenants/$TENANT_ID/topology" \
-H "Content-Type: application/json" \
-d @topology.json
Using Private Container Registries
To pull images from private registries (Docker Hub, Harbor, etc.), add registry credentials:
{
"token": "YOUR_API_TOKEN",
"registry_credentials": [
{
"name": "dockerhub",
"server": "https://index.docker.io/v1/",
"username": "your-username",
"password": "your-access-token"
}
],
"vpcs": [...],
"subnets": [...],
"pods": [...]
}
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.
Creating a VPC
From the Dashboard
Navigate to the VPCs tab and click "Create VPC". Enter a name and choose whether to enable internet access.
Via API
curl -k -X POST https://api.circloud.net/vpcs \
-H "X-Auth-Token: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"tenant_id": "YOUR_TENANT_ID",
"token": "YOUR_TOKEN",
"name": "production-vpc",
"enable_internet": true
}'
Core Services Subnet
Every VPC automatically includes a managed core subnet reserved for platform services. This subnet is created and maintained by Circloud and is not intended for user workloads.
- Hosts tenant-dns pods (2 replicas) for internal name resolution
- Hosts tunnel-service (cloudflared) pods when you create tunnels
- Provides 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 |
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.
Creating a Subnet
curl -k -X POST https://api.circloud.net/subnets \
-H "X-Auth-Token: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"tenant_id": "YOUR_TENANT_ID",
"token": "YOUR_TOKEN",
"vpc_id": "VPC_ID",
"name": "web-tier",
"cidr": "10.100.1.0/24",
"gateway_ip": "10.100.1.1"
}'
DNS & Service Discovery
Each VPC includes a dedicated DNS service (dnsmasq) running in the core subnet. 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 -> tenant-dns (core subnet) -> external DNS forwarder
Record Format
Pods and VIP services are registered automatically. Names are stable even when pods restart.
web.my-tenant.svc.k8s-lab
web.my-tenant
web
HA for DNS
DNS runs two replicas in the core subnet. 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.
Pods
Pods are the deployable units that run your containerized applications. Each pod can have multiple replicas for high availability and automatic load balancing.
Creating a Pod
curl -k -X POST https://api.circloud.net/pods \
-H "X-Auth-Token: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"tenant_id": "YOUR_TENANT_ID",
"token": "YOUR_TOKEN",
"vpc_id": "VPC_ID",
"subnet_id": "SUBNET_ID",
"name": "web-server",
"container_image": "nginx:latest",
"replica_count": 2,
"service_port": 80,
"external_access": true,
"external_inbound": true,
"auto_scaling": true,
"autoscale_max_replicas": 6,
"autoscale_cpu_target_millicores": 250
}'
Pod Options
| Option | Description |
|---|---|
replica_count |
Replica count (1-10). If auto_scaling is true, this is the initial replica count (min 2) |
service_port |
VIP service port for load balancing and tunnels (default 80) |
use_registry_credentials |
Use tenant registry secret for image pulls (default true) |
external_access |
Enable outbound internet via SNAT |
external_inbound |
Enable inbound access with external IP |
auto_healing |
Auto-restart pods on failure |
auto_scaling |
Enable autoscaling with HPA (CPU-based) |
autoscale_max_replicas |
Maximum replicas when autoscaling (default 10) |
autoscale_cpu_target_millicores |
Target average CPU usage per pod in millicores (default 200) |
Pod Actions (Actions Column)
Actions appear on the first row of each pod group.
| Icon | Action |
|---|---|
| ▶ | Start a stopped pod workload |
| ■ | Stop the pod workload |
| ↻ | Restart the pod workload |
| + | Add a replica (up to 10) |
| × | Remove a replica (minimum 1) |
| × | Delete the pod and its resources (persistent storage is removed) |
The amber × is for replica removal; the red × is for deleting the pod.
When autoscaling is enabled, manual replica changes are ignored and HPA controls scaling.
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)
Autoscaling (HPA)
Enable auto_scaling to create a Kubernetes HorizontalPodAutoscaler based on average CPU usage.
Auto-healing is implied (pods are managed by a Deployment), 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.
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 (only available when the pod is Ready).
# Example commands inside the console
whoami
df -h
ls -la /storage
Pod Status, Auto-Healing, and HA
Pod status is refreshed by a monitoring job that polls Kubernetes and writes status records to the CloudManager database. The dashboard displays per-replica status, IP address, and restart count.
Status Probes (Pods + Nodes)
Probes are shown as colored emoji indicators in the Pods, System Pods, and Nodes tables. Hover a probe to see the status tooltip.
| Probe | Meaning |
|---|---|
| 🟢 | Ready / Fresh (healthy) |
| 🟡 | Pending / Not Ready / Stale |
| 🔴 | Failed / Offline |
| ⚪ | Unknown (no data yet) |
Node probes are based on the last metrics update time: ≤30s = Fresh (green), ≤60s = Stale (yellow), >60s = Offline (red).
Status States
| Status | Meaning |
|---|---|
ready |
Pod is running and Ready condition is true |
not_ready |
Pod is running but not Ready |
pending |
Pod is being scheduled or pulling images |
failed |
Pod has failed or is in an Unknown phase |
unknown |
Status has not been observed yet |
Status records include the observed pod IP, Kubernetes phase, and restart count.
Auto-Healing
When auto_healing is enabled, pods are created as Deployments so Kubernetes recreates them on
failure. For replicated pods, each replica is managed by its own Deployment. Restart counts in the UI
help identify unstable workloads.
When auto_scaling is enabled, a Kubernetes HPA manages the Deployment. The UI shows the live
replica count as the HPA scales up and down based on CPU usage.
High Availability
For replica_count greater than 1, a single VIP service load-balances across replicas. DNS points
to the VIP, so clients are insulated from individual pod restarts.
client -> VIP service -> replica pods
Web Terminal
The terminal opens an interactive /bin/sh session via a WebSocket connection. Terminal access
is only available when the pod is running and Ready.
WebSocket endpoint: /ws/exec/<namespace>/<pod_name>.
If your image does not include /bin/sh, use a base image that provides a shell.
Registry Credentials
Registry credentials let your pods pull private images. Credentials are stored in the tenant database
and synchronized to a Kubernetes secret named <tenant>-registry-creds.
API Example
curl -k -X POST https://api.circloud.net/tenants/TENANT_ID/registry-credentials \
-H "X-Auth-Token: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "dockerhub",
"server": "https://index.docker.io/v1/",
"username": "myuser",
"password": "mytoken"
}'
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).
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 pod in the core subnet, 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.
Supported Protocols
HTTP
Standard web traffic for websites, REST APIs, and web applications. Cloudflare handles SSL/TLS termination automatically.
protocol_type: "http"
HTTPS
End-to-end encrypted traffic for services that handle their own TLS certificates internally.
protocol_type: "https"
SSH
Secure shell access for remote terminal and file transfer. Connect using cloudflared access ssh.
protocol_type: "ssh"
TCP
Generic TCP for databases (PostgreSQL, MySQL, Redis), RDP, and custom protocols.
protocol_type: "tcp"
UDP
UDP tunneling for gaming servers, VoIP, DNS, and real-time streaming applications.
protocol_type: "udp"
Creating Tunnels by Protocol
HTTP Tunnel (Web Applications)
For web applications, REST APIs, webhooks, and microservices:
curl -k -X POST https://api.circloud.net/pods/POD_ID/tunnel \
-H "X-Auth-Token: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"tunnel_name": "web-app",
"subdomain": "app",
"protocol_type": "http",
"service_port": 80
}'
# Access at: https://app.yourdomain.com
# SSL/TLS is automatic - no certificate management needed
HTTPS Tunnel (End-to-End Encryption)
For services that already handle TLS internally or require mTLS:
curl -k -X POST https://api.circloud.net/pods/POD_ID/tunnel \
-H "X-Auth-Token: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"tunnel_name": "secure-api",
"subdomain": "api",
"protocol_type": "https",
"service_port": 443
}'
# Traffic is encrypted end-to-end from client to your service
SSH Tunnel (Remote Terminal Access)
For remote shell access, SFTP file transfers, and development:
curl -k -X POST https://api.circloud.net/pods/POD_ID/tunnel \
-H "X-Auth-Token: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"tunnel_name": "ssh-access",
"subdomain": "ssh",
"protocol_type": "ssh",
"service_port": 22
}'
# Connect using cloudflared CLI:
# cloudflared access ssh --hostname ssh.yourdomain.com
# Or configure in ~/.ssh/config:
# Host ssh.yourdomain.com
# ProxyCommand cloudflared access ssh --hostname %h
TCP Tunnel (Databases & Custom Protocols)
For PostgreSQL, MySQL, MongoDB, Redis, and any TCP-based service:
curl -k -X POST https://api.circloud.net/pods/POD_ID/tunnel \
-H "X-Auth-Token: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"tunnel_name": "postgres-db",
"subdomain": "db",
"protocol_type": "tcp",
"service_port": 5432
}'
# Step 1: Start local proxy with cloudflared
# cloudflared access tcp --hostname db.yourdomain.com --url localhost:5432
# Step 2: Connect to your database through the local proxy
# psql -h localhost -p 5432 -U myuser mydb
# mysql -h localhost -P 3306 -u myuser -p
# redis-cli -h localhost -p 6379
UDP Tunnel (Gaming, VoIP, Streaming)
For game servers, voice chat, DNS servers, and real-time applications:
curl -k -X POST https://api.circloud.net/pods/POD_ID/tunnel \
-H "X-Auth-Token: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"tunnel_name": "game-server",
"subdomain": "game",
"protocol_type": "udp",
"service_port": 27015
}'
# Connect directly: game.yourdomain.com:27015
# UDP traffic is tunneled through Cloudflare's global network
Using Custom Domains
If custom domains have been assigned, you can use them:
curl -k -X POST https://api.circloud.net/pods/POD_ID/tunnel \
-H "X-Auth-Token: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"tunnel_name": "custom-tunnel",
"subdomain": "portal",
"protocol_type": "http",
"service_port": 80,
"domain": "mycompany.com"
}'
# Access at: https://portal.mycompany.com
- 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
Tunnels in Topology JSON
You can also define tunnels inline when deploying pods via the Topology API:
{
"pods": [
{
"name": "web-server",
"vpc_name": "my-vpc",
"subnet_name": "my-subnet",
"container_image": "nginx:latest",
"service_port": 80,
"tunnels": [
{
"subdomain": "www",
"protocol_type": "http",
"service_port": 80
},
{
"subdomain": "ssh",
"protocol_type": "ssh",
"service_port": 22
}
]
}
]
}
Managing Tunnels
View and delete tunnels from the Tunnels tab on your dashboard, or via API:
# List all tunnels
curl -k -X GET https://api.circloud.net/tenants/TENANT_ID/tunnels \
-H "X-Auth-Token: YOUR_TOKEN"
# Delete a tunnel
curl -k -X DELETE https://api.circloud.net/tunnels/TUNNEL_ID \
-H "X-Auth-Token: YOUR_TOKEN"
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.
Exporting Your Topology
From the Topology tab, you can view your current infrastructure as JSON and download it for backup or version control.
Deploying a Topology
curl -k -X POST https://api.circloud.net/tenants/TENANT_ID/topology \
-H "Content-Type: application/json" \
-d '{
"token": "YOUR_TOKEN",
"vpcs": [
{
"name": "production",
"enable_internet": true
}
],
"subnets": [
{
"name": "web",
"vpc_name": "production",
"cidr": "10.100.1.0/24",
"gateway_ip": "10.100.1.1"
},
{
"name": "api",
"vpc_name": "production",
"cidr": "10.100.2.0/24",
"gateway_ip": "10.100.2.1"
}
],
"pods": [
{
"name": "nginx",
"vpc_name": "production",
"subnet_name": "web",
"container_image": "nginx:latest",
"replica_count": 2,
"service_port": 80,
"external_inbound": true,
"auto_scaling": true,
"autoscale_max_replicas": 6,
"autoscale_cpu_target_millicores": 250
}
]
}'
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 all namespaces.
Access the Admin GUI locally at https://localhost:8443, or publicly at
https://admin.<cloudflare_domain> based on lab-config.yaml.
Auth Tab
Displays the admin API token used for privileged endpoints. Use this token as the
X-Admin-Token header when creating tenants or managing global settings.
Cloudflare Tab
Configure Cloudflare integration: API token, account ID, base domain, and Access policy settings. These values are used when creating tunnels and DNS records. Click Save Cloudflare Config to persist the changes.
Provider Tab
Shows provider networking settings, including external subnet CIDR, gateway, management network, and excluded IP ranges. These values define how external access is allocated for pods.
T.Defaults Tab (Tenant Defaults)
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 Defaults to update.
Monitoring Tab
Cluster overview for tenants, VPCs, pods, and node utilization. Includes aggregate CPU/RAM/storage metrics and highlights of high-usage pods to help identify hotspots.
System Pods Tab
Shows two groups: K8s infrastructure pods (kube-ovn, coredns, etc.) and Circloud services (API, GUI, monitor). Each row includes status, node, resource usage, VIPs, tunnels, and actions. You can restart or delete workloads when actions are enabled.
Nodes Tab
Health and utilization for every node, including CPU, RAM, storage, GPU metrics, and network traffic. Use this to confirm node capacity and detect failures.
Service Tunnels Tab
Admin-managed tunnels for platform services. Shows protocol, hostname, origin URL, Access policy, and status. Use the delete action to remove a tunnel.
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.
- Resources: Set per-tenant limits (pods, storage, VPCs, subnets, CPU, RAM).
- Domains: Add custom domains to a tenant for tunnel creation.
- Registry: Manage tenant registry credentials.
- Topology: View or apply tenant topology JSON.
- VPCs / Pods: Admin view of tenant networks and workloads, including pod actions.
Support
Support the Circloud project with a donation.
Support Circloud Project
Donate