Docker Deployment
Docker hosts the persistent OneBots manager without requiring Node.js on the host. The manager controls a separate gateway process, so Web management remains available when the gateway is stopped or fails. An empty volume starts without preselected adapters, protocols, accounts, or frameworks.
Prerequisites
- Docker installed (and optionally Docker Compose)
Keep the image, entrypoint, and CLI on the same release. Legacy images do not implement this manager workflow; preserve the complete
/datavolume during upgrades and do not reuse legacy startup flags.
Quick Start
Option 1: Docker Compose (recommended)
Create a docker-compose.yml in your project directory. You must mount ./data to /data so that user config (config.yaml) and data are persisted; otherwise they are lost when the container restarts.
# OneBots gateway - Docker Compose (official image)
# Usage: docker compose up -d
# Mount ./data to persist user config.yaml and data
services:
onebots:
image: ghcr.io/lc-cn/onebots:master
container_name: onebots
restart: unless-stopped
ports:
- "6727:6727"
volumes:
# Persist user config config.yaml and data (SQLite, logs)
- ./data:/data
environment:
- NODE_ENV=production
# Optional for deployments without a terminal; leave unset otherwise
- ONEBOTS_BOOTSTRAP_CODE
healthcheck:
test: ["CMD", "node", "/app/scripts/docker-healthcheck.mjs"]
interval: 30s
timeout: 5s
start_period: 30s
retries: 3Then run:
# Start (runs in background; config and data are in ./data)
docker compose up -d
# View logs
docker compose logs -f onebots
# Stop
docker compose downThe container runs a persistent management service, which owns the gateway subprocess. An empty workspace starts without platform accounts or protocol outputs. A damaged business configuration does not remove access to the management console.
Authorize the browser with a device pairing code issued locally:
docker exec -u node onebots node /app/packages/onebots/lib/bin.js auth bootstrap --data-dir /dataEnter the returned code within five minutes on the pairing page to create a management session. If browser authorization is lost, issue a local code with auth recover instead; the previous session is invalidated only when that code is redeemed. Keep it private. Management authentication no longer uses a token in config.yaml, ONEBOTS_ACCESS_TOKEN, or the old username/password login. Protocol access tokens remain separate business settings. Without a terminal, use the one-time deployment Secret described in the HF section below.
Use Web or TUI to select extensions, review the installation plan, install and verify a candidate generation, then explicitly activate it. Configure accounts and protocol connections separately; choosing a framework does not automatically enable a protocol. Configuration changes use validation and explicit application, with the management service remaining available during gateway restarts.
The deployment code in .env.example is commented out by default; do not set it to an empty string. Normal local deployments can use auth bootstrap without this environment variable.
Container user and volume permissions
The entrypoint creates /data if needed, assigns it to the built-in node user (uid/gid 1000) when started as root, then drops privileges with su-exec. The manager and gateway do not remain running as root. Existing volume ownership may change to 1000:1000.
If ownership changes fail, startup stops. An explicit Docker --user or Compose user: is preserved and must already have access to the workspace. Installed dependencies and verified generations are managed under /data/.control; do not use the old /data/extensions or ONEBOTS_EXTENSION_ROOT mechanism.
Container health status
The health check probes the management service at http://127.0.0.1:${PORT:-6727}/ready; it does not derive an address from business YAML. It validates the application/version identity, ready: true, response size and deadline, and rejects redirects. Inspect it with:
docker compose ps
docker inspect --format '{{json .State.Health}}' onebotsManagement readiness is separate from gateway and account health. An empty or stopped gateway, or damaged configuration, must not make the management console unavailable. Inspect gateway state in Web or with onebots doctor --data-dir /data. Docker restart policies do not restart containers solely because a health check fails.
Option 2: docker run
# Run official image (use -v to persist user config)
docker run -d \
--name onebots \
--restart unless-stopped \
-p 6727:6727 \
-v $(pwd)/data:/data \
ghcr.io/lc-cn/onebots:master
# View logs
docker logs -f onebots
# Stop and remove
docker stop onebots && docker rm onebotsUsing pre-built images from GitHub
Published images are available through GitHub Actions. Use master for the current branch build or pin a released version tag in production:
docker run -d \
--name onebots \
--restart unless-stopped \
-p 6727:6727 \
-v $(pwd)/data:/data \
ghcr.io/lc-cn/onebots:masterReleased versions use version tags, e.g. ghcr.io/lc-cn/onebots:1.0.0.
Data and configuration
| Path (in container) | Description |
|---|---|
/data/config.yaml | User config file; must be mounted or it is lost on container restart |
/data/data/ | Database and audit logs; created by the app |
/data/.control/ | Management authentication, operations and verified dependency generations; not a portable backup format |
Always mount a host directory to /data (e.g. -v $(pwd)/data:/data or ./data:/data in docker-compose) so that:
- User config
config.yamlis persisted on the host and survives restarts or rebuilds - Database and logs are not lost when the container is removed
- Adapters and protocols installed by the extension center survive container recreation
Custom adapters and protocols
The empty manager does not preselect adapters or protocols. Install the required packages and their required peers through the management installation workflow, verify the candidate, and activate it explicitly. Do not replace the Docker command with legacy -c/-r/-p startup flags.
Private dependencies such as ICQQ
Supply required package-download authorization through the installation workflow. Do not bake private tokens into image layers, command arguments or business configuration. Downloading a candidate is not installation success: validation must pass before activation.
Port and network
- The management listener defaults to 6727. Set
PORTand map the corresponding container port when changing it. - Business YAML does not determine the manager listener. HF uses 7860 without rewriting YAML.
Deploy to Hugging Face Spaces
The repo includes Docker files for Hugging Face Spaces: they use port 7860 (HF default) and do not require building from source on HF.
Steps:
- Create a Space on Hugging Face and choose Docker as the SDK.
- In the Space repo, add these four files (copy from this repo and preserve the
scripts/subdirectory):- Dockerfile: copy from
Dockerfile.hf(or renameDockerfile.hftoDockerfile). - docker-entrypoint-hf.sh: the entrypoint script next to
Dockerfile.hf. - scripts/hf-repository-download.mjs: the bounded restore downloader; keep its path aligned with the
COPYinstruction in the Dockerfile. - scripts/hf-data-archive-restore.mjs: the data archive inspector and isolated restorer; preserve this relative path as well.
- Dockerfile: copy from
- In Space → Settings → Secrets, add
ONEBOTS_BOOTSTRAP_CODE. Generate 32 random bytes as a 43-character base64url code withnode --input-type=module -e "import { randomBytes } from 'node:crypto'; process.stdout.write(randomBytes(32).toString('base64url'))". Enter it on the pairing page within five minutes of startup. Never put it in public Variables; remove the Secret after pairing. - To persist config and data, see Mounting and viewing /data on HF below.
Dockerfile.hf is based on the official image ghcr.io/lc-cn/onebots:master and only adds the HF port, entrypoint, and two dependency-free restore boundaries, so builds are fast and no GitHub Packages build secret is needed.
The deployment code only authorizes initial pairing. Only its digest is persisted; the code is removed from the manager environment and is not passed to the gateway. Restarting with the same code does not extend its expiry. Before pairing, you may rotate to a fresh random code and restart, with at most 16 distinct deployment codes. An existing paired session is never replaced by this Secret. With terminal access, use local onebots auth recover. Without it, remove the old ONEBOTS_BOOTSTRAP_CODE Secret, generate a fresh random code using the command above, save it as the private ONEBOTS_RECOVERY_CODE Secret, and restart. Enter it on the pairing page within five minutes, then remove the Secret. Only successful redemption revokes the old session. Restarting cannot reissue or extend the same code. Recovery cannot initialize an unpaired workspace; do not set both Secrets or reuse an earlier deployment code. An unexpired local recovery code takes priority; use it or wait until it expires before injecting another fresh deployment code. At most 16 recovery codes are recorded; beyond that use local recovery, never delete authentication files to bypass the limit. There is no permanent deployment-token login.
Use a base image from the same manager release. Pass --build-arg ONEBOTS_BASE_IMAGE=<matching-image> when pinning the base for Dockerfile.hf.
Mounting and viewing persistent /data on HF
Mount: Hugging Face mounts persistent storage at
/dataat runtime (same path OneBots uses). You do not add aVOLUMEor mount in the Dockerfile.- Open your Space → Settings → Storage (or Billing / storage).
- If Persistent storage is available, enable it; the platform will attach the volume to
/data. - If persistent storage is not offered for your account/region, anything under
/datais lost on Space restart; back up important config to a Dataset or external store.
View: HF does not provide a file browser for the container’s
/data. The Space Files tab shows only the repo (Dockerfile, scripts), not the runtime volume.- After pairing, use the OneBots configuration interface to inspect and edit configuration.
- On first run without persistent storage, the entrypoint creates a default
config.yamlunder/data; it will persist across restarts only if persistent storage is enabled.
Restoring an existing backup
Prefer persistent storage. The new manager has not integrated the old automatic “save in Web and upload to the Space repository” backup workflow. Do not assume a backup exists, and never upload plaintext configuration or account databases to a public repository.
Set HF_REPO_ID to restore an existing backup; use a read-only HF_TOKEN Secret for private repository downloads. The entrypoint attempts data_backup.tar.gz only when /data is completely empty, and tries config_backup.yaml if no archive was obtained. Existing volumes are never overwritten by a remote snapshot. No backup or damaged YAML still leaves the manager available for configuration repair.
Portable archives may contain config.yaml, account state and databases under data/, and static/. They must exclude .control, dependencies, package credentials, caches and temporary state. Do not restore management sessions, historical PIDs or verified-generation receipts. Reinstall and verify extensions through the manager after restoration. Stop the gateway and confirm its exit before backing up databases; copying live SQLite files is not proof of a consistent backup.
Restore retains limits of 15 MiB compressed, 128 MiB expanded and 10,000 entries, rejects traversal and links, and uses private staging. A downloaded archive that fails validation or restoration stops startup instead of falling back to configuration. Any residual .hf-restore-* blocks startup: preserve the volume and inspect the failure; restore into a fresh empty volume after confirming no process is running. Do not repeatedly restart or simply remove the marker.
PORT sets the manager listener, defaulting to 7860. The entrypoint neither rewrites business YAML nor replaces system DNS. Diagnose DNS and outbound access in the deployment environment.
docker build -t onebots-manager .
docker build -f Dockerfile.hf --build-arg ONEBOTS_BASE_IMAGE=onebots-manager -t onebots-hf .
docker run -p 7860:7860 -v $(pwd)/data:/data onebots-hfProduction tips
- Use docker compose or an orchestrator (e.g. Kubernetes) with a restart policy (
restart: unless-stoppedor equivalent). - Back up the
/datavolume regularly (includingconfig.yamland thedata/directory). - If exposing publicly, put a reverse proxy (Nginx, Caddy, etc.) in front and enable HTTPS.
- Use
http://localhost:6727/healthzand/readyfor health checks; see Production readiness.
See also
- Quick Start — non-Docker install and run
- Global config — configuration reference
- Production readiness — security, metrics, and health checks