Deploy a Go app on Bahriya

Go compiles to a single static binary, which makes for exceptionally small, fast container images. A multi-stage build compiles your application in the first stage and copies only the resulting binary into a minimal final image. This guide deploys a Go HTTP service as an HTTP container listening on port 8080.

Updated 3 Aug 20263 min read

Go compiles to a single static binary, which makes for exceptionally small, fast container images. A multi-stage build compiles your application in the first stage and copies only the resulting binary into a minimal final image. This guide deploys a Go HTTP service as an HTTP container listening on port 8080.

Only two things change between stacks on Bahriya: the Dockerfile that builds your image, and the port your application listens on. For a typical Go web service, that port is 8080.

Dockerfile

This is a multi-stage build. The builder stage compiles a static binary; the final stage is a minimal base (scratch here, or use gcr.io/distroless/static if you need CA certificates and timezone data) carrying only the binary.

# Build stage
FROM golang:1.23-alpine AS builder
 
WORKDIR /src
 
# Cache modules
COPY go.mod go.sum ./
RUN go mod download
 
COPY . .
 
# Build a fully static binary
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /app ./cmd/server
 
# Final stage
FROM scratch
 
COPY --from=builder /app /app
 
EXPOSE 8080
 
ENTRYPOINT ["/app"]

If your service makes outbound HTTPS calls, use a distroless base instead of scratch so the CA certificate bundle is present:

FROM gcr.io/distroless/static-debian12
COPY --from=builder /app /app
EXPOSE 8080
ENTRYPOINT ["/app"]

Binding and the PORT variable

Your server must bind to 0.0.0.0 (or an empty host, which is equivalent) so the platform's ingress can reach it — binding to 127.0.0.1 would leave it unreachable. A common pattern is to read the port from a PORT environment variable and fall back to a default:

port := os.Getenv("PORT")
if port == "" {
    port = "8080"
}
log.Fatal(http.ListenAndServe(":"+port, mux))

Listening on :8080 binds all interfaces, which is what you want. Keep the port your code listens on in step with the container port you configure below.

Deploy from the Console

  1. Create (or open) a project, then create a container.
  2. Set the image to your pushed image reference, and the port to 8080.
  3. Set a health check path your service answers with a 2xx, such as /healthz.
  4. Choose your regions, set CPU and memory, and attach any secrets.
  5. Create the container and wait for it to reach a running state.

See Deploy your first container for the full walkthrough.

Deploy with the Reis CLI

reis container:create \
  --type http \
  --name "Go Service" \
  --handle go-service \
  --image ghcr.io/myorg/go-service:v1.0.0 \
  --project my-project \
  --port 8080 \
  --healthcheck /healthz \
  --cpu 500 \
  --memory 256 \
  --regions falkenstein-1 \
  --env APP_ENV=production \
  --secrets DATABASE_URL=database-url

Go's low memory footprint means you can often run with a smaller memory allocation than other runtimes. See Deploy an HTTP container with flags for the full flag reference.

Configuration, secrets, and databases

  • Non-sensitive configuration — read log levels, feature flags, and the PORT value from plain environment variables with os.Getenv.
  • Sensitive values — database credentials, API keys, and tokens belong in secrets, encrypted at rest and injected as environment variables at runtime.
  • Database connections — Bahriya does not host your database. Connect to your own managed database using a connection string supplied through a secret.

Next steps