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.
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
- Create (or open) a project, then create a container.
- Set the image to your pushed image reference, and the port to
8080. - Set a health check path your service answers with a 2xx, such as
/healthz. - Choose your regions, set CPU and memory, and attach any secrets.
- 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-urlGo'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
PORTvalue from plain environment variables withos.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
- Deploy your first container — the end-to-end walkthrough.
- Environment variables — plain config versus secrets.
- Resources and scaling — sizing CPU, memory, and replicas.
- HTTP containers — hostnames, autoscaling, and security knobs.