FerricStore ships an in-process HTTP application in the normal OSS release. It uses the same authentication gateway, command planner, ACL checks, deadlines, resource limits, and storage path as the native protocol. The HTTP application is disabled by default and does not open a port until it is explicitly enabled.

Use the HTTP interface for SDK environments where persistent native connections are inconvenient, for ordered stateless command batches, and for the optional invocation API. Use the native protocol for transactions, Pub/Sub subscriptions, and other connection-scoped behavior. Blocking list and stream commands are supported in an ordered HTTP command batch, but the HTTP request deadline still bounds how long they may wait.

Create an ACL identity first

HTTP Basic authentication uses FerricStore ACL usernames and passwords. Before exposing the HTTP listener, create a least-privilege identity through a trusted native administration connection or the local dashboard setup flow. For example, the logical ACL command for an application restricted to one key prefix is:

ACL SETUSER web-api on resetpass >replace-with-a-long-random-password \
  resetkeys +GET +SET +DEL ~web-api:*

Every command and key in an HTTP batch is checked against this identity. Authentication-session caching does not bypass those checks, and an ACL or password change invalidates the cached session before the next batch executes.

For the normal OSS setup, that ACL username is also the invocation subject. No additional namespace identifier, identity header, or proxy configuration is required. Keep trusted context headers disabled unless a verified ingress is deliberately supplying identity.

Enable HTTPS in a native release

Provide a PEM certificate chain and its matching unencrypted PEM private key. The certificate must contain a subject alternative name for every DNS name or IP address used by clients. FerricStore accepts TLS 1.2 and TLS 1.3.

export FERRICSTORE_HTTP_ENABLED=true
export FERRICSTORE_HTTP_BIND=0.0.0.0
export FERRICSTORE_HTTP_PORT=8080
export FERRICSTORE_HTTP_TLS_ENABLED=true
export FERRICSTORE_HTTP_TLS_CERT_FILE=/run/secrets/ferricstore/http-cert.pem
export FERRICSTORE_HTTP_TLS_KEY_FILE=/run/secrets/ferricstore/http-key.pem

_build/prod/rel/ferricstore/bin/ferricstore start

The listener refuses to start when TLS is enabled without both files. Store the private key with the smallest practical read permission and make it readable only by the FerricStore process. The certificate file should include the leaf certificate followed by any required intermediate certificates.

For a short-lived local certificate:

mkdir -p certs
openssl req -x509 -newkey rsa:3072 -nodes -sha256 -days 30 \
  -subj "/CN=localhost" \
  -addext "subjectAltName=DNS:localhost,IP:127.0.0.1" \
  -keyout certs/http-key.pem \
  -out certs/http-cert.pem
chmod 600 certs/http-key.pem

This self-signed certificate is for local testing. Clients must explicitly trust certs/http-cert.pem; do not disable certificate or hostname verification.

Enable HTTPS in Docker

The image contains the HTTP application and exposes port 8080, but the listener remains disabled until configured. Mount certificates read-only:

docker run --rm \
  -p 6388:6388 \
  -p 8080:8080 \
  -e FERRICSTORE_HTTP_ENABLED=true \
  -e FERRICSTORE_HTTP_TLS_ENABLED=true \
  -e FERRICSTORE_HTTP_TLS_CERT_FILE=/run/secrets/ferricstore/http-cert.pem \
  -e FERRICSTORE_HTTP_TLS_KEY_FILE=/run/secrets/ferricstore/http-key.pem \
  -v "$PWD/certs:/run/secrets/ferricstore:ro" \
  -v ferricstore_data:/data \
  quay.io/ferricstore/ferricstore:0.11.12

The container runs as UID 10001; ensure that user can read the mounted certificate and key.

Send a command batch

The simplest JSON form is suitable for UTF-8-safe command arguments:

curl --fail-with-body \
  --cacert certs/http-cert.pem \
  --user 'web-api:replace-with-a-long-random-password' \
  --header 'content-type: application/json' \
  --data '{"commands":[["SET","web-api:example","value"],["GET","web-api:example"]]}' \
  https://localhost:8080/v1/commands

Use the binary-safe JSON or MessagePack envelope for arbitrary keys and values. See the complete HTTP wire contract.

Listener configuration

VariableDefaultPurpose
FERRICSTORE_HTTP_ENABLEDfalseStart the HTTP application listener.
FERRICSTORE_HTTP_BIND127.0.0.1Numeric IPv4 or IPv6 address on which to listen.
FERRICSTORE_HTTP_PORT8080Listener port.
FERRICSTORE_HTTP2_ENABLEDfalseAdvertise HTTP/2 in addition to HTTP/1.1.
FERRICSTORE_HTTP_TLS_ENABLEDfalseStart the listener with TLS.
FERRICSTORE_HTTP_TLS_CERT_FILEnonePEM certificate-chain path.
FERRICSTORE_HTTP_TLS_KEY_FILEnoneMatching PEM private-key path.
FERRICSTORE_HTTP_MAX_CONNECTIONS1024Maximum accepted HTTP connections.
FERRICSTORE_HTTP_MAX_IN_FLIGHT_REQUESTS1024Maximum admitted concurrent streams.
FERRICSTORE_HTTP_REQUEST_TIMEOUT_MS30000Absolute command-request time budget.
FERRICSTORE_HTTP_MAX_BODY_BYTES1048576Maximum request body size.
FERRICSTORE_HTTP_MAX_BATCH_COMMANDS1000Maximum commands in one request.
FERRICSTORE_HTTP_METRICS_ENABLEDtrueStart the metrics collector and expose GET /metrics.

The complete set also includes bounded header, keep-alive, authentication-cache, command-batching, invocation-runner, and outbound-target controls. Invalid values fail application startup rather than silently falling back.

The native-release bind default is loopback. The container image sets the bind value to 0.0.0.0 but still keeps the listener disabled, so publishing port 8080 has no effect until FERRICSTORE_HTTP_ENABLED=true is supplied.

Health and readiness

The API listener exposes:

  • GET /health for listener liveness;
  • GET /ready for listener and command-gateway readiness;
  • GET /metrics for HTTP metrics when enabled.

The existing isolated node health ports remain available independently. Point an HTTP API load balancer at the API listener's /ready endpoint.

TLS termination at an ingress

Direct TLS is preferred when the listener is reachable outside the host. A trusted ingress may terminate TLS only when the hop to FerricStore stays on a protected private or same-host network. The ingress must remove caller-supplied identity-context headers before adding verified values. Keep FERRICSTORE_HTTP_TRUST_CONTEXT_HEADERS=false unless that condition is enforced.

AWS Fargate

The repository's single-task and three-node cluster Terraform profiles can enable this listener in the existing FerricStore container with http_enabled = true. They add task port 8080, a separate NLB target group, and stable http_endpoint/http_readiness_endpoint outputs. The cluster profile creates one HTTP target group per stable node slot so ECS can move task IPs without changing the client endpoint.

With no certificate ARN, the listener is plaintext and must stay on a trusted private network. Supplying http_tls_certificate_arn, http_hostname, and normally http_listener_port = 443 makes the internal NLB terminate TLS 1.2/1.3. The hop to the task remains plaintext inside the private VPC; this is not end-to-end application TLS. The Fargate stacks keep trusted context headers disabled and do not turn NLB TLS identity into FerricStore identity—HTTP Basic ACL authentication is still required for command requests.

See single-task Fargate or clustered Fargate. On an existing three-node cluster, follow its staged sequential procedure when changing HTTP mode because ECS target-group changes can trigger task replacement.

Invocation routes and outbound targets

Invocation routes and the background runner are separate opt-ins. Definitions and invocation records use the shared FerricStore command engine, so the same command and key ACL checks apply to HTTP callers, the definition loader, and every runner operation.

Create a caller identity for one invocation name:

ACL SETUSER mail-api on resetpass >replace-with-a-long-random-password \
  resetkeys -@all +INVOCATION.CREATE +INVOCATION.GET +FLOW.GET \
  ~invocation:send-email ~invocation:send-email:*

Reading a result stored as a Flow value also requires +FLOW.VALUE.MGET and a key pattern matching generated f:* value references. The named value routes require +FLOW.VALUE.MGET for reads and +FLOW.VALUE.PUT for writes. Keep those permissions on a dedicated caller identity; the HTTP service additionally verifies the invocation record and the definition's allowed value names before accessing a reference.

Create a separate runner identity. The runner never reuses caller credentials:

ACL SETUSER http-invocation-runner on resetpass >replace-with-another-random-password \
  resetkeys -@all \
  +INVOCATION.DEFINITION.LIST +INVOCATION.PARTITION.LIST \
  +FLOW.CLAIM_DUE +FLOW.GET +FLOW.COMPLETE +FLOW.RETRY +FLOW.FAIL \
  ~invocation:*

If startup loads definitions from a file, also grant the runner +INVOCATION.DEFINITION.PUT ~invocation:definition:*. Narrow ~invocation:* to the invocation names and partition prefixes served by that runner when practical.

One definition file can contain a JSON array or a top-level definitions array:

{
  "definitions": [
    {
      "name": "send-email",
      "enabled": true,
      "flow_type": "email-delivery",
      "initial_state": "queued",
      "target": {
        "kind": "http_endpoint",
        "url": "https://worker.example.com/invocations",
        "timeout_ms": 10000
      },
      "partition": {"key": "invocation:{name}:{subject}"},
      "limits": {
        "idempotency_required": true,
        "max_payload_bytes": 262144,
        "max_result_bytes": 1048576
      },
      "refs": {
        "allowed_read_names": ["receipt"],
        "allowed_write_names": ["attachment"]
      }
    }
  ]
}

The partition field is optional. When omitted, FerricStore chooses a partition from the invocation id, which is the simplest single-installation setup. Use {subject} only when separate ACL users should receive distinct partitions; Basic authentication supplies it from the ACL username.

Enable the routes, definition loader, and runner with direct TLS and restricted outbound HTTPS:

export FERRICSTORE_HTTP_INVOCATIONS_ENABLED=true
export FERRICSTORE_HTTP_INVOCATION_DEFINITIONS_FILE=/etc/ferricstore/invocations.json
export FERRICSTORE_HTTP_RUNNER_ENABLED=true
export FERRICSTORE_HTTP_RUNNER_USERNAME=http-invocation-runner
export FERRICSTORE_HTTP_RUNNER_PASSWORD=replace-with-another-random-password
export FERRICSTORE_HTTP_TARGET_REQUIRE_HTTPS=true
export FERRICSTORE_HTTP_TARGET_ALLOWED_HOSTS=worker.example.com
export FERRICSTORE_HTTP_TARGET_DENY_PRIVATE_NETWORKS=true
export FERRICSTORE_HTTP_TARGET_MAX_RESPONSE_BYTES=1048576

Keep the runner password in the process secret store rather than a checked-in environment file. FERRICSTORE_HTTP_RUNNER_USERNAME_ENV and FERRICSTORE_HTTP_RUNNER_PASSWORD_ENV can point the runner at differently named secret variables. Target requests are bounded by both the configured target timeout and a runner job deadline. See HTTP architecture for the trust and execution boundaries.