Serverless guide
This is the end-to-end walkthrough for the Serverless service. It assumes nothing except that you have an account and a project, and it takes you from zero to a running, callable, auto-scaling service.
What Serverless is
Serverless runs your container — any image that speaks HTTP — and scales the number of running copies up and down with traffic, including all the way to zero when nobody is calling. Use it for public APIs, webhooks, internal services, scheduled jobs, and event handlers you do not want to babysit.
Use cases:
- Public REST or gRPC API you want automatically load-balanced and HTTPS-terminated.
- Webhook receiver that must wake on demand and sleep when quiet.
- Nightly or cron-triggered job that should not pay for idle time.
- Backend for an agent — a tool the agent invokes over HTTPS.
Quick start: working service in five commands
You need a container image in a registry the platform can reach. The example uses a tiny public "hello world" web server so nothing private is involved — substitute your own image reference here.
# 1. sign in once
platformctl login
# 2. create the service
platformctl serverless create hello --image ghcr.io/example/helloworld:latest
# 3. watch it come up
platformctl serverless get hello
# 4. publish a public HTTPS endpoint
platformctl serverless update hello --publish
# 5. call it
curl "$(platformctl serverless get hello -o json | jq -r .url)"
That is the whole loop. The same flow in the Console is Compute → Serverless → Create service → Publish.
Core concepts
- A service is the named object you deploy and call. Its URL is stable across revisions.
- A revision is one immutable version of the service — image, environment, limits. Every change creates a new revision.
- Min scale keeps N copies warm. Max scale caps how far it can grow. Both are service-level settings.
- Scale to zero happens when there is no traffic and min scale is 0. First request after idle pays a cold start.
- A trigger is a scheduled (cron) or Pub/Sub-subscribed invocation that calls your service without a public URL.
- A published service has a public HTTPS DNS name. An unpublished one is reachable only inside your project.
- Timeout (seconds) bounds a single request. Long-running work should be split or use a higher timeout.
- Environment variables can come from Secrets — you reference the secret by name and never paste the value.
- Logs and metrics are per-service and streamable from the CLI or Console without setting up anything.
- Every mutating call (create, patch, delete) is asynchronous; the service reports
readywhen the revision is serving.
API examples
The API is REST, bearer-token authenticated. The base is https://api.codyhill.dev and every path is project-scoped.
export API="https://api.codyhill.dev"
export PROJ="$(platformctl projects list -o json | jq -r '.[0].id')"
export TOK="<your session token or API key>"
Create a service:
curl -sX POST "$API/v1/projects/$PROJ/services" \
-H "Authorization: Bearer $TOK" -H 'Content-Type: application/json' \
-d '{"name":"hello","image":"ghcr.io/example/helloworld:latest","publish":{"enabled":true}}'
Fetch its status and URL:
curl -s "$API/v1/projects/$PROJ/services/hello" -H "Authorization: Bearer $TOK"
Roll out a new revision (new image tag) and watch the revision list:
curl -sX PATCH "$API/v1/projects/$PROJ/services/hello" \
-H "Authorization: Bearer $TOK" -H 'Content-Type: application/json' \
-d '{"image":"ghcr.io/example/helloworld:v2"}'
curl -s "$API/v1/projects/$PROJ/services/hello/revisions" -H "Authorization: Bearer $TOK"
Stream recent logs:
curl -s "$API/v1/projects/$PROJ/services/hello/logs?tail=200" -H "Authorization: Bearer $TOK"
CLI examples
platformctl serverless list # all services in the project
platformctl serverless get hello # status, URL, image, limits
platformctl serverless get hello -o json # machine-readable
platformctl serverless update hello --min-scale 1 # keep one copy warm
platformctl serverless update hello --timeout 600 # raise per-request timeout
platformctl serverless logs hello --tail 100 # recent logs
platformctl serverless metrics hello # current CPU, memory, RPS
platformctl serverless revisions hello # revision history
platformctl serverless delete hello # remove and release the URL
Console walkthrough
- Open the Console, pick your project.
- In the navigation, go to Compute → Serverless.
- Click Create service. Fill in a name, your image reference, and whether to Publish (public HTTPS endpoint).
- When the row in the list flips to Ready, click the service name to open its detail page.
- On the detail page: the URL is at the top, Revisions and Logs are tabs on the left, and Metrics are on the right.
- Click Edit to change image, environment, limits, or publish state. Every save rolls a new revision.
- To stop paying for cold copies, set Min scale to 0. To prevent a burst from running away, set Max scale.
Limits and quotas
The Serverless service enforces these defaults at the API:
| Setting | Default | Hard cap |
|---|---|---|
| Per-request timeout | 300 s | 3600 s (configurable per service) |
| Min scale | 0 (scale to zero) | 100 |
| Max scale | 10 | 1000 |
| CPU per instance | 1 vCPU | 4 vCPU |
| Memory per instance | 512 MiB | 8 GiB |
| Concurrent requests per instance | 100 | 1000 |
| Revision history kept | last 20 | revisions older than that are pruned |
A request that exceeds the timeout is terminated with 504. Larger values require a quota change — open a support request from the Console.
Troubleshooting snippets
| Symptom | First thing to check |
|---|---|
ImagePullBackOff on deploy | The image reference is wrong, private, or the registry credential is missing. See troubleshooting. |
| Cold-start feels slow | Your image takes too long to bind to the port. Keep startup under ~10 s or raise min-scale to keep one copy warm. |
504 Gateway timeout | Request exceeded the per-request timeout. Raise --timeout or split the work. |
| Logs show nothing | The service has not been hit yet, or logs are still flushing. platformctl serverless logs hello --tail 200 after a real request. |
Connection refused from another service | The target is unpublished. Unpublished services are reachable only on their private, in-project address. |
| Public URL stopped resolving | The --publish flag was cleared or the service was deleted. Re-create or re-publish. |
| High unhandled RPS | Concurrency per instance is throttled. Lower max scale cost by raising the per-instance concurrency, or paginate at the client. |
Security notes
- Published services are public HTTP. Put authentication at the edge of your app code, or use a Gateway policy to require a token.
- Environment values from Secrets are injected at run time and never appear in the API response. You reference the secret by name (see Secrets Manager).
- Image supply chain: pin images by digest when the source matters, because the platform pulls what you reference at revision-roll time.
- Inter-service traffic inside a project uses mutual TLS. A private (unpublished) service is not reachable from outside your project boundary.
- Revision history is immutable. Sensitive values baked into a prior image layer or environment are still reachable from the revision list; only delete the service to fully release them.
- The API is audited. Both the Console and
platformctluse the same project-scoped role checks that govern who can deploy, publish, or delete.
Where next
- Autoscaling and scale-to-zero — tuning warm and burst behavior.
- Public endpoints and domains — custom DNS and TLS.
- Triggers — cron and Pub/Sub subscriptions.
- Troubleshooting — the full failure catalog.