Skip to content
Get started

Self-hosting

f69 is self-hostable end to end. You run two HTTP services and a Postgres database; everything else (manifest sync, evaluation, metering) is in- process inside those services.

ComponentJob
Dashboard serviceBacks the web dashboard - the only surface humans use to author flags and mint tokens. Applies database migrations on startup.
Edge serviceRuntime API for /v1/identify and /v1/evaluate. Authenticates with service-account bearer tokens.
EvaluatorPure Rust library that turns a manifest plus an entity context into a boolean. Embedded in the edge service; also compiled to WebAssembly for SDKs that need offline evaluation.
PostgresSingle source of truth for workspaces, projects, environments, flags, segments, entities, and metering counters.
flowchart LR
Dashboard["Web dashboard"] --> DashboardSvc["Dashboard service (port 8080)"]
SDK["Server SDK"] --> Edge["Edge service (port 8081)"]
DashboardSvc --> Postgres[(Postgres)]
Edge --> Postgres
DashboardSvc -.->|"runs migrations on boot"| Postgres
  • Dashboard service: 8080
  • Edge service: 8081

Place a TLS-terminating reverse proxy in front of both. The web dashboard talks to its backing service on 8080; your application servers talk to the edge service on 8081.

f69 uses Postgres exclusively. Both binaries take a DATABASE_URL connection string of the standard postgres://user:pass@host:5432/db shape.

  • Only the dashboard service runs migrations at boot. Start it before the edge service so the schema exists when edge connects.
  • A standalone migration CLI is also available for ops or CI workflows that apply schema outside the dashboard process.
  • The repository ships a single greenfield baseline migration. New installs apply it cleanly; older dev databases that were on a different migration history must be dropped and recreated before running it - there is no in-place upgrade path between the legacy multi-file history and this baseline.

On a fresh install:

  1. Migrations create the schema, including a deterministic bootstrap workspace (slug default) and bootstrap project (slug default) with seeded environments.
  2. The first user to register becomes the owner of the bootstrap workspace and project, provided the workspace has no members yet.

After that, members are managed through the dashboard like any other workspace.

The edge service accepts a service-account bearer token of the shape xxxxxxxx@f69:<uuid>.<secret>. The plaintext is shown once at creation in the dashboard and stored as an Argon2 hash; if a token’s stored hash is empty (i.e. it was intentionally invalidated), edge returns 401 token_reissue_required and operators must mint a new one from the dashboard.

Service accounts are bound to a single environment for the life of the token. If you need to move a token to another environment, mint a new one rather than rebinding silently.

Run f69 like any other piece of infrastructure that holds user-scoped data:

  • Use TLS everywhere, including between your reverse proxy and the dashboard / edge services if your network isn’t fully trusted.
  • Keep secrets out of plaintext stores. Dashboard logins and service-account secrets are hashed with Argon2 server-side; treat the database password and any service-account tokens you copy as secrets too.
  • Rate-limit at the proxy. Brute-force protection on dashboard login lives at the reverse proxy in this architecture - make sure you’re not forwarding it publicly without a rate-limiter.
  • Plan for short-lived edge credentials. A roadmap item on the security side is to move edge auth toward OIDC federation and short- lived JWTs (modeled on RFC 8693). Even before that lands, treat service-account tokens as production secrets - rotate them on staff turnover and use one per workload.

If you would rather not run f69 yourself, the hosted offering uses the same APIs and the same evaluator - your application code does not change between modes. See the pricing page for the included limits per tier.