Transport modes
Choose direct HTTPS or an outbound tunnel without changing request verification.
Choose direct HTTPS or an outbound tunnel without changing request verification.
Transport controls how Farther Shore reaches your process. It does not control
who the process trusts: the gateway signs forwarded requests in both modes, and
@farthershore/backend verifies them in both modes.
| Direct | Tunnel | |
|---|---|---|
| Network path | Gateway to your public HTTPS origin | Backend opens an outbound Cloudflare tunnel |
| Inbound public service | Required | Not required |
| Origin ownership | You bind originUrl per environment | Platform provisions originHostname |
| Scaling fit | Serverless or long-running HTTP | Long-running process with stable outbound connectivity |
| SDK process | fs.start() is a no-op | fs.start() supervises embedded cloudflared |
| Availability | Always available | Subject to workspace entitlement |
Use direct mode for Railway, Render, Cloud Run, an ALB, or any other provider that gives the application a stable public HTTPS URL.
const api = fs.backend("api", {
transport: { mode: "direct" },
default: true,
});
farthershore backend create my-business \
--name "Application API" \
--slug api \
--transport direct \
--origin-url https://api.example.com \
--idempotency-key <persisted-backend-create-attempt-key> \
--default
Previews inherit the production origin by stable slug. To override one later:
farthershore backend bind my-business api \
--env staging \
--origin-url https://api-staging.example.com
The preview backend row must already exist. Create it with backend create --env staging if necessary.
A direct origin is network-public, but its business routes are not trusted public API endpoints. Strict SDK middleware rejects an unsigned request before handler code runs. Put unsigned provider health checks before the verifier.
Use tunnel mode when the process should have no public ingress and can maintain a long-running outbound connection on port 443.
const api = fs.backend("api", {
transport: { mode: "tunnel", runner: "embedded" },
default: true,
});
farthershore backend create my-business \
--name "Private API" \
--slug api \
--transport tunnel \
--runner embedded \
--idempotency-key <persisted-backend-create-attempt-key> \
--default
Do not pass an origin URL. The platform provisions the tunnel and returns its connection data through runtime bootstrap.
The application still listens locally, normally on PORT or port 3000:
const fs = fartherShore.initFromEnv();
app.listen(Number(process.env.PORT ?? 3000));
await fs.start();
fs.start() launches and supervises the SDK's optional, platform-specific
cloudflared binary for an embedded tunnel. Install dependencies on the target
OS and do not omit optional dependencies. On direct transport it is a no-op, so
the same application startup can support either contract.
Tunnel tokens need the tunnel operation in addition to verification,
metering, and health:
farthershore backend tokens create my-business \
--backend <backend-id> \
--operations gateway_verification,metering,health,tunnel \
--idempotency-key <persisted-backend-tokens-create-attempt-key> \
--format json
embedded is the self-contained path: the SDK starts cloudflared from the
same process/container and receives the credential during bootstrap.sidecar is for an independently supervised tunnel process. Provisioning and
lifecycle wiring are operator-managed; fs.start() does not start it.Use embedded unless your infrastructure already has a clear sidecar lifecycle.
origin_unavailable; traffic never falls through to another slug
or another preview.fs.start() is fail-open by default for process startup. Set the runtime
tunnel option to fail closed only when crashing the application is the desired
response to tunnel startup failure.Inspect the current environment rows and derived status with:
farthershore backend list my-business --format json