Deploy a Backend API
This guide deploys a complete Go HTTP API from source. It focuses on the backend-specific contract: listen on the configured port, expose a health endpoint, and verify both the workload and its public URL.
The same deployment flow works for any language that can be packaged in a container.
Prerequisites
Section titled “Prerequisites”Confirm your active account and organization:
1ctl auth status1. Create the API
Section titled “1. Create the API”Create a new project:
mkdir -p hello-backend-apicd hello-backend-apiCreate go.mod:
cat > go.mod <<'EOF'module hello-backend-api
go 1.23EOFCreate main.go:
cat > main.go <<'EOF'package main
import ( "encoding/json" "log" "net/http" "os" "time")
func main() { port := os.Getenv("PORT") if port == "" { port = "8080" }
mux := http.NewServeMux() mux.HandleFunc("/health", func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "application/json") _ = json.NewEncoder(w).Encode(map[string]string{"status": "ok"}) }) mux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "application/json") _ = json.NewEncoder(w).Encode(map[string]string{ "message": "hello from SatuSky", "time": time.Now().UTC().Format(time.RFC3339), }) })
log.Printf("server listening on 0.0.0.0:%s", port) log.Fatal(http.ListenAndServe("0.0.0.0:"+port, mux))}EOFYour server must listen on 0.0.0.0, not only localhost, so the platform can reach it.
2. Add a Dockerfile
Section titled “2. Add a Dockerfile”Create Dockerfile:
cat > Dockerfile <<'EOF'FROM golang:1.23-alpine AS builderWORKDIR /appCOPY go.mod main.go ./RUN CGO_ENABLED=0 go build -o server .
FROM alpine:3.20RUN apk add --no-cache ca-certificatesWORKDIR /appCOPY --from=builder /app/server .EXPOSE 8080USER 65532:65532CMD ["./server"]EOFThis multi-stage build compiles the API separately and keeps the runtime image small.
3. Configure the deployment
Section titled “3. Configure the deployment”Create satusky.toml:
cat > satusky.toml <<'EOF'[app]name = "hello-backend-api"port = 8080cpu_request = "100m"cpu_limit = "500m"memory = "256Mi"replicas = 1
[build]dockerfile = "Dockerfile"
[checks]health_path = "/health"
[deploy]strategy = "rolling"rolling_max_surge = "25%"rolling_max_unavailable = "0"EOFThe important backend settings are:
app.portmatches the port used by the process.checks.health_pathrequires a successful response from/healthafter deployment.deploy.strategyreplaces healthy replicas gradually on later deployments.
4. Deploy from source
Section titled “4. Deploy from source”Run the deployment from the directory containing satusky.toml:
1ctl deploy1ctl uploads the source, builds and publishes a private container image, then submits the application deployment. The cloud builder produces both linux/amd64 and linux/arm64 images, so the application can run on either supported machine architecture.
The command prints a deployment ID and a generated *.satusky.com URL. Deployment acceptance does not mean DNS has propagated yet.
5. Verify workload readiness
Section titled “5. Verify workload readiness”Check the durable application record:
1ctl app get hello-backend-apiWait until Status is ready. Inspect the detailed reconciliation state:
1ctl app status hello-backend-apiDuring initial provisioning, the detailed status can show the workload becoming ready before the public route and DNS are ready. Run the command again until the route is attached and DNS is no longer propagating.
Check the application logs:
1ctl logs --app hello-backend-api --tail 50You should see:
server listening on 0.0.0.0:80806. Test the public API
Section titled “6. Test the public API”Read the generated URL from 1ctl:
APP_URL="$(1ctl app get hello-backend-api | sed -n 's/^URL: //p')"printf '%s\n' "$APP_URL"DNS can take a short time on a new generated hostname. Retry the health request while it propagates:
curl \ --retry 24 \ --retry-delay 5 \ --retry-all-errors \ --fail \ --silent \ --show-error \ "$APP_URL/health"Expected response:
{ "status": "ok" }Then call the API root:
curl --fail --silent --show-error "$APP_URL/"The platform-managed public route forwards HTTPS traffic to port 8080; you do not need to create networking resources or certificates yourself.
Update the API
Section titled “Update the API”Edit the source or Dockerfile, then run the same command:
1ctl deployThe application name in satusky.toml identifies the existing deployment, so this creates a new release rather than a second application.
Clean up
Section titled “Clean up”Delete the example and its runtime resources:
1ctl app delete hello-backend-api --yesWhat you verified
Section titled “What you verified”- The application was built from source without a local Docker daemon.
- The published image supports AMD64 and ARM64 machines.
- The container listened on the configured port.
- The workload became ready and the public health endpoint passed an independent request.
- The generated hostname’s DNS condition matched its reserved target before the HTTPS route was tested.
Next steps
Section titled “Next steps”- Environment Configuration for runtime configuration and secrets
- Autoscaling for traffic-driven replica scaling
- Custom Domains for your own hostname
- CI/CD Integration for automated releases