Skip to content

Begin typing to search this documentation.

Static upstreams

Hoplite can place an immutable Nginx proxy prefix beside Hara routes. This is useful for a local gateway whose policy and discovery surface are written in Hara while a reviewed remote service owns a separate API.

(ns gw.beacon
(:require [hoplite.core :as h]))
(defn health
[_request]
{:status 200
:headers {"content-type" "application/json"}
:body "{\"status\":\"ready\"}"})
(def app
(h/app
{:name "greenways-beacon"
:proxies
[{:path "/space/"
:upstream "https://greenways.space/beacon/v1/"}]
:resources
[["/beacon/v1/health"
{:get {:name :beacon/health
:handler #'health}}]]}))

A request to /space/rooms/42?view=summary is sent to https://greenways.space/beacon/v1/rooms/42?view=summary. The method and body are forwarded by Nginx and never materialized in a Hara worker.

Static upstreams are deliberately narrower than a general forward proxy:

  • the source prefix and destination are selected by the built project;
  • request headers cannot choose a hostname, scheme or destination path;
  • remote destinations require HTTPS;
  • Hoplite enables SNI and verifies the upstream certificate against an explicit trusted CA bundle;
  • HTTP is accepted only for localhost, 127.0.0.1, or [::1] development targets;
  • user information, query strings, fragments, variables and dot segments are rejected in configuration;
  • local cookies, Origin, Referer, and X-Forwarded-* ambient authority are cleared;
  • Authorization and application-defined signed headers remain available for an explicit upstream protocol; and
  • generated OpenAPI carries an x-hoplite-static-proxies inventory so the built route is inspectable.

The upstream still authenticates and authorizes the caller. A proxy declaration proves only that the application author approved a route to that origin.

For secure upstreams, Hoplite searches common macOS and Linux CA-bundle locations. A build fails closed if no trust bundle is available. Select a specific PEM bundle with:

Terminal window
export HOPLITE_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
hoplite serve build --mode prod .

SSL_CERT_FILE is accepted as a secondary conventional override. The selected path must identify a regular file and be safe to place in generated Nginx configuration. Hoplite emits proxy_ssl_verify on, a bounded verification depth, SNI, and proxy_ssl_trusted_certificate for every HTTPS static upstream.

Both paths must be directory-like prefixes:

{:path "/space/"
:upstream "https://greenways.space/beacon/v1/"}

These are rejected:

;; Remote cleartext
{:path "/space/"
:upstream "http://greenways.space/beacon/v1/"}
;; Request-selected Nginx variable
{:path "/space/"
:upstream "https://greenways.space/$request_uri"}
;; Embedded credential
{:path "/space/"
:upstream "https://[email protected]/beacon/v1/"}
;; Ambiguous traversal
{:path "/space/"
:upstream "https://greenways.space/beacon/../private/"}

A local Space implementation may be selected in a separate app Var or profile:

{:path "/space/"
:upstream "http://127.0.0.1:5173/beacon/v1/"}

Do not make the destination configurable through a query parameter, request header, or unvalidated environment interpolation. Generate a reviewed application definition for each deployment profile instead.