Create and run game servers that cost nothing while nobody is playing. Pick a game and a region and get an address players can connect to; an idle server can go to sleep and is woken in seconds by the next player who connects. Scale a fleet of identical servers with a game server group, capture a set-up server as a schematic so new ones start in seconds, run on spare capacity at a discount with spot, and hand ready servers to matches with AllocateGameServer.
Creates a game server and boots it.
Long-running: placement, boot, install and launch take minutes for a modded game. The operation completes when the server is accepting players.
parentstringRequiredgamestringRequiredThe game to run. Must be launchable — a branch node has no build.
namestringIdentifierprojects/{project}/locations/{location}/gameServers/{game_server}.
Project- and region-scoped, like every resource that consumes capacity: it runs somewhere specific, and it is billed to the project that owns it.
display_namestringsettingsmap<string, string>Overrides for the game's declared settings, by key.
machine_typestringThe size to run at, by machine type id — standard-4, highmem-2.
Empty takes the smallest type that meets the game's own declared minimum,
and a type below that minimum is refused, because a server too small for
its game boots, installs, and is killed for memory at the first player.
ListMachineTypes is the catalogue. Changing it takes effect on the next
start.
spotSpotConfigRun on spare capacity at a discount, and accept being reclaimed with two
minutes' notice. Pro plan only. See SpotConfig.
Changing it takes effect on the next start.
enabledboolRun on spot capacity.
on_demand_fallbackboolStart on demand, at the on-demand rate, when no spot capacity is free.
Without it a start with no spot capacity waits for some and fails after a
minute, which is right for a server that is only worth running cheaply and
wrong for one players are waiting on. A server that fell back stays on
demand until it next stops; SpotStatus.running_on_spot says which it is.
notice_signalstringA signal to send the game's process when a notice arrives, e.g. SIGUSR1.
Empty sends nothing, and that is the default for a reason: the default
action of most signals is to terminate, so a signal a game does not handle
would stop it two minutes early. Name one only when the game handles it.
SIGTERM and SIGKILL are refused — the stop that follows the notice
sends the game's own stop signal already.
labelsmap<string, string>service_accountstringThe identity this server acts as.
Leave it empty and Playpute creates one per server, allowed to touch this server and nothing else — the right default, since a server runs your players' mods.
Set it to a service account you own and the server acts as that instead. That is for a fleet: grant one service account a role elsewhere, attach it to twenty servers, and those twenty can use it while the rest of the account cannot.
Attaching one requires iam.serviceAccounts.actAs on that service account, not merely permission to create a server — otherwise anybody who could create a server could act as anybody.
ssh_public_keysrepeated stringInput onlySSH keys allowed to log in to this server, for debugging.
They take effect only on a server booted from an image that includes an SSH server, and are read when the server boots, so a key added later needs a restart. Input only: the keys are not returned when the server is read.
imagestringInput onlyThe image to boot, by id. Empty uses Plany's current default, which is what almost every server should do.
An id from Plany's own published images; a server cannot boot an image of your own.
ephemeralboolKeep nothing. The world and the disks go when the server does.
The right shape for a match rather than a world: a minigame round has nothing worth carrying into the next one, and an ephemeral server saves the storage and the time of keeping it.
An ephemeral server never sleeps, because there is nothing to wake into, so sleep_after_idle is refused on one.
Immutable after creation: the guarantee is about data that was never kept, so it cannot be turned off afterwards.
exposureExposureWhether players outside the project can reach this server.
Immutable after creation: it decides whether a listener and a public address exist at all, and flipping it on a running server would change the address players were given.
EXPOSURE_PUBLICEXPOSURE_PROJECT_INTERNALschematicstringThe schematic this server's disk was copied from, if any.
What makes a scaled fleet viable: the build is already unpacked, the install script has already run and the world already exists, so a member reaches RUNNING in seconds where a cold boot is minutes.
A copy, not an attachment. The schematic is read once into a fresh disk and never referenced again, which is why deleting one does not disturb a server started from it — and why two members from one schematic diverge immediately rather than sharing anything.
secretsrepeated SecretAttachmentSecrets this server can read: database passwords, API keys, RCON passwords, a licence key a game wants in a file.
Each attachment names a secret in the same project and region and says how the server sees it. The value is never stored on the server's configuration — the server fetches it when it starts, as its own identity — so nothing you can read back from the server reveals it.
Changing this takes effect on the next start. A running server keeps what it read when it started.
secretstringRequiredprojects/{project}/locations/{location}/secrets/{secret}, optionally with
/versions/{version}.
Unqualified is the ordinary case and resolves to the latest enabled version, so a rotation reaches this server on its next start with nothing to edit. Pin a version when a server must not follow a rotation — which is rare, and worth being deliberate about, because the pin outlives the memory of why it was made.
environment_variablestringRequiredThe environment variable the server sees the secret as, e.g. RCON_PASSWORD.
Required, and must be a valid variable name — upper case letters, digits and underscores, not starting with a digit. It is not derived from the secret's id, because stripe-live-key is not a variable name.
The value has to be valid UTF-8 to be used this way. A secret holding binary data is refused when the server starts; use file_path for one.
file_pathstringAlso write the value to a file at this path, relative to the build root.
For the things that will not go in an environment variable: a service account JSON, a TLS key, a licence file a game reads by path. Optional, and when it is set the environment variable is still exported, because a value that is available two ways is easier to use than one with a rule about when it is which.
Written 0600 and owned by the game user, and deliberately not preserved
across restarts the way a plany.game.v1.ConfigFile can be: this is the platform's copy
of a value the platform holds, so the file is rewritten every launch and a
rotation cannot leave a stale one behind.
sleep_after_idleDurationPut the server to sleep after this long with nobody on it.
Sleep is hibernation: the server's memory is captured, its host released, and the next player's connection — or an allocation — restores it in seconds with everything it held in memory. Compute is not charged while it sleeps.
The counterpart of idle_shutdown_minutes, and different in the one way that
matters: that stops a server a customer forgot about, and this is the
platform doing what "pay when played" means for a server somebody wants
kept ready. A server the game has marked ALLOCATED or RESERVED never sleeps,
because it is somebody's match.
Idle is measured from the connection proxy's view of the server — no connections and no players — and a server whose presence could not be read is not idle. Refused on an ephemeral server, which cannot hibernate. Zero keeps it awake.
vpcstringImmutableThe private network this server is on. Empty is the project's default network in the server's region.
Decided by the server, never by its game: a game is a catalogue entry
shared by every project that runs it, and a network written there would be
one project's network named in everybody's servers. Requires
vpc.vpcs.use on the network, which must be in the server's own project
and region.
Immutable. A server that changed network would change address under the players connected to it, and the connection proxy in front of it is the proxy for that network — players reach a server through the proxy on the network it is on, so each network a project uses has a proxy of its own.
network_tagsrepeated stringNetwork tags on this server's interface, which firewall rules on its network can target. Lowercase letters, digits and hyphens.
game_server_idstringrequest_idstringAn Operation that resolves to GameServer.
grpcurl -H "authorization: Bearer $PLANY_API_KEY" \ -d '{ "parent": "projects//locations/", "game_server": { "display_name": "My server", "game": "games/my-game" } }' \ api.plany.cloud:443 plany.playpute.v1.PlayputeService/CreateGameServer{ "name": "projects//locations//gameServers/", "display_name": "My server", "game": "games/my-game", "build": "builds/my-build", "settings": { "key": "" }, "resources": { "cpu": { "vcpus": 0, "reserved_millis": "0", "limit_millis": "0", "architecture": "CPU_ARCHITECTURE_X86_64", "required_features": [ "" ], "dedicated_cores": false, "isolate_smt_siblings": false }, "memory": { "size_bytes": "0", "reserved_bytes": "0", "balloon_enabled": false, "hugepages": false, "hotplug_max_bytes": "0", "shared": false }, "disks": [ { "disk_id": "my-disk", "size_bytes": "0", "type": "DISK_TYPE_LOCAL_NVME", "read_only": false, "boot": false, "delete_on_instance_delete": false, "direct_io": false } ], "network_interfaces": [ { "interface_id": "my-interface", "network": "", "private_ipv4": "", "public_address_mode": "PUBLIC_ADDRESS_MODE_NONE", "tier": "NETWORK_TIER_STANDARD", "mac_address": "", "multi_queue": false, "tags": [ "" ], "deny_inbound": false, "no_default_route": false } ], "placement": { "zones": [ "" ], "placement_group": "", "policy": "PLACEMENT_POLICY_PACK", "capacity_class": "", "disallow_preemptible": false, "node": "" }, "scheduling": { "on_host_maintenance": "ON_HOST_MAINTENANCE_MIGRATE", "restart_policy": "RESTART_POLICY_NEVER", "preemptible": false, "preemption_notice": "300s", "max_run_duration": "300s", "termination_grace_period": "300s", "preemptible_fallback": false } }, "machine_type": "", "spot": { "enabled": false, "on_demand_fallback": false, "notice_signal": "" }, "spot_status": { "running_on_spot": false, "termination_time": "2026-10-04T12:00:00Z", "last_reclaim_time": "2026-10-04T12:00:00Z", "preserving_disk": false, "notice": "300s" }, "state": "STATE_PROVISIONING", "state_message": "", "error": {}, "endpoints": [ { "name": "", "host": "", "port": 0, "protocol": "", "address": "", "proxied": false } ], "instance": "", "labels": { "key": "" }, "create_time": "2026-10-04T12:00:00Z", "update_time": "2026-10-04T12:00:00Z", "last_active_time": "2026-10-04T12:00:00Z", "service_account": "accounts//serviceAccounts/my-service-account", "ephemeral": false, "exposure": "EXPOSURE_PUBLIC", "schematic": "projects//locations//schematics/my-schematic", "group": "projects//locations//gameServerGroups/", "draining": false, "secrets": [ { "secret": "projects//locations//secrets/", "environment_variable": "", "file_path": "" } ], "sdk": { "state": "STATE_READY", "labels": { "key": "" }, "annotations": { "key": "" }, "reserved_until": "2026-10-04T12:00:00Z", "allocate_time": "2026-10-04T12:00:00Z", "health_time": "2026-10-04T12:00:00Z", "version": "0", "update_time": "2026-10-04T12:00:00Z" }, "sleep_after_idle": "300s", "managed_by": "", "install_complete_time": "2026-10-04T12:00:00Z", "vpc": "projects//locations//vpcs/", "network_tags": [ "" ], "etag": "W/\"1\""}namestringRequiredgrpcurl -H "authorization: Bearer $PLANY_API_KEY" \ -d '{ "name": "projects//locations//gameServers/" }' \ api.plany.cloud:443 plany.playpute.v1.PlayputeService/GetGameServer{ "name": "projects//locations//gameServers/", "display_name": "My server", "game": "games/my-game", "build": "builds/my-build", "settings": { "key": "" }, "resources": { "cpu": { "vcpus": 0, "reserved_millis": "0", "limit_millis": "0", "architecture": "CPU_ARCHITECTURE_X86_64", "required_features": [ "" ], "dedicated_cores": false, "isolate_smt_siblings": false }, "memory": { "size_bytes": "0", "reserved_bytes": "0", "balloon_enabled": false, "hugepages": false, "hotplug_max_bytes": "0", "shared": false }, "disks": [ { "disk_id": "my-disk", "size_bytes": "0", "type": "DISK_TYPE_LOCAL_NVME", "read_only": false, "boot": false, "delete_on_instance_delete": false, "direct_io": false } ], "network_interfaces": [ { "interface_id": "my-interface", "network": "", "private_ipv4": "", "public_address_mode": "PUBLIC_ADDRESS_MODE_NONE", "tier": "NETWORK_TIER_STANDARD", "mac_address": "", "multi_queue": false, "tags": [ "" ], "deny_inbound": false, "no_default_route": false } ], "placement": { "zones": [ "" ], "placement_group": "", "policy": "PLACEMENT_POLICY_PACK", "capacity_class": "", "disallow_preemptible": false, "node": "" }, "scheduling": { "on_host_maintenance": "ON_HOST_MAINTENANCE_MIGRATE", "restart_policy": "RESTART_POLICY_NEVER", "preemptible": false, "preemption_notice": "300s", "max_run_duration": "300s", "termination_grace_period": "300s", "preemptible_fallback": false } }, "machine_type": "", "spot": { "enabled": false, "on_demand_fallback": false, "notice_signal": "" }, "spot_status": { "running_on_spot": false, "termination_time": "2026-10-04T12:00:00Z", "last_reclaim_time": "2026-10-04T12:00:00Z", "preserving_disk": false, "notice": "300s" }, "state": "STATE_PROVISIONING", "state_message": "", "error": {}, "endpoints": [ { "name": "", "host": "", "port": 0, "protocol": "", "address": "", "proxied": false } ], "instance": "", "labels": { "key": "" }, "create_time": "2026-10-04T12:00:00Z", "update_time": "2026-10-04T12:00:00Z", "last_active_time": "2026-10-04T12:00:00Z", "service_account": "accounts//serviceAccounts/my-service-account", "ephemeral": false, "exposure": "EXPOSURE_PUBLIC", "schematic": "projects//locations//schematics/my-schematic", "group": "projects//locations//gameServerGroups/", "draining": false, "secrets": [ { "secret": "projects//locations//secrets/", "environment_variable": "", "file_path": "" } ], "sdk": { "state": "STATE_READY", "labels": { "key": "" }, "annotations": { "key": "" }, "reserved_until": "2026-10-04T12:00:00Z", "allocate_time": "2026-10-04T12:00:00Z", "health_time": "2026-10-04T12:00:00Z", "version": "0", "update_time": "2026-10-04T12:00:00Z" }, "sleep_after_idle": "300s", "managed_by": "", "install_complete_time": "2026-10-04T12:00:00Z", "vpc": "projects//locations//vpcs/", "network_tags": [ "" ], "etag": "W/\"1\""}parentstringRequiredpage_sizeint32page_tokenstringfilterstringgrpcurl -H "authorization: Bearer $PLANY_API_KEY" \ -d '{ "parent": "projects//locations/", "page_size": 50 }' \ api.plany.cloud:443 plany.playpute.v1.PlayputeService/ListGameServers{ "game_servers": [ { "name": "projects//locations//gameServers/", "display_name": "My server", "game": "games/my-game", "build": "builds/my-build", "settings": { "key": "" }, "resources": {}, "machine_type": "", "spot": { "enabled": false, "on_demand_fallback": false, "notice_signal": "" }, "spot_status": { "running_on_spot": false, "termination_time": "2026-10-04T12:00:00Z", "last_reclaim_time": "2026-10-04T12:00:00Z", "preserving_disk": false, "notice": "300s" }, "state": "STATE_PROVISIONING", "state_message": "", "error": {}, "endpoints": [ { "name": "", "host": "", "port": 0, "protocol": "", "address": "", "proxied": false } ], "instance": "", "labels": { "key": "" }, "create_time": "2026-10-04T12:00:00Z", "update_time": "2026-10-04T12:00:00Z", "last_active_time": "2026-10-04T12:00:00Z", "service_account": "accounts//serviceAccounts/my-service-account", "ephemeral": false, "exposure": "EXPOSURE_PUBLIC", "schematic": "projects//locations//schematics/my-schematic", "group": "projects//locations//gameServerGroups/", "draining": false, "secrets": [ { "secret": "projects//locations//secrets/", "environment_variable": "", "file_path": "" } ], "sdk": { "state": "STATE_READY", "labels": { "key": "" }, "annotations": { "key": "" }, "reserved_until": "2026-10-04T12:00:00Z", "allocate_time": "2026-10-04T12:00:00Z", "health_time": "2026-10-04T12:00:00Z", "version": "0", "update_time": "2026-10-04T12:00:00Z" }, "sleep_after_idle": "300s", "managed_by": "", "install_complete_time": "2026-10-04T12:00:00Z", "vpc": "projects//locations//vpcs/", "network_tags": [ "" ], "etag": "W/\"1\"" } ], "next_page_token": ""}gamestringRequiredThe game to run. Must be launchable — a branch node has no build.
namestringIdentifierprojects/{project}/locations/{location}/gameServers/{game_server}.
Project- and region-scoped, like every resource that consumes capacity: it runs somewhere specific, and it is billed to the project that owns it.
display_namestringsettingsmap<string, string>Overrides for the game's declared settings, by key.
machine_typestringThe size to run at, by machine type id — standard-4, highmem-2.
Empty takes the smallest type that meets the game's own declared minimum,
and a type below that minimum is refused, because a server too small for
its game boots, installs, and is killed for memory at the first player.
ListMachineTypes is the catalogue. Changing it takes effect on the next
start.
spotSpotConfigRun on spare capacity at a discount, and accept being reclaimed with two
minutes' notice. Pro plan only. See SpotConfig.
Changing it takes effect on the next start.
enabledboolRun on spot capacity.
on_demand_fallbackboolStart on demand, at the on-demand rate, when no spot capacity is free.
Without it a start with no spot capacity waits for some and fails after a
minute, which is right for a server that is only worth running cheaply and
wrong for one players are waiting on. A server that fell back stays on
demand until it next stops; SpotStatus.running_on_spot says which it is.
notice_signalstringA signal to send the game's process when a notice arrives, e.g. SIGUSR1.
Empty sends nothing, and that is the default for a reason: the default
action of most signals is to terminate, so a signal a game does not handle
would stop it two minutes early. Name one only when the game handles it.
SIGTERM and SIGKILL are refused — the stop that follows the notice
sends the game's own stop signal already.
labelsmap<string, string>service_accountstringThe identity this server acts as.
Leave it empty and Playpute creates one per server, allowed to touch this server and nothing else — the right default, since a server runs your players' mods.
Set it to a service account you own and the server acts as that instead. That is for a fleet: grant one service account a role elsewhere, attach it to twenty servers, and those twenty can use it while the rest of the account cannot.
Attaching one requires iam.serviceAccounts.actAs on that service account, not merely permission to create a server — otherwise anybody who could create a server could act as anybody.
ssh_public_keysrepeated stringInput onlySSH keys allowed to log in to this server, for debugging.
They take effect only on a server booted from an image that includes an SSH server, and are read when the server boots, so a key added later needs a restart. Input only: the keys are not returned when the server is read.
imagestringInput onlyThe image to boot, by id. Empty uses Plany's current default, which is what almost every server should do.
An id from Plany's own published images; a server cannot boot an image of your own.
ephemeralboolKeep nothing. The world and the disks go when the server does.
The right shape for a match rather than a world: a minigame round has nothing worth carrying into the next one, and an ephemeral server saves the storage and the time of keeping it.
An ephemeral server never sleeps, because there is nothing to wake into, so sleep_after_idle is refused on one.
Immutable after creation: the guarantee is about data that was never kept, so it cannot be turned off afterwards.
exposureExposureWhether players outside the project can reach this server.
Immutable after creation: it decides whether a listener and a public address exist at all, and flipping it on a running server would change the address players were given.
EXPOSURE_PUBLICEXPOSURE_PROJECT_INTERNALschematicstringThe schematic this server's disk was copied from, if any.
What makes a scaled fleet viable: the build is already unpacked, the install script has already run and the world already exists, so a member reaches RUNNING in seconds where a cold boot is minutes.
A copy, not an attachment. The schematic is read once into a fresh disk and never referenced again, which is why deleting one does not disturb a server started from it — and why two members from one schematic diverge immediately rather than sharing anything.
secretsrepeated SecretAttachmentSecrets this server can read: database passwords, API keys, RCON passwords, a licence key a game wants in a file.
Each attachment names a secret in the same project and region and says how the server sees it. The value is never stored on the server's configuration — the server fetches it when it starts, as its own identity — so nothing you can read back from the server reveals it.
Changing this takes effect on the next start. A running server keeps what it read when it started.
secretstringRequiredprojects/{project}/locations/{location}/secrets/{secret}, optionally with
/versions/{version}.
Unqualified is the ordinary case and resolves to the latest enabled version, so a rotation reaches this server on its next start with nothing to edit. Pin a version when a server must not follow a rotation — which is rare, and worth being deliberate about, because the pin outlives the memory of why it was made.
environment_variablestringRequiredThe environment variable the server sees the secret as, e.g. RCON_PASSWORD.
Required, and must be a valid variable name — upper case letters, digits and underscores, not starting with a digit. It is not derived from the secret's id, because stripe-live-key is not a variable name.
The value has to be valid UTF-8 to be used this way. A secret holding binary data is refused when the server starts; use file_path for one.
file_pathstringAlso write the value to a file at this path, relative to the build root.
For the things that will not go in an environment variable: a service account JSON, a TLS key, a licence file a game reads by path. Optional, and when it is set the environment variable is still exported, because a value that is available two ways is easier to use than one with a rule about when it is which.
Written 0600 and owned by the game user, and deliberately not preserved
across restarts the way a plany.game.v1.ConfigFile can be: this is the platform's copy
of a value the platform holds, so the file is rewritten every launch and a
rotation cannot leave a stale one behind.
sleep_after_idleDurationPut the server to sleep after this long with nobody on it.
Sleep is hibernation: the server's memory is captured, its host released, and the next player's connection — or an allocation — restores it in seconds with everything it held in memory. Compute is not charged while it sleeps.
The counterpart of idle_shutdown_minutes, and different in the one way that
matters: that stops a server a customer forgot about, and this is the
platform doing what "pay when played" means for a server somebody wants
kept ready. A server the game has marked ALLOCATED or RESERVED never sleeps,
because it is somebody's match.
Idle is measured from the connection proxy's view of the server — no connections and no players — and a server whose presence could not be read is not idle. Refused on an ephemeral server, which cannot hibernate. Zero keeps it awake.
vpcstringImmutableThe private network this server is on. Empty is the project's default network in the server's region.
Decided by the server, never by its game: a game is a catalogue entry
shared by every project that runs it, and a network written there would be
one project's network named in everybody's servers. Requires
vpc.vpcs.use on the network, which must be in the server's own project
and region.
Immutable. A server that changed network would change address under the players connected to it, and the connection proxy in front of it is the proxy for that network — players reach a server through the proxy on the network it is on, so each network a project uses has a proxy of its own.
network_tagsrepeated stringNetwork tags on this server's interface, which firewall rules on its network can target. Lowercase letters, digits and hyphens.
request_idstringAn Operation that resolves to GameServer.
grpcurl -H "authorization: Bearer $PLANY_API_KEY" \ -d '{ "game_server": { "display_name": "My server", "game": "games/my-game" }, "update_mask": "display_name" }' \ api.plany.cloud:443 plany.playpute.v1.PlayputeService/UpdateGameServer{ "name": "projects//locations//gameServers/", "display_name": "My server", "game": "games/my-game", "build": "builds/my-build", "settings": { "key": "" }, "resources": { "cpu": { "vcpus": 0, "reserved_millis": "0", "limit_millis": "0", "architecture": "CPU_ARCHITECTURE_X86_64", "required_features": [ "" ], "dedicated_cores": false, "isolate_smt_siblings": false }, "memory": { "size_bytes": "0", "reserved_bytes": "0", "balloon_enabled": false, "hugepages": false, "hotplug_max_bytes": "0", "shared": false }, "disks": [ { "disk_id": "my-disk", "size_bytes": "0", "type": "DISK_TYPE_LOCAL_NVME", "read_only": false, "boot": false, "delete_on_instance_delete": false, "direct_io": false } ], "network_interfaces": [ { "interface_id": "my-interface", "network": "", "private_ipv4": "", "public_address_mode": "PUBLIC_ADDRESS_MODE_NONE", "tier": "NETWORK_TIER_STANDARD", "mac_address": "", "multi_queue": false, "tags": [ "" ], "deny_inbound": false, "no_default_route": false } ], "placement": { "zones": [ "" ], "placement_group": "", "policy": "PLACEMENT_POLICY_PACK", "capacity_class": "", "disallow_preemptible": false, "node": "" }, "scheduling": { "on_host_maintenance": "ON_HOST_MAINTENANCE_MIGRATE", "restart_policy": "RESTART_POLICY_NEVER", "preemptible": false, "preemption_notice": "300s", "max_run_duration": "300s", "termination_grace_period": "300s", "preemptible_fallback": false } }, "machine_type": "", "spot": { "enabled": false, "on_demand_fallback": false, "notice_signal": "" }, "spot_status": { "running_on_spot": false, "termination_time": "2026-10-04T12:00:00Z", "last_reclaim_time": "2026-10-04T12:00:00Z", "preserving_disk": false, "notice": "300s" }, "state": "STATE_PROVISIONING", "state_message": "", "error": {}, "endpoints": [ { "name": "", "host": "", "port": 0, "protocol": "", "address": "", "proxied": false } ], "instance": "", "labels": { "key": "" }, "create_time": "2026-10-04T12:00:00Z", "update_time": "2026-10-04T12:00:00Z", "last_active_time": "2026-10-04T12:00:00Z", "service_account": "accounts//serviceAccounts/my-service-account", "ephemeral": false, "exposure": "EXPOSURE_PUBLIC", "schematic": "projects//locations//schematics/my-schematic", "group": "projects//locations//gameServerGroups/", "draining": false, "secrets": [ { "secret": "projects//locations//secrets/", "environment_variable": "", "file_path": "" } ], "sdk": { "state": "STATE_READY", "labels": { "key": "" }, "annotations": { "key": "" }, "reserved_until": "2026-10-04T12:00:00Z", "allocate_time": "2026-10-04T12:00:00Z", "health_time": "2026-10-04T12:00:00Z", "version": "0", "update_time": "2026-10-04T12:00:00Z" }, "sleep_after_idle": "300s", "managed_by": "", "install_complete_time": "2026-10-04T12:00:00Z", "vpc": "projects//locations//vpcs/", "network_tags": [ "" ], "etag": "W/\"1\""}namestringRequiredetagstringrequest_idstringgrpcurl -H "authorization: Bearer $PLANY_API_KEY" \ -d '{ "name": "projects//locations//gameServers/" }' \ api.plany.cloud:443 plany.playpute.v1.PlayputeService/DeleteGameServer{}namestringRequiredrequest_idstringAn Operation that resolves to GameServer.
grpcurl -H "authorization: Bearer $PLANY_API_KEY" \ -d '{ "name": "projects//locations//gameServers/" }' \ api.plany.cloud:443 plany.playpute.v1.PlayputeService/StartGameServer{ "name": "projects//locations//gameServers/", "display_name": "My server", "game": "games/my-game", "build": "builds/my-build", "settings": { "key": "" }, "resources": { "cpu": { "vcpus": 0, "reserved_millis": "0", "limit_millis": "0", "architecture": "CPU_ARCHITECTURE_X86_64", "required_features": [ "" ], "dedicated_cores": false, "isolate_smt_siblings": false }, "memory": { "size_bytes": "0", "reserved_bytes": "0", "balloon_enabled": false, "hugepages": false, "hotplug_max_bytes": "0", "shared": false }, "disks": [ { "disk_id": "my-disk", "size_bytes": "0", "type": "DISK_TYPE_LOCAL_NVME", "read_only": false, "boot": false, "delete_on_instance_delete": false, "direct_io": false } ], "network_interfaces": [ { "interface_id": "my-interface", "network": "", "private_ipv4": "", "public_address_mode": "PUBLIC_ADDRESS_MODE_NONE", "tier": "NETWORK_TIER_STANDARD", "mac_address": "", "multi_queue": false, "tags": [ "" ], "deny_inbound": false, "no_default_route": false } ], "placement": { "zones": [ "" ], "placement_group": "", "policy": "PLACEMENT_POLICY_PACK", "capacity_class": "", "disallow_preemptible": false, "node": "" }, "scheduling": { "on_host_maintenance": "ON_HOST_MAINTENANCE_MIGRATE", "restart_policy": "RESTART_POLICY_NEVER", "preemptible": false, "preemption_notice": "300s", "max_run_duration": "300s", "termination_grace_period": "300s", "preemptible_fallback": false } }, "machine_type": "", "spot": { "enabled": false, "on_demand_fallback": false, "notice_signal": "" }, "spot_status": { "running_on_spot": false, "termination_time": "2026-10-04T12:00:00Z", "last_reclaim_time": "2026-10-04T12:00:00Z", "preserving_disk": false, "notice": "300s" }, "state": "STATE_PROVISIONING", "state_message": "", "error": {}, "endpoints": [ { "name": "", "host": "", "port": 0, "protocol": "", "address": "", "proxied": false } ], "instance": "", "labels": { "key": "" }, "create_time": "2026-10-04T12:00:00Z", "update_time": "2026-10-04T12:00:00Z", "last_active_time": "2026-10-04T12:00:00Z", "service_account": "accounts//serviceAccounts/my-service-account", "ephemeral": false, "exposure": "EXPOSURE_PUBLIC", "schematic": "projects//locations//schematics/my-schematic", "group": "projects//locations//gameServerGroups/", "draining": false, "secrets": [ { "secret": "projects//locations//secrets/", "environment_variable": "", "file_path": "" } ], "sdk": { "state": "STATE_READY", "labels": { "key": "" }, "annotations": { "key": "" }, "reserved_until": "2026-10-04T12:00:00Z", "allocate_time": "2026-10-04T12:00:00Z", "health_time": "2026-10-04T12:00:00Z", "version": "0", "update_time": "2026-10-04T12:00:00Z" }, "sleep_after_idle": "300s", "managed_by": "", "install_complete_time": "2026-10-04T12:00:00Z", "vpc": "projects//locations//vpcs/", "network_tags": [ "" ], "etag": "W/\"1\""}Stops a server, keeping its world.
namestringRequiredforceboolSkip the clean shutdown. Game servers write world state on exit, so this risks losing player progress — it exists for a server that has hung.
request_idstringAn Operation that resolves to GameServer.
grpcurl -H "authorization: Bearer $PLANY_API_KEY" \ -d '{ "name": "projects//locations//gameServers/" }' \ api.plany.cloud:443 plany.playpute.v1.PlayputeService/StopGameServer{ "name": "projects//locations//gameServers/", "display_name": "My server", "game": "games/my-game", "build": "builds/my-build", "settings": { "key": "" }, "resources": { "cpu": { "vcpus": 0, "reserved_millis": "0", "limit_millis": "0", "architecture": "CPU_ARCHITECTURE_X86_64", "required_features": [ "" ], "dedicated_cores": false, "isolate_smt_siblings": false }, "memory": { "size_bytes": "0", "reserved_bytes": "0", "balloon_enabled": false, "hugepages": false, "hotplug_max_bytes": "0", "shared": false }, "disks": [ { "disk_id": "my-disk", "size_bytes": "0", "type": "DISK_TYPE_LOCAL_NVME", "read_only": false, "boot": false, "delete_on_instance_delete": false, "direct_io": false } ], "network_interfaces": [ { "interface_id": "my-interface", "network": "", "private_ipv4": "", "public_address_mode": "PUBLIC_ADDRESS_MODE_NONE", "tier": "NETWORK_TIER_STANDARD", "mac_address": "", "multi_queue": false, "tags": [ "" ], "deny_inbound": false, "no_default_route": false } ], "placement": { "zones": [ "" ], "placement_group": "", "policy": "PLACEMENT_POLICY_PACK", "capacity_class": "", "disallow_preemptible": false, "node": "" }, "scheduling": { "on_host_maintenance": "ON_HOST_MAINTENANCE_MIGRATE", "restart_policy": "RESTART_POLICY_NEVER", "preemptible": false, "preemption_notice": "300s", "max_run_duration": "300s", "termination_grace_period": "300s", "preemptible_fallback": false } }, "machine_type": "", "spot": { "enabled": false, "on_demand_fallback": false, "notice_signal": "" }, "spot_status": { "running_on_spot": false, "termination_time": "2026-10-04T12:00:00Z", "last_reclaim_time": "2026-10-04T12:00:00Z", "preserving_disk": false, "notice": "300s" }, "state": "STATE_PROVISIONING", "state_message": "", "error": {}, "endpoints": [ { "name": "", "host": "", "port": 0, "protocol": "", "address": "", "proxied": false } ], "instance": "", "labels": { "key": "" }, "create_time": "2026-10-04T12:00:00Z", "update_time": "2026-10-04T12:00:00Z", "last_active_time": "2026-10-04T12:00:00Z", "service_account": "accounts//serviceAccounts/my-service-account", "ephemeral": false, "exposure": "EXPOSURE_PUBLIC", "schematic": "projects//locations//schematics/my-schematic", "group": "projects//locations//gameServerGroups/", "draining": false, "secrets": [ { "secret": "projects//locations//secrets/", "environment_variable": "", "file_path": "" } ], "sdk": { "state": "STATE_READY", "labels": { "key": "" }, "annotations": { "key": "" }, "reserved_until": "2026-10-04T12:00:00Z", "allocate_time": "2026-10-04T12:00:00Z", "health_time": "2026-10-04T12:00:00Z", "version": "0", "update_time": "2026-10-04T12:00:00Z" }, "sleep_after_idle": "300s", "managed_by": "", "install_complete_time": "2026-10-04T12:00:00Z", "vpc": "projects//locations//vpcs/", "network_tags": [ "" ], "etag": "W/\"1\""}namestringRequiredrequest_idstringAn Operation that resolves to GameServer.
grpcurl -H "authorization: Bearer $PLANY_API_KEY" \ -d '{ "name": "projects//locations//gameServers/" }' \ api.plany.cloud:443 plany.playpute.v1.PlayputeService/RestartGameServer{ "name": "projects//locations//gameServers/", "display_name": "My server", "game": "games/my-game", "build": "builds/my-build", "settings": { "key": "" }, "resources": { "cpu": { "vcpus": 0, "reserved_millis": "0", "limit_millis": "0", "architecture": "CPU_ARCHITECTURE_X86_64", "required_features": [ "" ], "dedicated_cores": false, "isolate_smt_siblings": false }, "memory": { "size_bytes": "0", "reserved_bytes": "0", "balloon_enabled": false, "hugepages": false, "hotplug_max_bytes": "0", "shared": false }, "disks": [ { "disk_id": "my-disk", "size_bytes": "0", "type": "DISK_TYPE_LOCAL_NVME", "read_only": false, "boot": false, "delete_on_instance_delete": false, "direct_io": false } ], "network_interfaces": [ { "interface_id": "my-interface", "network": "", "private_ipv4": "", "public_address_mode": "PUBLIC_ADDRESS_MODE_NONE", "tier": "NETWORK_TIER_STANDARD", "mac_address": "", "multi_queue": false, "tags": [ "" ], "deny_inbound": false, "no_default_route": false } ], "placement": { "zones": [ "" ], "placement_group": "", "policy": "PLACEMENT_POLICY_PACK", "capacity_class": "", "disallow_preemptible": false, "node": "" }, "scheduling": { "on_host_maintenance": "ON_HOST_MAINTENANCE_MIGRATE", "restart_policy": "RESTART_POLICY_NEVER", "preemptible": false, "preemption_notice": "300s", "max_run_duration": "300s", "termination_grace_period": "300s", "preemptible_fallback": false } }, "machine_type": "", "spot": { "enabled": false, "on_demand_fallback": false, "notice_signal": "" }, "spot_status": { "running_on_spot": false, "termination_time": "2026-10-04T12:00:00Z", "last_reclaim_time": "2026-10-04T12:00:00Z", "preserving_disk": false, "notice": "300s" }, "state": "STATE_PROVISIONING", "state_message": "", "error": {}, "endpoints": [ { "name": "", "host": "", "port": 0, "protocol": "", "address": "", "proxied": false } ], "instance": "", "labels": { "key": "" }, "create_time": "2026-10-04T12:00:00Z", "update_time": "2026-10-04T12:00:00Z", "last_active_time": "2026-10-04T12:00:00Z", "service_account": "accounts//serviceAccounts/my-service-account", "ephemeral": false, "exposure": "EXPOSURE_PUBLIC", "schematic": "projects//locations//schematics/my-schematic", "group": "projects//locations//gameServerGroups/", "draining": false, "secrets": [ { "secret": "projects//locations//secrets/", "environment_variable": "", "file_path": "" } ], "sdk": { "state": "STATE_READY", "labels": { "key": "" }, "annotations": { "key": "" }, "reserved_until": "2026-10-04T12:00:00Z", "allocate_time": "2026-10-04T12:00:00Z", "health_time": "2026-10-04T12:00:00Z", "version": "0", "update_time": "2026-10-04T12:00:00Z" }, "sleep_after_idle": "300s", "managed_by": "", "install_complete_time": "2026-10-04T12:00:00Z", "vpc": "projects//locations//vpcs/", "network_tags": [ "" ], "etag": "W/\"1\""}Lists the sizes a game server can run at, each with this region's spot record beside it.
parentstringRequiredprojects/{project}/locations/{location}.
grpcurl -H "authorization: Bearer $PLANY_API_KEY" \ -d '{ "parent": "projects//locations/" }' \ api.plany.cloud:443 plany.playpute.v1.PlayputeService/ListMachineTypes{ "machine_types": [ { "name": "projects//locations//machineTypes/my-machine-type", "display_name": "My server", "family": "", "vcpus": 0, "memory_bytes": "0", "spot": { "available_now": false, "availability_7d": 0, "reclaims_per_day_7d": 0, "sample_time": "2026-10-04T12:00:00Z" } } ]}namestringRequiredgrpcurl -H "authorization: Bearer $PLANY_API_KEY" \ -d '{ "name": "projects//locations//machineTypes/my-machine-type" }' \ api.plany.cloud:443 plany.playpute.v1.PlayputeService/GetMachineType{ "name": "projects//locations//machineTypes/my-machine-type", "display_name": "My server", "family": "", "vcpus": 0, "memory_bytes": "0", "spot": { "available_now": false, "availability_7d": 0, "reclaims_per_day_7d": 0, "sample_time": "2026-10-04T12:00:00Z" }}Reads a machine type's spot record over an interval: how often a spot server of that type could have been placed, and how often one was reclaimed.
Hourly buckets over at most thirty days, which is also how long the record is kept. A bucket with no samples says so rather than reading as zero.
machine_typestringRequiredintervalIntervalThe interval to read. Unset reads the last seven days; an interval reaching further back than thirty days is refused, because nothing older is kept and an answer padded with empty buckets would look like a record.
grpcurl -H "authorization: Bearer $PLANY_API_KEY" \ -d '{ "machine_type": "projects//locations//machineTypes/my-machine-type" }' \ api.plany.cloud:443 plany.playpute.v1.PlayputeService/QuerySpotHistory{ "points": [ { "interval": { "start_time": "2026-10-01T00:00:00Z", "end_time": "2026-10-04T00:00:00Z" }, "availability": 0, "reclaims": "0", "running_hours": 0, "measured": false } ]}Captures a running game server as a fast-start template.
Long-running: copying a server's disk takes minutes for one with an installed world. The server keeps running throughout — capturing a world you have already set up is the ordinary case.
parentstringRequiredprojects/{project}/locations/{location}.
game_serverstringRequiredThe running server to capture. Must be in this parent.
schematic_idstringdisplay_namestringlabelsmap<string, string>request_idstringAn Operation that resolves to GameServerSchematic.
grpcurl -H "authorization: Bearer $PLANY_API_KEY" \ -d '{ "parent": "", "game_server": "projects//locations//gameServers/" }' \ api.plany.cloud:443 plany.playpute.v1.PlayputeService/CreateGameServerSchematic{ "name": "projects//locations//schematics/my-schematic", "display_name": "My server", "game": "games/my-game", "build": "builds/my-build", "source_game_server": "", "state": "STATE_PENDING", "error": {}, "size_bytes": "0", "labels": { "key": "" }, "create_time": "2026-10-04T12:00:00Z", "ready_time": "2026-10-04T12:00:00Z", "etag": "W/\"1\""}namestringRequiredgrpcurl -H "authorization: Bearer $PLANY_API_KEY" \ -d '{ "name": "projects//locations//schematics/my-schematic" }' \ api.plany.cloud:443 plany.playpute.v1.PlayputeService/GetGameServerSchematic{ "name": "projects//locations//schematics/my-schematic", "display_name": "My server", "game": "games/my-game", "build": "builds/my-build", "source_game_server": "", "state": "STATE_PENDING", "error": {}, "size_bytes": "0", "labels": { "key": "" }, "create_time": "2026-10-04T12:00:00Z", "ready_time": "2026-10-04T12:00:00Z", "etag": "W/\"1\""}parentstringRequiredprojects/{project}/locations/{location}.
page_sizeint32page_tokenstringgrpcurl -H "authorization: Bearer $PLANY_API_KEY" \ -d '{ "parent": "", "page_size": 50 }' \ api.plany.cloud:443 plany.playpute.v1.PlayputeService/ListGameServerSchematics{ "schematics": [ { "name": "projects//locations//schematics/my-schematic", "display_name": "My server", "game": "games/my-game", "build": "builds/my-build", "source_game_server": "", "state": "STATE_PENDING", "error": {}, "size_bytes": "0", "labels": { "key": "" }, "create_time": "2026-10-04T12:00:00Z", "ready_time": "2026-10-04T12:00:00Z", "etag": "W/\"1\"" } ], "next_page_token": ""}Deletes a schematic and the disk behind it.
Servers already started from it are unaffected. A schematic is copied into a fresh disk at boot rather than attached, so a running server holds no reference to it — which is the difference between this and deleting a volume, and why there is no in-use guard.
namestringRequiredgrpcurl -H "authorization: Bearer $PLANY_API_KEY" \ -d '{ "name": "projects//locations//schematics/my-schematic" }' \ api.plany.cloud:443 plany.playpute.v1.PlayputeService/DeleteGameServerSchematic{}Creates a group and, unless warmup_duration is zero or a schematic was
supplied, the warm-up server it captures its schematic from.
Long-running because the warm-up is: a server is created, left to install and generate its world for the declared duration, captured, and deleted. The warm-up server is not billed — it exists so the customer's members do not each pay for that install, and charging for it would be charging for the platform's own optimisation.
The operation completes when the group is ACTIVE and scaling. Members are
created by the group's own loop and not by this call, so an operation that
has completed does not mean a server is running — min_size decides that.
parentstringRequiredprojects/{project}/locations/{location}.
gamestringRequiredThe game every member runs.
max_sizeint32Requiredmin_sizeint32Members never to go below, and never to go above.
A minimum of zero is legitimate and is what a group for an off-peak game wants: no players, no servers, no bill. The first player then pays a boot, which is what the schematic is for.
target_player_percentdoubleHold members at this fraction of their player capacity. 1..100.
The headline signal for a minigame: "keep servers 70% full" is the sentence a customer says. Needs the game to declare how many players a server holds; without that this term sits out rather than guessing.
min_free_player_slotsint32Keep at least this many player slots free across the whole group, so a party arriving together finds room without waiting for a boot.
Additive to the percentage rather than an alternative — they answer different questions, and a group that sets both gets whichever needs more.
scale_on_waiting_connectionsboolAdd members when connections are open against servers nobody is playing on.
The only leading signal available: every other term here reacts to load that has already landed, and this one is somebody who could not get in. It needs no capacity and no sample, so it works for a game the platform knows nothing about.
target_cpu_percentdoubleHold the group's mean CPU at this percentage of each member's allocation. 1..100.
scale_out_cooldownDurationHow long after growing before the group may grow again.
A member takes tens of seconds to accept its first player, and every pass inside that window sees the same load on the same members. Without this a group creates one member per pass until the first finishes booting.
scale_in_patienceDurationHow long a member must have been empty before it may be removed.
Longer than the cooldown by default and by intent. Scaling in on a momentary zero is the failure that matters here: presence is derived from the game's own log lines, which can be late or missed, so a server between two rounds reads as empty for a few seconds. Growing late is a queue; shrinking early is a disconnection, and only the first is fixed by waiting.
max_scale_out_batchint32Most members to add or remove in one pass.
max_scale_in_batchint32drain_timeoutDurationHow long a drained member is given to empty before it is removed anyway.
A drain is not a disconnection: the member stops being sent new players and keeps the ones it has. Somebody who never leaves would otherwise hold a member forever, so there is a deadline — long enough that a match finishes inside it.
buffer_sizeint32Keep this many members READY and unallocated, on top of those allocated.
Agones' FleetAutoscaler buffer, and the shape a lobby needs: "always two
servers accepting players, however many are mid-match". Reads the SDK state
the game reports, so it needs a game that calls Ready() and Allocate() —
for one that does not, every member is unallocated and the term asks only
for the buffer itself.
A sleeping READY member counts: it can be allocated. That is what makes a buffer cheap while nobody plays.
Combined with the other terms by maximum, like all of them, and bounded by
min_size and max_size.
buffer_percentdoubleThe buffer as a percentage of the group's size. 1..100. The larger of this
and buffer_size when both are set.
namestringIdentifierprojects/{p}/locations/{l}/gameServerGroups/{g}.
display_namestringbuildstringThe build every member runs.
Pinned like a game server's, and for a stronger reason: members are created and destroyed continuously, so a group that resolved the game's current build per member would put two versions of a customer's game in one fleet, with players matched across them by accident.
Updatable, and changing it is a rollout, never a mixture by accident. The
group goes on creating members on the old build while a warm-up bakes the new
one (pending_build), switches when the capture lands, and then replaces
outdated members within rollout — never one the game has marked ALLOCATED,
which is somebody's match and finishes on the build it started on.
settingsmap<string, string>Settings handed to every member, exactly as GameServer.settings.
machine_typestringThe machine type every member runs at, as GameServer.machine_type. Empty
takes the smallest type that meets the game's minimum.
Updatable, and a change reaches a member the next time it starts; it is not a rollout, because a size is not what a match is played on.
spotSpotConfigRun members on spot capacity, as GameServer.spot. Pro plan only.
A fleet is where spot is most useful — a minigame server reclaimed between
rounds costs nobody anything — and it composes with scaling in one way worth
knowing: a reclaimed member counts as not running, so a group that needs it
creates or starts another. With on_demand_fallback that one is on demand
when spot has nothing free, which is what keeps a fleet at size while the
region is busy.
enabledboolRun on spot capacity.
on_demand_fallbackboolStart on demand, at the on-demand rate, when no spot capacity is free.
Without it a start with no spot capacity waits for some and fails after a
minute, which is right for a server that is only worth running cheaply and
wrong for one players are waiting on. A server that fell back stays on
demand until it next stops; SpotStatus.running_on_spot says which it is.
notice_signalstringA signal to send the game's process when a notice arrives, e.g. SIGUSR1.
Empty sends nothing, and that is the default for a reason: the default
action of most signals is to terminate, so a signal a game does not handle
would stop it two minutes early. Name one only when the game handles it.
SIGTERM and SIGKILL are refused — the stop that follows the notice
sends the game's own stop signal already.
ephemeralboolWhether members keep their data.
Almost always true for the workload a group is for: a match has nothing worth carrying into the next one, and a member that hibernated would write its whole RAM to object storage on the way out of a world nobody will read.
It also changes what scaling in means. An ephemeral member is deleted when it is drained; a durable one is stopped, keeps its disks, and is started again when the group grows.
exposureExposureWhether players can reach members directly.
PROJECT_INTERNAL is the right default for a scaled fleet and the reason the field exists: members behind a matchmaker or a lobby are dialled from inside the project, and giving each one a public listener would be an entry point nobody intended and a proxy charge per member. The choice is the customer's, because a fleet of servers players do pick from a list is just as real a shape.
EXPOSURE_PUBLICEXPOSURE_PROJECT_INTERNALwarmup_durationDurationHow long a warm-up server runs before it is captured as the schematic.
The one number that decides how fast this group scales. A member started from a schematic skips the download, the install and the world generation — seconds instead of minutes — and what makes the schematic worth having is that the capture happened after all of that finished.
So this is "how long does your game take to be ready to play", and getting it wrong is visible in one direction only: too long wastes a few minutes once, and too short captures a server mid-install, which every member then starts from.
Zero skips the warm-up entirely and members boot cold. That is the right choice for a game that starts in seconds anyway, and the only choice for one whose first run must not be cloned.
schematicstringThe schematic members are started from.
Set by the group when its warm-up capture lands, or supplied at creation to reuse one that already exists — which is the faster path and the one a customer takes for their second group of the same game.
Empty means members boot cold, which is correct rather than broken: a group whose capture failed still scales, just slowly, and stopping it from scaling would turn a performance problem into an outage.
labelsmap<string, string>vpcstringImmutableThe private network every member is on, and the warm-up server before them. Empty is the project's default network in the group's region.
On the group rather than on each member because a member is the group's
to create: two members on different networks would be one fleet that
cannot reach itself. Requires vpc.vpcs.use on the network. Immutable,
for the reason GameServer.vpc is.
network_tagsrepeated stringNetwork tags on every member's interface, and the warm-up's, which firewall rules on the group's network can target. Lowercase letters, digits and hyphens.
rolloutRolloutPolicyHow members are replaced when build changes.
strategyRolloutPolicy.StrategySTRATEGY_ROLLING_UPDATESTRATEGY_RECREATEmax_surgeint32Members above the desired size a rolling update may create, as a count or as a percentage of the desired size. The larger of the two when both are set; 25% when neither is.
max_surge_percentint32max_unavailableint32Members below the desired size a rolling update may leave the group at, as a count or a percentage. 25% when neither is set.
max_unavailable_percentint32sleep_after_idleDurationPut members to sleep after this long with nobody on them. See
GameServer.sleep_after_idle, which every member is created with.
A sleeping member still counts toward the group's size and, if the game said it is READY, toward its buffer: it can be allocated or connected to, and either wakes it. That is the point of keeping it rather than removing it. Refused on an ephemeral group, whose members cannot hibernate.
member_labelsmap<string, string>Labels every member carries, and what an allocation selects on.
Not labels, which describe the group itself. Changing these reaches
members created afterwards; existing members keep what they were created
with, as a pod keeps its labels when a template changes.
game_server_group_idstringrequest_idstringAn Operation that resolves to GameServerGroup.
grpcurl -H "authorization: Bearer $PLANY_API_KEY" \ -d '{ "parent": "projects//locations/", "game_server_group": { "display_name": "My server", "game": "games/my-game", "policy": { "max_size": 0 } } }' \ api.plany.cloud:443 plany.playpute.v1.PlayputeService/CreateGameServerGroup{ "name": "projects//locations//gameServerGroups/", "display_name": "My server", "game": "games/my-game", "build": "builds/my-build", "settings": { "key": "" }, "resources": { "cpu": { "vcpus": 0, "reserved_millis": "0", "limit_millis": "0", "architecture": "CPU_ARCHITECTURE_X86_64", "required_features": [ "" ], "dedicated_cores": false, "isolate_smt_siblings": false }, "memory": { "size_bytes": "0", "reserved_bytes": "0", "balloon_enabled": false, "hugepages": false, "hotplug_max_bytes": "0", "shared": false }, "disks": [ { "disk_id": "my-disk", "size_bytes": "0", "type": "DISK_TYPE_LOCAL_NVME", "read_only": false, "boot": false, "delete_on_instance_delete": false, "direct_io": false } ], "network_interfaces": [ { "interface_id": "my-interface", "network": "", "private_ipv4": "", "public_address_mode": "PUBLIC_ADDRESS_MODE_NONE", "tier": "NETWORK_TIER_STANDARD", "mac_address": "", "multi_queue": false, "tags": [ "" ], "deny_inbound": false, "no_default_route": false } ], "placement": { "zones": [ "" ], "placement_group": "", "policy": "PLACEMENT_POLICY_PACK", "capacity_class": "", "disallow_preemptible": false, "node": "" }, "scheduling": { "on_host_maintenance": "ON_HOST_MAINTENANCE_MIGRATE", "restart_policy": "RESTART_POLICY_NEVER", "preemptible": false, "preemption_notice": "300s", "max_run_duration": "300s", "termination_grace_period": "300s", "preemptible_fallback": false } }, "machine_type": "", "spot": { "enabled": false, "on_demand_fallback": false, "notice_signal": "" }, "policy": { "min_size": 0, "max_size": 0, "target_player_percent": 0, "min_free_player_slots": 0, "scale_on_waiting_connections": false, "target_cpu_percent": 0, "scale_out_cooldown": "300s", "scale_in_patience": "300s", "max_scale_out_batch": 0, "max_scale_in_batch": 0, "drain_timeout": "300s", "buffer_size": 0, "buffer_percent": 0 }, "ephemeral": false, "exposure": "EXPOSURE_PUBLIC", "warmup_duration": "300s", "schematic": "projects//locations//schematics/my-schematic", "state": "STATE_WARMING_UP", "state_message": "", "error": {}, "current_size": 0, "desired_size": 0, "labels": { "key": "" }, "create_time": "2026-10-04T12:00:00Z", "update_time": "2026-10-04T12:00:00Z", "last_scale_out_time": "2026-10-04T12:00:00Z", "vpc": "projects//locations//vpcs/", "network_tags": [ "" ], "etag": "W/\"1\"", "managed_by": "", "pending_build": "builds/my-build", "rollout": { "strategy": "STRATEGY_ROLLING_UPDATE", "max_surge": 0, "max_surge_percent": 0, "max_unavailable": 0, "max_unavailable_percent": 0 }, "sleep_after_idle": "300s", "member_labels": { "key": "" }, "outdated_size": 0, "ready_size": 0, "allocated_size": 0, "sleeping_size": 0, "pending_game": "games/my-game"}namestringRequiredgrpcurl -H "authorization: Bearer $PLANY_API_KEY" \ -d '{ "name": "projects//locations//gameServerGroups/" }' \ api.plany.cloud:443 plany.playpute.v1.PlayputeService/GetGameServerGroup{ "name": "projects//locations//gameServerGroups/", "display_name": "My server", "game": "games/my-game", "build": "builds/my-build", "settings": { "key": "" }, "resources": { "cpu": { "vcpus": 0, "reserved_millis": "0", "limit_millis": "0", "architecture": "CPU_ARCHITECTURE_X86_64", "required_features": [ "" ], "dedicated_cores": false, "isolate_smt_siblings": false }, "memory": { "size_bytes": "0", "reserved_bytes": "0", "balloon_enabled": false, "hugepages": false, "hotplug_max_bytes": "0", "shared": false }, "disks": [ { "disk_id": "my-disk", "size_bytes": "0", "type": "DISK_TYPE_LOCAL_NVME", "read_only": false, "boot": false, "delete_on_instance_delete": false, "direct_io": false } ], "network_interfaces": [ { "interface_id": "my-interface", "network": "", "private_ipv4": "", "public_address_mode": "PUBLIC_ADDRESS_MODE_NONE", "tier": "NETWORK_TIER_STANDARD", "mac_address": "", "multi_queue": false, "tags": [ "" ], "deny_inbound": false, "no_default_route": false } ], "placement": { "zones": [ "" ], "placement_group": "", "policy": "PLACEMENT_POLICY_PACK", "capacity_class": "", "disallow_preemptible": false, "node": "" }, "scheduling": { "on_host_maintenance": "ON_HOST_MAINTENANCE_MIGRATE", "restart_policy": "RESTART_POLICY_NEVER", "preemptible": false, "preemption_notice": "300s", "max_run_duration": "300s", "termination_grace_period": "300s", "preemptible_fallback": false } }, "machine_type": "", "spot": { "enabled": false, "on_demand_fallback": false, "notice_signal": "" }, "policy": { "min_size": 0, "max_size": 0, "target_player_percent": 0, "min_free_player_slots": 0, "scale_on_waiting_connections": false, "target_cpu_percent": 0, "scale_out_cooldown": "300s", "scale_in_patience": "300s", "max_scale_out_batch": 0, "max_scale_in_batch": 0, "drain_timeout": "300s", "buffer_size": 0, "buffer_percent": 0 }, "ephemeral": false, "exposure": "EXPOSURE_PUBLIC", "warmup_duration": "300s", "schematic": "projects//locations//schematics/my-schematic", "state": "STATE_WARMING_UP", "state_message": "", "error": {}, "current_size": 0, "desired_size": 0, "labels": { "key": "" }, "create_time": "2026-10-04T12:00:00Z", "update_time": "2026-10-04T12:00:00Z", "last_scale_out_time": "2026-10-04T12:00:00Z", "vpc": "projects//locations//vpcs/", "network_tags": [ "" ], "etag": "W/\"1\"", "managed_by": "", "pending_build": "builds/my-build", "rollout": { "strategy": "STRATEGY_ROLLING_UPDATE", "max_surge": 0, "max_surge_percent": 0, "max_unavailable": 0, "max_unavailable_percent": 0 }, "sleep_after_idle": "300s", "member_labels": { "key": "" }, "outdated_size": 0, "ready_size": 0, "allocated_size": 0, "sleeping_size": 0, "pending_game": "games/my-game"}parentstringRequiredprojects/{project}/locations/{location}, or projects/-/locations/{l}
for every project's groups in a location — internal callers only, and what
the scaling loop itself uses.
page_sizeint32page_tokenstringgrpcurl -H "authorization: Bearer $PLANY_API_KEY" \ -d '{ "parent": "", "page_size": 50 }' \ api.plany.cloud:443 plany.playpute.v1.PlayputeService/ListGameServerGroups{ "game_server_groups": [ { "name": "projects//locations//gameServerGroups/", "display_name": "My server", "game": "games/my-game", "build": "builds/my-build", "settings": { "key": "" }, "resources": {}, "machine_type": "", "spot": { "enabled": false, "on_demand_fallback": false, "notice_signal": "" }, "policy": { "min_size": 0, "max_size": 0, "target_player_percent": 0, "min_free_player_slots": 0, "scale_on_waiting_connections": false, "target_cpu_percent": 0, "scale_out_cooldown": "300s", "scale_in_patience": "300s", "max_scale_out_batch": 0, "max_scale_in_batch": 0, "drain_timeout": "300s", "buffer_size": 0, "buffer_percent": 0 }, "ephemeral": false, "exposure": "EXPOSURE_PUBLIC", "warmup_duration": "300s", "schematic": "projects//locations//schematics/my-schematic", "state": "STATE_WARMING_UP", "state_message": "", "error": {}, "current_size": 0, "desired_size": 0, "labels": { "key": "" }, "create_time": "2026-10-04T12:00:00Z", "update_time": "2026-10-04T12:00:00Z", "last_scale_out_time": "2026-10-04T12:00:00Z", "vpc": "projects//locations//vpcs/", "network_tags": [ "" ], "etag": "W/\"1\"", "managed_by": "", "pending_build": "builds/my-build", "rollout": { "strategy": "STRATEGY_ROLLING_UPDATE", "max_surge": 0, "max_surge_percent": 0, "max_unavailable": 0, "max_unavailable_percent": 0 }, "sleep_after_idle": "300s", "member_labels": { "key": "" }, "outdated_size": 0, "ready_size": 0, "allocated_size": 0, "sleeping_size": 0, "pending_game": "games/my-game" } ], "next_page_token": ""}Updates a group's policy, its build, or pauses and resumes its scaling.
game, ephemeral and exposure decide what a member is, and members
already exist, so they are refused. build is the exception and is a
rollout rather than an edit — see GameServerGroup.build.
A managed group is refused: change the manifest that created it.
gamestringRequiredThe game every member runs.
max_sizeint32Requiredmin_sizeint32Members never to go below, and never to go above.
A minimum of zero is legitimate and is what a group for an off-peak game wants: no players, no servers, no bill. The first player then pays a boot, which is what the schematic is for.
target_player_percentdoubleHold members at this fraction of their player capacity. 1..100.
The headline signal for a minigame: "keep servers 70% full" is the sentence a customer says. Needs the game to declare how many players a server holds; without that this term sits out rather than guessing.
min_free_player_slotsint32Keep at least this many player slots free across the whole group, so a party arriving together finds room without waiting for a boot.
Additive to the percentage rather than an alternative — they answer different questions, and a group that sets both gets whichever needs more.
scale_on_waiting_connectionsboolAdd members when connections are open against servers nobody is playing on.
The only leading signal available: every other term here reacts to load that has already landed, and this one is somebody who could not get in. It needs no capacity and no sample, so it works for a game the platform knows nothing about.
target_cpu_percentdoubleHold the group's mean CPU at this percentage of each member's allocation. 1..100.
scale_out_cooldownDurationHow long after growing before the group may grow again.
A member takes tens of seconds to accept its first player, and every pass inside that window sees the same load on the same members. Without this a group creates one member per pass until the first finishes booting.
scale_in_patienceDurationHow long a member must have been empty before it may be removed.
Longer than the cooldown by default and by intent. Scaling in on a momentary zero is the failure that matters here: presence is derived from the game's own log lines, which can be late or missed, so a server between two rounds reads as empty for a few seconds. Growing late is a queue; shrinking early is a disconnection, and only the first is fixed by waiting.
max_scale_out_batchint32Most members to add or remove in one pass.
max_scale_in_batchint32drain_timeoutDurationHow long a drained member is given to empty before it is removed anyway.
A drain is not a disconnection: the member stops being sent new players and keeps the ones it has. Somebody who never leaves would otherwise hold a member forever, so there is a deadline — long enough that a match finishes inside it.
buffer_sizeint32Keep this many members READY and unallocated, on top of those allocated.
Agones' FleetAutoscaler buffer, and the shape a lobby needs: "always two
servers accepting players, however many are mid-match". Reads the SDK state
the game reports, so it needs a game that calls Ready() and Allocate() —
for one that does not, every member is unallocated and the term asks only
for the buffer itself.
A sleeping READY member counts: it can be allocated. That is what makes a buffer cheap while nobody plays.
Combined with the other terms by maximum, like all of them, and bounded by
min_size and max_size.
buffer_percentdoubleThe buffer as a percentage of the group's size. 1..100. The larger of this
and buffer_size when both are set.
namestringIdentifierprojects/{p}/locations/{l}/gameServerGroups/{g}.
display_namestringbuildstringThe build every member runs.
Pinned like a game server's, and for a stronger reason: members are created and destroyed continuously, so a group that resolved the game's current build per member would put two versions of a customer's game in one fleet, with players matched across them by accident.
Updatable, and changing it is a rollout, never a mixture by accident. The
group goes on creating members on the old build while a warm-up bakes the new
one (pending_build), switches when the capture lands, and then replaces
outdated members within rollout — never one the game has marked ALLOCATED,
which is somebody's match and finishes on the build it started on.
settingsmap<string, string>Settings handed to every member, exactly as GameServer.settings.
machine_typestringThe machine type every member runs at, as GameServer.machine_type. Empty
takes the smallest type that meets the game's minimum.
Updatable, and a change reaches a member the next time it starts; it is not a rollout, because a size is not what a match is played on.
spotSpotConfigRun members on spot capacity, as GameServer.spot. Pro plan only.
A fleet is where spot is most useful — a minigame server reclaimed between
rounds costs nobody anything — and it composes with scaling in one way worth
knowing: a reclaimed member counts as not running, so a group that needs it
creates or starts another. With on_demand_fallback that one is on demand
when spot has nothing free, which is what keeps a fleet at size while the
region is busy.
enabledboolRun on spot capacity.
on_demand_fallbackboolStart on demand, at the on-demand rate, when no spot capacity is free.
Without it a start with no spot capacity waits for some and fails after a
minute, which is right for a server that is only worth running cheaply and
wrong for one players are waiting on. A server that fell back stays on
demand until it next stops; SpotStatus.running_on_spot says which it is.
notice_signalstringA signal to send the game's process when a notice arrives, e.g. SIGUSR1.
Empty sends nothing, and that is the default for a reason: the default
action of most signals is to terminate, so a signal a game does not handle
would stop it two minutes early. Name one only when the game handles it.
SIGTERM and SIGKILL are refused — the stop that follows the notice
sends the game's own stop signal already.
ephemeralboolWhether members keep their data.
Almost always true for the workload a group is for: a match has nothing worth carrying into the next one, and a member that hibernated would write its whole RAM to object storage on the way out of a world nobody will read.
It also changes what scaling in means. An ephemeral member is deleted when it is drained; a durable one is stopped, keeps its disks, and is started again when the group grows.
exposureExposureWhether players can reach members directly.
PROJECT_INTERNAL is the right default for a scaled fleet and the reason the field exists: members behind a matchmaker or a lobby are dialled from inside the project, and giving each one a public listener would be an entry point nobody intended and a proxy charge per member. The choice is the customer's, because a fleet of servers players do pick from a list is just as real a shape.
EXPOSURE_PUBLICEXPOSURE_PROJECT_INTERNALwarmup_durationDurationHow long a warm-up server runs before it is captured as the schematic.
The one number that decides how fast this group scales. A member started from a schematic skips the download, the install and the world generation — seconds instead of minutes — and what makes the schematic worth having is that the capture happened after all of that finished.
So this is "how long does your game take to be ready to play", and getting it wrong is visible in one direction only: too long wastes a few minutes once, and too short captures a server mid-install, which every member then starts from.
Zero skips the warm-up entirely and members boot cold. That is the right choice for a game that starts in seconds anyway, and the only choice for one whose first run must not be cloned.
schematicstringThe schematic members are started from.
Set by the group when its warm-up capture lands, or supplied at creation to reuse one that already exists — which is the faster path and the one a customer takes for their second group of the same game.
Empty means members boot cold, which is correct rather than broken: a group whose capture failed still scales, just slowly, and stopping it from scaling would turn a performance problem into an outage.
labelsmap<string, string>vpcstringImmutableThe private network every member is on, and the warm-up server before them. Empty is the project's default network in the group's region.
On the group rather than on each member because a member is the group's
to create: two members on different networks would be one fleet that
cannot reach itself. Requires vpc.vpcs.use on the network. Immutable,
for the reason GameServer.vpc is.
network_tagsrepeated stringNetwork tags on every member's interface, and the warm-up's, which firewall rules on the group's network can target. Lowercase letters, digits and hyphens.
rolloutRolloutPolicyHow members are replaced when build changes.
strategyRolloutPolicy.StrategySTRATEGY_ROLLING_UPDATESTRATEGY_RECREATEmax_surgeint32Members above the desired size a rolling update may create, as a count or as a percentage of the desired size. The larger of the two when both are set; 25% when neither is.
max_surge_percentint32max_unavailableint32Members below the desired size a rolling update may leave the group at, as a count or a percentage. 25% when neither is set.
max_unavailable_percentint32sleep_after_idleDurationPut members to sleep after this long with nobody on them. See
GameServer.sleep_after_idle, which every member is created with.
A sleeping member still counts toward the group's size and, if the game said it is READY, toward its buffer: it can be allocated or connected to, and either wakes it. That is the point of keeping it rather than removing it. Refused on an ephemeral group, whose members cannot hibernate.
member_labelsmap<string, string>Labels every member carries, and what an allocation selects on.
Not labels, which describe the group itself. Changing these reaches
members created afterwards; existing members keep what they were created
with, as a pod keeps its labels when a template changes.
update_maskFieldMaskgrpcurl -H "authorization: Bearer $PLANY_API_KEY" \ -d '{ "game_server_group": { "display_name": "My server", "game": "games/my-game", "policy": { "max_size": 0 } } }' \ api.plany.cloud:443 plany.playpute.v1.PlayputeService/UpdateGameServerGroup{ "name": "projects//locations//gameServerGroups/", "display_name": "My server", "game": "games/my-game", "build": "builds/my-build", "settings": { "key": "" }, "resources": { "cpu": { "vcpus": 0, "reserved_millis": "0", "limit_millis": "0", "architecture": "CPU_ARCHITECTURE_X86_64", "required_features": [ "" ], "dedicated_cores": false, "isolate_smt_siblings": false }, "memory": { "size_bytes": "0", "reserved_bytes": "0", "balloon_enabled": false, "hugepages": false, "hotplug_max_bytes": "0", "shared": false }, "disks": [ { "disk_id": "my-disk", "size_bytes": "0", "type": "DISK_TYPE_LOCAL_NVME", "read_only": false, "boot": false, "delete_on_instance_delete": false, "direct_io": false } ], "network_interfaces": [ { "interface_id": "my-interface", "network": "", "private_ipv4": "", "public_address_mode": "PUBLIC_ADDRESS_MODE_NONE", "tier": "NETWORK_TIER_STANDARD", "mac_address": "", "multi_queue": false, "tags": [ "" ], "deny_inbound": false, "no_default_route": false } ], "placement": { "zones": [ "" ], "placement_group": "", "policy": "PLACEMENT_POLICY_PACK", "capacity_class": "", "disallow_preemptible": false, "node": "" }, "scheduling": { "on_host_maintenance": "ON_HOST_MAINTENANCE_MIGRATE", "restart_policy": "RESTART_POLICY_NEVER", "preemptible": false, "preemption_notice": "300s", "max_run_duration": "300s", "termination_grace_period": "300s", "preemptible_fallback": false } }, "machine_type": "", "spot": { "enabled": false, "on_demand_fallback": false, "notice_signal": "" }, "policy": { "min_size": 0, "max_size": 0, "target_player_percent": 0, "min_free_player_slots": 0, "scale_on_waiting_connections": false, "target_cpu_percent": 0, "scale_out_cooldown": "300s", "scale_in_patience": "300s", "max_scale_out_batch": 0, "max_scale_in_batch": 0, "drain_timeout": "300s", "buffer_size": 0, "buffer_percent": 0 }, "ephemeral": false, "exposure": "EXPOSURE_PUBLIC", "warmup_duration": "300s", "schematic": "projects//locations//schematics/my-schematic", "state": "STATE_WARMING_UP", "state_message": "", "error": {}, "current_size": 0, "desired_size": 0, "labels": { "key": "" }, "create_time": "2026-10-04T12:00:00Z", "update_time": "2026-10-04T12:00:00Z", "last_scale_out_time": "2026-10-04T12:00:00Z", "vpc": "projects//locations//vpcs/", "network_tags": [ "" ], "etag": "W/\"1\"", "managed_by": "", "pending_build": "builds/my-build", "rollout": { "strategy": "STRATEGY_ROLLING_UPDATE", "max_surge": 0, "max_surge_percent": 0, "max_unavailable": 0, "max_unavailable_percent": 0 }, "sleep_after_idle": "300s", "member_labels": { "key": "" }, "outdated_size": 0, "ready_size": 0, "allocated_size": 0, "sleeping_size": 0, "pending_game": "games/my-game"}Deletes a group and every member it created.
Members go first and they are drained, not killed: a group deleted while
people are playing gives them the length of drain_timeout to finish.
namestringRequiredetagstringrequest_idstringgrpcurl -H "authorization: Bearer $PLANY_API_KEY" \ -d '{ "name": "projects//locations//gameServerGroups/" }' \ api.plany.cloud:443 plany.playpute.v1.PlayputeService/DeleteGameServerGroup{}parentstringRequiredprojects/{project}/locations/{location}.
page_sizeint32page_tokenstringgrpcurl -H "authorization: Bearer $PLANY_API_KEY" \ -d '{ "parent": "", "page_size": 50 }' \ api.plany.cloud:443 plany.playpute.v1.PlayputeService/ListProxyRoutes{ "proxy_routes": [ { "name": "projects//locations//gameServers//proxyRoutes/my-proxy-route", "game_server": "projects//locations//gameServers/", "game": "games/my-game", "port_name": "", "listen_host": "", "listen_port": 0, "protocol": "", "target_port": 0, "billable": false, "proxy": "", "create_time": "2026-10-04T12:00:00Z" } ], "next_page_token": ""}Reports that somebody is trying to play a server, and returns where to send them.
Called by Plany's connection proxy when a connection arrives for a server. If the server is running, the answer is its address; if it is not, this starts it and the caller asks again. Idempotent: a client that times out and retries, or twenty friends connecting at once, is one start.
You do not normally call this: connecting to the server's proxied address does it for you.
namestringRequiredport_namestringRequiredThe game's port name the connection arrived on, e.g. "game". Determines which endpoint comes back — a game with a query port has two, and sending a player to the wrong one is a connection that establishes and then does nothing.
client_addressstringThe connecting player's address, for logs. Never used to decide anything: it is whatever the proxy saw, and a wake is authorized by the proxy being an internal caller, not by who is connecting.
probe_onlyboolAsk where the server is without starting it.
A stopped server answers with its state and a retry_after exactly as it would otherwise, and stays stopped. Used so that server browsers and port scanners probing a sleeping server do not wake it; only sustained traffic does.
grpcurl -H "authorization: Bearer $PLANY_API_KEY" \ -d '{ "name": "projects//locations//gameServers/", "port_name": "" }' \ api.plany.cloud:443 plany.playpute.v1.PlayputeService/WakeGameServer{ "state": "STATE_PROVISIONING", "ready": false, "upstream": { "name": "", "host": "", "port": 0, "protocol": "", "address": "", "proxied": false }, "retry_after": "300s"}Hands a READY game server to a match.
Picks one server matching the selectors, tried in order, and moves it to ALLOCATED atomically — two allocations can never take the same server. Agones' GameServerAllocation, with a Plany project and region in place of a cluster and namespace.
An awake server is preferred to a sleeping one, and a sleeping one is allocated and woken in the same call. The answer does not wait for the wake: the server's address is reachable while it sleeps, and players' connections are held until it is up.
Nothing matching is RESOURCE_EXHAUSTED, as Agones' allocator answers, so a matchmaker already written for Agones handles it unchanged.
parentstringRequiredprojects/{project}/locations/{location}.
selectorsrepeated GameServerSelectorTried in order; the first that matches a server wins. Empty matches any READY server in the project and region that uses the SDK.
match_labelsmap<string, string>Every one of these must equal a label on the server — its own labels or its SDK labels.
match_expressionsrepeated LabelRequirementKubernetes' set-based requirements, all of which must hold.
keystringRequiredOPERATOR_INOPERATOR_NOT_INOPERATOR_EXISTSOPERATOR_DOES_NOT_EXISTvaluesrepeated stringstateSdkStatus.StateREADY (the default) or ALLOCATED — the second is Agones' re-allocation of a server that is already in use and has room, which is how a lobby is joined.
STATE_READYSTATE_ALLOCATEDSTATE_RESERVEDSTATE_SHUTDOWNSTATE_UNHEALTHYschedulingAllocateGameServerRequest.SchedulingSCHEDULING_PACKEDSCHEDULING_DISTRIBUTEDlabelsmap<string, string>Written onto the chosen server's SDK labels and annotations, where the game
reads them through WatchGameServer — how a matchmaker tells a server which
match it is.
annotationsmap<string, string>grpcurl -H "authorization: Bearer $PLANY_API_KEY" \ -d '{ "parent": "projects//locations/" }' \ api.plany.cloud:443 plany.playpute.v1.PlayputeService/AllocateGameServer{ "game_server": { "name": "projects//locations//gameServers/", "display_name": "My server", "game": "games/my-game", "build": "builds/my-build", "settings": { "key": "" }, "resources": {}, "machine_type": "", "spot": { "enabled": false, "on_demand_fallback": false, "notice_signal": "" }, "spot_status": { "running_on_spot": false, "termination_time": "2026-10-04T12:00:00Z", "last_reclaim_time": "2026-10-04T12:00:00Z", "preserving_disk": false, "notice": "300s" }, "state": "STATE_PROVISIONING", "state_message": "", "error": {}, "endpoints": [ { "name": "", "host": "", "port": 0, "protocol": "", "address": "", "proxied": false } ], "instance": "", "labels": { "key": "" }, "create_time": "2026-10-04T12:00:00Z", "update_time": "2026-10-04T12:00:00Z", "last_active_time": "2026-10-04T12:00:00Z", "service_account": "accounts//serviceAccounts/my-service-account", "ephemeral": false, "exposure": "EXPOSURE_PUBLIC", "schematic": "projects//locations//schematics/my-schematic", "group": "projects//locations//gameServerGroups/", "draining": false, "secrets": [ { "secret": "projects//locations//secrets/", "environment_variable": "", "file_path": "" } ], "sdk": { "state": "STATE_READY", "labels": { "key": "" }, "annotations": { "key": "" }, "reserved_until": "2026-10-04T12:00:00Z", "allocate_time": "2026-10-04T12:00:00Z", "health_time": "2026-10-04T12:00:00Z", "version": "0", "update_time": "2026-10-04T12:00:00Z" }, "sleep_after_idle": "300s", "managed_by": "", "install_complete_time": "2026-10-04T12:00:00Z", "vpc": "projects//locations//vpcs/", "network_tags": [ "" ], "etag": "W/\"1\"" }, "endpoints": [ { "name": "", "host": "", "port": 0, "protocol": "", "address": "", "proxied": false } ], "woken": false}Reports an Agones SDK call made by the game inside a server.
Called from inside the server, as the server's own identity, and only for that server. A game using the Agones SDK does this through the SDK; you do not call it directly.
namestringRequiredReady().
Allocate(), the game allocating itself.
Shutdown().
Reserve(d).
SetLabel(key, value), stored under agones.dev/sdk-.
keystringvaluestringSetAnnotation(key, value), likewise.
keystringvaluestringA Health() ping. Batched by the agent: at most one per period reaches
here, not one per ping.
The agent's own verdict that Health() stopped.
The install finished. Not an SDK call; the agent's report, on the same channel because it is the same caller asking the same question of the same row.
grpcurl -H "authorization: Bearer $PLANY_API_KEY" \ -d '{ "name": "projects//locations//gameServers/" }' \ api.plany.cloud:443 plany.playpute.v1.PlayputeService/UpdateGameServerSdk{ "state": "STATE_READY", "labels": { "key": "" }, "annotations": { "key": "" }, "reserved_until": "2026-10-04T12:00:00Z", "allocate_time": "2026-10-04T12:00:00Z", "health_time": "2026-10-04T12:00:00Z", "version": "0", "update_time": "2026-10-04T12:00:00Z"}Streams a server's SDK status to the server itself, now and on every change.
How an allocation reaches a game waiting in the Agones SDK's WatchGameServer. A game using the Agones SDK does this through the SDK; you do not call it directly.
namestringRequiredSdkStatus, as a stream.
grpcurl -H "authorization: Bearer $PLANY_API_KEY" \ -d '{ "name": "projects//locations//gameServers/" }' \ api.plany.cloud:443 plany.playpute.v1.PlayputeService/WatchGameServerSdk{ "state": "STATE_READY", "labels": { "key": "" }, "annotations": { "key": "" }, "reserved_until": "2026-10-04T12:00:00Z", "allocate_time": "2026-10-04T12:00:00Z", "health_time": "2026-10-04T12:00:00Z", "version": "0", "update_time": "2026-10-04T12:00:00Z"}Endpoint is an address players connect to.
namestringMatches the game's plany.game.v1.PortMapping name, e.g. "game".
hoststringportint32protocolstring"tcp" or "udp".
addressstringReady-to-paste form, e.g. "play.example.com:25565". Populated because every console and support conversation ends up building this string anyway, and building it in one place avoids three subtly different ones.
proxiedboolWhether this address is Plany's proxy rather than the server itself.
A proxied address is reachable while the server is stopped or asleep, and connecting to it starts the server — so it is the one to give to players. A player's first connection after a sleep waits a few seconds while the server comes back.
{ "name": "", "host": "", "port": 0, "protocol": "", "address": "", "proxied": false}GameServerSelector matches game servers for an allocation.
match_labelsmap<string, string>Every one of these must equal a label on the server — its own labels or its SDK labels.
match_expressionsrepeated LabelRequirementKubernetes' set-based requirements, all of which must hold.
keystringRequiredOPERATOR_INOPERATOR_NOT_INOPERATOR_EXISTSOPERATOR_DOES_NOT_EXISTvaluesrepeated stringstateSdkStatus.StateREADY (the default) or ALLOCATED — the second is Agones' re-allocation of a server that is already in use and has room, which is how a lobby is joined.
STATE_READYSTATE_ALLOCATEDSTATE_RESERVEDSTATE_SHUTDOWNSTATE_UNHEALTHY{ "match_labels": { "key": "" }, "match_expressions": [ { "key": "", "operator": "OPERATOR_IN", "values": [ "" ] } ], "state": "STATE_READY"}LabelRequirement is a set-based label selector term.
keystringRequiredOPERATOR_INOPERATOR_NOT_INOPERATOR_EXISTSOPERATOR_DOES_NOT_EXISTvaluesrepeated string{ "key": "", "operator": "OPERATOR_IN", "values": [ "" ]}OperationMetadata is the metadata on every Playpute long-running operation.
{ "create_time": "2026-10-04T12:00:00Z", "end_time": "2026-10-04T12:00:00Z", "target": "", "verb": "", "status_message": "", "requested_cancellation": false, "api_version": ""}ProxyRoute is one address players connect to, in front of a game server.
It is the answer to the question the product could not otherwise ask: a server that is hibernated has no host, no address and nothing listening, so "somebody wants to play" cannot be observed on the server itself. A route is a listener that outlives the server behind it. A connection arriving on it is the signal, and forwarding that same connection once the server is up is what makes the signal free of charge to the player — they connected, they waited, they are in.
A route is created per public port a game declares, because a player types one address and the game decides which port it means. RCON is not proxied: a route is reachable by anyone who can reach the proxy, and waking a server on a connection to its administrative console would let a stranger both start a customer's server and reach its shell prompt.
Internal. Customers never name a route — they see its address on
GameServer.endpoints, marked proxied.
namestringIdentifierprojects/{p}/locations/{l}/gameServers/{s}/proxyRoutes/{port_name}.
The last segment is the game's own port name — "game", "query" — rather than a generated id, so a route is addressable from the thing that produced it and a re-allocation cannot leave two routes for one port.
game_serverstringOutput onlygamestringOutput onlyThe game being served.
port_namestringOutput onlyThe game's plany.game.v1.PortMapping name this route fronts, e.g. "game".
listen_hoststringOutput onlyWhere the proxy listens, and what players are told to connect to.
listen_portint32Output onlyprotocolstringOutput only"tcp" or "udp". A game declaring both gets two routes: they are two listeners on two sockets, and a UDP session has no relationship to a TCP connection on the same number.
target_portint32Output onlyThe port the game listens on inside the server. Not the port the proxy listens on: a shared address cannot give every server 25565, so the two differ and the proxy translates.
billableboolOutput onlyWhether this route is charged for.
False for a game Plany publishes, true for a customer's own. Waking a Minecraft server costs Plany the same either way; the difference is what the platform is selling. A pre-configured game is the product, and its proxy is part of the price of the server. A customer's own game is a platform capability being used to host something Plany did not build, and charging for it is what stops the listener pool being free infrastructure for arbitrary traffic.
proxystringOutput onlyThe connection proxy this route is a listener on.
Every route on one network shares one, and it is what listen_port is
unique within — which is why two projects, or two networks of one project,
can both use 25565.
{ "name": "projects//locations//gameServers//proxyRoutes/my-proxy-route", "game_server": "projects//locations//gameServers/", "game": "games/my-game", "port_name": "", "listen_host": "", "listen_port": 0, "protocol": "", "target_port": 0, "billable": false, "proxy": "", "create_time": "2026-10-04T12:00:00Z"}RolloutPolicy is how a group replaces members running an old build.
Agones' Fleet.spec.strategy, and the same defaults: a rolling replacement,
a quarter of the group at a time in each direction.
strategyRolloutPolicy.StrategySTRATEGY_ROLLING_UPDATESTRATEGY_RECREATEmax_surgeint32Members above the desired size a rolling update may create, as a count or as a percentage of the desired size. The larger of the two when both are set; 25% when neither is.
max_surge_percentint32max_unavailableint32Members below the desired size a rolling update may leave the group at, as a count or a percentage. 25% when neither is set.
max_unavailable_percentint32{ "strategy": "STRATEGY_ROLLING_UPDATE", "max_surge": 0, "max_surge_percent": 0, "max_unavailable": 0, "max_unavailable_percent": 0}ScalingPolicy is what a group scales on.
Every target is a number to hold, never a threshold to cross, because a threshold answers "should I scale" and a target answers "to what" — and only the second can be satisfied in one step. A group that adds one member per pass while a threshold stays crossed takes as many passes as it needs members, with players queueing for all of them.
Zero means the term is off. Not "target zero", which read literally is an instruction to grow forever.
Terms combine by maximum: every one answers "how many members does this load need", and the largest answer is taken. Satisfying a smaller one would leave the larger term unsatisfied and the next pass would grow again anyway.
max_sizeint32Requiredmin_sizeint32Members never to go below, and never to go above.
A minimum of zero is legitimate and is what a group for an off-peak game wants: no players, no servers, no bill. The first player then pays a boot, which is what the schematic is for.
target_player_percentdoubleHold members at this fraction of their player capacity. 1..100.
The headline signal for a minigame: "keep servers 70% full" is the sentence a customer says. Needs the game to declare how many players a server holds; without that this term sits out rather than guessing.
min_free_player_slotsint32Keep at least this many player slots free across the whole group, so a party arriving together finds room without waiting for a boot.
Additive to the percentage rather than an alternative — they answer different questions, and a group that sets both gets whichever needs more.
scale_on_waiting_connectionsboolAdd members when connections are open against servers nobody is playing on.
The only leading signal available: every other term here reacts to load that has already landed, and this one is somebody who could not get in. It needs no capacity and no sample, so it works for a game the platform knows nothing about.
target_cpu_percentdoubleHold the group's mean CPU at this percentage of each member's allocation. 1..100.
scale_out_cooldownDurationHow long after growing before the group may grow again.
A member takes tens of seconds to accept its first player, and every pass inside that window sees the same load on the same members. Without this a group creates one member per pass until the first finishes booting.
scale_in_patienceDurationHow long a member must have been empty before it may be removed.
Longer than the cooldown by default and by intent. Scaling in on a momentary zero is the failure that matters here: presence is derived from the game's own log lines, which can be late or missed, so a server between two rounds reads as empty for a few seconds. Growing late is a queue; shrinking early is a disconnection, and only the first is fixed by waiting.
max_scale_out_batchint32Most members to add or remove in one pass.
max_scale_in_batchint32drain_timeoutDurationHow long a drained member is given to empty before it is removed anyway.
A drain is not a disconnection: the member stops being sent new players and keeps the ones it has. Somebody who never leaves would otherwise hold a member forever, so there is a deadline — long enough that a match finishes inside it.
buffer_sizeint32Keep this many members READY and unallocated, on top of those allocated.
Agones' FleetAutoscaler buffer, and the shape a lobby needs: "always two
servers accepting players, however many are mid-match". Reads the SDK state
the game reports, so it needs a game that calls Ready() and Allocate() —
for one that does not, every member is unallocated and the term asks only
for the buffer itself.
A sleeping READY member counts: it can be allocated. That is what makes a buffer cheap while nobody plays.
Combined with the other terms by maximum, like all of them, and bounded by
min_size and max_size.
buffer_percentdoubleThe buffer as a percentage of the group's size. 1..100. The larger of this
and buffer_size when both are set.
{ "min_size": 0, "max_size": 0, "target_player_percent": 0, "min_free_player_slots": 0, "scale_on_waiting_connections": false, "target_cpu_percent": 0, "scale_out_cooldown": "300s", "scale_in_patience": "300s", "max_scale_out_batch": 0, "max_scale_in_batch": 0, "drain_timeout": "300s", "buffer_size": 0, "buffer_percent": 0}SecretAttachment makes one secret readable by one game server.
The secret appears as an environment variable, and the same variable can be substituted into config files and the launch command as ${VAR}. So a Minecraft server's RCON password is one attachment: RCON_PASSWORD in the environment, and rcon.password=${RCON_PASSWORD} in server.properties.
Attaching does not copy the value. It allows this server to read that one secret, and stops the secret being deleted while it is attached. Rotating a secret is adding a new version and restarting the server.
secretstringRequiredprojects/{project}/locations/{location}/secrets/{secret}, optionally with
/versions/{version}.
Unqualified is the ordinary case and resolves to the latest enabled version, so a rotation reaches this server on its next start with nothing to edit. Pin a version when a server must not follow a rotation — which is rare, and worth being deliberate about, because the pin outlives the memory of why it was made.
environment_variablestringRequiredThe environment variable the server sees the secret as, e.g. RCON_PASSWORD.
Required, and must be a valid variable name — upper case letters, digits and underscores, not starting with a digit. It is not derived from the secret's id, because stripe-live-key is not a variable name.
The value has to be valid UTF-8 to be used this way. A secret holding binary data is refused when the server starts; use file_path for one.
file_pathstringAlso write the value to a file at this path, relative to the build root.
For the things that will not go in an environment variable: a service account JSON, a TLS key, a licence file a game reads by path. Optional, and when it is set the environment variable is still exported, because a value that is available two ways is easier to use than one with a rule about when it is which.
Written 0600 and owned by the game user, and deliberately not preserved
across restarts the way a plany.game.v1.ConfigFile can be: this is the platform's copy
of a value the platform holds, so the file is rewritten every launch and a
rotation cannot leave a stale one behind.
{ "secret": "projects//locations//secrets/", "environment_variable": "", "file_path": ""}SpotAvailability summarises a machine type's spot record in one region.
Deliberately never a count of free machines. How much spare capacity a region holds is Plany's fleet size read back through a side door; what a customer needs is whether they can have one and how often it will be taken away, and both are answerable as a fraction.
available_nowboolWhether a spot server of this type could be placed right now.
A reading, not a promise: spare capacity is whatever on-demand servers are not using, and the next on-demand create may take it.
availability_7ddoubleThe fraction of the last seven days in which a spot server of this type could have been placed, 0 to 1.
reclaims_per_day_7ddoubleHow often a running spot server of this type was reclaimed over the last seven days, as reclaims per server-day. 0.1 means one reclaim every ten days of running, on average.
sample_timeTimestampWhen the record was last sampled. Unset when this region has never recorded anything for the type — which is not the same as zero availability, and a console must not draw it as such.
{ "available_now": false, "availability_7d": 0, "reclaims_per_day_7d": 0, "sample_time": "2026-10-04T12:00:00Z"}SpotConfig asks for a game server to run on spare capacity.
Spot is spare capacity, sold at 60% off. The price of the discount is that it can be taken back: when an on-demand server needs the room, a spot server on it is given two minutes' notice and then stopped.
The notice reaches the game three ways, and a game may use any of them:
GET http://169.254.169.254/metadata/spot/instance-action answers 404 until a notice exists and then {"action":"stop","time":"<RFC 3339>"}. Poll it every few seconds.WatchGameServer delivers the annotation plany.cloud/spot-termination-time with the same RFC 3339 time.notice_signal names one.Everything on disk. A reclaimed server stops with its disk kept, and its next start brings that disk to wherever there is room — so a start just after a reclaim is slower than usual, and nothing on disk is lost. Memory is not kept: a reclaimed server boots from scratch.
Accounts on the Pro plan. Spot is refused on any other plan, and a server whose account has since left Pro starts on demand.
enabledboolRun on spot capacity.
on_demand_fallbackboolStart on demand, at the on-demand rate, when no spot capacity is free.
Without it a start with no spot capacity waits for some and fails after a
minute, which is right for a server that is only worth running cheaply and
wrong for one players are waiting on. A server that fell back stays on
demand until it next stops; SpotStatus.running_on_spot says which it is.
notice_signalstringA signal to send the game's process when a notice arrives, e.g. SIGUSR1.
Empty sends nothing, and that is the default for a reason: the default
action of most signals is to terminate, so a signal a game does not handle
would stop it two minutes early. Name one only when the game handles it.
SIGTERM and SIGKILL are refused — the stop that follows the notice
sends the game's own stop signal already.
{ "enabled": false, "on_demand_fallback": false, "notice_signal": ""}SpotHistoryPoint is one bucket of a machine type's spot record.
intervalIntervalavailabilitydoubleThe fraction of this bucket in which a spot server of the type could have
been placed. Unset (with measured false) for a bucket the platform took
no samples in.
reclaimsint64Spot servers of this type reclaimed during the bucket.
running_hoursdoubleServer-hours of spot running of this type during the bucket. What makes
reclaims a rate rather than a count: two reclaims among two servers and
two among two hundred are different records.
measuredboolWhether any sample landed in this bucket. A gap is "not measured", never "unavailable".
{ "interval": { "start_time": "2026-10-01T00:00:00Z", "end_time": "2026-10-04T00:00:00Z" }, "availability": 0, "reclaims": "0", "running_hours": 0, "measured": false}SpotStatus is what spot is doing for a server right now.
running_on_spotboolOutput onlyWhether the current run is on spot capacity. False for a server that fell back to on demand, and for one that is not running.
When the current run will be stopped, once a notice has been given.
When this server was last reclaimed.
preserving_diskboolOutput onlyWhether the disk of a reclaimed server is still being captured. A start is refused as retryable until it finishes, because starting before it would boot a server without its world.
How long the notice was, for a console that wants to draw a countdown.
{ "running_on_spot": false, "termination_time": "2026-10-04T12:00:00Z", "last_reclaim_time": "2026-10-04T12:00:00Z", "preserving_disk": false, "notice": "300s"}The empty message, named here so an action with no argument is still a distinct arm of the oneof.
No parameters.
{}keystringvaluestring{ "key": "", "value": ""}AllocateGameServerResponse is the server a match was given.
game_serverGameServergamestringRequiredThe game to run. Must be launchable — a branch node has no build.
namestringIdentifierprojects/{project}/locations/{location}/gameServers/{game_server}.
Project- and region-scoped, like every resource that consumes capacity: it runs somewhere specific, and it is billed to the project that owns it.
display_namestringbuildstringOutput onlyResolved at create time and never re-resolved.
A game's build moves on; a running server's must not. Pinning it here means an update to "Minecraft Forge 1.20.4" cannot silently change what a customer's server is running under their players' feet.
settingsmap<string, string>Overrides for the game's declared settings, by key.
What the server runs with: the machine type's vCPUs and memory, and the game's declared disk.
Output only. A size is chosen by naming a machine_type; this field used
to take any vCPU count and any amount of memory, and a create or update
that sets it is refused with a pointer to machine_type. See
MachineType for why sizes are named now.
disksrepeated DiskSpecBlock devices, in attachment order. Exactly one must set boot unless the
workload boots from an initramfs alone.
network_interfacesrepeated NetworkInterfaceSpecplacementPlacementSpecschedulingSchedulingSpecmachine_typestringThe size to run at, by machine type id — standard-4, highmem-2.
Empty takes the smallest type that meets the game's own declared minimum,
and a type below that minimum is refused, because a server too small for
its game boots, installs, and is killed for memory at the first player.
ListMachineTypes is the catalogue. Changing it takes effect on the next
start.
spotSpotConfigRun on spare capacity at a discount, and accept being reclaimed with two
minutes' notice. Pro plan only. See SpotConfig.
Changing it takes effect on the next start.
enabledboolRun on spot capacity.
on_demand_fallbackboolStart on demand, at the on-demand rate, when no spot capacity is free.
Without it a start with no spot capacity waits for some and fails after a
minute, which is right for a server that is only worth running cheaply and
wrong for one players are waiting on. A server that fell back stays on
demand until it next stops; SpotStatus.running_on_spot says which it is.
notice_signalstringA signal to send the game's process when a notice arrives, e.g. SIGUSR1.
Empty sends nothing, and that is the default for a reason: the default
action of most signals is to terminate, so a signal a game does not handle
would stop it two minutes early. Name one only when the game handles it.
SIGTERM and SIGKILL are refused — the stop that follows the notice
sends the game's own stop signal already.
What spot is doing for this server right now.
running_on_spotboolOutput onlyWhether the current run is on spot capacity. False for a server that fell back to on demand, and for one that is not running.
When the current run will be stopped, once a notice has been given.
When this server was last reclaimed.
preserving_diskboolOutput onlyWhether the disk of a reclaimed server is still being captured. A start is refused as retryable until it finishes, because starting before it would boot a server without its world.
How long the notice was, for a console that wants to draw a countdown.
STATE_PROVISIONINGSTATE_STARTINGSTATE_RUNNINGSTATE_STOPPEDSTATE_STOPPINGSTATE_FAILEDSTATE_DELETINGstate_messagestringOutput onlyHow to reach it. Empty until the server is running and has an address.
A port may appear twice: once as Plany's proxy and once as the server's own address, distinguished by proxied. Give players the proxied one: it is reachable while the server is stopped, and connecting to it starts the server.
Proxied entries come first, so endpoints[0] is the address to hand out.
namestringMatches the game's plany.game.v1.PortMapping name, e.g. "game".
hoststringportint32protocolstring"tcp" or "udp".
addressstringReady-to-paste form, e.g. "play.example.com:25565". Populated because every console and support conversation ends up building this string anyway, and building it in one place avoids three subtly different ones.
proxiedboolWhether this address is Plany's proxy rather than the server itself.
A proxied address is reachable while the server is stopped or asleep, and connecting to it starts the server — so it is the one to give to players. A player's first connection after a sleep waits a few seconds while the server comes back.
instancestringOutput onlyAn identifier Plany support may ask for when investigating a server. Output only; nothing in the API acts on it.
labelsmap<string, string>When it last had a player. Drives idle shutdown, and is the field activity billing will read.
service_accountstringThe identity this server acts as.
Leave it empty and Playpute creates one per server, allowed to touch this server and nothing else — the right default, since a server runs your players' mods.
Set it to a service account you own and the server acts as that instead. That is for a fleet: grant one service account a role elsewhere, attach it to twenty servers, and those twenty can use it while the rest of the account cannot.
Attaching one requires iam.serviceAccounts.actAs on that service account, not merely permission to create a server — otherwise anybody who could create a server could act as anybody.
ssh_public_keysrepeated stringInput onlySSH keys allowed to log in to this server, for debugging.
They take effect only on a server booted from an image that includes an SSH server, and are read when the server boots, so a key added later needs a restart. Input only: the keys are not returned when the server is read.
imagestringInput onlyThe image to boot, by id. Empty uses Plany's current default, which is what almost every server should do.
An id from Plany's own published images; a server cannot boot an image of your own.
ephemeralboolKeep nothing. The world and the disks go when the server does.
The right shape for a match rather than a world: a minigame round has nothing worth carrying into the next one, and an ephemeral server saves the storage and the time of keeping it.
An ephemeral server never sleeps, because there is nothing to wake into, so sleep_after_idle is refused on one.
Immutable after creation: the guarantee is about data that was never kept, so it cannot be turned off afterwards.
exposureExposureWhether players outside the project can reach this server.
Immutable after creation: it decides whether a listener and a public address exist at all, and flipping it on a running server would change the address players were given.
EXPOSURE_PUBLICEXPOSURE_PROJECT_INTERNALschematicstringThe schematic this server's disk was copied from, if any.
What makes a scaled fleet viable: the build is already unpacked, the install script has already run and the world already exists, so a member reaches RUNNING in seconds where a cold boot is minutes.
A copy, not an attachment. The schematic is read once into a fresh disk and never referenced again, which is why deleting one does not disturb a server started from it — and why two members from one schematic diverge immediately rather than sharing anything.
groupstringOutput onlyThe group that created and owns this server, if any.
Output-only and not settable: a server does not join a group, a group creates it. The distinction matters because the group's loop deletes what it owns, and a server that could name a group it was not created by would be a way to have somebody else'"'"'s fleet delete your server.
A member deleted by hand comes back. Its size is the group'"'"'s to decide, so removing one is a decision the next pass overrules.
drainingboolOutput onlyWhether this server is draining: serving the players it has and being sent no new ones, on its way out.
Its own field rather than a state, because a draining server is still
RUNNING in every way that matters — it holds players, it bills, it serves.
Folding it into state would make every consumer that switches on state
handle a case that behaves identically to RUNNING, and the one that forgot
would stop showing a server people are on.
secretsrepeated SecretAttachmentSecrets this server can read: database passwords, API keys, RCON passwords, a licence key a game wants in a file.
Each attachment names a secret in the same project and region and says how the server sees it. The value is never stored on the server's configuration — the server fetches it when it starts, as its own identity — so nothing you can read back from the server reveals it.
Changing this takes effect on the next start. A running server keeps what it read when it started.
secretstringRequiredprojects/{project}/locations/{location}/secrets/{secret}, optionally with
/versions/{version}.
Unqualified is the ordinary case and resolves to the latest enabled version, so a rotation reaches this server on its next start with nothing to edit. Pin a version when a server must not follow a rotation — which is rare, and worth being deliberate about, because the pin outlives the memory of why it was made.
environment_variablestringRequiredThe environment variable the server sees the secret as, e.g. RCON_PASSWORD.
Required, and must be a valid variable name — upper case letters, digits and underscores, not starting with a digit. It is not derived from the secret's id, because stripe-live-key is not a variable name.
The value has to be valid UTF-8 to be used this way. A secret holding binary data is refused when the server starts; use file_path for one.
file_pathstringAlso write the value to a file at this path, relative to the build root.
For the things that will not go in an environment variable: a service account JSON, a TLS key, a licence file a game reads by path. Optional, and when it is set the environment variable is still exported, because a value that is available two ways is easier to use than one with a rule about when it is which.
Written 0600 and owned by the game user, and deliberately not preserved
across restarts the way a plany.game.v1.ConfigFile can be: this is the platform's copy
of a value the platform holds, so the file is rewritten every launch and a
rotation cannot leave a stale one behind.
What the game has told the platform about itself through the Agones SDK.
Every game server runs the SDK server, whether or not it came from an Agones
manifest, so a customer's own game can call Ready() and Allocate() the
way an Agones game does. A game that never calls it has an empty sdk, and
nothing reads one: allocation, the buffer term and idle sleep all treat an
unset state as "not using the SDK" rather than as not ready.
Separate from state for the reason activity is. state is what the
machine is doing and the platform decides it; this is what the game says
it is doing, and a RUNNING server is READY, ALLOCATED or neither.
STATE_READYSTATE_ALLOCATEDSTATE_RESERVEDSTATE_SHUTDOWNSTATE_UNHEALTHYlabelsmap<string, string>Output onlyLabels and annotations the game and its allocations wrote.
SetLabel("mode", "ranked") is stored as agones.dev/sdk-mode, which is
Agones' own prefix and what a selector written for Agones asks for. An
allocation's metadata is stored as given. Kept apart from
GameServer.labels, which the customer or the manifest owns: a game writing
its own labels must not be able to rewrite the ones its fleet selects on.
annotationsmap<string, string>Output onlyWhen a RESERVED server returns to READY.
When it was last allocated.
When the game last sent Health().
versionint64Output onlyIncreases on every change. Reported to the game as the Agones resource_version.
sleep_after_idleDurationPut the server to sleep after this long with nobody on it.
Sleep is hibernation: the server's memory is captured, its host released, and the next player's connection — or an allocation — restores it in seconds with everything it held in memory. Compute is not charged while it sleeps.
The counterpart of idle_shutdown_minutes, and different in the one way that
matters: that stops a server a customer forgot about, and this is the
platform doing what "pay when played" means for a server somebody wants
kept ready. A server the game has marked ALLOCATED or RESERVED never sleeps,
because it is somebody's match.
Idle is measured from the connection proxy's view of the server — no connections and no players — and a server whose presence could not be read is not idle. Refused on an ephemeral server, which cannot hibernate. Zero keeps it awake.
managed_bystringOutput onlyThe product that created and owns this server, if it was not you.
autopilot.agones.plany.cloud for a server Agones Autopilot created from a manifest. Change such a server by changing the manifest: Playpute's own update and delete refuse it.
When the server finished installing its build — for a container build, the image pulled and unpacked; for any other, the build downloaded and its install script run.
vpcstringImmutableThe private network this server is on. Empty is the project's default network in the server's region.
Decided by the server, never by its game: a game is a catalogue entry
shared by every project that runs it, and a network written there would be
one project's network named in everybody's servers. Requires
vpc.vpcs.use on the network, which must be in the server's own project
and region.
Immutable. A server that changed network would change address under the players connected to it, and the connection proxy in front of it is the proxy for that network — players reach a server through the proxy on the network it is on, so each network a project uses has a proxy of its own.
network_tagsrepeated stringNetwork tags on this server's interface, which firewall rules on its network can target. Lowercase letters, digits and hyphens.
etagstringOutput onlyendpointsrepeated EndpointWhere players connect: the proxied endpoints, which are reachable whether or not the server is awake yet.
namestringMatches the game's plany.game.v1.PortMapping name, e.g. "game".
hoststringportint32protocolstring"tcp" or "udp".
addressstringReady-to-paste form, e.g. "play.example.com:25565". Populated because every console and support conversation ends up building this string anyway, and building it in one place avoids three subtly different ones.
proxiedboolWhether this address is Plany's proxy rather than the server itself.
A proxied address is reachable while the server is stopped or asleep, and connecting to it starts the server — so it is the one to give to players. A player's first connection after a sleep waits a few seconds while the server comes back.
wokenboolWhether the allocation woke a sleeping server. Players connecting now wait a few seconds for the restore; nothing about the address changes.
GameServer is one running copy of a game.
It is the product's unit: you pick a game and a region, and get something players can connect to.
gamestringRequiredThe game to run. Must be launchable — a branch node has no build.
namestringIdentifierprojects/{project}/locations/{location}/gameServers/{game_server}.
Project- and region-scoped, like every resource that consumes capacity: it runs somewhere specific, and it is billed to the project that owns it.
display_namestringbuildstringOutput onlyResolved at create time and never re-resolved.
A game's build moves on; a running server's must not. Pinning it here means an update to "Minecraft Forge 1.20.4" cannot silently change what a customer's server is running under their players' feet.
settingsmap<string, string>Overrides for the game's declared settings, by key.
What the server runs with: the machine type's vCPUs and memory, and the game's declared disk.
Output only. A size is chosen by naming a machine_type; this field used
to take any vCPU count and any amount of memory, and a create or update
that sets it is refused with a pointer to machine_type. See
MachineType for why sizes are named now.
vcpusint32RequiredNumber of virtual CPUs the workload sees. Required, must be at least 1.
reserved_millisint64CPU time reserved on the host, in millicores (1000 = one full core).
Must be <= vcpus * 1000. Zero means "reserve the full vcpus * 1000", i.e. no oversubscription. Below that, the VM is burstable and the difference is the burst headroom.
limit_millisint64Hard ceiling on host CPU time, in millicores, enforced by the agent via cgroup cpu.max. Zero means the ceiling is vcpus * 1000. Set this below vcpus * 1000 to cap a burstable VM that would otherwise consume all idle capacity on the node.
architectureCpuArchitectureCPU_ARCHITECTURE_X86_64CPU_ARCHITECTURE_ARM64required_featuresrepeated stringCPUID feature flags the workload requires, lowercase as they appear in /proc/cpuinfo — e.g. "avx2", "aes". Placement rejects nodes lacking any of them. Anti-cheat and DRM in game servers occasionally depend on these.
dedicated_coresboolPin each vCPU to a distinct physical core and let no other workload share those cores. Removes noisy-neighbour jitter for latency-sensitive tick loops, at the cost of a dedicated-core price.
isolate_smt_siblingsboolRequire SMT siblings of the pinned cores to stay idle. Only meaningful with dedicated_cores; used for workloads that are sensitive to hyperthread contention or that need side-channel isolation.
size_bytesint64RequiredMemory the workload sees, in bytes. Required.
reserved_bytesint64Memory guaranteed to the workload, in bytes. Must be no more than size_bytes. Zero means all of size_bytes is guaranteed.
Reserving less than size_bytes requires balloon_enabled, so unused memory can be reclaimed when it is needed elsewhere.
balloon_enabledboolAllow memory the workload is not using to be reclaimed. Required when reserved_bytes is less than size_bytes.
hugepagesboolBack the workload's memory with 2 MiB pages. Noticeably faster for memory-heavy servers — large voxel worlds, big entity counts — but can only be placed where such memory is available.
hotplug_max_bytesint64Allow memory to grow to this size while running, without a restart. Zero disables it. Must be at least size_bytes when set.
sharedboolAllow identical memory pages to be shared with other workloads on the same machine. Saves memory when many servers run the same game, at some CPU cost and with weaker isolation between them.
disksrepeated DiskSpecBlock devices, in attachment order. Exactly one must set boot unless the
workload boots from an initramfs alone.
disk_idstringRequiredIdentifier for this disk within the workload, e.g. "root" or "world-data". Must be unique within it.
size_bytesint64Size of the device. Required for a blank disk; for an image or snapshot source, zero means "the source's own size" and any larger value grows the filesystem on first boot.
typeDiskTypeDISK_TYPE_LOCAL_NVMEDISK_TYPE_NETWORK_SSDDISK_TYPE_NETWORK_SSD_HIGH_IOPSread_onlyboolAttach read-only. Several instances may share one read-only volume, which is how a common asset bundle is mounted into many game servers at once.
bootboolMarks the disk the workload boots from. Exactly one disk may set this.
delete_on_instance_deleteboolDelete the underlying storage when the instance is deleted. Always true in effect for LOCAL_NVME.
io_limitsDiskSpec.IoLimitsdirect_ioboolUse direct IO (O_DIRECT), bypassing the host page cache. Lowers memory pressure on the node and makes latency more predictable, at the cost of losing host-side caching.
network_interfacesrepeated NetworkInterfaceSpecinterface_idstringRequiredStable identifier within the instance, e.g. "eth0".
networkstringPrivate network to attach to, as a resource name. Empty means the project's default network in this location.
private_ipv4stringRequested private IPv4 address. Empty allocates one from the subnet.
public_address_modeNetworkInterfaceSpec.PublicAddressModePUBLIC_ADDRESS_MODE_NONEPUBLIC_ADDRESS_MODE_SHARED_IPV4PUBLIC_ADDRESS_MODE_DEDICATED_IPV4PUBLIC_ADDRESS_MODE_IPV6tierNetworkTierNETWORK_TIER_STANDARDNETWORK_TIER_PREMIUMrate_limitsNetworkInterfaceSpec.RateLimitsmac_addressstringThe interface's MAC address. Empty generates one. Pinning it matters for game licences tied to a MAC.
multi_queueboolEnable multi-queue virtio-net with one queue pair per vCPU. Raises packet throughput for servers handling many concurrent clients.
tagsrepeated stringNetwork tags, which firewall rules on this interface's network target.
Per interface rather than per instance because a rule belongs to one network, and an instance with an interface on each of two networks is answerable to two sets of rules. Lowercase letters, digits and hyphens, up to 63 characters each.
deny_inboundboolRefuse every inbound connection on this interface, whatever the network's firewall rules say. Replies to connections the workload opened still arrive.
For an interface that exists so a workload can reach a network rather than be reached on it — a sandbox connected to one of your networks, for example.
no_default_routeboolSend no internet traffic and no DNS through this interface: only the network's own range is reached through it. Without this, a workload with two interfaces could send its internet traffic out of either.
placementPlacementSpeczonesrepeated stringZones the instance may land in, as location ids ("eu-west-2a"). Empty means any zone in the region. More than one entry is a preference list in priority order, not a hard set.
required_node_selectorsrepeated NodeSelectorRequirementHard node requirements. A node must satisfy every entry.
preferred_node_selectorsrepeated NodeSelectorRequirementSoft node preferences. Nodes satisfying more of these score higher, but none of them can make placement fail.
placement_groupstringGroup this workload belongs to, scoped to the project. Workloads sharing a group are spread out or packed together according to policy.
policyPlacementPolicyPLACEMENT_POLICY_PACKPLACEMENT_POLICY_SPREADPLACEMENT_POLICY_STRICT_SPREAD_NODEPLACEMENT_POLICY_STRICT_SPREAD_ZONEcapacity_classstringClass of capacity to draw from. Leave empty to let Plany choose, which is right for almost every workload.
disallow_preemptibleboolRefuse to place onto pre-emptible (spot) capacity. Spot is materially cheaper and fine for a dev server, but wrong for a ranked match in progress.
nodestringPin to one node by resource name. Bypasses scoring entirely; intended for debugging and for rescheduling a VM back onto the node holding its local disk.
schedulingSchedulingSpecon_host_maintenanceSchedulingSpec.OnHostMaintenanceON_HOST_MAINTENANCE_MIGRATEON_HOST_MAINTENANCE_TERMINATErestart_policySchedulingSpec.RestartPolicyRESTART_POLICY_NEVERRESTART_POLICY_ALWAYSRESTART_POLICY_ON_FAILUREpreemptibleboolRun as spot: on spare capacity, at the spot rate, reclaimable with two minutes' notice when an on-demand workload needs the room.
preemption_noticeDurationWarning given before a spot reclaim, readable at /metadata/spot/instance-action on the metadata service. The notice is always two minutes; leave this unset.
max_run_durationDurationStop the instance automatically once it has run this long. Zero means no limit. This is the guard rail that stops a forgotten dev server draining a hobby account's credit overnight.
termination_grace_periodDurationTime between the shutdown signal and a forced stop, so a game server can save its world. Zero uses the default of thirty seconds.
preemptible_fallbackboolWith preemptible: place as an ordinary on-demand workload when no spare
capacity fits, rather than waiting for some. The allocation says which
happened, and it is what the instance is billed at.
machine_typestringThe size to run at, by machine type id — standard-4, highmem-2.
Empty takes the smallest type that meets the game's own declared minimum,
and a type below that minimum is refused, because a server too small for
its game boots, installs, and is killed for memory at the first player.
ListMachineTypes is the catalogue. Changing it takes effect on the next
start.
spotSpotConfigRun on spare capacity at a discount, and accept being reclaimed with two
minutes' notice. Pro plan only. See SpotConfig.
Changing it takes effect on the next start.
enabledboolRun on spot capacity.
on_demand_fallbackboolStart on demand, at the on-demand rate, when no spot capacity is free.
Without it a start with no spot capacity waits for some and fails after a
minute, which is right for a server that is only worth running cheaply and
wrong for one players are waiting on. A server that fell back stays on
demand until it next stops; SpotStatus.running_on_spot says which it is.
notice_signalstringA signal to send the game's process when a notice arrives, e.g. SIGUSR1.
Empty sends nothing, and that is the default for a reason: the default
action of most signals is to terminate, so a signal a game does not handle
would stop it two minutes early. Name one only when the game handles it.
SIGTERM and SIGKILL are refused — the stop that follows the notice
sends the game's own stop signal already.
What spot is doing for this server right now.
running_on_spotboolOutput onlyWhether the current run is on spot capacity. False for a server that fell back to on demand, and for one that is not running.
When the current run will be stopped, once a notice has been given.
When this server was last reclaimed.
preserving_diskboolOutput onlyWhether the disk of a reclaimed server is still being captured. A start is refused as retryable until it finishes, because starting before it would boot a server without its world.
How long the notice was, for a console that wants to draw a countdown.
STATE_PROVISIONINGSTATE_STARTINGSTATE_RUNNINGSTATE_STOPPEDSTATE_STOPPINGSTATE_FAILEDSTATE_DELETINGstate_messagestringOutput onlyHow to reach it. Empty until the server is running and has an address.
A port may appear twice: once as Plany's proxy and once as the server's own address, distinguished by proxied. Give players the proxied one: it is reachable while the server is stopped, and connecting to it starts the server.
Proxied entries come first, so endpoints[0] is the address to hand out.
namestringMatches the game's plany.game.v1.PortMapping name, e.g. "game".
hoststringportint32protocolstring"tcp" or "udp".
addressstringReady-to-paste form, e.g. "play.example.com:25565". Populated because every console and support conversation ends up building this string anyway, and building it in one place avoids three subtly different ones.
proxiedboolWhether this address is Plany's proxy rather than the server itself.
A proxied address is reachable while the server is stopped or asleep, and connecting to it starts the server — so it is the one to give to players. A player's first connection after a sleep waits a few seconds while the server comes back.
instancestringOutput onlyAn identifier Plany support may ask for when investigating a server. Output only; nothing in the API acts on it.
labelsmap<string, string>When it last had a player. Drives idle shutdown, and is the field activity billing will read.
service_accountstringThe identity this server acts as.
Leave it empty and Playpute creates one per server, allowed to touch this server and nothing else — the right default, since a server runs your players' mods.
Set it to a service account you own and the server acts as that instead. That is for a fleet: grant one service account a role elsewhere, attach it to twenty servers, and those twenty can use it while the rest of the account cannot.
Attaching one requires iam.serviceAccounts.actAs on that service account, not merely permission to create a server — otherwise anybody who could create a server could act as anybody.
ssh_public_keysrepeated stringInput onlySSH keys allowed to log in to this server, for debugging.
They take effect only on a server booted from an image that includes an SSH server, and are read when the server boots, so a key added later needs a restart. Input only: the keys are not returned when the server is read.
imagestringInput onlyThe image to boot, by id. Empty uses Plany's current default, which is what almost every server should do.
An id from Plany's own published images; a server cannot boot an image of your own.
ephemeralboolKeep nothing. The world and the disks go when the server does.
The right shape for a match rather than a world: a minigame round has nothing worth carrying into the next one, and an ephemeral server saves the storage and the time of keeping it.
An ephemeral server never sleeps, because there is nothing to wake into, so sleep_after_idle is refused on one.
Immutable after creation: the guarantee is about data that was never kept, so it cannot be turned off afterwards.
exposureExposureWhether players outside the project can reach this server.
Immutable after creation: it decides whether a listener and a public address exist at all, and flipping it on a running server would change the address players were given.
EXPOSURE_PUBLICEXPOSURE_PROJECT_INTERNALschematicstringThe schematic this server's disk was copied from, if any.
What makes a scaled fleet viable: the build is already unpacked, the install script has already run and the world already exists, so a member reaches RUNNING in seconds where a cold boot is minutes.
A copy, not an attachment. The schematic is read once into a fresh disk and never referenced again, which is why deleting one does not disturb a server started from it — and why two members from one schematic diverge immediately rather than sharing anything.
groupstringOutput onlyThe group that created and owns this server, if any.
Output-only and not settable: a server does not join a group, a group creates it. The distinction matters because the group's loop deletes what it owns, and a server that could name a group it was not created by would be a way to have somebody else'"'"'s fleet delete your server.
A member deleted by hand comes back. Its size is the group'"'"'s to decide, so removing one is a decision the next pass overrules.
drainingboolOutput onlyWhether this server is draining: serving the players it has and being sent no new ones, on its way out.
Its own field rather than a state, because a draining server is still
RUNNING in every way that matters — it holds players, it bills, it serves.
Folding it into state would make every consumer that switches on state
handle a case that behaves identically to RUNNING, and the one that forgot
would stop showing a server people are on.
secretsrepeated SecretAttachmentSecrets this server can read: database passwords, API keys, RCON passwords, a licence key a game wants in a file.
Each attachment names a secret in the same project and region and says how the server sees it. The value is never stored on the server's configuration — the server fetches it when it starts, as its own identity — so nothing you can read back from the server reveals it.
Changing this takes effect on the next start. A running server keeps what it read when it started.
secretstringRequiredprojects/{project}/locations/{location}/secrets/{secret}, optionally with
/versions/{version}.
Unqualified is the ordinary case and resolves to the latest enabled version, so a rotation reaches this server on its next start with nothing to edit. Pin a version when a server must not follow a rotation — which is rare, and worth being deliberate about, because the pin outlives the memory of why it was made.
environment_variablestringRequiredThe environment variable the server sees the secret as, e.g. RCON_PASSWORD.
Required, and must be a valid variable name — upper case letters, digits and underscores, not starting with a digit. It is not derived from the secret's id, because stripe-live-key is not a variable name.
The value has to be valid UTF-8 to be used this way. A secret holding binary data is refused when the server starts; use file_path for one.
file_pathstringAlso write the value to a file at this path, relative to the build root.
For the things that will not go in an environment variable: a service account JSON, a TLS key, a licence file a game reads by path. Optional, and when it is set the environment variable is still exported, because a value that is available two ways is easier to use than one with a rule about when it is which.
Written 0600 and owned by the game user, and deliberately not preserved
across restarts the way a plany.game.v1.ConfigFile can be: this is the platform's copy
of a value the platform holds, so the file is rewritten every launch and a
rotation cannot leave a stale one behind.
What the game has told the platform about itself through the Agones SDK.
Every game server runs the SDK server, whether or not it came from an Agones
manifest, so a customer's own game can call Ready() and Allocate() the
way an Agones game does. A game that never calls it has an empty sdk, and
nothing reads one: allocation, the buffer term and idle sleep all treat an
unset state as "not using the SDK" rather than as not ready.
Separate from state for the reason activity is. state is what the
machine is doing and the platform decides it; this is what the game says
it is doing, and a RUNNING server is READY, ALLOCATED or neither.
STATE_READYSTATE_ALLOCATEDSTATE_RESERVEDSTATE_SHUTDOWNSTATE_UNHEALTHYlabelsmap<string, string>Output onlyLabels and annotations the game and its allocations wrote.
SetLabel("mode", "ranked") is stored as agones.dev/sdk-mode, which is
Agones' own prefix and what a selector written for Agones asks for. An
allocation's metadata is stored as given. Kept apart from
GameServer.labels, which the customer or the manifest owns: a game writing
its own labels must not be able to rewrite the ones its fleet selects on.
annotationsmap<string, string>Output onlyWhen a RESERVED server returns to READY.
When it was last allocated.
When the game last sent Health().
versionint64Output onlyIncreases on every change. Reported to the game as the Agones resource_version.
sleep_after_idleDurationPut the server to sleep after this long with nobody on it.
Sleep is hibernation: the server's memory is captured, its host released, and the next player's connection — or an allocation — restores it in seconds with everything it held in memory. Compute is not charged while it sleeps.
The counterpart of idle_shutdown_minutes, and different in the one way that
matters: that stops a server a customer forgot about, and this is the
platform doing what "pay when played" means for a server somebody wants
kept ready. A server the game has marked ALLOCATED or RESERVED never sleeps,
because it is somebody's match.
Idle is measured from the connection proxy's view of the server — no connections and no players — and a server whose presence could not be read is not idle. Refused on an ephemeral server, which cannot hibernate. Zero keeps it awake.
managed_bystringOutput onlyThe product that created and owns this server, if it was not you.
autopilot.agones.plany.cloud for a server Agones Autopilot created from a manifest. Change such a server by changing the manifest: Playpute's own update and delete refuse it.
When the server finished installing its build — for a container build, the image pulled and unpacked; for any other, the build downloaded and its install script run.
vpcstringImmutableThe private network this server is on. Empty is the project's default network in the server's region.
Decided by the server, never by its game: a game is a catalogue entry
shared by every project that runs it, and a network written there would be
one project's network named in everybody's servers. Requires
vpc.vpcs.use on the network, which must be in the server's own project
and region.
Immutable. A server that changed network would change address under the players connected to it, and the connection proxy in front of it is the proxy for that network — players reach a server through the proxy on the network it is on, so each network a project uses has a proxy of its own.
network_tagsrepeated stringNetwork tags on this server's interface, which firewall rules on its network can target. Lowercase letters, digits and hyphens.
etagstringOutput onlyGameServerGroup is a fleet of identical game servers that grows and shrinks with demand.
The shape a minigame needs: a lobby fills and more servers arrive, a round ends and they go away. Everything about a member — the game, the build, the resources, whether it keeps data, whether players can reach it directly — is declared once here, so members never differ from each other.
A member is a GameServer with group set, and every call that works on a server works on it: it can be read and its logs listed. What is different is deleting one by hand — it is recreated, because the group decides its own size.
A group adds no charge of its own. Its members are billed as any other game server, and its schematic as storage.
gamestringRequiredThe game every member runs.
max_sizeint32Requiredmin_sizeint32Members never to go below, and never to go above.
A minimum of zero is legitimate and is what a group for an off-peak game wants: no players, no servers, no bill. The first player then pays a boot, which is what the schematic is for.
target_player_percentdoubleHold members at this fraction of their player capacity. 1..100.
The headline signal for a minigame: "keep servers 70% full" is the sentence a customer says. Needs the game to declare how many players a server holds; without that this term sits out rather than guessing.
min_free_player_slotsint32Keep at least this many player slots free across the whole group, so a party arriving together finds room without waiting for a boot.
Additive to the percentage rather than an alternative — they answer different questions, and a group that sets both gets whichever needs more.
scale_on_waiting_connectionsboolAdd members when connections are open against servers nobody is playing on.
The only leading signal available: every other term here reacts to load that has already landed, and this one is somebody who could not get in. It needs no capacity and no sample, so it works for a game the platform knows nothing about.
target_cpu_percentdoubleHold the group's mean CPU at this percentage of each member's allocation. 1..100.
scale_out_cooldownDurationHow long after growing before the group may grow again.
A member takes tens of seconds to accept its first player, and every pass inside that window sees the same load on the same members. Without this a group creates one member per pass until the first finishes booting.
scale_in_patienceDurationHow long a member must have been empty before it may be removed.
Longer than the cooldown by default and by intent. Scaling in on a momentary zero is the failure that matters here: presence is derived from the game's own log lines, which can be late or missed, so a server between two rounds reads as empty for a few seconds. Growing late is a queue; shrinking early is a disconnection, and only the first is fixed by waiting.
max_scale_out_batchint32Most members to add or remove in one pass.
max_scale_in_batchint32drain_timeoutDurationHow long a drained member is given to empty before it is removed anyway.
A drain is not a disconnection: the member stops being sent new players and keeps the ones it has. Somebody who never leaves would otherwise hold a member forever, so there is a deadline — long enough that a match finishes inside it.
buffer_sizeint32Keep this many members READY and unallocated, on top of those allocated.
Agones' FleetAutoscaler buffer, and the shape a lobby needs: "always two
servers accepting players, however many are mid-match". Reads the SDK state
the game reports, so it needs a game that calls Ready() and Allocate() —
for one that does not, every member is unallocated and the term asks only
for the buffer itself.
A sleeping READY member counts: it can be allocated. That is what makes a buffer cheap while nobody plays.
Combined with the other terms by maximum, like all of them, and bounded by
min_size and max_size.
buffer_percentdoubleThe buffer as a percentage of the group's size. 1..100. The larger of this
and buffer_size when both are set.
namestringIdentifierprojects/{p}/locations/{l}/gameServerGroups/{g}.
display_namestringbuildstringThe build every member runs.
Pinned like a game server's, and for a stronger reason: members are created and destroyed continuously, so a group that resolved the game's current build per member would put two versions of a customer's game in one fleet, with players matched across them by accident.
Updatable, and changing it is a rollout, never a mixture by accident. The
group goes on creating members on the old build while a warm-up bakes the new
one (pending_build), switches when the capture lands, and then replaces
outdated members within rollout — never one the game has marked ALLOCATED,
which is somebody's match and finishes on the build it started on.
settingsmap<string, string>Settings handed to every member, exactly as GameServer.settings.
What each member gets. Uniform across the fleet by construction.
Output only: resolved from machine_type and the game's disk, exactly as
GameServer.resources is.
vcpusint32RequiredNumber of virtual CPUs the workload sees. Required, must be at least 1.
reserved_millisint64CPU time reserved on the host, in millicores (1000 = one full core).
Must be <= vcpus * 1000. Zero means "reserve the full vcpus * 1000", i.e. no oversubscription. Below that, the VM is burstable and the difference is the burst headroom.
limit_millisint64Hard ceiling on host CPU time, in millicores, enforced by the agent via cgroup cpu.max. Zero means the ceiling is vcpus * 1000. Set this below vcpus * 1000 to cap a burstable VM that would otherwise consume all idle capacity on the node.
architectureCpuArchitectureCPU_ARCHITECTURE_X86_64CPU_ARCHITECTURE_ARM64required_featuresrepeated stringCPUID feature flags the workload requires, lowercase as they appear in /proc/cpuinfo — e.g. "avx2", "aes". Placement rejects nodes lacking any of them. Anti-cheat and DRM in game servers occasionally depend on these.
dedicated_coresboolPin each vCPU to a distinct physical core and let no other workload share those cores. Removes noisy-neighbour jitter for latency-sensitive tick loops, at the cost of a dedicated-core price.
isolate_smt_siblingsboolRequire SMT siblings of the pinned cores to stay idle. Only meaningful with dedicated_cores; used for workloads that are sensitive to hyperthread contention or that need side-channel isolation.
size_bytesint64RequiredMemory the workload sees, in bytes. Required.
reserved_bytesint64Memory guaranteed to the workload, in bytes. Must be no more than size_bytes. Zero means all of size_bytes is guaranteed.
Reserving less than size_bytes requires balloon_enabled, so unused memory can be reclaimed when it is needed elsewhere.
balloon_enabledboolAllow memory the workload is not using to be reclaimed. Required when reserved_bytes is less than size_bytes.
hugepagesboolBack the workload's memory with 2 MiB pages. Noticeably faster for memory-heavy servers — large voxel worlds, big entity counts — but can only be placed where such memory is available.
hotplug_max_bytesint64Allow memory to grow to this size while running, without a restart. Zero disables it. Must be at least size_bytes when set.
sharedboolAllow identical memory pages to be shared with other workloads on the same machine. Saves memory when many servers run the same game, at some CPU cost and with weaker isolation between them.
disksrepeated DiskSpecBlock devices, in attachment order. Exactly one must set boot unless the
workload boots from an initramfs alone.
disk_idstringRequiredIdentifier for this disk within the workload, e.g. "root" or "world-data". Must be unique within it.
size_bytesint64Size of the device. Required for a blank disk; for an image or snapshot source, zero means "the source's own size" and any larger value grows the filesystem on first boot.
typeDiskTypeDISK_TYPE_LOCAL_NVMEDISK_TYPE_NETWORK_SSDDISK_TYPE_NETWORK_SSD_HIGH_IOPSread_onlyboolAttach read-only. Several instances may share one read-only volume, which is how a common asset bundle is mounted into many game servers at once.
bootboolMarks the disk the workload boots from. Exactly one disk may set this.
delete_on_instance_deleteboolDelete the underlying storage when the instance is deleted. Always true in effect for LOCAL_NVME.
io_limitsDiskSpec.IoLimitsdirect_ioboolUse direct IO (O_DIRECT), bypassing the host page cache. Lowers memory pressure on the node and makes latency more predictable, at the cost of losing host-side caching.
network_interfacesrepeated NetworkInterfaceSpecinterface_idstringRequiredStable identifier within the instance, e.g. "eth0".
networkstringPrivate network to attach to, as a resource name. Empty means the project's default network in this location.
private_ipv4stringRequested private IPv4 address. Empty allocates one from the subnet.
public_address_modeNetworkInterfaceSpec.PublicAddressModePUBLIC_ADDRESS_MODE_NONEPUBLIC_ADDRESS_MODE_SHARED_IPV4PUBLIC_ADDRESS_MODE_DEDICATED_IPV4PUBLIC_ADDRESS_MODE_IPV6tierNetworkTierNETWORK_TIER_STANDARDNETWORK_TIER_PREMIUMrate_limitsNetworkInterfaceSpec.RateLimitsmac_addressstringThe interface's MAC address. Empty generates one. Pinning it matters for game licences tied to a MAC.
multi_queueboolEnable multi-queue virtio-net with one queue pair per vCPU. Raises packet throughput for servers handling many concurrent clients.
tagsrepeated stringNetwork tags, which firewall rules on this interface's network target.
Per interface rather than per instance because a rule belongs to one network, and an instance with an interface on each of two networks is answerable to two sets of rules. Lowercase letters, digits and hyphens, up to 63 characters each.
deny_inboundboolRefuse every inbound connection on this interface, whatever the network's firewall rules say. Replies to connections the workload opened still arrive.
For an interface that exists so a workload can reach a network rather than be reached on it — a sandbox connected to one of your networks, for example.
no_default_routeboolSend no internet traffic and no DNS through this interface: only the network's own range is reached through it. Without this, a workload with two interfaces could send its internet traffic out of either.
placementPlacementSpeczonesrepeated stringZones the instance may land in, as location ids ("eu-west-2a"). Empty means any zone in the region. More than one entry is a preference list in priority order, not a hard set.
required_node_selectorsrepeated NodeSelectorRequirementHard node requirements. A node must satisfy every entry.
preferred_node_selectorsrepeated NodeSelectorRequirementSoft node preferences. Nodes satisfying more of these score higher, but none of them can make placement fail.
placement_groupstringGroup this workload belongs to, scoped to the project. Workloads sharing a group are spread out or packed together according to policy.
policyPlacementPolicyPLACEMENT_POLICY_PACKPLACEMENT_POLICY_SPREADPLACEMENT_POLICY_STRICT_SPREAD_NODEPLACEMENT_POLICY_STRICT_SPREAD_ZONEcapacity_classstringClass of capacity to draw from. Leave empty to let Plany choose, which is right for almost every workload.
disallow_preemptibleboolRefuse to place onto pre-emptible (spot) capacity. Spot is materially cheaper and fine for a dev server, but wrong for a ranked match in progress.
nodestringPin to one node by resource name. Bypasses scoring entirely; intended for debugging and for rescheduling a VM back onto the node holding its local disk.
schedulingSchedulingSpecon_host_maintenanceSchedulingSpec.OnHostMaintenanceON_HOST_MAINTENANCE_MIGRATEON_HOST_MAINTENANCE_TERMINATErestart_policySchedulingSpec.RestartPolicyRESTART_POLICY_NEVERRESTART_POLICY_ALWAYSRESTART_POLICY_ON_FAILUREpreemptibleboolRun as spot: on spare capacity, at the spot rate, reclaimable with two minutes' notice when an on-demand workload needs the room.
preemption_noticeDurationWarning given before a spot reclaim, readable at /metadata/spot/instance-action on the metadata service. The notice is always two minutes; leave this unset.
max_run_durationDurationStop the instance automatically once it has run this long. Zero means no limit. This is the guard rail that stops a forgotten dev server draining a hobby account's credit overnight.
termination_grace_periodDurationTime between the shutdown signal and a forced stop, so a game server can save its world. Zero uses the default of thirty seconds.
preemptible_fallbackboolWith preemptible: place as an ordinary on-demand workload when no spare
capacity fits, rather than waiting for some. The allocation says which
happened, and it is what the instance is billed at.
machine_typestringThe machine type every member runs at, as GameServer.machine_type. Empty
takes the smallest type that meets the game's minimum.
Updatable, and a change reaches a member the next time it starts; it is not a rollout, because a size is not what a match is played on.
spotSpotConfigRun members on spot capacity, as GameServer.spot. Pro plan only.
A fleet is where spot is most useful — a minigame server reclaimed between
rounds costs nobody anything — and it composes with scaling in one way worth
knowing: a reclaimed member counts as not running, so a group that needs it
creates or starts another. With on_demand_fallback that one is on demand
when spot has nothing free, which is what keeps a fleet at size while the
region is busy.
enabledboolRun on spot capacity.
on_demand_fallbackboolStart on demand, at the on-demand rate, when no spot capacity is free.
Without it a start with no spot capacity waits for some and fails after a
minute, which is right for a server that is only worth running cheaply and
wrong for one players are waiting on. A server that fell back stays on
demand until it next stops; SpotStatus.running_on_spot says which it is.
notice_signalstringA signal to send the game's process when a notice arrives, e.g. SIGUSR1.
Empty sends nothing, and that is the default for a reason: the default
action of most signals is to terminate, so a signal a game does not handle
would stop it two minutes early. Name one only when the game handles it.
SIGTERM and SIGKILL are refused — the stop that follows the notice
sends the game's own stop signal already.
ephemeralboolWhether members keep their data.
Almost always true for the workload a group is for: a match has nothing worth carrying into the next one, and a member that hibernated would write its whole RAM to object storage on the way out of a world nobody will read.
It also changes what scaling in means. An ephemeral member is deleted when it is drained; a durable one is stopped, keeps its disks, and is started again when the group grows.
exposureExposureWhether players can reach members directly.
PROJECT_INTERNAL is the right default for a scaled fleet and the reason the field exists: members behind a matchmaker or a lobby are dialled from inside the project, and giving each one a public listener would be an entry point nobody intended and a proxy charge per member. The choice is the customer's, because a fleet of servers players do pick from a list is just as real a shape.
EXPOSURE_PUBLICEXPOSURE_PROJECT_INTERNALwarmup_durationDurationHow long a warm-up server runs before it is captured as the schematic.
The one number that decides how fast this group scales. A member started from a schematic skips the download, the install and the world generation — seconds instead of minutes — and what makes the schematic worth having is that the capture happened after all of that finished.
So this is "how long does your game take to be ready to play", and getting it wrong is visible in one direction only: too long wastes a few minutes once, and too short captures a server mid-install, which every member then starts from.
Zero skips the warm-up entirely and members boot cold. That is the right choice for a game that starts in seconds anyway, and the only choice for one whose first run must not be cloned.
schematicstringThe schematic members are started from.
Set by the group when its warm-up capture lands, or supplied at creation to reuse one that already exists — which is the faster path and the one a customer takes for their second group of the same game.
Empty means members boot cold, which is correct rather than broken: a group whose capture failed still scales, just slowly, and stopping it from scaling would turn a performance problem into an outage.
STATE_WARMING_UPSTATE_ACTIVESTATE_PAUSEDSTATE_FAILEDSTATE_DELETINGstate_messagestringOutput onlyWhy the group is in this state, in a sentence — including, when it is ACTIVE and holding steady, why it is not scaling. A customer asking "why do I have three servers" should be able to read the answer.
current_sizeint32Output onlyMembers that exist right now, in any state.
desired_sizeint32Output onlyMembers the last pass decided there should be.
Differs from current_size while a member is booting or draining, which is
most of the time a group is doing anything.
labelsmap<string, string>When the group last grew. What the scale-out cooldown is measured from.
vpcstringImmutableThe private network every member is on, and the warm-up server before them. Empty is the project's default network in the group's region.
On the group rather than on each member because a member is the group's
to create: two members on different networks would be one fleet that
cannot reach itself. Requires vpc.vpcs.use on the network. Immutable,
for the reason GameServer.vpc is.
network_tagsrepeated stringNetwork tags on every member's interface, and the warm-up's, which firewall rules on the group's network can target. Lowercase letters, digits and hyphens.
etagstringOutput onlymanaged_bystringOutput onlyThe product that created and owns this group, if it was not you.
See GameServer.managed_by: the same meaning, and the same refusal of your own update or delete. Its members carry it too.
pending_buildstringOutput onlyA build the group is baking and will roll onto when the capture lands.
Empty when the group is on the build it was asked for.
rolloutRolloutPolicyHow members are replaced when build changes.
strategyRolloutPolicy.StrategySTRATEGY_ROLLING_UPDATESTRATEGY_RECREATEmax_surgeint32Members above the desired size a rolling update may create, as a count or as a percentage of the desired size. The larger of the two when both are set; 25% when neither is.
max_surge_percentint32max_unavailableint32Members below the desired size a rolling update may leave the group at, as a count or a percentage. 25% when neither is set.
max_unavailable_percentint32sleep_after_idleDurationPut members to sleep after this long with nobody on them. See
GameServer.sleep_after_idle, which every member is created with.
A sleeping member still counts toward the group's size and, if the game said it is READY, toward its buffer: it can be allocated or connected to, and either wakes it. That is the point of keeping it rather than removing it. Refused on an ephemeral group, whose members cannot hibernate.
member_labelsmap<string, string>Labels every member carries, and what an allocation selects on.
Not labels, which describe the group itself. Changing these reaches
members created afterwards; existing members keep what they were created
with, as a pod keeps its labels when a template changes.
outdated_sizeint32Output onlyMembers running a build other than build, while a rollout replaces them.
ready_sizeint32Output onlyMembers whose game has said READY, awake or asleep.
allocated_sizeint32Output onlyMembers whose game is ALLOCATED or RESERVED.
sleeping_sizeint32Output onlyMembers asleep.
pending_gamestringOutput onlyA game the group is baking and will roll onto with pending_build.
Only a managed group moves its game: an Agones template change alters the runtime (the command, the environment, the ports) as well as the image, and a runtime lives on a game. A customer's group keeps its game for life.
GameServerSchematic is a game server captured as a fast-start template.
A server is started, left to install its build and generate its world, and its disk is captured — so every server started from it skips the download, the install and the world generation. For a modded server that is the difference between minutes and tens of seconds.
A schematic is stored, so it is billed. It is charged per GiB-hour from the moment the capture completes until you delete it, whether or not anything starts from it.
namestringIdentifierdisplay_namestringgamestringOutput onlyThe game this was captured from, so a schematic can be offered for the game it actually fits. Starting a Minecraft server from a captured Garry's Mod disk is not a thing anybody means to do.
buildstringOutput onlyThe build that was installed when the capture was taken.
A schematic pins what it contains: the disk holds one build's files, and a game whose build has since moved on cannot be started from this.
source_game_serverstringOutput onlyThe server it was captured from. Retained after that server is deleted, which is the ordinary case — provenance rather than a reference.
STATE_PENDINGSTATE_READYSTATE_FAILEDSTATE_DELETINGsize_bytesint64Output onlySize of the captured disk. What storage is billed on.
labelsmap<string, string>When the capture completed and storage began accruing.
etagstringOutput onlygame_server_groupsrepeated GameServerGroupgamestringRequiredThe game every member runs.
max_sizeint32Requiredmin_sizeint32Members never to go below, and never to go above.
A minimum of zero is legitimate and is what a group for an off-peak game wants: no players, no servers, no bill. The first player then pays a boot, which is what the schematic is for.
target_player_percentdoubleHold members at this fraction of their player capacity. 1..100.
The headline signal for a minigame: "keep servers 70% full" is the sentence a customer says. Needs the game to declare how many players a server holds; without that this term sits out rather than guessing.
min_free_player_slotsint32Keep at least this many player slots free across the whole group, so a party arriving together finds room without waiting for a boot.
Additive to the percentage rather than an alternative — they answer different questions, and a group that sets both gets whichever needs more.
scale_on_waiting_connectionsboolAdd members when connections are open against servers nobody is playing on.
The only leading signal available: every other term here reacts to load that has already landed, and this one is somebody who could not get in. It needs no capacity and no sample, so it works for a game the platform knows nothing about.
target_cpu_percentdoubleHold the group's mean CPU at this percentage of each member's allocation. 1..100.
scale_out_cooldownDurationHow long after growing before the group may grow again.
A member takes tens of seconds to accept its first player, and every pass inside that window sees the same load on the same members. Without this a group creates one member per pass until the first finishes booting.
scale_in_patienceDurationHow long a member must have been empty before it may be removed.
Longer than the cooldown by default and by intent. Scaling in on a momentary zero is the failure that matters here: presence is derived from the game's own log lines, which can be late or missed, so a server between two rounds reads as empty for a few seconds. Growing late is a queue; shrinking early is a disconnection, and only the first is fixed by waiting.
max_scale_out_batchint32Most members to add or remove in one pass.
max_scale_in_batchint32drain_timeoutDurationHow long a drained member is given to empty before it is removed anyway.
A drain is not a disconnection: the member stops being sent new players and keeps the ones it has. Somebody who never leaves would otherwise hold a member forever, so there is a deadline — long enough that a match finishes inside it.
buffer_sizeint32Keep this many members READY and unallocated, on top of those allocated.
Agones' FleetAutoscaler buffer, and the shape a lobby needs: "always two
servers accepting players, however many are mid-match". Reads the SDK state
the game reports, so it needs a game that calls Ready() and Allocate() —
for one that does not, every member is unallocated and the term asks only
for the buffer itself.
A sleeping READY member counts: it can be allocated. That is what makes a buffer cheap while nobody plays.
Combined with the other terms by maximum, like all of them, and bounded by
min_size and max_size.
buffer_percentdoubleThe buffer as a percentage of the group's size. 1..100. The larger of this
and buffer_size when both are set.
namestringIdentifierprojects/{p}/locations/{l}/gameServerGroups/{g}.
display_namestringbuildstringThe build every member runs.
Pinned like a game server's, and for a stronger reason: members are created and destroyed continuously, so a group that resolved the game's current build per member would put two versions of a customer's game in one fleet, with players matched across them by accident.
Updatable, and changing it is a rollout, never a mixture by accident. The
group goes on creating members on the old build while a warm-up bakes the new
one (pending_build), switches when the capture lands, and then replaces
outdated members within rollout — never one the game has marked ALLOCATED,
which is somebody's match and finishes on the build it started on.
settingsmap<string, string>Settings handed to every member, exactly as GameServer.settings.
What each member gets. Uniform across the fleet by construction.
Output only: resolved from machine_type and the game's disk, exactly as
GameServer.resources is.
disksrepeated DiskSpecBlock devices, in attachment order. Exactly one must set boot unless the
workload boots from an initramfs alone.
network_interfacesrepeated NetworkInterfaceSpecplacementPlacementSpecschedulingSchedulingSpecmachine_typestringThe machine type every member runs at, as GameServer.machine_type. Empty
takes the smallest type that meets the game's minimum.
Updatable, and a change reaches a member the next time it starts; it is not a rollout, because a size is not what a match is played on.
spotSpotConfigRun members on spot capacity, as GameServer.spot. Pro plan only.
A fleet is where spot is most useful — a minigame server reclaimed between
rounds costs nobody anything — and it composes with scaling in one way worth
knowing: a reclaimed member counts as not running, so a group that needs it
creates or starts another. With on_demand_fallback that one is on demand
when spot has nothing free, which is what keeps a fleet at size while the
region is busy.
enabledboolRun on spot capacity.
on_demand_fallbackboolStart on demand, at the on-demand rate, when no spot capacity is free.
Without it a start with no spot capacity waits for some and fails after a
minute, which is right for a server that is only worth running cheaply and
wrong for one players are waiting on. A server that fell back stays on
demand until it next stops; SpotStatus.running_on_spot says which it is.
notice_signalstringA signal to send the game's process when a notice arrives, e.g. SIGUSR1.
Empty sends nothing, and that is the default for a reason: the default
action of most signals is to terminate, so a signal a game does not handle
would stop it two minutes early. Name one only when the game handles it.
SIGTERM and SIGKILL are refused — the stop that follows the notice
sends the game's own stop signal already.
ephemeralboolWhether members keep their data.
Almost always true for the workload a group is for: a match has nothing worth carrying into the next one, and a member that hibernated would write its whole RAM to object storage on the way out of a world nobody will read.
It also changes what scaling in means. An ephemeral member is deleted when it is drained; a durable one is stopped, keeps its disks, and is started again when the group grows.
exposureExposureWhether players can reach members directly.
PROJECT_INTERNAL is the right default for a scaled fleet and the reason the field exists: members behind a matchmaker or a lobby are dialled from inside the project, and giving each one a public listener would be an entry point nobody intended and a proxy charge per member. The choice is the customer's, because a fleet of servers players do pick from a list is just as real a shape.
EXPOSURE_PUBLICEXPOSURE_PROJECT_INTERNALwarmup_durationDurationHow long a warm-up server runs before it is captured as the schematic.
The one number that decides how fast this group scales. A member started from a schematic skips the download, the install and the world generation — seconds instead of minutes — and what makes the schematic worth having is that the capture happened after all of that finished.
So this is "how long does your game take to be ready to play", and getting it wrong is visible in one direction only: too long wastes a few minutes once, and too short captures a server mid-install, which every member then starts from.
Zero skips the warm-up entirely and members boot cold. That is the right choice for a game that starts in seconds anyway, and the only choice for one whose first run must not be cloned.
schematicstringThe schematic members are started from.
Set by the group when its warm-up capture lands, or supplied at creation to reuse one that already exists — which is the faster path and the one a customer takes for their second group of the same game.
Empty means members boot cold, which is correct rather than broken: a group whose capture failed still scales, just slowly, and stopping it from scaling would turn a performance problem into an outage.
STATE_WARMING_UPSTATE_ACTIVESTATE_PAUSEDSTATE_FAILEDSTATE_DELETINGstate_messagestringOutput onlyWhy the group is in this state, in a sentence — including, when it is ACTIVE and holding steady, why it is not scaling. A customer asking "why do I have three servers" should be able to read the answer.
current_sizeint32Output onlyMembers that exist right now, in any state.
desired_sizeint32Output onlyMembers the last pass decided there should be.
Differs from current_size while a member is booting or draining, which is
most of the time a group is doing anything.
labelsmap<string, string>When the group last grew. What the scale-out cooldown is measured from.
vpcstringImmutableThe private network every member is on, and the warm-up server before them. Empty is the project's default network in the group's region.
On the group rather than on each member because a member is the group's
to create: two members on different networks would be one fleet that
cannot reach itself. Requires vpc.vpcs.use on the network. Immutable,
for the reason GameServer.vpc is.
network_tagsrepeated stringNetwork tags on every member's interface, and the warm-up's, which firewall rules on the group's network can target. Lowercase letters, digits and hyphens.
etagstringOutput onlymanaged_bystringOutput onlyThe product that created and owns this group, if it was not you.
See GameServer.managed_by: the same meaning, and the same refusal of your own update or delete. Its members carry it too.
pending_buildstringOutput onlyA build the group is baking and will roll onto when the capture lands.
Empty when the group is on the build it was asked for.
rolloutRolloutPolicyHow members are replaced when build changes.
strategyRolloutPolicy.StrategySTRATEGY_ROLLING_UPDATESTRATEGY_RECREATEmax_surgeint32Members above the desired size a rolling update may create, as a count or as a percentage of the desired size. The larger of the two when both are set; 25% when neither is.
max_surge_percentint32max_unavailableint32Members below the desired size a rolling update may leave the group at, as a count or a percentage. 25% when neither is set.
max_unavailable_percentint32sleep_after_idleDurationPut members to sleep after this long with nobody on them. See
GameServer.sleep_after_idle, which every member is created with.
A sleeping member still counts toward the group's size and, if the game said it is READY, toward its buffer: it can be allocated or connected to, and either wakes it. That is the point of keeping it rather than removing it. Refused on an ephemeral group, whose members cannot hibernate.
member_labelsmap<string, string>Labels every member carries, and what an allocation selects on.
Not labels, which describe the group itself. Changing these reaches
members created afterwards; existing members keep what they were created
with, as a pod keeps its labels when a template changes.
outdated_sizeint32Output onlyMembers running a build other than build, while a rollout replaces them.
ready_sizeint32Output onlyMembers whose game has said READY, awake or asleep.
allocated_sizeint32Output onlyMembers whose game is ALLOCATED or RESERVED.
sleeping_sizeint32Output onlyMembers asleep.
pending_gamestringOutput onlyA game the group is baking and will roll onto with pending_build.
Only a managed group moves its game: an Agones template change alters the runtime (the command, the environment, the ports) as well as the image, and a runtime lives on a game. A customer's group keeps its game for life.
next_page_tokenstringschematicsrepeated GameServerSchematicnamestringIdentifierdisplay_namestringgamestringOutput onlyThe game this was captured from, so a schematic can be offered for the game it actually fits. Starting a Minecraft server from a captured Garry's Mod disk is not a thing anybody means to do.
buildstringOutput onlyThe build that was installed when the capture was taken.
A schematic pins what it contains: the disk holds one build's files, and a game whose build has since moved on cannot be started from this.
source_game_serverstringOutput onlyThe server it was captured from. Retained after that server is deleted, which is the ordinary case — provenance rather than a reference.
STATE_PENDINGSTATE_READYSTATE_FAILEDSTATE_DELETINGsize_bytesint64Output onlySize of the captured disk. What storage is billed on.
labelsmap<string, string>When the capture completed and storage began accruing.
etagstringOutput onlynext_page_tokenstringgame_serversrepeated GameServergamestringRequiredThe game to run. Must be launchable — a branch node has no build.
namestringIdentifierprojects/{project}/locations/{location}/gameServers/{game_server}.
Project- and region-scoped, like every resource that consumes capacity: it runs somewhere specific, and it is billed to the project that owns it.
display_namestringbuildstringOutput onlyResolved at create time and never re-resolved.
A game's build moves on; a running server's must not. Pinning it here means an update to "Minecraft Forge 1.20.4" cannot silently change what a customer's server is running under their players' feet.
settingsmap<string, string>Overrides for the game's declared settings, by key.
What the server runs with: the machine type's vCPUs and memory, and the game's declared disk.
Output only. A size is chosen by naming a machine_type; this field used
to take any vCPU count and any amount of memory, and a create or update
that sets it is refused with a pointer to machine_type. See
MachineType for why sizes are named now.
disksrepeated DiskSpecBlock devices, in attachment order. Exactly one must set boot unless the
workload boots from an initramfs alone.
network_interfacesrepeated NetworkInterfaceSpecplacementPlacementSpecschedulingSchedulingSpecmachine_typestringThe size to run at, by machine type id — standard-4, highmem-2.
Empty takes the smallest type that meets the game's own declared minimum,
and a type below that minimum is refused, because a server too small for
its game boots, installs, and is killed for memory at the first player.
ListMachineTypes is the catalogue. Changing it takes effect on the next
start.
spotSpotConfigRun on spare capacity at a discount, and accept being reclaimed with two
minutes' notice. Pro plan only. See SpotConfig.
Changing it takes effect on the next start.
enabledboolRun on spot capacity.
on_demand_fallbackboolStart on demand, at the on-demand rate, when no spot capacity is free.
Without it a start with no spot capacity waits for some and fails after a
minute, which is right for a server that is only worth running cheaply and
wrong for one players are waiting on. A server that fell back stays on
demand until it next stops; SpotStatus.running_on_spot says which it is.
notice_signalstringA signal to send the game's process when a notice arrives, e.g. SIGUSR1.
Empty sends nothing, and that is the default for a reason: the default
action of most signals is to terminate, so a signal a game does not handle
would stop it two minutes early. Name one only when the game handles it.
SIGTERM and SIGKILL are refused — the stop that follows the notice
sends the game's own stop signal already.
What spot is doing for this server right now.
running_on_spotboolOutput onlyWhether the current run is on spot capacity. False for a server that fell back to on demand, and for one that is not running.
When the current run will be stopped, once a notice has been given.
When this server was last reclaimed.
preserving_diskboolOutput onlyWhether the disk of a reclaimed server is still being captured. A start is refused as retryable until it finishes, because starting before it would boot a server without its world.
How long the notice was, for a console that wants to draw a countdown.
STATE_PROVISIONINGSTATE_STARTINGSTATE_RUNNINGSTATE_STOPPEDSTATE_STOPPINGSTATE_FAILEDSTATE_DELETINGstate_messagestringOutput onlyHow to reach it. Empty until the server is running and has an address.
A port may appear twice: once as Plany's proxy and once as the server's own address, distinguished by proxied. Give players the proxied one: it is reachable while the server is stopped, and connecting to it starts the server.
Proxied entries come first, so endpoints[0] is the address to hand out.
namestringMatches the game's plany.game.v1.PortMapping name, e.g. "game".
hoststringportint32protocolstring"tcp" or "udp".
addressstringReady-to-paste form, e.g. "play.example.com:25565". Populated because every console and support conversation ends up building this string anyway, and building it in one place avoids three subtly different ones.
proxiedboolWhether this address is Plany's proxy rather than the server itself.
A proxied address is reachable while the server is stopped or asleep, and connecting to it starts the server — so it is the one to give to players. A player's first connection after a sleep waits a few seconds while the server comes back.
instancestringOutput onlyAn identifier Plany support may ask for when investigating a server. Output only; nothing in the API acts on it.
labelsmap<string, string>When it last had a player. Drives idle shutdown, and is the field activity billing will read.
service_accountstringThe identity this server acts as.
Leave it empty and Playpute creates one per server, allowed to touch this server and nothing else — the right default, since a server runs your players' mods.
Set it to a service account you own and the server acts as that instead. That is for a fleet: grant one service account a role elsewhere, attach it to twenty servers, and those twenty can use it while the rest of the account cannot.
Attaching one requires iam.serviceAccounts.actAs on that service account, not merely permission to create a server — otherwise anybody who could create a server could act as anybody.
ssh_public_keysrepeated stringInput onlySSH keys allowed to log in to this server, for debugging.
They take effect only on a server booted from an image that includes an SSH server, and are read when the server boots, so a key added later needs a restart. Input only: the keys are not returned when the server is read.
imagestringInput onlyThe image to boot, by id. Empty uses Plany's current default, which is what almost every server should do.
An id from Plany's own published images; a server cannot boot an image of your own.
ephemeralboolKeep nothing. The world and the disks go when the server does.
The right shape for a match rather than a world: a minigame round has nothing worth carrying into the next one, and an ephemeral server saves the storage and the time of keeping it.
An ephemeral server never sleeps, because there is nothing to wake into, so sleep_after_idle is refused on one.
Immutable after creation: the guarantee is about data that was never kept, so it cannot be turned off afterwards.
exposureExposureWhether players outside the project can reach this server.
Immutable after creation: it decides whether a listener and a public address exist at all, and flipping it on a running server would change the address players were given.
EXPOSURE_PUBLICEXPOSURE_PROJECT_INTERNALschematicstringThe schematic this server's disk was copied from, if any.
What makes a scaled fleet viable: the build is already unpacked, the install script has already run and the world already exists, so a member reaches RUNNING in seconds where a cold boot is minutes.
A copy, not an attachment. The schematic is read once into a fresh disk and never referenced again, which is why deleting one does not disturb a server started from it — and why two members from one schematic diverge immediately rather than sharing anything.
groupstringOutput onlyThe group that created and owns this server, if any.
Output-only and not settable: a server does not join a group, a group creates it. The distinction matters because the group's loop deletes what it owns, and a server that could name a group it was not created by would be a way to have somebody else'"'"'s fleet delete your server.
A member deleted by hand comes back. Its size is the group'"'"'s to decide, so removing one is a decision the next pass overrules.
drainingboolOutput onlyWhether this server is draining: serving the players it has and being sent no new ones, on its way out.
Its own field rather than a state, because a draining server is still
RUNNING in every way that matters — it holds players, it bills, it serves.
Folding it into state would make every consumer that switches on state
handle a case that behaves identically to RUNNING, and the one that forgot
would stop showing a server people are on.
secretsrepeated SecretAttachmentSecrets this server can read: database passwords, API keys, RCON passwords, a licence key a game wants in a file.
Each attachment names a secret in the same project and region and says how the server sees it. The value is never stored on the server's configuration — the server fetches it when it starts, as its own identity — so nothing you can read back from the server reveals it.
Changing this takes effect on the next start. A running server keeps what it read when it started.
secretstringRequiredprojects/{project}/locations/{location}/secrets/{secret}, optionally with
/versions/{version}.
Unqualified is the ordinary case and resolves to the latest enabled version, so a rotation reaches this server on its next start with nothing to edit. Pin a version when a server must not follow a rotation — which is rare, and worth being deliberate about, because the pin outlives the memory of why it was made.
environment_variablestringRequiredThe environment variable the server sees the secret as, e.g. RCON_PASSWORD.
Required, and must be a valid variable name — upper case letters, digits and underscores, not starting with a digit. It is not derived from the secret's id, because stripe-live-key is not a variable name.
The value has to be valid UTF-8 to be used this way. A secret holding binary data is refused when the server starts; use file_path for one.
file_pathstringAlso write the value to a file at this path, relative to the build root.
For the things that will not go in an environment variable: a service account JSON, a TLS key, a licence file a game reads by path. Optional, and when it is set the environment variable is still exported, because a value that is available two ways is easier to use than one with a rule about when it is which.
Written 0600 and owned by the game user, and deliberately not preserved
across restarts the way a plany.game.v1.ConfigFile can be: this is the platform's copy
of a value the platform holds, so the file is rewritten every launch and a
rotation cannot leave a stale one behind.
What the game has told the platform about itself through the Agones SDK.
Every game server runs the SDK server, whether or not it came from an Agones
manifest, so a customer's own game can call Ready() and Allocate() the
way an Agones game does. A game that never calls it has an empty sdk, and
nothing reads one: allocation, the buffer term and idle sleep all treat an
unset state as "not using the SDK" rather than as not ready.
Separate from state for the reason activity is. state is what the
machine is doing and the platform decides it; this is what the game says
it is doing, and a RUNNING server is READY, ALLOCATED or neither.
STATE_READYSTATE_ALLOCATEDSTATE_RESERVEDSTATE_SHUTDOWNSTATE_UNHEALTHYlabelsmap<string, string>Output onlyLabels and annotations the game and its allocations wrote.
SetLabel("mode", "ranked") is stored as agones.dev/sdk-mode, which is
Agones' own prefix and what a selector written for Agones asks for. An
allocation's metadata is stored as given. Kept apart from
GameServer.labels, which the customer or the manifest owns: a game writing
its own labels must not be able to rewrite the ones its fleet selects on.
annotationsmap<string, string>Output onlyWhen a RESERVED server returns to READY.
When it was last allocated.
When the game last sent Health().
versionint64Output onlyIncreases on every change. Reported to the game as the Agones resource_version.
sleep_after_idleDurationPut the server to sleep after this long with nobody on it.
Sleep is hibernation: the server's memory is captured, its host released, and the next player's connection — or an allocation — restores it in seconds with everything it held in memory. Compute is not charged while it sleeps.
The counterpart of idle_shutdown_minutes, and different in the one way that
matters: that stops a server a customer forgot about, and this is the
platform doing what "pay when played" means for a server somebody wants
kept ready. A server the game has marked ALLOCATED or RESERVED never sleeps,
because it is somebody's match.
Idle is measured from the connection proxy's view of the server — no connections and no players — and a server whose presence could not be read is not idle. Refused on an ephemeral server, which cannot hibernate. Zero keeps it awake.
managed_bystringOutput onlyThe product that created and owns this server, if it was not you.
autopilot.agones.plany.cloud for a server Agones Autopilot created from a manifest. Change such a server by changing the manifest: Playpute's own update and delete refuse it.
When the server finished installing its build — for a container build, the image pulled and unpacked; for any other, the build downloaded and its install script run.
vpcstringImmutableThe private network this server is on. Empty is the project's default network in the server's region.
Decided by the server, never by its game: a game is a catalogue entry
shared by every project that runs it, and a network written there would be
one project's network named in everybody's servers. Requires
vpc.vpcs.use on the network, which must be in the server's own project
and region.
Immutable. A server that changed network would change address under the players connected to it, and the connection proxy in front of it is the proxy for that network — players reach a server through the proxy on the network it is on, so each network a project uses has a proxy of its own.
network_tagsrepeated stringNetwork tags on this server's interface, which firewall rules on its network can target. Lowercase letters, digits and hyphens.
etagstringOutput onlynext_page_tokenstringmachine_typesrepeated MachineTypeEvery type, smallest first. The catalogue is short, so it is not paged.
namestringIdentifierprojects/{project}/locations/{location}/machineTypes/{machine_type}.
The last segment — standard-4 — is what a GameServer names in
machine_type. Scoped under a project and a region only so that reading
it is authorized like everything else a customer reads here; the catalogue
itself does not vary by project.
display_namestringOutput onlyHuman-readable, e.g. "Standard, 4 vCPU".
familystringOutput onlyThe family: standard (2 GiB per vCPU) or highmem (4 GiB per vCPU).
vcpusint32Output onlymemory_bytesint64Output onlySpot capacity for this type in this region, right now and recently.
available_nowboolWhether a spot server of this type could be placed right now.
A reading, not a promise: spare capacity is whatever on-demand servers are not using, and the next on-demand create may take it.
availability_7ddoubleThe fraction of the last seven days in which a spot server of this type could have been placed, 0 to 1.
reclaims_per_day_7ddoubleHow often a running spot server of this type was reclaimed over the last seven days, as reclaims per server-day. 0.1 means one reclaim every ten days of running, on average.
sample_timeTimestampWhen the record was last sampled. Unset when this region has never recorded anything for the type — which is not the same as zero availability, and a console must not draw it as such.
proxy_routesrepeated ProxyRoutenamestringIdentifierprojects/{p}/locations/{l}/gameServers/{s}/proxyRoutes/{port_name}.
The last segment is the game's own port name — "game", "query" — rather than a generated id, so a route is addressable from the thing that produced it and a re-allocation cannot leave two routes for one port.
game_serverstringOutput onlygamestringOutput onlyThe game being served.
port_namestringOutput onlyThe game's plany.game.v1.PortMapping name this route fronts, e.g. "game".
listen_hoststringOutput onlyWhere the proxy listens, and what players are told to connect to.
listen_portint32Output onlyprotocolstringOutput only"tcp" or "udp". A game declaring both gets two routes: they are two listeners on two sockets, and a UDP session has no relationship to a TCP connection on the same number.
target_portint32Output onlyThe port the game listens on inside the server. Not the port the proxy listens on: a shared address cannot give every server 25565, so the two differ and the proxy translates.
billableboolOutput onlyWhether this route is charged for.
False for a game Plany publishes, true for a customer's own. Waking a Minecraft server costs Plany the same either way; the difference is what the platform is selling. A pre-configured game is the product, and its proxy is part of the price of the server. A customer's own game is a platform capability being used to host something Plany did not build, and charging for it is what stops the listener pool being free infrastructure for arbitrary traffic.
proxystringOutput onlyThe connection proxy this route is a listener on.
Every route on one network shares one, and it is what listen_port is
unique within — which is why two projects, or two networks of one project,
can both use 25565.
next_page_tokenstringMachineType is a named size a game server runs at.
Sizes are named so that spot capacity has a history you can read: QuerySpotHistory can tell you that standard-4 was available 99% of last week and was reclaimed twice. The catalogue is the same in every project and region; this resource is that list with a region's spot record beside each entry.
A game still declares the resources it needs, and that is the floor a type must meet. A server that names no type gets the smallest one that meets it — so you never have to know what a game needs to create one.
namestringIdentifierprojects/{project}/locations/{location}/machineTypes/{machine_type}.
The last segment — standard-4 — is what a GameServer names in
machine_type. Scoped under a project and a region only so that reading
it is authorized like everything else a customer reads here; the catalogue
itself does not vary by project.
display_namestringOutput onlyHuman-readable, e.g. "Standard, 4 vCPU".
familystringOutput onlyThe family: standard (2 GiB per vCPU) or highmem (4 GiB per vCPU).
vcpusint32Output onlymemory_bytesint64Output onlySpot capacity for this type in this region, right now and recently.
available_nowboolWhether a spot server of this type could be placed right now.
A reading, not a promise: spare capacity is whatever on-demand servers are not using, and the next on-demand create may take it.
availability_7ddoubleThe fraction of the last seven days in which a spot server of this type could have been placed, 0 to 1.
reclaims_per_day_7ddoubleHow often a running spot server of this type was reclaimed over the last seven days, as reclaims per server-day. 0.1 means one reclaim every ten days of running, on average.
sample_timeTimestampWhen the record was last sampled. Unset when this region has never recorded anything for the type — which is not the same as zero availability, and a console must not draw it as such.
One point per hour, oldest first.
intervalIntervalavailabilitydoubleThe fraction of this bucket in which a spot server of the type could have
been placed. Unset (with measured false) for a bucket the platform took
no samples in.
reclaimsint64Spot servers of this type reclaimed during the bucket.
running_hoursdoubleServer-hours of spot running of this type during the bucket. What makes
reclaims a rate rather than a count: two reclaims among two servers and
two among two hundred are different records.
measuredboolWhether any sample landed in this bucket. A gap is "not measured", never "unavailable".
SdkStatus is a game server's Agones SDK state.
STATE_READYSTATE_ALLOCATEDSTATE_RESERVEDSTATE_SHUTDOWNSTATE_UNHEALTHYlabelsmap<string, string>Output onlyLabels and annotations the game and its allocations wrote.
SetLabel("mode", "ranked") is stored as agones.dev/sdk-mode, which is
Agones' own prefix and what a selector written for Agones asks for. An
allocation's metadata is stored as given. Kept apart from
GameServer.labels, which the customer or the manifest owns: a game writing
its own labels must not be able to rewrite the ones its fleet selects on.
annotationsmap<string, string>Output onlyWhen a RESERVED server returns to READY.
When it was last allocated.
When the game last sent Health().
versionint64Output onlyIncreases on every change. Reported to the game as the Agones resource_version.
stateGameServer.StateThe server's state after this call. STARTING means a start was issued or was already under way.
STATE_PROVISIONINGSTATE_STARTINGSTATE_RUNNINGSTATE_STOPPEDSTATE_STOPPINGSTATE_FAILEDSTATE_DELETINGreadyboolWhether upstream can be connected to now.
Distinct from state == RUNNING: a server is RUNNING before the game inside it is listening. A hint that saves a connection attempt rather than a promise.
upstreamEndpointWhere to forward, once ready: the server's own address, not the proxy's.
namestringMatches the game's plany.game.v1.PortMapping name, e.g. "game".
hoststringportint32protocolstring"tcp" or "udp".
addressstringReady-to-paste form, e.g. "play.example.com:25565". Populated because every console and support conversation ends up building this string anyway, and building it in one place avoids three subtly different ones.
proxiedboolWhether this address is Plany's proxy rather than the server itself.
A proxied address is reachable while the server is stopped or asleep, and connecting to it starts the server — so it is the one to give to players. A player's first connection after a sleep waits a few seconds while the server comes back.
retry_afterDurationHow long to wait before asking again. Zero means the caller may retry immediately.
Which of several matching servers to choose.
| Value | Description |
|---|---|
| SCHEDULING_UNSPECIFIED | PACKED. |
| SCHEDULING_PACKED | The oldest matching server, so a fleet empties from its newest members and scale-in has something to remove. Agones' default. |
| SCHEDULING_DISTRIBUTED | Any matching server, spread across the fleet. |
Exposure says who can reach a game server.
The distinction exists for fleets that are fronted by something else — a lobby, a matchmaker, a game's own directory service. Those want servers players never dial directly, and giving each one a listener anyway would be a public entry point nobody intended and a charge for a route nobody uses.
| Value | Description |
|---|---|
| EXPOSURE_UNSPECIFIED | Public, which is what an ordinary game server is. |
| EXPOSURE_PUBLIC | Reachable by players. A listener is held open on the project's connection proxy for every public port the game declares, and that address is what the server advertises and what players are given. |
| EXPOSURE_PROJECT_INTERNAL | Reachable only from inside the project's own network. No public address: the server is reached at its private address by something already on that network — another game server, or a matchmaker of your own. **A server nothing outside can reach cannot be woken by a player connecting**, so an internal server is started by whatever directs traffic to it. |
| Value | Description |
|---|---|
| STATE_UNSPECIFIED | |
| STATE_PROVISIONING | Accepted, and the server is being placed and started. |
| STATE_STARTING | Booted; the game's install and launch are running. |
| STATE_RUNNING | Accepting players. |
| STATE_STOPPED | Deliberately stopped. The world is retained and nothing is billed for compute; storage still is. |
| STATE_STOPPING | Stopping. |
| STATE_FAILED | Something failed. `error` says what. |
| STATE_DELETING | Being torn down. |
| Value | Description |
|---|---|
| STATE_UNSPECIFIED | |
| STATE_WARMING_UP | Accepted, and the warm-up server is being created and captured. Members are not created yet — the whole point of the schematic is that the first member starts from it. |
| STATE_ACTIVE | Scaling. The ordinary state, whatever the current size is, including zero: a group holding no members because nobody is playing is working, not idle. |
| STATE_PAUSED | Scaling suspended by the customer. Members keep running and keep serving players; nothing is created and nothing is removed. Deliberately not "stopped": a paused group that tore its members down would be a way to disconnect everybody by asking to stop *changing* things. |
| STATE_FAILED | Something failed that scaling cannot fix. `error` says what. |
| STATE_DELETING | Being torn down, members first. |
| Value | Description |
|---|---|
| STATE_UNSPECIFIED | |
| STATE_PENDING | The host is capturing the disk. Minutes, for a server with a world. |
| STATE_READY | Captured and startable. |
| STATE_FAILED | The capture failed. `error` says why. |
| STATE_DELETING | Being removed. |
| Value | Description |
|---|---|
| OPERATOR_UNSPECIFIED | |
| OPERATOR_IN | |
| OPERATOR_NOT_IN | |
| OPERATOR_EXISTS | |
| OPERATOR_DOES_NOT_EXIST |
| Value | Description |
|---|---|
| STRATEGY_UNSPECIFIED | ROLLING_UPDATE. |
| STRATEGY_ROLLING_UPDATE | Replace outdated members a few at a time, creating before removing. |
| STRATEGY_RECREATE | Remove every outdated member that is not allocated at once, then create. Faster, and a group with no spare capacity for a while. |
The states a game moves itself through, named as Agones names them.
Only the ones a game causes. Agones' Creating, Starting and Scheduled are
the machine's business and are GameServer.state here; Error is
GameServer.error.
| Value | Description |
|---|---|
| STATE_UNSPECIFIED | The game has not called the SDK. Not "not ready": a game that does not use the SDK is left entirely alone by everything that reads this. |
| STATE_READY | `Ready()`: may be handed to a match. |
| STATE_ALLOCATED | Handed to a match, by an allocation or by the game's own `Allocate()`. Never scaled in, never put to sleep, never re-allocated unless a selector asks for allocated servers. |
| STATE_RESERVED | `Reserve(d)`: held back from allocation and from scale-in until `reserved_until`, then READY again. |
| STATE_SHUTDOWN | `Shutdown()`: finished. A group member is deleted and replaced; a server on its own is deleted. |
| STATE_UNHEALTHY | Stopped sending `Health()`. A group member is deleted and replaced. |