Skip to main content

Self-hosting (alpha)

By default the Vulkro for Salesforce console runs on your own machine: vulkro-sf serve boots a local web app, binds to loopback (127.0.0.1), and opens your browser. Nothing leaves the box.

Self-hosting changes one thing: instead of every developer running the console on their own laptop, you run one console on a shared box and the team points their browsers at it. The scanner is still the same point-in-time, offline engine. It does not phone home, and it still reads a live org only through each operator's own sf CLI login.

This is an alpha deployment shape

The console ships no built-in authentication and no multi-tenant isolation in this release. Anyone who can reach the port gets the full console. Treat the steps below as a way to share the tool inside a trusted network, behind a reverse proxy that adds TLS and auth. Do not put it on the public internet as-is.

The model

  • Point-in-time, offline scanner. A scan reflects the code and (if you run the org passes) the org configuration at the moment it ran. There is no always-on agent and no background polling.
  • One shared console, many viewers. The self-hosted container holds the projects, scans, and triage decisions in a SQLite database on a mounted volume. Everyone on the box's network sees the same state.
  • Org access stays per-operator. The live-org subcommands still shell out to the sf CLI. The container does not hold a Salesforce token. See Live-org setup for the precise privacy contract.
  • No vendor round-trip. The console does not send scans to Vulkro. Self-hosting does not change that; it only moves where the binary runs.

Environment variables

The same three variables drive both vulkro-sf serve directly and the container.

VariableDefaultPurpose
VULKRO_SF_BIND127.0.0.1Bind IP. Loopback keeps the console local-only. Set to 0.0.0.0 to expose it on the network (then put a reverse proxy in front; see the caveat below).
VULKRO_SF_PORTOS-picked free portPin a fixed port. The --port flag overrides this variable.
VULKRO_SF_DATA_DIR~/.vulkro-sf/dataDirectory for the SQLite database and on-disk state. Point it at a mounted volume so data survives container restarts.

When vulkro-sf serve binds to a non-loopback address it prints a warning to that effect, because the console has no auth of its own:

WARNING: bound to a non-loopback address. Put this behind a reverse
proxy with authentication; the console has no built-in auth yet.

Docker quickstart

The build context is the repository root because the image compiles the whole cargo workspace and builds the web UI bundle.

A ready-to-edit compose file lives at deploy/self-hosted/docker-compose.yml. It defines one service, a named volume for the data directory, and a commented-out reverse-proxy stub.

cd deploy/self-hosted
docker compose up -d --build

By default the compose file maps the console to 127.0.0.1:8923 on the host, so it is reachable only from the box itself. Reach it over an SSH tunnel from your laptop:

ssh -L 8923:127.0.0.1:8923 user@your-host
# then open http://127.0.0.1:8923 in your browser

With plain docker

# Build (run from the repo root):
docker build -f crates/vulkro-sf/Dockerfile -t vulkro-sf:local .

# Run, persisting data to a named volume, console on loopback:
docker run -d \
--name vulkro-sf \
-p 127.0.0.1:8923:8923 \
-v vulkro_sf_data:/data \
vulkro-sf:local

The image sets VULKRO_SF_BIND=0.0.0.0, VULKRO_SF_PORT=8923, and VULKRO_SF_DATA_DIR=/data so it binds predictably inside the container and stores state on the volume. It runs vulkro-sf serve --no-browser as a non-root user.

Building the UI bundle

The container build runs npm run build:sf in an earlier stage and copies the result into the cargo build, so a clean checkout builds end-to-end with no extra steps. If you would rather build the UI on the host, populate web-ui-sf/dist/ first and that stage becomes a fast cache hit.

Put a reverse proxy in front

Because the console has no authentication, exposing it beyond a trusted network means terminating TLS and adding auth at a layer in front. The compose file ships a commented stub for both Caddy and nginx showing exactly where the TLS certs and the basic-auth credentials go.

The recommended shape:

  1. Keep the app container's published port on loopback (or move it to an internal-only Docker network).
  2. Run a reverse proxy (Caddy or nginx) that listens on 443, terminates TLS, enforces basic-auth or your SSO, and proxies to the app container.
  3. Publish only the proxy.

This is an interim arrangement. Built-in authentication for the self-hosted console is on the roadmap; until then the proxy is the front door.

What this is not (yet)

  • Not multi-tenant. All viewers share one project list and one triage queue. There is no per-user or per-team separation.
  • Not authenticated at the app layer. Auth lives in the reverse proxy you place in front, not in the console.
  • Not a managed service. You run and patch the box. Rebuild the image to pick up a new vulkro-sf release.

For the single-developer workflow, you do not need any of this: just run vulkro-sf serve and use the console locally. See Install and Your first scan.