diff --git a/docs/docs/self-host/agents/02-daytona.mdx b/docs/docs/self-host/agents/02-daytona.mdx index eaf42338c0..706e091abf 100644 --- a/docs/docs/self-host/agents/02-daytona.mdx +++ b/docs/docs/self-host/agents/02-daytona.mdx @@ -117,17 +117,39 @@ resolve: a Compose service name such as `http://seaweedfs:8333` (the default for store), `localhost`, or a private IP. If it already points at a public S3 endpoint, as on Railway and on Kubernetes with public ingress, skip this step. -Two ways to fix it: +There are three ways to fix it. Most self-hosted deployments use the first. -**Point the store at a public endpoint.** Use an external S3-compatible bucket, or expose the -bundled store on a public hostname, and set the store endpoint to that URL: +**Expose the bundled store through traefik.** The `gh` Compose stacks can publish the bundled +store on its own subdomain. This is off by default. Pick a hostname such as `store.example.com` +and add a DNS record that points it at the same server as your main domain. Then set these +variables in your env file (`.env.oss.gh`, or `.env.oss.gh.ssl` on the `--ssl` stack): ```bash -AGENTA_STORE_ENDPOINT_URL=https:// +AGENTA_STORE_TRAEFIK_ENABLE=true +AGENTA_STORE_DOMAIN=store.example.com +AGENTA_STORE_ENDPOINT_URL=https://store.example.com ``` -**Or tunnel the bundled store.** The dev Compose stack ships an ngrok service that publishes the -bundled store on a public URL, which the runner discovers automatically. Create an +Recreate the stack. On the `--ssl` stack, traefik requests a Let's Encrypt certificate for the +new hostname from the same resolver it uses for your main domain. On the plain `gh` stack, traefik +serves the store on port 80 and your own proxy terminates TLS. The router matches on the hostname +and never rewrites the path, which the S3 request signature requires, so do not place the store +behind a path prefix. + +To verify, run an agent on Daytona (step 5) and write a file. The runner logs +`remote mounted ... (verified alive)` for the session instead of a `mount degraded` line, and the +file is still there on the next turn. + +**Point the store at an external S3 endpoint.** Use an external S3-compatible bucket (AWS S3, +Cloudflare R2, MinIO) that is already reachable from the internet, and set the store endpoint to +its URL: + +```bash +AGENTA_STORE_ENDPOINT_URL=https:// +``` + +**Tunnel the bundled store (dev only).** The dev Compose stack ships an ngrok service that +publishes the bundled store on a public URL, which the runner discovers automatically. Create an [ngrok authtoken](https://dashboard.ngrok.com/get-started/your-authtoken), put it in your env file, and start the stack with the `with-tunnel` profile: diff --git a/hosting/docker-compose/ee/docker-compose.gh.yml b/hosting/docker-compose/ee/docker-compose.gh.yml index 6aca96639b..0877f2a80f 100644 --- a/hosting/docker-compose/ee/docker-compose.gh.yml +++ b/hosting/docker-compose/ee/docker-compose.gh.yml @@ -458,8 +458,17 @@ services: ports: - "127.0.0.1:${AGENTA_STORE_PORT:-8333}:8333" # === LABELS =============================================== # + # Off by default. Daytona cloud sandboxes reach the store over the internet, so set + # AGENTA_STORE_TRAEFIK_ENABLE=true and AGENTA_STORE_DOMAIN= to publish the + # S3 endpoint on its own subdomain, terminate TLS at your own proxy, then point + # AGENTA_STORE_ENDPOINT_URL at https://. The router is Host-only (no path + # rewrite), which SeaweedFS S3 SigV4 requires. labels: - - "traefik.enable=false" + - "traefik.enable=${AGENTA_STORE_TRAEFIK_ENABLE:-false}" + - "traefik.http.routers.store.rule=Host(`${AGENTA_STORE_DOMAIN:-store.localhost}`)" + - "traefik.http.routers.store.entrypoints=web" + - "traefik.http.routers.store.service=store" + - "traefik.http.services.store.loadbalancer.server.port=8333" # === LIFECYCLE ============================================ # restart: always healthcheck: diff --git a/hosting/docker-compose/ee/env.ee.gh.example b/hosting/docker-compose/ee/env.ee.gh.example index 3da3dbf54c..a8de6f8618 100644 --- a/hosting/docker-compose/ee/env.ee.gh.example +++ b/hosting/docker-compose/ee/env.ee.gh.example @@ -376,5 +376,14 @@ AGENTA_STORE_SIGNING_KEY=replace-me # api replica works with this unset. If you scale the api past one replica, set the SAME PEM on # every replica or STS token minting fails intermittently (SeaweedFS caches one JWKS). # AGENTA_STORE_JWT_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----" +# +# Publish the bundled store on the internet (Daytona sandboxes only). Daytona runs each agent in a +# cloud sandbox that reaches the store from outside the deployment, so the internal `seaweedfs:8333` +# endpoint is unreachable and agent file writes are silently dropped. Set both vars below to expose +# the store on its own subdomain through traefik, add a DNS record for that host, then set +# AGENTA_STORE_ENDPOINT_URL=https://store.example.com. Leave this off for local sandboxes. +# See https://docs.agenta.ai/self-host/agent-execution/daytona +# AGENTA_STORE_TRAEFIK_ENABLE=true +# AGENTA_STORE_DOMAIN=store.example.com # AGENTA_WORKER_STREAMS / AGENTA_WORKER_QUEUES: worker topology selectors — # set inline per-service in compose, not here; see docs/designs/workers-sprawl/specs.md diff --git a/hosting/docker-compose/oss/docker-compose.gh.ssl.yml b/hosting/docker-compose/oss/docker-compose.gh.ssl.yml index 07ced46957..a44f83cbdf 100644 --- a/hosting/docker-compose/oss/docker-compose.gh.ssl.yml +++ b/hosting/docker-compose/oss/docker-compose.gh.ssl.yml @@ -468,8 +468,19 @@ services: ports: - "127.0.0.1:${AGENTA_STORE_PORT:-8333}:8333" # === LABELS =============================================== # + # Off by default. Daytona cloud sandboxes reach the store over the internet, so set + # AGENTA_STORE_TRAEFIK_ENABLE=true and AGENTA_STORE_DOMAIN= to publish the + # S3 endpoint on its own subdomain with a Let's Encrypt cert, then point + # AGENTA_STORE_ENDPOINT_URL at https://. The router is Host-only (no path + # rewrite), which SeaweedFS S3 SigV4 requires. labels: - - "traefik.enable=false" + - "traefik.enable=${AGENTA_STORE_TRAEFIK_ENABLE:-false}" + - "traefik.http.routers.store.rule=Host(`${AGENTA_STORE_DOMAIN:-store.localhost}`)" + - "traefik.http.routers.store.entrypoints=web,web-secure" + - "traefik.http.routers.store.service=store" + - "traefik.http.routers.store.tls=true" + - "traefik.http.routers.store.tls.certresolver=myResolver" + - "traefik.http.services.store.loadbalancer.server.port=8333" # === LIFECYCLE ============================================ # restart: always healthcheck: diff --git a/hosting/docker-compose/oss/docker-compose.gh.yml b/hosting/docker-compose/oss/docker-compose.gh.yml index 8fa8e7af2c..c08d24d555 100644 --- a/hosting/docker-compose/oss/docker-compose.gh.yml +++ b/hosting/docker-compose/oss/docker-compose.gh.yml @@ -475,8 +475,17 @@ services: ports: - "127.0.0.1:${AGENTA_STORE_PORT:-8333}:8333" # === LABELS =============================================== # + # Off by default. Daytona cloud sandboxes reach the store over the internet, so set + # AGENTA_STORE_TRAEFIK_ENABLE=true and AGENTA_STORE_DOMAIN= to publish the + # S3 endpoint on its own subdomain, terminate TLS at your own proxy, then point + # AGENTA_STORE_ENDPOINT_URL at https://. The router is Host-only (no path + # rewrite), which SeaweedFS S3 SigV4 requires. labels: - - "traefik.enable=false" + - "traefik.enable=${AGENTA_STORE_TRAEFIK_ENABLE:-false}" + - "traefik.http.routers.store.rule=Host(`${AGENTA_STORE_DOMAIN:-store.localhost}`)" + - "traefik.http.routers.store.entrypoints=web" + - "traefik.http.routers.store.service=store" + - "traefik.http.services.store.loadbalancer.server.port=8333" # === LIFECYCLE ============================================ # restart: always healthcheck: diff --git a/hosting/docker-compose/oss/env.oss.gh.example b/hosting/docker-compose/oss/env.oss.gh.example index bd06f014c5..7cf53d9c10 100644 --- a/hosting/docker-compose/oss/env.oss.gh.example +++ b/hosting/docker-compose/oss/env.oss.gh.example @@ -376,5 +376,14 @@ AGENTA_STORE_SIGNING_KEY=replace-me # api replica works with this unset. If you scale the api past one replica, set the SAME PEM on # every replica or STS token minting fails intermittently (SeaweedFS caches one JWKS). # AGENTA_STORE_JWT_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----" +# +# Publish the bundled store on the internet (Daytona sandboxes only). Daytona runs each agent in a +# cloud sandbox that reaches the store from outside the deployment, so the internal `seaweedfs:8333` +# endpoint is unreachable and agent file writes are silently dropped. Set both vars below to expose +# the store on its own subdomain through traefik, add a DNS record for that host, then set +# AGENTA_STORE_ENDPOINT_URL=https://store.example.com. Leave this off for local sandboxes. +# See https://docs.agenta.ai/self-host/agent-execution/daytona +# AGENTA_STORE_TRAEFIK_ENABLE=true +# AGENTA_STORE_DOMAIN=store.example.com # AGENTA_WORKER_STREAMS / AGENTA_WORKER_QUEUES: worker topology selectors — # set inline per-service in compose, not here; see docs/designs/workers-sprawl/specs.md