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.
Security boundary
Section titled “Security boundary”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, andX-Forwarded-*ambient authority are cleared; Authorizationand application-defined signed headers remain available for an explicit upstream protocol; and- generated OpenAPI carries an
x-hoplite-static-proxiesinventory 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.
Certificate trust
Section titled “Certificate trust”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:
export HOPLITE_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crthoplite 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.
Prefix rules
Section titled “Prefix rules”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/"
;; Ambiguous traversal{:path "/space/" :upstream "https://greenways.space/beacon/../private/"}Development
Section titled “Development”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.