Web Services

Web Services

Deploy HTTP servers that receive public traffic. StackBlaze handles TLS, load balancing, health checks, and zero-downtime rolling updates.

What is a Web Service?

A web app is any process that listens on a TCP port and serves HTTP(S) traffic. StackBlaze gives it a public URL in the form https://your-app.stackblaze.app. You can also attach a custom domain.

Web apps support HTTP/1.1, HTTP/2, and WebSockets. You do not terminate TLS yourself — the platform handles it and forwards HTTP to your container.

The deploy feed streams build logs live until the app opens on its public URL.

Service types

A service runs one built image, but that image can power three kinds of processes. The type decides what StackBlaze provisions around your container:

TypeRuns asTrafficTypical use
webAlways-on process with rolling updates and health checksPublic URL + TLS; listens on PORTHTTP APIs, websites, WebSocket servers
workerAlways-on process from the same image, no ingressNone — no port, no URL, no HTTP health checksQueue consumers, schedulers, background processing
jobCron job on a schedule you setNone — runs its command to completion, then exitsPeriodic tasks: cleanups, reports, syncs

Web and worker processes run side by side from the same image, each with its own replica count and its own start command. Every container is told which role it plays through the PROC_TYPE environment variable (web or worker), so a single entrypoint can serve both. Jobs are declared with a name, a cron schedule, and a command; by default a job runs your service's own built image, so it sees the same code and environment variables as the web process.

Port detection

StackBlaze reads the PORT environment variable to know which port your container listens on. The default is 8080. Always bind to 0.0.0.0 (not 127.0.0.1) so the pod can receive traffic from the load balancer.

server.js
// Node.js example
const port = process.env.PORT || 8080
app.listen(port, '0.0.0.0', () => {
  console.log(`Listening on port ${port}`)
})
main.py
# Python / Gunicorn example
# StackBlaze sets PORT automatically
# gunicorn reads $PORT via --bind flag
# Procfile: web: gunicorn app:app --bind 0.0.0.0:$PORT

Warning

Do not hardcode a port number. Always read from process.env.PORT (Node.js) or os.environ["PORT"] (Python). PORT always follows the port configured in your service settings, so an app that reads it never needs a code change — or a rebuild — when that setting changes.

Health checks

StackBlaze uses health checks to decide when a new replica is ready to receive traffic. Traffic is only sent after the readiness check passes. If an instance fails health checks repeatedly, it is restarted automatically.

Default health check

By default, StackBlaze sends HTTP GET requests to / on your service port. A 2xx or 3xx response is considered healthy.

Custom health check path

Specify a custom health check path in Service Settings → Health Check. A dedicated endpoint like /health or /ping is recommended, it should return quickly without triggering expensive database queries.

server.js
// Recommended: lightweight health endpoint
app.get('/health', (req, res) => {
  res.json({ status: 'ok', uptime: process.uptime() })
})

Health check settings

Three probes run against the same path (default /, configurable):

ProbeWhat it doesDefaults
StartupGrace window while your app boots — the other probes wait for itChecks every 1s, allows up to 90s to come up (configurable)
ReadinessDecides whether the instance receives trafficEvery 10s after a 2s initial delay, 3s timeout
LivenessRestarts an instance that stops respondingEvery 3s after a 5s initial delay, 3s timeout, restart after 3 consecutive failures

Start command

The start command is the entrypoint of your container. It should start your HTTP server and block (not exit). If it exits, the platform restarts the instance.

RuntimeTypical start command
Node.jsnode dist/server.js
Node.js (npm)npm start
Pythongunicorn app:app --bind 0.0.0.0:$PORT
Python (FastAPI)uvicorn main:app --host 0.0.0.0 --port $PORT
Rubybundle exec puma -C config/puma.rb
Go./bin/server
Javajava -jar target/app.jar

Declaring your service in a Dockerfile

With the Dockerfile build strategy, your container runs exactly what the image declares: the ENTRYPOINT/CMD is the start command, unless you override it per process type in Service Settings → Start command. Two rules matter:

Read PORT, ignore EXPOSE. Routing follows the port configured for the service (injected as PORT, default 8080) — an EXPOSE line is fine as documentation but has no effect on traffic.

Use exec-form CMD. Rolling updates stop old instances with a signal; CMD ["/server"] delivers it to your process, while shell form (CMD ./server) traps it in a shell and turns every deploy into a hard kill after the grace period.

Dockerfile
FROM golang:1.22 AS build
WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 go build -o /out/server .

FROM gcr.io/distroless/static
COPY --from=build /out/server /server
# EXPOSE is optional documentation  routing follows the PORT setting
EXPOSE 8080
CMD ["/server"]

To run a worker from the same image, either give the worker its own start command in Service Settings (it overrides CMD for the worker only), or branch on PROC_TYPE in a single entrypoint:

entrypoint.sh
#!/bin/sh
if [ "$PROC_TYPE" = "worker" ]; then
  exec ./worker
fi
exec ./server

Jobs never use the image's CMD — each job declares its own command alongside its schedule and runs it against the same image.

Scaling

You can scale web apps horizontally (more replicas) or vertically (more CPU and memory per replica). StackBlaze supports both manual and automatic scaling.

Manual scaling

From the dashboard, go to the app → Settings → Scaling. Set the number of replicas. The change takes effect immediately, no rebuild needed. There is no npm CLI — use the dashboard or the REST API.

Autoscaling

Set a minimum and maximum replica count and StackBlaze's autoscaler will adjust replicas based on CPU utilization (target: 70%). Scale-out happens within seconds; scale-in is delayed 5 minutes to avoid oscillation.

Zero-downtime rolling updates

Every deploy uses a rolling update. New replicas start and must pass health checks before old replicas are stopped. The parameters:

ParameterValueMeaning
maxSurge1One extra pod above desired count during update
maxUnavailable0No pods taken down until replacements are ready

This means a deploy with 2 replicas will temporarily run 3 instances: the 2 old ones serving traffic and 1 new one warming up. Once the new instance is healthy, one old instance is stopped, and so on until all replicas are updated.

Tip

If your application requires a database schema migration before the new code can run, use a pre-deploy hook or run the migration in your container's startup sequence before binding the port.

Node.js example

server.js
import express from 'express'

const app = express()
const port = parseInt(process.env.PORT || '8080', 10)

app.use(express.json())

app.get('/health', (req, res) => {
  res.json({ status: 'ok' })
})

app.get('/', (req, res) => {
  res.json({ message: 'Hello from StackBlaze!' })
})

app.listen(port, '0.0.0.0', () => {
  console.log(`Server listening on port ${port}`)
})

Python example

main.py
from fastapi import FastAPI
import os

app = FastAPI()

@app.get("/health")
def health():
    return {"status": "ok"}

@app.get("/")
def root():
    return {"message": "Hello from StackBlaze!"}

# Start with: uvicorn main:app --host 0.0.0.0 --port $PORT

Environment variables

StackBlaze injects two variables into every container. Add your own in the dashboard. Do not rely on undocumented STACKBLAZE_* names.

VariableDescription
PORTThe port your app should listen on
PROC_TYPEweb or worker — which process type this container is running as

Read more about environment variables in Security → Environment Variables.