Dokploy Wizard is a Python-first installer for standing up a real self-hosted stack on a fresh Ubuntu VPS with Dokploy, Cloudflare Tunnel, optional Cloudflare Access, optional Tailscale host access, and a set of opinionated application packs.
Today this repo is not a scaffold or mock planner. It performs real deployment, real rerun/modify/uninstall flows, and has been validated on fresh VPS rebuilds.
- Dokploy as the deployment control plane
- Cloudflare Tunnel for public ingress
- Cloudflare Access for browser-safe advisor surfaces
- Tailscale for private/admin host access
- Shared Core services used by packs
- PostgreSQL
- Redis
- Nextcloud + OnlyOffice + Talk
- Moodle
- DocuSeal
- OpenClaw (user-visible name: Nexa Claw)
- Nexa, embedded inside OpenClaw as the Nextcloud/Talk/OnlyOffice-facing agent runtime
- Telly, embedded inside OpenClaw as the Telegram-facing agent persona
- My Farm Advisor (user-visible name: Nexa Farm) — separate advisor runtime with Field Operations and Data Pipeline workspaces
- SeaweedFS for S3-compatible object storage
- Coder with a seeded Ubuntu + VS Code workspace template
Optional packs also include Headscale, Matrix, and Coder. My Farm Advisor is optional but can run side-by-side with OpenClaw.
- Fresh-VPS install works
- Same-host rerun / noop proof works
- fresh-VPS install, rerun, and inspect-state flows are part of the validation path
- OpenClaw, Nexa, Nextcloud Talk, OnlyOffice, SeaweedFS, and Coder are all part of the wizard-managed path
- Unchanged healthy services skip Dokploy update/deploy on rerun through compose artifact hash tracking
%%{init: {
"theme": "base",
"themeVariables": {
"primaryColor": "#eef6ff",
"primaryTextColor": "#10243e",
"primaryBorderColor": "#8eb8e8",
"lineColor": "#5f7ea3",
"secondaryColor": "#f7f9fc",
"tertiaryColor": "#fffaf0",
"clusterBkg": "#fbfdff",
"clusterBorder": "#c9d9ee",
"fontFamily": "Inter, ui-sans-serif, system-ui, sans-serif"
}
}}%%
flowchart LR
Internet([🌍 Internet]) --> CF[☁️ Cloudflare Tunnel]
CF --> Traefik[🚦 Dokploy / Traefik ingress]
Tailnet([🔐 Tailscale Tailnet]) --> Host[🖥️ Host access]
Host --> Dokploy[📦 Dokploy]
subgraph Apps[Wizard-managed application surfaces]
OpenClaw[🤖 OpenClaw]
Nextcloud[🗂️ Nextcloud]
OnlyOffice[📝 OnlyOffice]
Coder[💻 Coder]
Seaweed[🪣 SeaweedFS / S3]
end
subgraph Internal[Internal-only sidecars and shared services]
Shared[(🧱 Shared Core\nPostgres + Redis)]
Mem0[🧠 Mem0]
Qdrant[🔎 Qdrant]
NexaRuntime[🧵 Nexa runtime]
end
Traefik --> OpenClaw
Traefik --> Nextcloud
Traefik --> OnlyOffice
Traefik --> Coder
Traefik --> Seaweed
Dokploy --> Shared
Dokploy --> OpenClaw
Dokploy --> Nextcloud
Dokploy --> Coder
Dokploy --> Seaweed
OpenClaw --> Mem0
OpenClaw --> Qdrant
OpenClaw --> NexaRuntime
NexaRuntime --> OpenClaw
NexaRuntime --> Nextcloud
Nextcloud --> OnlyOffice
Apps --> Shared
%%{init: {
"theme": "base",
"themeVariables": {
"primaryColor": "#f4fbf6",
"primaryTextColor": "#173226",
"primaryBorderColor": "#8fc8a8",
"lineColor": "#5c8f74",
"fontFamily": "Inter, ui-sans-serif, system-ui, sans-serif"
}
}}%%
stateDiagram-v2
[*] --> Input : guided install\nor env file
Input --> DesiredState : resolve hostnames\nsecrets\npacks
DesiredState --> Preflight
Preflight --> DokployBootstrap
DokployBootstrap --> Tailscale
Tailscale --> CloudflareNetworking
CloudflareNetworking --> CloudflareAccess
CloudflareAccess --> SharedCore
SharedCore --> Headscale
Headscale --> Matrix
Matrix --> NextcloudOnlyOffice
NextcloudOnlyOffice --> SeaweedFS
SeaweedFS --> OpenClaw
OpenClaw --> MyFarmAdvisor
MyFarmAdvisor --> Installed
Installed --> Modify
Installed --> Resume
Installed --> Uninstall
Modify --> DesiredState
Resume --> Preflight
Uninstall --> [*]
Dokploy is the control plane the wizard targets for all compose app deployment. The wizard bootstraps Dokploy, mints or reuses an API key, and then uses that API key for all managed pack operations.
Shared Core is the common substrate for packs that need databases or cache services. Today that means:
- PostgreSQL for Coder, Nextcloud, and OpenClaw
- Redis for Nextcloud
These are wizard-owned resources, tracked in the ownership ledger, and reused across modify / rerun operations.
The nextcloud pack always includes OnlyOffice as its paired document editor runtime and Talk for real-time chat/voice/video.
What the wizard wires today:
- Nextcloud service + persistent volume
- OnlyOffice service + persistent volume
- shared-core Postgres + Redis bindings
- trusted domain configuration
- OnlyOffice JWT configuration wiring
- Nextcloud Talk app verification
- OpenClaw workspace mount into Nextcloud when Nexa is enabled
OpenClaw is deployed as an advisor runtime with:
- browser-facing access through Cloudflare Tunnel
- Cloudflare Access OTP protection on its public hostname
- trusted-proxy browser auth for the Control UI
- generated gateway config and agent bindings
gateway.http.endpoints.responses.enabled = trueso internal adapters can hand requests into OpenClaw’s own runtime
Nexa is not a standalone pack. It is embedded inside the OpenClaw deployment when OPENCLAW_NEXA_* env values are present.
Nexa’s current role is to bridge OpenClaw into the Nextcloud ecosystem:
- Nextcloud Talk message handling
- Nextcloud file creation and sharing via WebDAV/OCS
- OnlyOffice callback ingestion and reconcile contract wiring
- Mem0-backed memory lookup and memory write policy
- OpenClaw pass-through for grounded tool use and command execution
The important design point is that Nexa is not just a prompt file. The wizard deploys a dedicated nexa-runtime sidecar and associated contract files under the OpenClaw volume, but some Talk and OnlyOffice behaviors are still intentionally conservative and continue to depend on upstream OpenClaw/runtime behavior.
Telly is the Telegram-facing OpenClaw agent persona. Like Nexa, it is seeded by the OpenClaw deployment code rather than installed as a separate pack.
What the wizard currently does for Telly:
- seeds a dedicated Telegram-facing agent persona
- binds the Telegram channel to
telly - configures Telegram DM allowlist / ownership values from
OPENCLAW_TELEGRAM_* - seeds a
workspace-tellywith operator-facing guidance files
My Farm Advisor is a separate advisor runtime from OpenClaw. It runs its own container image (ghcr.io/borealbytes/my-farm-advisor:latest) on its own hostname (default farm.<root-domain>) and does not share the OpenClaw Nexa sidecars.
What the wizard does for My Farm Advisor:
- deploys a standalone service with its own Dokploy compose app
- wires Cloudflare Access OTP on
farm.<root-domain> - seeds two workspaces under
/data:workspace(field ops) andworkspace-data-pipeline - mounts both workspaces into Nextcloud as external storage when Nextcloud is enabled
- maps wizard env keys into the container using a dedicated farm runtime contract so farm-only flags cannot leak into OpenClaw
My Farm Advisor and OpenClaw can run side by side. There is no slot conflict.
Coder gets a seeded Ubuntu + VS Code template and a first default workspace.
On first successful bootstrap the wizard:
-
provisions the initial Coder admin
-
pushes the seeded templates:
Template What it provides ubuntu-vscodeBase Ubuntu + VS Code with curl,git,wget,btop,opencode,zellijubuntu-vscode-opencode-webOpenCode Web (browser-based IDE) ubuntu-vscode-openworkOpenWork (AI-assisted workspace) ubuntu-vscode-kdense-byokK-Dense BYOK (Bring Your Own Key for local model inference) ubuntu-vscode-hermesHermes (on-device AI assistant) -
creates a default workspace for the operator
That default template installs:
curlgitwgetbtopopencodezellij
The workspace home directory lives on a per-workspace Docker volume. The control plane state lives in shared-core Postgres.
The wizard supports two different ideas for how browser-facing Coder apps should be routed:
- The ideal Coder-native shape is
*.coder.<root-domain>. - The currently selected no-fee fallback is
*.<root-domain>limited by a strict app-host pattern, so only Coder app-style hostnames route into Coder.
Why the fallback exists:
- Cloudflare Universal SSL on a full zone covers the zone apex and first-level subdomains.
- A hostname like
foo.coder.example.comis a deeper subdomain and is not covered by Universal SSL. - Cloudflare's supported paid fix is Advanced Certificate Manager, which can issue edge certificates for
*.coder.<root-domain>.
Current decision:
- Keep the fallback
*.<root-domain>for live installs until a future architecture change is chosen. - Preserve a strict router pattern so service hosts like
dokploy.<root-domain>,nextcloud.<root-domain>, andopenclaw.<root-domain>are not hijacked by Coder.
Future architecture options:
- Keep the current fallback: lowest risk and already working. Coder app hosts look like
app--workspace--user.<root-domain>. - Use
*.coder.<root-domain>with Cloudflare Advanced Certificate Manager: closest to the Coder docs and cleanest hostname model, but requires ACM on the zone. - Keep
*.coder.<root-domain>but move Coder off Cloudflare Tunnel: terminate public TLS directly in Dokploy/Traefik using DNS-01 wildcard certificates. This avoids the ACM fee but changes the ingress architecture for Coder. - Convert selected Coder apps to path-based routing: works without wildcard subdomain TLS, but app compatibility is weaker than subdomain routing and usually requires template-specific base-path work.
Operational note:
- Hermes, OpenCode Web, and OpenWork are already path-based Coder apps in this repo.
- K-Dense BYOK is the current outlier that uses
subdomain = trueand benefits the most from proper wildcard app routing.
SeaweedFS provides the S3-compatible object-storage surface. The wizard wires:
- service + data volume
- generated access key + secret key in guided mode
- public
s3.<root-domain>hostname
%%{init: {
"theme": "base",
"themeVariables": {
"primaryColor": "#fff8ef",
"primaryTextColor": "#3b2b10",
"primaryBorderColor": "#e7bb74",
"lineColor": "#a77834",
"fontFamily": "Inter, ui-sans-serif, system-ui, sans-serif"
}
}}%%
flowchart TD
CFOTP[✉️ Cloudflare Access OTP] --> OpenClaw[openclaw.<root-domain>]
CFOTP --> Farm[farm.<root-domain>]
subgraph AppLogins[Own login surfaces]
Dokploy[Dokploy admin login]
Nextcloud[Nextcloud admin + users]
Coder[Coder admin login]
Seaweed[SeaweedFS access key / secret key]
end
subgraph InternalSecrets[Server-owned runtime secrets]
Nexa[Nexa Talk/WebDAV/OnlyOffice secrets]
DB[Database / Redis secret refs]
Model[OpenRouter / NVIDIA / local model config]
end
Current Cloudflare Access scope:
openclaw.<root-domain>farm.<root-domain>
Not behind Cloudflare Access in the current implementation:
dokploy.<root-domain>nextcloud.<root-domain>office.<root-domain>s3.<root-domain>coder.<root-domain>- Coder workspace app hosts, currently routed via a controlled
*.<root-domain>fallback matrix.<root-domain>headscale.<root-domain>
Why:
- Dokploy still needs a usable API/control plane path
- Nextcloud and OnlyOffice have client/protocol concerns
- SeaweedFS is an object-storage protocol surface
- Coder has its own application login
- Matrix and Headscale are protocol/control-plane surfaces
| Surface | Credential model | Source |
|---|---|---|
| Dokploy | admin email + password, then API key | operator-supplied + wizard-generated API key |
| OpenClaw | Cloudflare Access OTP + trusted-proxy browser auth, plus gateway password/token surfaces | generated gateway password, optional token |
| Nextcloud | admin user/password and internal service accounts | currently derived from Dokploy admin credentials, plus Nexa service account from env |
| OnlyOffice | JWT integration value shared with Nextcloud | currently wired by deployment bootstrap/runtime config |
| Coder | Coder admin login | currently derived from Dokploy admin credentials |
| SeaweedFS / S3 | access key + secret key | wizard-generated in guided mode or env-file provided |
| Nexa internals | Talk/WebDAV/OnlyOffice/API secrets | server-owned env |
The wizard currently uses three broad credential sources:
-
Operator-supplied values
- Cloudflare token/account/zone
- Dokploy admin login
- Tailscale auth key
- model/provider API keys
-
Wizard-generated values
- SeaweedFS access key + secret key in guided mode
- OpenClaw browser/control password in guided mode
- My Farm Advisor browser/control password in guided mode
- Dokploy API key after bootstrap
-
Server-owned runtime secrets
- Nextcloud and Nexa runtime integration values
- Nexa Talk signing/shared secrets
- Nexa WebDAV auth
- Nexa service-account credentials
- Mem0/Qdrant private runtime configuration
Nexa is intentionally treated as a server-owned runtime surface.
That means:
- the wizard keeps sensitive Nexa values in env/config surfaces owned by the deployment
- the Nextcloud-visible Nexa workspace is an operator/user surface, not the source of truth
- the runtime contract records presence and source, not raw secret values
The current repo uses .install.env at repo root as the working operator env file.
Important details:
- it contains sensitive credentials and should remain
0600 - the fresh-VPS harness copies it explicitly to the remote host
- Nexa functionality is enabled by the presence of
OPENCLAW_NEXA_*values - runtime-only values like internal sidecar URLs are synthesized later during deployment
The repo includes a real fresh-VPS proof flow with:
- first install success
- service verification after install
inspect-stateexecution as part of the proof loop- optional strict idempotency mode for explicit double-install checks
The local proof artifacts live under:
.sisyphus/evidence/fresh-vps-validation/fresh-reinstall-live-proof/
What that means in practice:
- the wizard can package the repo and install env
- copy both to a fresh host
- run the installer non-interactively
- verify that all enabled services are healthy and reachable
- inspect the resulting state as part of the same reproducibility loop
By default, proof installs once, runs service verification, and then captures inspect-state. It does not run a second install pass. This is the standard operator path for validating a fresh host.
./bin/dokploy-wizard-remote proof \
--host <host> \
--password <redacted> \
--env-file ./.install.envUse --strict-idempotency when you want an explicit double-install check. The second install pass should produce zero Dokploy update/deploy calls for unchanged healthy services because compose artifact hash tracking skips mutations when the rendered compose is unchanged and verification passes.
./bin/dokploy-wizard-remote proof \
--host <host> \
--password <redacted> \
--env-file ./.install.env \
--strict-idempotencyThe proof flow invokes the service verification runner after install. You can also run it independently:
python3 -m dokploy_wizard.service_verification_runner \
--env-file ./.install.env \
--state-dir .dokploy-wizard-stateThe checked-in proof artifact is useful as a concrete example run, but it should not be treated as the only source of truth for current drift status after later inspection fixes.
./bin/dokploy-wizard installUse this when you do not already have an env file. The wizard prompts for domains, Dokploy credentials, Cloudflare values, optional Tailscale settings, and pack selection, then writes a reusable env file and runs the same install flow as env-file mode.
./bin/dokploy-wizard install --env-file path/to/install.env --non-interactive./bin/dokploy-wizard inspect-state --env-file path/to/install.env --state-dir .dokploy-wizard-state./bin/dokploy-wizard modify --env-file path/to/install.env --non-interactive
./bin/dokploy-wizard uninstall --retain-data --non-interactive --confirm-file fixtures/retain.confirm
./bin/dokploy-wizard uninstall --destroy-data --non-interactive --confirm-file fixtures/destroy.confirmThe repo also contains a real fresh-host validation harness:
python -m src.dokploy_wizard.fresh_vps_validation_harness \
--install-env-file ./.install.env \
--target-host <host> \
--target-user root \
--target-password <password> \
--target-path /root/dokploy-proof \
--label proof-runWhat it does:
- packages the repo
- uploads repo +
.install.env - runs wizard install
- runs service verification
- runs
inspect-state - collects remote state and logs locally
The harness does not rerun install by default. Use --strict-idempotency with ./bin/dokploy-wizard-remote proof when you need an explicit unchanged-healthy idempotency check.
Quick checks:
pytest -q
ruff check .
mypy .Focused modules that matter most for the current stack:
pytest tests/unit/test_openclaw_pack.py -q
pytest tests/unit/test_nextcloud_pack.py -q
pytest tests/unit/test_nexa_runtime.py -q
pytest tests/integration/test_openclaw_pack.py -q
pytest tests/integration/test_nextcloud_pack.py -q
pytest tests/test_cli.py -q- This is still a fresh-host workflow, not a general migration framework.
- Docker can be bootstrap-remediated by the wizard on supported Ubuntu hosts.
- The chosen state directory stores wizard metadata and the generated env file, not the Docker volumes themselves.
- The ownership ledger is the uninstall authority.
- OpenClaw/Nexa/Telly behavior is now wizard-managed, not just manually drifted on one VPS.
- Reruns and modify operations skip Dokploy update/deploy for services whose rendered compose hash matches the stored hash and whose verification checks pass. Changed compose or unhealthy services still redeploy normally.
- Dokploy itself is not yet protected by Cloudflare Access because the wizard still needs a safe machine-auth/control path.
- Nexa features are env-gated, not universal defaults. For your deployment that is fine, because
.install.envalready carries the requiredOPENCLAW_NEXA_*values. - Some channel/runtime behavior still depends on the upstream OpenClaw image, so operational behavior can evolve as that image evolves.
- For the OpenClaw trusted-proxy control UI scope regression and the bootstrap fixes that keep fresh installs repeatable, see
docs/incidents/openclaw-trusted-proxy-scopes.md.
LiteLLM is always installed as core infrastructure. It is not a pack you opt into, and it runs as a shared-core service alongside Postgres and Redis. Every AI consumer in the stack, including My Farm Advisor, OpenClaw, and Coder templates, routes model calls through LiteLLM using a per-consumer virtual key.
The operator env file stays flat. .install.env contains only key=value pairs. The wizard generates the nested LiteLLM config.yaml internally during deployment. You do not edit raw LiteLLM proxy config by hand.
The generated LiteLLM config enforces a strict precedence:
local/unsloth-active— the local vLLM or Tailnet endpoint, whenLITELLM_LOCAL_BASE_URLis configured- OpenCode Go wildcard — a single
openai/*route that covers the OpenCode Go provider fleet - Explicit OpenRouter aliases — each alias is declared individually with
alias=target-modelpairs inLITELLM_OPENROUTER_MODELS
OpenRouter wildcard routes are not allowed. The config renderer rejects openrouter/* or broad * aliases.
The wizard auto-generates stable virtual keys for each consumer:
- My Farm Advisor
- OpenClaw
- Coder Hermes
- Coder K-Dense
These keys are generated once and reused across reruns and modify operations. They are stored in the wizard state directory, not written back into .install.env. If you need to rotate a key, that is a future operator action, not something that happens silently on reinstall.
LiteLLM management UI and API are reachable at litellm.<root-domain>. This hostname is protected by Cloudflare Access before any public DNS or tunnel routing is created. Internal consumers use the Docker network URL http://<stack-name>-shared-litellm:4000, not the public admin hostname.
The public LiteLLM admin URL is supposed to be protected, not publicly healthy. Anonymous checks should return a Cloudflare Access challenge or denial such as 302, 401, or 403. An unauthenticated 200 is a failure.
From repo root, agents can print or execute the post-deploy QA harness without completing a human OTP flow:
python -m src.dokploy_wizard.litellm.qa_harness --env-file ./.install.env --print-commands
python -m src.dokploy_wizard.litellm.qa_harness --env-file ./.install.envThe harness verifies three paths:
-
Public admin ingress stays Access-protected and never returns unauthenticated
200. -
Internal LiteLLM readiness stays reachable from the shared Docker network:
docker run --rm --network <stack-name>-shared curlimages/curl:8.7.1 -fsS \ http://<stack-name>-shared-litellm:4000/health/readiness
-
When Tailscale host access and Tailscale SSH are enabled, the same internal readiness probe can be executed over the Tailnet without OTP:
tailscale ssh <tailscale-hostname> \ docker run --rm --network <stack-name>-shared curlimages/curl:8.7.1 -fsS \ http://<stack-name>-shared-litellm:4000/health/readiness
This keeps admin verification aligned with the intended trust boundary: public admin ingress must challenge anonymous users, while container-to-container and Tailnet-admin paths stay testable by automation.
If you previously set direct provider keys like MY_FARM_ADVISOR_OPENROUTER_API_KEY or ANTHROPIC_API_KEY, those values are still accepted as upstream inputs for LiteLLM config generation. After cutover, consumers no longer receive those raw upstream keys. Instead, each consumer gets its own LiteLLM virtual key and the internal base URL. Upstream secrets terminate at the LiteLLM proxy.
Quick checks:
pytest -q
ruff check .
mypy .My Farm Advisor is enabled with ENABLE_MY_FARM_ADVISOR=true. When it is enabled, you must provide at least one model provider path.
| Key | Example | Notes |
|---|---|---|
ENABLE_MY_FARM_ADVISOR |
true |
Pack flag |
MY_FARM_ADVISOR_CHANNELS |
telegram |
Comma-separated; telegram and matrix are supported. Matrix requires the Matrix pack. |
MY_FARM_ADVISOR_SUBDOMAIN |
farm |
Defaults to farm |
MY_FARM_ADVISOR_GATEWAY_PASSWORD |
changeme |
Browser/control UI password. ADVISOR_GATEWAY_PASSWORD is a shared fallback for both advisors. |
| Provider (at least one) | ||
MY_FARM_ADVISOR_OPENROUTER_API_KEY |
<your-openrouter-key> |
Farm-only OpenRouter key |
MY_FARM_ADVISOR_NVIDIA_API_KEY |
<your-nvidia-key> |
Farm-only NVIDIA key |
ANTHROPIC_API_KEY |
<your-anthropic-key> |
Shared across packs |
AI_DEFAULT_API_KEY + AI_DEFAULT_BASE_URL |
sk-... + https://... |
Shared fallback pair; both must be present to count as a valid provider path |
| Key | Example | Notes |
|---|---|---|
MY_FARM_ADVISOR_REPLICAS |
1 |
Defaults to 1 |
MY_FARM_ADVISOR_PRIMARY_MODEL |
openrouter/openrouter/hunter-alpha |
|
MY_FARM_ADVISOR_FALLBACK_MODELS |
openrouter/openrouter/healer-alpha,openrouter/nvidia/... |
Comma-separated |
MY_FARM_ADVISOR_TELEGRAM_BOT_TOKEN |
... |
Main farm Telegram bot |
MY_FARM_ADVISOR_TELEGRAM_OWNER_USER_ID |
12345678 |
DM allowlist owner |
NVIDIA_BASE_URL |
https://integrate.api.nvidia.com/v1 |
|
TZ |
America/Chicago |
Container timezone |
These keys are accepted only when the my-farm-advisor pack is enabled, but they are not required.
Field Operations and Data Pipeline Telegram bots
| Key | Purpose |
|---|---|
TELEGRAM_FIELD_OPERATIONS_BOT_TOKEN |
Field ops bot |
TELEGRAM_FIELD_OPERATIONS_BOT_PAIRING_CODE |
Pairing code |
TELEGRAM_FIELD_OPERATIONS_ALLOWED_USERS |
Allowlist |
TELEGRAM_DATA_PIPELINE_BOT_TOKEN |
Data pipeline bot |
TELEGRAM_DATA_PIPELINE_BOT_PAIRING_CODE |
Pairing code |
TELEGRAM_DATA_PIPELINE_ALLOWED_USERS |
Allowlist |
TELEGRAM_DATA_PIPELINE_BOT_ALLOWED_USERS |
Secondary allowlist |
TELEGRAM_ALLOWED_USERS |
General allowlist |
OPENCLAW_TELEGRAM_GROUP_POLICY |
allowlist or open |
R2 / data pipeline persistence
R2 is only mounted when all of the following are present and WORKSPACE_DATA_R2_RCLONE_MOUNT=1:
| Key | Example |
|---|---|
R2_BUCKET_NAME |
my-farm-advisor |
R2_ENDPOINT |
https://your-account-id.r2.cloudflarestorage.com |
R2_ACCESS_KEY_ID |
... |
R2_SECRET_ACCESS_KEY |
... |
CF_ACCOUNT_ID |
... |
DATA_MODE |
volume |
WORKSPACE_DATA_R2_RCLONE_MOUNT |
0 or 1 |
WORKSPACE_DATA_R2_PREFIX |
workspace/data |
When R2 is not fully configured, the container explicitly sets OPENCLAW_SYNC_SKILLS_ON_START=0 so local skill sync does not run.
Skill and bootstrap control
| Key | Default | Purpose |
|---|---|---|
OPENCLAW_SYNC_SKILLS_ON_START |
0 when R2 is off |
Enable skill sync on start |
OPENCLAW_SYNC_SKILLS_OVERWRITE |
1 |
Overwrite existing skills |
OPENCLAW_FORCE_SKILL_SYNC |
0 |
Force a one-time sync |
OPENCLAW_BOOTSTRAP_REFRESH |
0 |
Re-seed config on next start |
OPENCLAW_MEMORY_SEARCH_ENABLED |
0 |
Enable memory search |
When Nextcloud is enabled alongside My Farm Advisor, the wizard creates two external storage mounts:
| Mount name | Purpose |
|---|---|
/Nexa Farm |
Field ops workspace (/data/workspace) |
/Nexa Farm Data Pipeline |
Data pipeline workspace (/data/workspace-data-pipeline) |
For reference, OpenClaw uses /Nexa Claw (new installs) or /OpenClaw (legacy).
My Farm Advisor and OpenClaw can be enabled in the same install. They use separate Dokploy compose apps, separate hostnames, and separate volumes. Shared provider keys like AI_DEFAULT_API_KEY and ANTHROPIC_API_KEY are reused by both advisors unless you override them with pack-specific keys.
If you have an existing My Farm Advisor deployment from the Coolify era, the key names have changed. The wizard now uses prefixed keys so farm settings do not collide with OpenClaw.
| Old Coolify key | New wizard key |
|---|---|
OPENROUTER_API_KEY |
MY_FARM_ADVISOR_OPENROUTER_API_KEY (or shared AI_DEFAULT_API_KEY) |
NVIDIA_API_KEY |
MY_FARM_ADVISOR_NVIDIA_API_KEY |
PRIMARY_MODEL |
MY_FARM_ADVISOR_PRIMARY_MODEL |
FALLBACK_MODELS |
MY_FARM_ADVISOR_FALLBACK_MODELS |
TELEGRAM_BOT_TOKEN |
MY_FARM_ADVISOR_TELEGRAM_BOT_TOKEN |
TELEGRAM_ACCOUNT_ID |
Not mapped; use MY_FARM_ADVISOR_TELEGRAM_OWNER_USER_ID instead |
Keys that kept the same name:
ANTHROPIC_API_KEYNVIDIA_BASE_URLTELEGRAM_FIELD_OPERATIONS_BOT_TOKENTELEGRAM_FIELD_OPERATIONS_BOT_PAIRING_CODETELEGRAM_FIELD_OPERATIONS_ALLOWED_USERSTELEGRAM_DATA_PIPELINE_BOT_TOKENTELEGRAM_DATA_PIPELINE_BOT_PAIRING_CODETELEGRAM_DATA_PIPELINE_ALLOWED_USERSTELEGRAM_DATA_PIPELINE_BOT_ALLOWED_USERSTELEGRAM_ALLOWED_USERSOPENCLAW_TELEGRAM_GROUP_POLICYR2_BUCKET_NAMER2_ENDPOINTR2_ACCESS_KEY_IDR2_SECRET_ACCESS_KEYCF_ACCOUNT_IDDATA_MODEWORKSPACE_DATA_R2_RCLONE_MOUNTWORKSPACE_DATA_R2_PREFIXOPENCLAW_SYNC_SKILLS_ON_STARTOPENCLAW_SYNC_SKILLS_OVERWRITEOPENCLAW_FORCE_SKILL_SYNCOPENCLAW_BOOTSTRAP_REFRESHOPENCLAW_MEMORY_SEARCH_ENABLEDTZ
- No more
OPENCLAW_GATEWAY_TOKENfor farm. The wizard manages gateway tokens and passwords throughADVISOR_GATEWAY_PASSWORDorMY_FARM_ADVISOR_GATEWAY_PASSWORD. - No
CLOUDFLARE_TUNNEL_TOKENin env. The wizard wires ingress through its own Cloudflare Tunnel phase. - No
OPENCLAW_PUBLIC_HOSTNAMEin env. The hostname is derived fromMY_FARM_ADVISOR_SUBDOMAINandROOT_DOMAIN. - Provider keys are prefixed. Unprefixed
OPENROUTER_API_KEYandNVIDIA_API_KEYare no longer read for farm; use theMY_FARM_ADVISOR_*versions or the sharedAI_DEFAULT_*pair. - R2 is opt-in and gated. Partial R2 config is ignored; all five credential fields plus
WORKSPACE_DATA_R2_RCLONE_MOUNT=1must be present for the mount to activate.
src/dokploy_wizard/cli.py— lifecycle entrypoint and backend constructionsrc/dokploy_wizard/networking/— Cloudflare tunnel/DNS/Access planningsrc/dokploy_wizard/tailscale/— host-level Tailscale phasesrc/dokploy_wizard/dokploy/— Dokploy-backed deployment backendssrc/dokploy_wizard/packs/— pack models and reconcilerstemplates/— deployment templates, including Coder template assetstests/— unit, integration, and lifecycle coverage
Dokploy Wizard now installs a real, stateful self-hosted stack, not just a set of placeholders. It bootstraps Dokploy, wires ingress and auth, deploys application packs, embeds OpenClaw-facing agents like Nexa and Telly, and supports fresh-host reruns with state-aware lifecycle behavior.
The current repo is built around a real fresh-VPS proof workflow and is intended to be the baseline for repeatable full rebuilds.