Skip to content

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.

Confirm your active account and organization:

Terminal window
1ctl auth status

Create a new project:

Terminal window
mkdir -p hello-backend-api
cd hello-backend-api

Create go.mod:

Terminal window
cat > go.mod <<'EOF'
module hello-backend-api
go 1.23
EOF

Create main.go:

Terminal window
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))
}
EOF

Your server must listen on 0.0.0.0, not only localhost, so the platform can reach it.

Create Dockerfile:

Terminal window
cat > Dockerfile <<'EOF'
FROM golang:1.23-alpine AS builder
WORKDIR /app
COPY go.mod main.go ./
RUN CGO_ENABLED=0 go build -o server .
FROM alpine:3.20
RUN apk add --no-cache ca-certificates
WORKDIR /app
COPY --from=builder /app/server .
EXPOSE 8080
USER 65532:65532
CMD ["./server"]
EOF

This multi-stage build compiles the API separately and keeps the runtime image small.

Create satusky.toml:

Terminal window
cat > satusky.toml <<'EOF'
[app]
name = "hello-backend-api"
port = 8080
cpu_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"
EOF

The important backend settings are:

  • app.port matches the port used by the process.
  • checks.health_path requires a successful response from /health after deployment.
  • deploy.strategy replaces healthy replicas gradually on later deployments.

Run the deployment from the directory containing satusky.toml:

Terminal window
1ctl deploy

1ctl 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.

Check the durable application record:

Terminal window
1ctl app get hello-backend-api

Wait until Status is ready. Inspect the detailed reconciliation state:

Terminal window
1ctl app status hello-backend-api

During 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:

Terminal window
1ctl logs --app hello-backend-api --tail 50

You should see:

server listening on 0.0.0.0:8080

Read the generated URL from 1ctl:

Terminal window
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:

Terminal window
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:

Terminal window
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.

Edit the source or Dockerfile, then run the same command:

Terminal window
1ctl deploy

The application name in satusky.toml identifies the existing deployment, so this creates a new release rather than a second application.

Delete the example and its runtime resources:

Terminal window
1ctl app delete hello-backend-api --yes
  • 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.