DorkOS
Self-Hosting

Docker

Run DorkOS in a Docker container with persistent data, custom configuration, and Docker Compose

Docker

Run DorkOS as a container. The official image bundles Node.js, the DorkOS CLI, and the built client, so Docker is the only thing you need on the host.

Quick Start

docker run -d --name dorkos \
  -p 4242:4242 \
  -e ANTHROPIC_API_KEY=your-key-here \
  -v dorkos-data:/home/node/.dork \
  ghcr.io/dork-labs/dorkos:latest

This runs DorkOS in the background (-d), maps port 4242 on your machine to the container, passes your API key, and creates a named volume so your data survives container restarts.

Open http://localhost:4242.

Image Versioning

Every release publishes the image with multiple tags:

TagExampleDescription
latestghcr.io/dork-labs/dorkos:latestMost recent non-prerelease version
Exact versionghcr.io/dork-labs/dorkos:0.52.0Pinned to a specific release
Minor trackghcr.io/dork-labs/dorkos:0.52Tracks the latest patch within a minor version
Commit SHAghcr.io/dork-labs/dorkos:sha-abc1234Pinned to a specific build commit

For production deployments, pin to an exact version:

docker pull ghcr.io/dork-labs/dorkos:0.52.0

The latest tag always points to the most recent non-prerelease version. Pre-release tags (e.g., 0.53.0-beta.1) are available by exact version but do not update latest.

Docker Hub mirror

The same image is mirrored to Docker Hub as dorkai/dorkos, with the same tags. GitHub Container Registry (the ghcr.io address above) stays the main home for the image. Docker Hub is a convenience copy, useful if your setup already pulls from there:

docker pull dorkai/dorkos:latest

Multi-Platform Support

The image is built for both linux/amd64 and linux/arm64. Docker automatically pulls the correct architecture for your machine:

  • Intel/AMD servers and desktops: linux/amd64
  • Apple Silicon (M1/M2/M3) via Docker Desktop: linux/arm64
  • ARM servers (AWS Graviton, Ampere): linux/arm64

You don't need to configure anything: docker pull selects the right platform automatically.

Supply Chain Verification

Every published image includes a build provenance attestation (a signed record of exactly which source commit built it) proving it came from the dork-labs/dorkos repository, not a fork. Verify any image with the GitHub CLI:

gh attestation verify oci://ghcr.io/dork-labs/dorkos:0.52.0 --owner dork-labs

A passing check confirms GitHub Actions built the image, not someone's laptop.

Configuration

Pass environment variables with -e or an env file. DorkOS reads the same variables whether it's running in Docker or installed directly.

Prop

Type

Custom port

Set DORKOS_PORT instead of using the --port flag. The container's built-in health check reads DORKOS_PORT to know which port to test, so setting the env var keeps DorkOS and its health check pointed at the same place. Match it with the container side of -p host:container:

docker run -d --name dorkos \
  -p 8080:8080 \
  -e ANTHROPIC_API_KEY=your-key-here \
  -e DORKOS_PORT=8080 \
  -v dorkos-data:/home/node/.dork \
  ghcr.io/dork-labs/dorkos:latest

The --port flag still works, but it only tells DorkOS which port to listen on. The health check keeps checking port 4242, so docker ps would report the container unhealthy even though it's running fine. Use DORKOS_PORT instead so both stay in sync.

Environment file

Keep secrets out of your shell history:

.env.dorkos
ANTHROPIC_API_KEY=your-key-here
docker run -d --name dorkos \
  -p 4242:4242 \
  --env-file .env.dorkos \
  -v dorkos-data:/home/node/.dork \
  ghcr.io/dork-labs/dorkos:latest

Persistent Data

DorkOS stores configuration, session transcripts, agent registrations, and the SQLite database in /home/node/.dork inside the container. Without a volume mount, all of this is lost when the container is removed. Mount a named volume or host directory to persist data across container restarts and upgrades.

Upgrading from 0.48 or earlier? The container now runs as a non-root user, and its data directory moved from /root/.dork to /home/node/.dork. See Upgrading from an older image below before you pull the new version.

docker run -d --name dorkos \
  -p 4242:4242 \
  -e ANTHROPIC_API_KEY=your-key-here \
  -v dorkos-data:/home/node/.dork \
  ghcr.io/dork-labs/dorkos:latest

Docker manages the volume lifecycle. Inspect it with docker volume inspect dorkos-data.

mkdir -p ~/.dork
docker run -d --name dorkos \
  -p 4242:4242 \
  -e ANTHROPIC_API_KEY=your-key-here \
  -v ~/.dork:/home/node/.dork \
  ghcr.io/dork-labs/dorkos:latest

Useful for backup or inspection, since the data directory is directly accessible on the host.

Upgrading from an older image

Versions 0.48.0 and earlier ran the container as root, and stored data at /root/.dork. The image now runs as a regular, unprivileged user (node, uid 1000) instead of root, so a compromised agent or a bug can't touch the rest of the container as easily. That move means two things for anyone upgrading:

  1. The data path changed. Change every -v ...:/root/.dork in your docker run command or Compose file to -v ...:/home/node/.dork.
  2. Existing files need new ownership. Files created by the old root image are owned by root, and the new non-root user can't write to them until you fix that. Run this once, before starting the new image, against the same volume or host directory you already use:
docker run --rm -v dorkos-data:/data alpine chown -R 1000:1000 /data

Replace dorkos-data with your volume name, or with the host path (e.g. ~/.dork:/data) if you mounted a directory instead of a named volume. After that, start the new image with the updated /home/node/.dork mount path as shown above.

Mounting a project directory

By default, agents running inside the container can only see the container's own filesystem. They have no access to your code on the host machine. To let agents read and write files in one of your projects, mount the project directory into the container and tell DorkOS to use it as the default working directory:

docker run -d --name dorkos \
  -p 4242:4242 \
  -e ANTHROPIC_API_KEY=your-key-here \
  -e DORKOS_DEFAULT_CWD=/workspace \
  -e DORKOS_BOUNDARY=/workspace \
  -v dorkos-data:/home/node/.dork \
  -v ~/projects/my-app:/workspace \
  ghcr.io/dork-labs/dorkos:latest

Set DORKOS_BOUNDARY to the mounted directory to restrict agent file access. Without it, agents can access the entire container filesystem.

Since the container runs as an unprivileged user, files agents create in your mounted project are owned by uid 1000 instead of root, so they're usually already owned by your own user account on Linux hosts.

Backing up your data

Copy everything in the data volume into a single archive file you can store somewhere safe. Stop the container first so the SQLite database isn't being written to mid-copy:

docker stop dorkos
docker run --rm -v dorkos-data:/data -v "$(pwd)":/backup alpine \
  tar czf /backup/dorkos-backup.tgz -C /data .
docker start dorkos

This drops dorkos-backup.tgz in your current folder. To restore, extract that archive into a fresh volume the same way:

docker run --rm -v dorkos-data:/data -v "$(pwd)":/backup alpine \
  tar xzf /backup/dorkos-backup.tgz -C /data

Docker Compose

The docker run commands above work fine for trying DorkOS out, but they're unwieldy to maintain. You end up with long shell commands that are easy to mistype and hard to version control. Docker Compose captures the full configuration in one file, so it's reproducible, easy to update, and simple to tear down with docker compose down.

The quickest way to start: download the ready-made file and run it.

curl -O https://dorkos.ai/compose.yml
export ANTHROPIC_API_KEY=your-key-here
docker compose up -d

docker compose finds compose.yml in the current directory automatically, no -f flag needed.

Want to see or customize it first? Here's what that file contains (minus a short comment header):

compose.yml
services:
  dorkos:
    image: ghcr.io/dork-labs/dorkos:latest
    container_name: dorkos
    restart: unless-stopped
    ports:
      - '4242:4242'
    environment:
      - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
    volumes:
      - dorkos-data:/home/node/.dork

volumes:
  dorkos-data:

No healthcheck: entry needed: the image already checks its own health every 30 seconds. Run docker ps and look at the STATUS column to see whether the container reports healthy or unhealthy.

With a reverse proxy

Turn on login before you point a domain at DorkOS. The Docker image ships with login off, and it binds to every network address so port forwarding works. With login off, anyone who reaches the port gets full control: your sessions, your files, and your agents, spending your Claude quota. Create the owner account and require login first:

docker exec -it dorkos dorkos auth enable

This walks you through an email and password, then requires login from then on. You can also pass --email and --password to skip the prompts. Full details are in Securing Your Instance.

The standalone Compose setup above serves DorkOS over plain HTTP on port 4242. That's fine for local use. But if you're exposing DorkOS over the internet (a VPS, a home server with a domain, or any machine other people will connect to), you need HTTPS. Without TLS, browsers block mixed content, credentials travel in the clear, and SSE streams (the live updates DorkOS uses to stream agent output) can be intercepted.

A reverse proxy sits in front of DorkOS, handles HTTPS, and forwards requests to the container. Caddy is the simplest option: it obtains and renews Let's Encrypt certificates automatically, so there's no manual cert management. It also handles the buffering settings SSE needs.

Add Caddy to the Compose file for automatic HTTPS:

compose.yml
services:
  dorkos:
    image: ghcr.io/dork-labs/dorkos:latest
    container_name: dorkos
    restart: unless-stopped
    expose:
      - '4242'
    environment:
      - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
    volumes:
      - dorkos-data:/home/node/.dork

  caddy:
    image: caddy:2-alpine
    restart: unless-stopped
    ports:
      - '80:80'
      - '443:443'
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy-data:/data
      - caddy-config:/config

volumes:
  dorkos-data:
  caddy-data:
  caddy-config:
Caddyfile
dorkos.example.com {
    reverse_proxy dorkos:4242 {
        flush_interval -1
    }
}

flush_interval -1 disables response buffering, which is required for SSE streaming. See the reverse proxy guide for nginx configuration.

Health Check

The image checks its own health automatically: every 30 seconds it asks itself whether the server is responding, and reports the result to Docker. Run docker ps and check the STATUS column for healthy or unhealthy, no setup required.

You can also check it yourself at any time:

curl http://localhost:4242/api/health
# { "status": "ok", "version": "0.52.0", "uptime": 12345 }

The health endpoint is unauthenticated and suitable for load balancer or container orchestrator use.

Using MCP tools

DorkOS exposes its tools to other AI clients at /mcp. Read-only tools work without any setup. Anything that changes state (running an agent, editing files) needs the instance's MCP token, or the call comes back with a 401 error that names where to find it.

Fetch the token from inside the container:

docker exec dorkos cat /home/node/.dork/mcp-local-token

Send it as a Bearer token (a key you attach to each request) on your calls to /mcp. Once you turn on login, per-user API keys replace this token. See the MCP server guide for the full setup.

Building from Source

The official image from the container registry is the easiest path. Build from source if you need to run unreleased changes, test a fork, or include local modifications. One Dockerfile at the repository root covers both cases below.

Build the CLI tarball

git clone https://github.com/dork-labs/dorkos.git
cd dorkos
pnpm install
pnpm docker:build

This builds the CLI package and creates the dorkos:latest image locally.

Run the local image

docker run -d --name dorkos \
  -p 4242:4242 \
  -e ANTHROPIC_API_KEY=your-key-here \
  -v dorkos-data:/home/node/.dork \
  dorkos:latest

From published npm (no clone needed)

If you want a custom Docker image but don't need local code changes, you can build one that installs a published version directly from npm, no tarball or local build required:

docker build \
  --build-arg INSTALL_MODE=npm \
  --build-arg DORKOS_VERSION=latest \
  -t dorkos:npm .

Updating

Pull the latest image

docker pull ghcr.io/dork-labs/dorkos:latest

Recreate the container

docker stop dorkos && docker rm dorkos
docker run -d --name dorkos \
  -p 4242:4242 \
  -e ANTHROPIC_API_KEY=your-key-here \
  -v dorkos-data:/home/node/.dork \
  ghcr.io/dork-labs/dorkos:latest

Or with Compose:

docker compose pull
docker compose up -d

Data in the dorkos-data volume persists across updates.

Troubleshooting

Port forwarding not working

Cause: The server is binding to localhost inside the container.

Fix: The official image sets DORKOS_HOST=0.0.0.0 automatically. If you're using a custom image, ensure this variable is set.

Pull fails with "unauthorized" or "denied"

Cause: A registry hiccup, a rate limit, or a stale login on your machine.

Fix: Try the Docker Hub mirror, which carries the same image:

docker pull dorkai/dorkos:latest

If you were signed into the GitHub registry with an old token, sign out and pull again:

docker logout ghcr.io
docker pull ghcr.io/dork-labs/dorkos:latest

Container exits immediately

Check the logs:

docker logs dorkos

Common causes: missing ANTHROPIC_API_KEY, port already in use on the host, or insufficient memory.

Data lost after restart

Cause: No volume mounted for /home/node/.dork.

Fix: Add -v dorkos-data:/home/node/.dork to persist configuration and session data.

Upgrading from a root-based image and the new container can't write its data

Cause: Images from version 0.48.0 and earlier ran as root and stored data at /root/.dork. The new image runs as an unprivileged user instead, and that user can't write to files the old root image created.

Fix: Fix ownership once, then switch to the new mount path:

docker run --rm -v dorkos-data:/data alpine chown -R 1000:1000 /data

Then start the new container with -v dorkos-data:/home/node/.dork (not /root/.dork). See Upgrading from an older image above for the full walkthrough.

Next Steps