Self-Hosting with Docker

Run dbxlite as a container on your own infrastructure - one image, no backend to operate.

Why self-host

dbxlite is client-side by design - the container only serves static UI assets (HTML, JS, the DuckDB WASM engine). Queries run in each user's browser tab against their own local and remote files. Nothing is uploaded to the container or to any dbxlite service.

Good fits: internal SQL training, a self-hosted analytics scratchpad, air-gapped/offline environments, or giving a team a shared query tool without provisioning any infrastructure.

Quick Start

docker run -p 8080:80 hfmsio/dbxlite
# then open http://localhost:8080

With Docker Compose:

services:
  dbxlite:
    image: hfmsio/dbxlite:latest
    ports:
      - "8080:80"
    restart: unless-stopped
docker compose up -d

No volumes, environment variables, or secrets are required for the core DuckDB workflow.

Tags & architectures

  • latest - most recent release
  • X.Y.Z (e.g. 0.5.0) - pinned version, recommended for reproducible deployments
  • X.Y - latest patch within a minor line

Every tag is a multi-arch manifest for linux/amd64 and linux/arm64 - Intel/AMD servers, Apple Silicon, and ARM cloud instances (AWS Graviton, etc.) all work natively.

Configuration

Port. The container serves on port 80; map it wherever you like (-p 8080:80).

Cross-origin isolation headers (built in). The bundled nginx config sets the headers DuckDB needs for OPFS persistence and file export:

  • Cross-Origin-Opener-Policy: same-origin
  • Cross-Origin-Embedder-Policy: credentialless - keeps the context cross-origin-isolated while still letting httpfs fetch remote files/CSVs that don't send CORP headers
  • Cross-Origin-Resource-Policy: cross-origin

This is why the Docker image is the recommended path over serving the built assets from a bare web server - omitting these headers silently disables OPFS features. If you put dbxlite behind your own reverse proxy or TLS terminator, preserve these headers.

Behind a reverse proxy / sub-path. Assets are referenced relatively, so the app can be served from any host or sub-path. Terminate TLS at your proxy and forward to the container's port 80.

Server mode still works

The container serves the same UI that DuckDB's ui extension uses, so a user can point a native DuckDB running on their own machine at it for full extensions, unlimited memory, and direct filesystem access:

export ui_remote_url="http://localhost:8080"   # this container
duckdb -unsigned -ui                            # native engine + dbxlite UI on :4213

The engine runs locally next to the user's files; the container only ships the interface. Don't run a shared DuckDB engine inside the container for multiple users - arbitrary SQL implies filesystem and extension access, and a single shared engine has no per-user isolation. Keep the engine on each user's machine. See Server Mode for the full setup.

Health check & operations

  • The app is a static site; an HTTP GET on / returns 200 when ready.
  • Stateless - no persistent volumes needed. Restart freely.
  • Logs are standard nginx access/error logs on stdout/stderr.

Links