Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 0 additions & 11 deletions .github/dependabot.yml

This file was deleted.

4 changes: 3 additions & 1 deletion .github/workflows/gateway-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: "Build & Publish Gateway Image"

on:
push:
branches: [main]
branches: [main, develop]
tags: ["v*.*.*"]
paths:
- "nginx/**"
Expand Down Expand Up @@ -95,6 +95,8 @@ jobs:
TAGS="${IMAGE}:${VERSION},${IMAGE}:latest"
elif [[ "${GH_REF}" == refs/heads/main ]]; then
TAGS="${IMAGE}:latest,${IMAGE}:main-${SHA_SHORT}"
elif [[ "${GH_REF}" == refs/heads/develop ]]; then
TAGS="${IMAGE}:develop,${IMAGE}:develop-${SHA_SHORT}"
fi

echo "tags=${TAGS}" >> "$GITHUB_OUTPUT"
Expand Down
12 changes: 12 additions & 0 deletions docker-compose.swarm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,18 @@ services:
# ---------------------------------------------------------------------------
evo_gateway:
image: evoapicloud/evo-crm-gateway:latest
# The gateway routes to the 5 backend services by their docker service
# names. Defaults match the names used in this stack (evo_auth, evo_crm,
# evo_core, evo_processor, evo_bot_runtime). If you rename the services
# in your own stack (e.g. using a different prefix), uncomment and set
# the matching *_UPSTREAM env var — otherwise the gateway cannot resolve
# them and every request returns 502. See nginx/README.md for details.
# environment:
# AUTH_UPSTREAM: my_auth:3001
# CRM_UPSTREAM: my_crm:3000
# CORE_UPSTREAM: my_core:5555
# PROCESSOR_UPSTREAM: my_processor:8000
# BOT_RUNTIME_UPSTREAM: my_bot_runtime:8080
networks:
- network_public
deploy:
Expand Down
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ services:
LISTEN_ADDR: 0.0.0.0:8080
REDIS_URL: redis://:${REDIS_PASSWORD:-evoai_redis_pass}@redis:6379
AI_PROCESSOR_URL: http://evo-processor:8000
BOT_RUNTIME_SECRET: ${BOT_RUNTIME_SECRET:-evo-bot-runtime-dev-secret}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 issue (security): The default BOT_RUNTIME_SECRET value is predictable and might be unsafe if reused beyond local dev.

A hard-coded default secret is fine for local dev, but if this compose file is ever used in shared or production-like environments the value becomes trivial to guess. Consider requiring it to be explicitly set (${BOT_RUNTIME_SECRET:?must_be_set}) or clearly marking this default as local-only and unsafe to use elsewhere.

depends_on:
redis:
condition: service_healthy
Expand Down
16 changes: 15 additions & 1 deletion nginx/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
FROM nginx:alpine
COPY nginx.conf /etc/nginx/conf.d/default.conf

# Default upstream targets. Override any of these at deploy time when the
# backend service names in your stack differ from the defaults below.
ENV AUTH_UPSTREAM=evo_auth:3001 \
CRM_UPSTREAM=evo_crm:3000 \
CORE_UPSTREAM=evo_core:5555 \
PROCESSOR_UPSTREAM=evo_processor:8000 \
BOT_RUNTIME_UPSTREAM=evo_bot_runtime:8080

# Limit envsubst to the upstream vars so nginx's own $variables (e.g. $host,
# $request_uri) are not touched at render time.
ENV NGINX_ENVSUBST_FILTER="^(AUTH|CRM|CORE|PROCESSOR|BOT_RUNTIME)_UPSTREAM$"

COPY default.conf.template /etc/nginx/templates/default.conf.template

EXPOSE 3030
97 changes: 97 additions & 0 deletions nginx/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# Evo CRM — API Gateway

Single-entrypoint nginx that dispatches incoming requests to the five
backend services by URL path. Packaged as
`evoapicloud/evo-crm-gateway` and meant to sit behind a TLS-terminating
reverse proxy (Traefik, Caddy, an ALB, etc.).

## Routing

Targets are declared as nginx variables at the top of the rendered config:

| Variable | Receives requests for |
|---------------------------|------------------------------------------------------|
| `$auth_service` | `/oauth`, `/.well-known`, `/setup/*`, `/api/v1/auth`, `/api/v1/users`, `/api/v1/accounts`, `/platform/*`, `/api/v1/super_admin` (most) |
| `$crm_service` | `/cable`, `/webhooks/*`, `/rails/active_storage`, `/api/v1/accounts/:id/webhooks`, `/api/v1/super_admin/{whitelabel,app_configs,upload,agent_bots,installation_configs,account_users}`, catch-all for unmatched `/api/v1/*` and `/` |
| `$evoai_service` | `/api/v1/{agents,folders,mcp-servers,custom-mcp-servers,custom-tools}` |
| `$processor_service` | `/api/v1/{chat,a2a,sessions,tools,clients}`, `/api/v1/agents/:id/integrations`, `/api/v1/integrations/:provider/callback`, `/api/v1/custom-mcp-servers/discover-tools`, `/health`, `/ready` |
| `$bot_runtime_service` | `/api/v1/bot-runtime` |

Full path matrix is in [`default.conf.template`](./default.conf.template).

## Configurable upstreams

Each of the five variables above is rendered at container start from an
environment variable. Defaults match the service names used by the
reference `docker-compose.yaml` and `docker-compose.swarm.yaml`.

| Env var | Default | Points to |
|-------------------------|-------------------------|-----------|
| `AUTH_UPSTREAM` | `evo_auth:3001` | `evo-auth-service-community` |
| `CRM_UPSTREAM` | `evo_crm:3000` | `evo-ai-crm-community` |
| `CORE_UPSTREAM` | `evo_core:5555` | `evo-ai-core-service-community` |
| `PROCESSOR_UPSTREAM` | `evo_processor:8000` | `evo-ai-processor-community` |
| `BOT_RUNTIME_UPSTREAM` | `evo_bot_runtime:8080` | `evo-bot-runtime` |

Format is always `host:port`, no scheme. The gateway concatenates `http://`
at the front when rendering.

### When you need to override

If your deployment renames any of the backend services (e.g. applying a
`evocrm_` prefix, or shortening to `auth`/`crm`/…) the gateway cannot
Comment on lines +41 to +42
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (typo): Use "an" instead of "a" before evocrm_ for correct article usage.

Because evocrm_ begins with a vowel sound, this should be "applying an evocrm_ prefix" for correct grammar.

Suggested change
If your deployment renames any of the backend services (e.g. applying a
`evocrm_` prefix, or shortening to `auth`/`crm`/…) the gateway cannot
If your deployment renames any of the backend services (e.g. applying an
`evocrm_` prefix, or shortening to `auth`/`crm`/…) the gateway cannot

resolve the default hostnames and every proxied request returns **502 Bad
Gateway**. Set the matching `*_UPSTREAM` env vars on the gateway service
to the service names you actually used.

### Example — prefixed service names

Stack uses `evocrm_auth`, `evocrm_crm`, `evocrm_core`, `evocrm_processor`,
`evocrm_bot_runtime`:

```yaml
services:
evocrm_gateway:
image: evoapicloud/evo-crm-gateway:latest
environment:
AUTH_UPSTREAM: evocrm_auth:3001
CRM_UPSTREAM: evocrm_crm:3000
CORE_UPSTREAM: evocrm_core:5555
PROCESSOR_UPSTREAM: evocrm_processor:8000
BOT_RUNTIME_UPSTREAM: evocrm_bot_runtime:8080
```

### Example — non-standard ports

If you expose the auth service on `4001` instead of `3001`:

```yaml
environment:
AUTH_UPSTREAM: evo_auth:4001
```

## Verifying the rendered config

To confirm the variables were substituted correctly, inspect the rendered
file inside a running container:

```bash
docker exec <gateway-container> \
grep -E "set \$(auth|crm|evoai|processor|bot_runtime)_service" \
/etc/nginx/conf.d/default.conf
```

You should see the expected hostnames. If any line still contains
`${VARNAME}` literally, the env var was not set and envsubst skipped it.

## Build

```bash
docker build -t evo-crm-gateway:local nginx/
```

The image uses the stock `nginx:alpine` base and the image's built-in
template rendering — templates in `/etc/nginx/templates/*.template` are
processed by envsubst at container start. `NGINX_ENVSUBST_FILTER` is
restricted to the five `*_UPSTREAM` vars so the substitution pass does
not touch nginx's own runtime variables (`$host`, `$request_uri`, etc.).
14 changes: 9 additions & 5 deletions nginx/nginx.conf → nginx/default.conf.template
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,16 @@ server {

# =============================================================================
# Upstream targets as variables
#
# Hosts/ports are rendered at container start by envsubst from the
# *_UPSTREAM env vars (see Dockerfile for defaults). Override them
# when the backend service names in your stack differ from the defaults.
# =============================================================================
set $auth_service http://evo_auth:3001;
set $evoai_service http://evo_core:5555;
set $crm_service http://evo_crm:3000;
set $processor_service http://evo_processor:8000;
set $bot_runtime_service http://evo_bot_runtime:8080;
set $auth_service http://${AUTH_UPSTREAM};
set $evoai_service http://${CORE_UPSTREAM};
set $crm_service http://${CRM_UPSTREAM};
set $processor_service http://${PROCESSOR_UPSTREAM};
set $bot_runtime_service http://${BOT_RUNTIME_UPSTREAM};

underscores_in_headers on;

Expand Down
Loading