Skip to main content
If your app runs behind NGINX, Apache httpd, Caddy, or Traefik, that proxy usually does four jobs:
  • Ends TLS
  • Routes requests by hostname and path
  • Spreads requests across copies of your app
  • Keeps unwanted traffic out
On Datum Compute, the Application Load Balancer (ALB) does all four at the edge, so you only have to deploy your app’s container. The examples use NGINX syntax. The same approach applies to Apache httpd, Caddy, and Traefik.
This guide covers the common cases. The ALB as httpd reference has the rest:
  • A directive-by-directive mapping
  • Limits
  • Troubleshooting
  • The results of the live tests behind this guide
Its sections use the same headings as this guide. The tests ran on October 28, 2026, against preview APIs, so recheck edge cases before you rely on them.
This guide covers:
Compute is in preview. The v1alpha APIs can change, and Datum reviews Compute access requests manually.

Before you begin

  • Create a Datum Cloud account, an organization, and a project. For more information, see Account setup.
  • Install datumctl and run datumctl login. For more information, see Install.
  • Run datumctl plugin install compute, and make sure that Compute access is active for the project: run datumctl compute access and check that the Status line shows Active. For more information, see Deploy an app.
  • Run datumctl plugin install alb. This guide uses the alb plugin for most ALB changes.
  • Have a container image for your app, without the proxy container.
This guide names the app workload web and a second workload api, and shows the hostnames from a test run, such as tile-desire-9gpyk.datumproxy.net. Replace them with your own names and hostnames everywhere they appear, including inside YAML files. This guide assumes your app serves HTTP itself, on a port you name. The ALB ends TLS and sends plain HTTP to that port. If your app needs its proxy to translate requests for it, see Apps that need a gateway proxy first.

How proxy concepts map to ALB

Datum uses a few terms that differ from proxy configuration:
  • Workload: your app on Datum Compute. It runs as one or more Instances in each location you choose. See Compute.
  • HTTPProxy: the ALB resource you edit. It holds hostnames, routing rules, and backends, much like an NGINX server block. See HTTPProxy.
  • Backend: where a rule sends requests, usually a Compute workload. This is the NGINX upstream. See Load balancing and health checks.
  • Policy: a separate resource attached to the ALB. In NGINX these are directives inside the config file. On Datum they sit beside the HTTPProxy. See ALB configuration. Policies cover:
    • WAF
    • Sign-in
    • IP rules
    • Timeouts
    • Rate limits
The following table maps the parts of a proxy configuration you use most: For Apache, Caddy, and Traefik equivalents, and for every NGINX directive, see Directive mapping in the reference. Your ALB hostname is anycast. Each request reaches the nearest Datum location, where a managed fleet of Envoy proxies ends TLS and forwards plain HTTP to a healthy Instance. There is no proxy server for you to size, patch, or reload. Changes take up to three minutes to reach every location, and usually less than a minute. Check for the new behavior before you test anything else. For how to wait for a change from a script, see Edge model in the reference.

What stays in your app

The ALB routes, protects, and balances requests. It doesn’t store files or change response bodies, so keep these in your app or its image:
  • Static files
  • Response compression
  • Caching
  • Custom error pages
For the full list, see What stays in your app in the reference.

Deploy your app without a proxy container

datumctl compute deploy --http-port creates:
  • The workload
  • An ALB
  • The HTTPProxy that connects them
The ALB it creates is minimal:
  • It serves plain HTTP alongside HTTPS.
  • It has no WAF.
The steps after the deploy add both. For how the ALB attaches to a workload, see Serve public traffic with ALB. For test results, see Deploy your app without a proxy container in the reference.
1

Deploy the app with an ALB

To deploy your app to Dallas (us-central-1) with two Instances, run the following command:
Replace the image with your app’s image, and 8080 with the port your app listens on. The workload attaches to the project’s network named default. If the project has no network by that name, the command offers to create it. To use another network, add --network=NAME. To skip the prompts, for example in a script or CI, add --yes. Run at least two Instances in each location: a rollout replaces one Instance at a time, so a single Instance means a short outage on every deploy.The end of the output is similar to the following:
The last line is the ALB’s hostname. Your hostname is different. The command also saves the workload definition to workload.yaml in the current directory, replacing any file of that name. The ALB has the same name as the workload, so you can inspect it with the alb plugin:
Force HTTPS: no and Traffic protection: off are the two gaps the next steps close.
2

Redirect HTTP to HTTPS

To redirect plain HTTP requests to HTTPS, run the following command:
After a minute or two, a plain HTTP request gets a permanent redirect:
For a redirect you write yourself, such as one with a different status code, see HTTP to HTTPS redirect.
3

Turn on traffic protection

Start the WAF in Observe mode. Observe mode logs requests the WAF would block but lets them through:
After the WAF has seen real traffic and you have checked the logs, switch to Enforce mode:
In Enforce mode, a request that matches a WAF rule gets 403. To see blocked requests, filter the access logs:
For how long to stay in Observe and how to tune rules, see Roll out traffic protection safely.
4

Add your domain

To serve the app on your own hostname, run the following command:
Then run datumctl alb describe web and follow the hostname through its four steps: claimed, ownership verified, DNS record, and certificate. Datum issues and renews the certificate for you. For the DNS records to create, see Serve traffic on your own domain.

Translate common proxy configuration

Each example shows the datumctl commands and, where NGINX has an equivalent block, the nginx.conf next to the HTTPProxy that replaces it. For the following, see Translate common proxy configuration in the reference:
  • Headers
  • CORS
  • Client IPs
  • Regex matching

Route paths to different apps

Send /api to one workload and everything else to another. For more information, see Path-based routing and Send paths to different origins. Deploy the API as its own workload, on the same network as web:
This also gives api an ALB of its own, which Require sign-in uses later. Then add a route for api to the web ALB:
compute deploy creates a network service for each workload, named after the workload, with its HTTP port named http. The route sends requests to it. The web HTTPProxy now holds three rules: the HTTPS redirect from step 2, the default route, and the /api route. The following tabs show the NGINX equivalent and the HTTPProxy rules:
To see the whole HTTPProxy, run datumctl get httpproxy web -o yaml. As in NGINX, the most specific match wins, whatever the order of the rules, so /api/users goes to api even though its rule comes second. A PathPrefix matches whole path segments: /api matches /api/users but not /apiv2. For more matching behavior, see Route paths to different apps in the reference.

Redirect and rewrite URLs

Remove a path prefix before the request reaches your app. For more information, see URL rewrite. For redirects to a canonical hostname, see Redirect and rewrite URLs in the reference. By default, the ALB forwards the path unchanged, so the API above receives /api/users. To strip /api, add a URLRewrite filter to the /api rule. Start from the live HTTPProxy, not a new file. A file that you write from scratch replaces every rule on the ALB, including the HTTPS redirect from step 2. Save the live HTTPProxy to a file:
In httpproxy.yaml, find the rule that matches /api and add the filters block, so that the rule looks like the httpproxy.yaml tab:
Where you ran nginx -t before a reload, compare the file with what’s live and validate it on the server:
Because the file started from the live HTTPProxy, the diff shows only your change:
Then apply it:
The first apply on an HTTPProxy that a datumctl alb or compute deploy command created prints a warning about a missing last-applied-configuration annotation. The annotation is added for you, and you can ignore the warning.

Require sign-in

Put sign-in in front of an app without running oauth2-proxy or a forward-auth container. For setup with a specific provider, see Sign in with Google or Per-user access with Auth0. Sign-in is a SecurityPolicy with an oidc section, plus a Secret that holds your client secret. This example protects the api workload’s own ALB. Save it as oidc.yaml and replace the following values:
  • CLIENT_ID and CLIENT_SECRET: the OAuth client from your identity provider. For Google, the client ID ends in .apps.googleusercontent.com.
  • targetRefs name: the HTTPRoute for the ALB. It has the same name as the ALB and the workload. To list them, run datumctl get httproutes.
  • redirectURL: your ALB’s hostname from datumctl alb describe api, followed by /oauth2/callback.
The Secret needs the gateway-sync label, or the ALB can’t read it:
oidc.yaml
A request without a session now goes to the identity provider:
The ALB checks that a user signed in, but not who they are. It has no equivalent of the oauth2-proxy --email-domain flag, so restrict who can sign in with your identity provider. For more information, see Access control in the reference.

Production review

An app that worked behind its old proxy can still fail behind the ALB, because some defaults differ. Check each item before you move production traffic:

Response timeout

A response that takes longer than about 15 seconds gets 504, whatever your app does. To see it, request a route in your app that takes about 20 seconds. In the following example, /slow is such a route:
To raise the limit, attach a BackendTrafficPolicy to the ALB’s Gateway, which has the same name as the ALB:
timeout.yaml
After the change reaches the edge, usually within a minute, the same 20-second request succeeds:
Unlike NGINX proxy_read_timeout, which limits the gap between reads, this limits the whole response. For streaming and WebSocket behavior, see Timeouts, streaming, WebSockets, and gRPC in the reference.

TLS and custom domains

Datum issues and renews a certificate for each hostname on the ALB. These leave with the proxy container:
  • Certificate files
  • certbot
  • ACME settings
To check certificate status, run datumctl alb describe web and read the Certificates line. For more information, see Serve traffic on your own domain and Serve a wildcard hostname.

Health checks and failover

The ALB has no active health checks. Its passive health checks watch real responses instead: once you turn them on, an Instance that returns a run of 5xx errors is taken out of rotation, separately on each edge node. For settings, see Passive health checks. For how Instances are replaced during an update, see How rollouts work. For test results, see Load balancing and rollouts in the reference. To turn on passive health checks with the default settings, run the following command:
datumctl alb describe web then shows:
To change the thresholds, use --consecutive-5xx and --base-ejection-time.

Headers and request limits

  • Your app sees the client’s address in forwarded headers, not on the connection.
  • The WAF caps request size.
  • Responses go out uncompressed unless your app compresses them.
For numbers, see Limits and quotas in the reference and ALB limits and quotas. These are the forwarding headers your app receives on each request:

Placement and scaling

The ALB runs in every Datum location and scales with traffic, so you don’t size it. Where you run Instances decides how close your app is to users. For more information, see Placement and scaling. To see where your Instances run, run the following command:

Access metrics

For the metrics Datum publishes for each ALB, see Metrics. To send them to Grafana Cloud or another Prometheus remote-write endpoint, see Metrics export.

Access logs

datumctl alb logs shows recent requests for one ALB. datumctl telemetry logs shows the full Envoy fields, including the response flags that explain 502 and 503 errors. For more information, see Access logs. For the commands used in testing, see Verify and debug in the reference.
The PATH column shows the path after any rewrite, so a request for /api/users appears as /users. To find which Instance served a failing request, add --code and -o wide:
UPSTREAM is the Instance’s private address, which matches the INTERNAL IP column of datumctl compute instances. For every Envoy field, including response_flags, query the logs with the telemetry plugin. To install it, run datumctl plugin install telemetry. A query is a LogQL stream selector, and without a hostname it matches every ALB in the project. To see the 504 responses for one ALB, match its hostname with the authority label:
To list every label you can match on, run datumctl telemetry labels. A 504 from the response timeout has response_flags="UT", upstream timeout.

Security review

An ALB that compute deploy creates has no WAF. One that datumctl alb create creates starts with the WAF in Enforce mode. Confirm which you have:
With no WAF, the output is one line:
After step 3 of the deploy, it shows the mode and sensitivity:
To turn the WAF on without blocking real users, see Roll out traffic protection safely. For sign-in options, see Authentication. For test results, see Protection and Access control in the reference.

Rollback plan

Keep the old proxy container deployable until the ALB has carried production traffic for a while. Lower your DNS TTL before cutover so you can point back quickly. See Cut over in the reference.

Apps that need a gateway proxy

Some apps don’t speak HTTP. They speak a gateway protocol, and the proxy in front of them translates:
  • FastCGI: PHP-FPM and similar process managers. NGINX reaches them with fastcgi_pass.
  • uWSGI: the uwsgi protocol used by many Python apps. NGINX reaches them with uwsgi_pass.
  • CGI: older scripts that the web server runs once per request.
The ALB forwards only HTTP, and an Instance runs one container, so a proxy sidecar can’t do the translation. You have two options. Switch to an image that serves HTTP directly. This is the simpler option. Examples:
  • PHP: FrankenPHP, or Apache with mod_php
  • Python: gunicorn or uvicorn
Then follow this guide from the start. For details, see Before you begin in the reference. Run the gateway as its own workload. Deploy your existing proxy, such as NGINX with fastcgi_pass, as one workload behind the ALB, and your app as another. Both attach to the same network, in the same or different locations. The gateway reaches your app Instances by their private IPv6 addresses. To find them, run the following command:
The gateway connects to the address before the /96, in square brackets, such as fastcgi_pass [fd20:0:4d::3:0:0]:9000;. Keep the following points in mind:
  • Private DNS names aren’t available in the preview, so pass the app Instances’ addresses to the gateway in environment variables or a ConfigMap.
  • Addresses can change when Instances are replaced. To keep them, see Keep addresses after scale-down.
  • Networks don’t filter traffic between Instances yet. Any Instance on the network can reach your FastCGI or uWSGI port, so put these two workloads on a network of their own.
For more information, see Addressing and Traffic and connecting.

Verify the migration

Test through the ALB hostname while the old proxy still serves production, and switch DNS last. Start by checking that each path reaches the right app:
A 200 alone doesn’t prove the right app answered. Check for something only that app returns, such as a version endpoint or a response header. The verification checklist in the reference has:
  • A curl check for each route, redirect, and production-review item
  • Log and metric checks
If the ALB isn’t serving, see When a load balancer is not serving.

Clean up

After cutover and your rollback window, retire:
  • The old proxy container
  • Its configuration
  • Any certificate renewal jobs
If you deployed a test app to follow along, delete the policies you applied first. compute destroy doesn’t remove them:
Then destroy each workload:
compute destroy removes:
  • The workload
  • Its HTTPProxy
  • Its network service
Run datumctl compute destroy api -y for the api workload. If you created a network only for this guide, delete it after both workloads are gone:
For more information, see Compute operations.

What’s next

Last modified on October 29, 2026