Run with Docker
Run staqly as one pre-built, hardened container with docker run. No checkout, no Compose.
The alternative to the binary for Staqly Community Edition: the
pre-built image ghcr.io/staqly/staqly runs everything staqly serve runs (API, MCP, background workers and the dashboard) in one
container, with all data in one volume. You need Docker and nothing else: no repository, no
Compose, no make. Choose it when you already run your tools in Docker or want a read-only,
capability-free container.
Start staqly
Run the container
docker run -d --name staqly --restart unless-stopped \
-p 127.0.0.1:3333:3333 -p 8080:8080 \
-v staqly-data:/data \
--read-only --tmpfs /tmp:size=64m,mode=1777 \
--cap-drop ALL --security-opt no-new-privileges:true \
--memory 640m --pids-limit 256 \
ghcr.io/staqly/staqly:latestDocker pulls the image the first time. After a few seconds docker ps shows the container as
healthy. With --restart unless-stopped it starts again with Docker (and with your computer,
if Docker starts at login) until you stop it.
Sign in to the dashboard
Every browser signs in once, this computer included. On first start staqly made an access token, the one key of your install; print it with a link that signs the browser in:
docker exec staqly server tokenstk_local_dkzqs4w2v7hn3mxa6rjtbye5cfgu8pql2nwo4ks7vd3h6mxzaqbt
Sign a browser in: http://localhost:8080/#token=stk_local_dkzqs4w2v7hn3mxa6rjtbye5cfgu8pql2nwo4ks7vd3h6mxzaqbtOpen the link (the token stays in the part after #, which never reaches a server), or open
http://localhost:8080 and paste the token. docker logs staqly shows the same link from
every start.
Phones and tablets scan the QR code from Connect a device instead. The container can't see
your computer's Wi-Fi address, so the first time the dialog asks for it (for example
192.168.1.23) and remembers it in this browser; -e PUBLIC_DASHBOARD_URL=http://192.168.1.23:8080
sets it for every browser. See Phones & tablets.
Connect an agent
Agents and scripts use http://localhost:3333 and http://localhost:3333/mcp with the access
token as Authorization: Bearer (export STAQLY_API_KEY=$(docker exec staqly server token)) —
see Connect an agent. docker exec -i staqly mcp-stdio needs no token.
What the flags do
| Flag | Why |
|---|---|
-p 127.0.0.1:3333:3333 | The API and MCP endpoint, on this computer only. Every request needs the access token anyway; keeping the port off the network is defense in depth. |
-p 8080:8080 | The dashboard, reachable from your network so phones can use it. Every browser signs in once. |
-v staqly-data:/data | The named volume with the database, uploads, keys and the access token. Removing or upgrading the container keeps it. |
--read-only, --tmpfs /tmp:... | Immutable root filesystem; all state lives in /data, plus a small /tmp. |
--cap-drop ALL, --security-opt no-new-privileges:true | No Linux capabilities, no privilege escalation. The image already runs as an unprivileged user (uid 10001). |
--memory 640m, --pids-limit 256 | Bounded memory and processes. Raise --memory for large uploads or many channels publishing at once. |
--restart unless-stopped | Starts again after a crash or a reboot, until you docker stop it. |
Keep the API on 127.0.0.1
With -p 3333:3333 other computers on your network could reach the API: they would still need the
access token, but there is no reason to offer it to them. Containers that call staqly (n8n) reach it
over a Docker network instead.
Everyday commands
| Command | Does |
|---|---|
docker exec staqly server token | Prints the access token and a link that signs a browser in |
docker exec staqly server token --rotate | Makes a new access token: the old one stops working and every browser is signed out |
docker exec staqly server connect-link | Prints a one-time sign-in link for a browser (5 minutes, single use) |
docker logs -f staqly | Follows the logs (JSON lines; see Logs & tracing) |
docker ps --filter name=staqly | Shows whether it runs and is healthy |
docker stop staqly / docker start staqly | Stops / starts it again (the data volume is kept) |
docker exec -i staqly mcp-stdio | MCP over STDIO for clients without HTTP support — see MCP |
docker exec staqly server <command> | Operator commands: token, connect-link, backup, storage migrate |
Backups use docker exec staqly server backup — see Backup & restore.
Settings
Pass settings with -e NAME=value, or put them in a file and add --env-file staqly.env to
docker run. All variables are on Configuration. A container
keeps the settings it was created with: to change one, remove the container and run it again
(the data stays in the volume):
docker rm -f staqly
docker run -d --name staqly ... -e LOG_FORMAT=text ghcr.io/staqly/staqly:latest # the full command from aboveFor example, -e LOCAL_USER_NAME="$USER" shows your name instead of Local in the activity log.
Other ports
The host ports are the left side of -p. The image listens on 3333 and 8080 inside the
container; tell staqly the host ports so links, QR codes and snippets point to them:
docker run -d --name staqly --restart unless-stopped \
-p 127.0.0.1:4333:3333 -p 9090:8080 \
-e PUBLIC_API_URL=http://localhost:4333 -e DASHBOARD_PORT=9090 \
...Update your MCP client URLs to the new API port.
Reach n8n on this computer (Linux)
Docker Desktop (macOS, Windows) resolves host.docker.internal to your computer. On Linux,
add --add-host host.docker.internal:host-gateway so webhooks can reach n8n or other receivers
running on the host. See n8n.
Data
All state is in the volume staqly-data, mounted at /data:
/data/workspace.db SQLite database (WAL: -wal / -shm side files while running)
/data/uploads/ media files, one folder per workspace (uploads/workspaces/<id>/)
/data/access_token the access token every request needs (created on first start, owner-only)
/data/secret.key key for channel credentials and developer app secrets (created on first start, unless STAQLY_SECRET_KEY is set)
/data/notify_secret.key key for alert secrets (created with the first alert, unless NOTIFY_SECRET_KEY is set)
/data/backups/ scratch space for server backupBack it up with Backup & restore. To delete everything:
docker rm -f staqly
docker volume rm staqly-data # deletes the database and uploads for goodUpgrade
Back up first, then pull the new image and recreate the container with the same command:
docker pull ghcr.io/staqly/staqly:latest
docker rm -f staqly
docker run -d --name staqly ... ghcr.io/staqly/staqly:latest # the full command from aboveMigrations run automatically on start. To stay on one release, use its tag instead of
latest, for example ghcr.io/staqly/staqly:v0.2.0. See Upgrades.
The image
ghcr.io/staqly/staqly is published for linux/amd64 and linux/arm64 with every release
(:v0.2.0, and :latest for the newest), the same version as the staqly binary. It runs one
process (server) as uid 10001 and is health-checked via /health and the dashboard. The
dashboard relays /api/* to the API in the same process without buffering request bodies,
capped at 110 MB (the API's default upload limit is 100 MB); larger bodies get
413 too_large.
Binaries in the image: server (the server and its operator commands)
and mcp-stdio.
Working on staqly itself? Develop with Docker Compose builds the image from a checkout.