Skip to content

Deployment

Both setups run one container, claude-discord, with a TTY (Claude Code is a terminal app), restart: unless-stopped, a 4 GB memory limit and 2 CPUs.

docker-compose.yml builds the image from the local Dockerfile.

Terminal window
cp .env.example .env # then fill in the values
docker compose up -d --build
docker compose logs -f
Volume Mount Contents
claude-home (named) /home/node/.claude Config, installed plugin, access.json, conversation history.
./workspace (bind) /workspace The code the bot works on, visible on the host.

The bind-mounted ./workspace must be writable by UID 1000 (the node user):

Terminal window
mkdir -p workspace && sudo chown 1000:1000 workspace

Every release has a ready-made image attached, built by the Release image workflow (.github/workflows/release.yml).

  1. Open the repository’s Releases and download the image for your server:
    • claude-discord-<version>-arm64.tar.gz: Raspberry Pi and other ARM servers
    • claude-discord-<version>-amd64.tar.gz: x86 servers
  2. Portainer → Images → Import → upload the file. It loads as claude-discord:latest (and claude-discord:<version>).
  3. Create the stack as in steps 2–4 below, or for an update, recreate the container (pull disabled) so it uses the new claude-discord:latest.

Command line instead: docker load -i claude-discord-<version>-arm64.tar.gz.

To make a release, push a version tag, or run the workflow from the Actions tab with a tag name:

Terminal window
git tag v1.0.0 && git push origin v1.0.0

The workflow builds arm64 (emulated, the slow part) and amd64 images, attaches them with SHA-256 checksums and the Portainer build-context tar, then publishes the release.

docker-compose.portainer.yml uses a pre-built image, because Portainer’s stack editor cannot build from a local folder.

  1. Build the image (or import one from a release, see above). Create the tar from the repository root with tar cf claude-discord-build.tar --exclude=node_modules --exclude=dist Dockerfile entrypoint.sh bridge. Then Images → Build a new image → Upload, choose claude-discord-build.tar, name it claude-discord:latest.
  2. Create the stack. Stacks → Add stack → Web editor, paste docker-compose.portainer.yml.
  3. Add variables. Under Environment variables, switch to Advanced mode and paste your filled-in .env. Portainer saves them as stack.env, which the stack file reads.
  4. Deploy the stack.
Volume Mount Contents
claude-home /home/node/.claude Config, plugin, access.json, conversation history.
claude-workspace /workspace The code the bot works on.

Both are named volumes here, so the workspace is not on the host filesystem directly. Use the container console or docker cp to get files out.

  • The bot is invited to the server with permission to read and send messages in the channels listed in DISCORD_CHANNELS.
  • Message Content Intent is enabled for the bot in the Developer Portal.
  • The logs show Claude starting with no ... is required error.
  • With DISCORD_REQUIRE_MENTION=true, @mention the bot in an allowed channel to test it.