The problemOn-demand, without the trade-offs

Containers that provide functionality used only occasionally still consume memory and CPU while they sit idle, waiting to be needed. If usage follows a regular schedule, a cron job can start the container when needed and stop it afterwards. If usage is purely interactive, a person can start it by hand. But when the functionality is needed on demand — triggered by an event such as a step in an automated workflow — neither option fits: nothing is watching for the event, so the container either runs continuously to be ready (wasting resources) or isn't there when the event happens.

The obvious workaround, for local automation, is to give the calling process access to the Docker socket so it can start containers itself. That solves the on-demand problem, but at a cost: anything with socket access can run arbitrary containers with no restriction on image, command, or resources — an unauthenticated, unaudited path to full control of the Docker daemon.

FExec exists to close that gap. It replaces direct Docker socket access with a narrow, authenticated HTTP API: callers can only trigger commands or containers an operator has explicitly pre-defined as aliases, with every parameter validated before use. Functionality that's needed only occasionally can be started exactly when it's needed — without leaving it running all the time, and without handing callers unrestricted control of the host.

OriginBackground

FExec grew out of a concrete need: running browser-based web automation (via Playwright) as part of a larger workflow. Playwright containers are memory-heavy, and running them permanently — especially alongside other, similar occasional-use workloads competing for the same memory — wasn't a good trade-off.

The automation itself was orchestrated by an internal n8n instance, but the intent was to expose the ability to trigger it more broadly, including to callers outside the local network, while tightly restricting which containers could run and what they were allowed to do. That requirement put potentially dangerous operations — starting arbitrary containers or processes — behind three layers of protection: authentication of every call to FExec, a strict operator-defined whitelist of what can be run at all, and granular authorization that determines, per caller, which of those pre-defined aliases they're actually allowed to invoke.

Configuration modelExecution modes & types

Every action FExec's API can perform is defined as an alias — a named, operator-authored configuration that combines what to run, how input and output are mapped, how it's logged, and other execution details. Each alias is configured along two independent dimensions: type (what runs) and mode (how its lifecycle and invocation are handled).

Container type

FExec starts a Docker container, runs it to completion, and returns the result. Input/output are exchanged through whichever combination of environment variables, extra command-line arguments, streams, and files the alias maps to the API's parameters.

Process type

FExec starts a normal host process instead of a container, using the same range of input/output mapping options.

Both types share the same authentication, authorization, and parameter validation — the only difference is what actually runs. Every alias also declares a mode, optional (default inline): in Inline mode the API call blocks until the container/process runs to completion, and its output/exit code is returned inline with the response; in Standalone mode FExec starts a long-lived process/container and returns once it's up, and the caller talks to the started instance directly until it's stopped explicitly or by an idle timeout.

See the Configuration reference for the full alias YAML format, or HOWTO.md for complete, runnable example configurations.

Trust boundarySecurity model

  • Whitelist execution — only pre-configured aliases run; no arbitrary commands.
  • Per-parameter validation — every input validated against a regex defined in the alias.
  • Container isolation — Docker aliases always run with --cap-drop ALL; network isolation and a read-only filesystem are configurable per alias.
  • No state leakage — per-execution temp directories are deleted after each run.
  • Opaque errors — internal failures return 500 without stack traces; details go to the log.
  • Audit log — every call is recorded with user identity, alias name, parameters, and exit status.
  • Optional public surfaces — the landing page and API documentation can both be disabled (PublicInfoEnabled=false) if you don't want either publicly reachable.
200 means both succeeded. A 200 response from FExec means both FExec and the invoked process/container succeeded — not merely that FExec was able to run it — except when the alias's exitCodeMap has explicitly reassigned that exit code's status.

Continue to the API reference for authentication, request/response formats, and status codes.