Deploy an HTTP container with YAML
Deploy an HTTP container on Bahriya with a Reis YAML manifest: workload, autoscaling, custom hostnames, observability and security, field by field.
An HTTP container is a long-running service that accepts incoming requests on a port and gets a hostname, TLS, autoscaling, rate limiting, IP allow/deny, and basic auth out of the box. Pick this type when you're deploying an API, a web app, or anything else that fronts traffic.
This guide walks through the full YAML shape for an HTTP container. For the same deployment driven from the shell, see Deploy an HTTP container with flags.
Minimal example
kind: container
project: my-project
handle: web-api
name: Web API
type: http
regions:
- falkenstein-1
workload:
image: ghcr.io/myorg/api:v1.0.0
cpu: "500"
memory: "512"
port: 8080
healthcheck: /healthz
networking:
external: trueApply it:
reis apply -f web-api.ymlThat's the entire path from "empty file" to "production HTTP container."
Anatomy of the YAML
The top-level keys identify the container and place it; the workload group covers the image, runtime sizing and the HTTP-specific port and health check; networking.external decides whether the container is reachable from the internet.
kind: container
project: my-project # the project handle this container lives under
handle: web-api # immutable identifier — Reis looks this up to update later
name: Web API # display name in the console
type: http # required; immutable after create
regions:
- falkenstein-1
- virginia-1 # multi-region by listing more regions
workload:
image: ghcr.io/myorg/api:v1.0.0 # image reference with tag
registry: ghcr # registry handle if the image is private
cpu: "500" # CPU in millicores; required
memory: "512" # memory in MB; required
port: 8080 # the port your app listens on
healthcheck: /healthz # HTTP path that returns 200 when healthy
protocol: http # http (default), https, or tcp
env: # environment variables as plain key/value
NODE_ENV: production
LOG_LEVEL: info
secrets: # ENV_VAR_NAME → secret-handle
DB_PASSWORD: db-password
API_KEY: api-key
networking:
external: true # reachable from the internet at its hostnamesReaching the container
networking.external decides who can reach an HTTP container:
true: the container is reachable from the internet at its hostnames.false: only workloads in the same project can reach it.
State it in every HTTP container document. It has no default for HTTP containers, so a hostname is published only when the file says so: reis apply refuses to create an HTTP container without it, and warns when an update leaves it out. If an HTTP container is created through the API directly without it, the API makes the container reachable from the internet.
Autoscaling
Set max_replicas to enable autoscaling. The minimum is replicas; autoscaling works between the two based on CPU and memory targets.
scaling:
replicas: 2
max_replicas: 8
target_cpu: 70 # percent of requested CPU
target_memory: 80 # percent of requested memoryIf you don't include max_replicas, the container runs at exactly replicas instances. Autoscaling cannot be enabled while persistent volumes are attached.
Custom hostnames
By default, an HTTP container gets a hostname from Bahriya. Add your own:
networking:
external: true
domains:
- hostname: app.example.com
wwwredirect: true # serves www.app.example.com → app.example.comThe platform issues a TLS certificate for each hostname automatically once its DNS records are in place. See Custom domain setup for the records to create.
A container deployed in two or more regions can spread traffic across them on its vanity hostname with networking.custom_dns_mode:
networking:
custom_dns_mode: geo # none (default), round-robin or geoA mode other than none requires two or more regions.
Observability
Expose Prometheus metrics so the platform scrapes them:
observability:
prometheus_port: 9090
prometheus_path: /metricsSecurity
Rate limiting and IP allow/deny lists sit under security:
security:
rate_limiting:
enabled: true
per_minute: 60
basic_auth:
- username: ops
password: <bcrypt-or-plaintext>Field reference
| YAML path | Maps to | Notes |
|---|---|---|
type | container type | required: http |
workload.image | image reference | required |
workload.registry | registry handle | for a private image |
workload.port | container port | default 8080 |
workload.healthcheck | health check path | default /healthz |
workload.protocol | protocol your app speaks on its port: http, https or tcp. Used for health checks and for delivering traffic | optional, default http |
workload.cpu | CPU (millicores) | required to create; no default |
workload.memory | memory (MB) | required to create; no default |
workload.env | environment variables | key/value map |
workload.secrets | injected secrets | ENV_NAME → secret-handle |
scaling.replicas | min instances | default 1 |
scaling.max_replicas | max instances | enables autoscaling |
networking.external | reachable from the internet | state it: true or false |
networking.domains | custom hostnames | TLS issued automatically |
networking.custom_dns_mode | traffic across regions on the vanity hostname | none (default), round-robin, geo |
observability.prometheus_port | metrics port | enables scraping |
observability.prometheus_path | metrics path | default /metrics |
For the complete list of every group and field, see the YAML mode reference.
Updating an HTTP container
Re-apply the same file with any changes:
reis apply -f web-api.ymlReis looks up the container by handle and updates it to match the file. A field the file leaves out returns to its default. If that would clear values the container holds today, such as its environment variables, or return a field you set to its default, such as the port, Reis asks first (--yes confirms in scripts). Keep the file complete, and check it with reis apply -f web-api.yml --dry-run before applying. See Applying a file that would clear or reset values.
Related
- Deploy a worker with YAML — same
kind: container, different surface - Deploy an HTTP container with flags — the equivalent flow without a file