This repo supports three independent deployment paths. Each one uses a different set of files, and none of them interferes with the others:
| Path | Files used | Who it's for |
|---|---|---|
VPS bare-metal — git clone + make setup + install-service.sh |
setup.py, install-service.sh, Makefile |
Single-VPS installs with systemd |
Local dev with Docker Compose — docker compose up |
Dockerfile, Dockerfile.dashboard, docker-compose.yml |
Local development, single-machine demos |
| Production on Docker Swarm — Portainer / Traefik | Dockerfile.swarm, Dockerfile.swarm.dashboard, evonexus.stack.yml |
Multi-node production behind a reverse proxy |
This guide covers the third path. The first two are documented elsewhere and are not modified by the Swarm overlay.
Three Swarm services in one stack:
| Service | Image | Purpose |
|---|---|---|
evonexus_dashboard |
evo-nexus-dashboard |
Flask + React + embedded terminal-server, exposed through Traefik |
evonexus_telegram |
evo-nexus-runtime |
Long-running claude --channels plugin:telegram… daemon |
evonexus_scheduler |
evo-nexus-runtime |
Background scheduler for ADW routines (scheduler.py) |
Seven named volumes (auto-created by Portainer on first deploy):
evonexus_config — the UI-editable .env and providers config (writable)evonexus_workspace — agent workspace (daily-logs, projects, finance, etc.)evonexus_dashboard_data — dashboard SQLiteevonexus_memory — persistent agent memoryevonexus_adw_logs — routine execution logsevonexus_agent_memory — per-agent scratch memoryevonexus_codex_auth — ~/.codex/auth.json persisted across restartsOne external overlay network (traefik-public by default — rename to match
your Traefik setup).
The stack intentionally ships zero API keys and zero integration tokens. Everything is configured through the dashboard after the first boot:
/providers) — Anthropic, OpenAI API Key, Codex OAuth, OpenRouter, Gemini, etc./integrations) — Telegram, Stripe, Omie, Bling, Asaas, Fathom, Todoist, GitHub, Linear, Gmail, Calendar, YouTube, Instagram, LinkedIn, Evolution API, Evo CRM, …When you save a value in the dashboard, it lands in /workspace/config/.env
inside the evonexus_config volume. On the next container start, the
entrypoint sources that .env so every process sees the value as a regular
environment variable.
Only channels that maintain a persistent connection need a dedicated long-running service. External REST APIs do not.
| Channel | Dedicated service? | Notes |
|---|---|---|
| Telegram | ✅ Included (evonexus_telegram) |
Already in the stack |
| Discord | Optional | Duplicate the evonexus_telegram block; swap plugin:telegram → plugin:discord |
| iMessage | Optional | Same pattern; needs a BlueBubbles server on a Mac |
| WhatsApp (Evolution API / Go) | ❌ Not needed | External HTTP API — run the evolution_api stack separately |
| Stripe / Omie / Bling / Asaas / Fathom / Todoist | ❌ Not needed | External REST APIs, called on demand |
| GitHub / Linear / Gmail / Calendar / YouTube / Instagram / LinkedIn | ❌ Not needed | OAuth via dashboard, REST calls on demand |
| Evo CRM | ❌ Not needed | Reached via cross-stack HTTP over the shared Traefik network |
traefik-public — rename to match your setup).websecure entrypoint and a certificate
resolver called letsencryptresolver (rename in the stack labels if
your resolver has a different name).evonexus.<yourdomain> to the Swarm ingress.evoapicloud/evo-nexus-{dashboard,runtime} (published by the included
GitHub Actions workflow on every version tag and push to main).docker login is needed on the Swarm
managers. If you fork the project and publish to your own namespace,
update the image: lines in evonexus.stack.yml.Build and publish the images. Push a version tag (vX.Y.Z) or use
the Actions tab to run Build & Publish Docker Images (Swarm)
manually. The workflow builds both images in parallel and publishes
them with the version tag and :latest.
Open Portainer → Stacks → Add stack.
evonexusevonexus.stack.ymlevonexus.example.com (your hostname,
two places) and traefik-public (your Traefik overlay network
name, several places). The images already point at the official
evoapicloud/evo-nexus-* namespace on Docker Hub.Click Deploy
Watch the containers come up. evonexus_dashboard serves the SPA
immediately. evonexus_telegram and evonexus_scheduler will log
waiting for ANTHROPIC_API_KEY every 30 seconds — this is expected
until step 4.
Open https://evonexus.<yourdomain> → Setup wizard → create the
admin user → Providers → pick and save a provider:
sk-ant-… (default, no extra setup).sk-… (create at
platform.openai.com/api-keys
with All permissions, not Restricted).Codex OAuth — click the Login button and complete the ChatGPT
device flow. The token is written to the evonexus_codex_auth
volume and persists across restarts.
Wait ~30 seconds. The telegram and scheduler services detect the key on their next polling cycle and start running.
Integrations. Configure channels and external APIs from
/integrations. Values land in the same config volume and are picked
up at container startup. After changing something the telegram daemon
uses, force-restart that service in Portainer
(docker service update --force evonexus_telegram).
Confirm the dashboard container logs show both processes on boot:
[start-dashboard] terminal-server on :32352, Flask on :8080
🚀 Terminal server running at http://localhost:32352
* Running on http://127.0.0.1:8080
If only Flask is running, the image is an old build — redeploy with the
latest tag. Also verify that the Traefik router includes the
evonexus_terminal_strip middleware (visible in the Traefik dashboard
if you have one enabled).
They should not crash — they wait for ANTHROPIC_API_KEY via the
entrypoint's poll loop. If they exit immediately, the image predates
the bootstrap entrypoint. Redeploy with a current tag.
Portainer preserves named volumes across stack updates by default. If
you removed and recreated the stack, data in evonexus_config,
evonexus_workspace, etc. is gone unless you backed them up. Confirm
with docker volume ls on the manager.
The Swarm overlay is purely additive. Every upstream file is unmodified and continues to support the VPS and local Compose paths:
Dockerfile, Dockerfile.dashboard, docker-compose.ymlsetup.py, install-service.sh, Makefilepyproject.toml, uv.lockSwarm-specific files added by this overlay:
Dockerfile.swarm, Dockerfile.swarm.dashboardentrypoint.sh, start-dashboard.shevonexus.stack.yml.github/workflows/docker-publish.ymlREADME.swarm.md (this file)$ claude mcp add evo-nexus \
-- python -m otcore.mcp_server <graph>