fix(deploy): reuse shared server n8n
This commit is contained in:
+17
-14
@@ -1,8 +1,9 @@
|
||||
# Unraid deployment
|
||||
|
||||
MobilityOps is deployed from a committed source archive; the server does not need Gitea
|
||||
credentials. The portable `compose.yaml` is combined with `compose.unraid.yaml` so that
|
||||
only the web application is reachable from the LAN.
|
||||
credentials. The portable `compose.yaml` is combined with `compose.unraid.yaml`; of the
|
||||
MobilityOps-owned services, only the web application is reachable from the LAN. The host's
|
||||
existing shared n8n remains available on its established port 5678.
|
||||
|
||||
## Server layout
|
||||
|
||||
@@ -10,7 +11,7 @@ only the web application is reachable from the LAN.
|
||||
- Compose project: `mobilityops`
|
||||
- Web: `http://192.168.10.150:1236` (`1236` on the host to `80` in `web`)
|
||||
- API and PostgreSQL: Compose network only
|
||||
- n8n editor: server loopback `127.0.0.1:15678` only; use an SSH tunnel for setup
|
||||
- Shared n8n: `http://192.168.10.150:5678` (outside the MobilityOps Compose project)
|
||||
|
||||
## Deploy
|
||||
|
||||
@@ -21,25 +22,26 @@ available. Keep `MCP_HUB_REGISTRATION_ENABLED=false` until the central Hub is re
|
||||
|
||||
```bash
|
||||
cd /mnt/user/appdata/mobilityops
|
||||
./deploy/unraid/configure-env.sh http://192.168.10.150:1236
|
||||
docker compose -p mobilityops -f compose.yaml -f compose.unraid.yaml up --build -d
|
||||
./deploy/unraid/configure-env.sh \
|
||||
http://192.168.10.150:1236 \
|
||||
http://192.168.10.150:5678/webhook/mobilityops-return
|
||||
docker compose -p mobilityops -f compose.yaml -f compose.unraid.yaml up --build -d db api web
|
||||
docker compose -p mobilityops -f compose.yaml -f compose.unraid.yaml exec api \
|
||||
python -m app.cli seed --reset
|
||||
```
|
||||
|
||||
Migrations run automatically in the API entrypoint. Complete the one-time n8n owner
|
||||
setup without exposing its editor to the LAN, then import and publish the workflow:
|
||||
Migrations run automatically in the API entrypoint. Import and publish the MobilityOps
|
||||
workflow into the existing n8n container:
|
||||
|
||||
```bash
|
||||
./deploy/unraid/setup-n8n.sh http://127.0.0.1:15678
|
||||
docker compose -p mobilityops -f compose.yaml -f compose.unraid.yaml exec n8n \
|
||||
n8n import:workflow --input=//imports/mobilityops-return-processing.json
|
||||
docker compose -p mobilityops -f compose.yaml -f compose.unraid.yaml exec n8n \
|
||||
n8n publish:workflow --id=mobilityops-return-processing
|
||||
docker compose -p mobilityops -f compose.yaml -f compose.unraid.yaml restart n8n
|
||||
./deploy/unraid/setup-existing-n8n.sh \
|
||||
n8n \
|
||||
http://192.168.10.150:1236/api/v1/integrations/n8n/return-callback
|
||||
```
|
||||
|
||||
The generated n8n owner credentials remain only in the mode-`0600` server `.env`.
|
||||
The callback token remains server-side and is never written to the repository. The
|
||||
bundled n8n service is retained only as a standalone fallback behind the explicit
|
||||
`bundled-n8n` Compose profile; it is not started in this deployment.
|
||||
|
||||
## Operate
|
||||
|
||||
@@ -48,4 +50,5 @@ cd /mnt/user/appdata/mobilityops
|
||||
docker compose -p mobilityops -f compose.yaml -f compose.unraid.yaml ps
|
||||
docker compose -p mobilityops -f compose.yaml -f compose.unraid.yaml logs --tail=200
|
||||
docker compose -p mobilityops -f compose.yaml -f compose.unraid.yaml exec api alembic current
|
||||
docker logs --tail=200 n8n
|
||||
```
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
set -eu
|
||||
|
||||
public_url="${1:-http://192.168.10.150:1236}"
|
||||
n8n_webhook_url="${2:-http://192.168.10.150:5678/webhook/mobilityops-return}"
|
||||
|
||||
if [ -e .env ]; then
|
||||
echo "Refusing to overwrite existing .env" >&2
|
||||
@@ -25,6 +26,7 @@ sed -i \
|
||||
-e "s|^DATABASE_URL=.*|DATABASE_URL=postgresql+psycopg://mobilityops:${db_password}@db:5432/mobilityops|" \
|
||||
-e "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=${db_password}|" \
|
||||
-e "s|^APP_SECRET=.*|APP_SECRET=${app_secret}|" \
|
||||
-e "s|^N8N_WEBHOOK_URL=.*|N8N_WEBHOOK_URL=${n8n_webhook_url}|" \
|
||||
-e "s|^N8N_ENCRYPTION_KEY=.*|N8N_ENCRYPTION_KEY=${n8n_key}|" \
|
||||
-e "s|^N8N_BASIC_AUTH_PASSWORD=.*|N8N_BASIC_AUTH_PASSWORD=${n8n_password}|" \
|
||||
-e "s|^MOBILITYOPS_CALLBACK_TOKEN=.*|MOBILITYOPS_CALLBACK_TOKEN=${callback_token}|" \
|
||||
@@ -35,4 +37,4 @@ sed -i \
|
||||
|
||||
unset db_password app_secret n8n_key n8n_password callback_token mcp_token
|
||||
|
||||
echo "Created server .env with generated secrets for ${public_url}"
|
||||
echo "Created server .env for ${public_url} using n8n webhook ${n8n_webhook_url}"
|
||||
|
||||
Executable
+46
@@ -0,0 +1,46 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
container_name="${1:-n8n}"
|
||||
callback_url="${2:-http://192.168.10.150:1236/api/v1/integrations/n8n/return-callback}"
|
||||
source_workflow="${3:-n8n/mobilityops-return-processing.json}"
|
||||
|
||||
if [ ! -f .env ]; then
|
||||
echo "Missing deployment .env" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "$source_workflow" ]; then
|
||||
echo "Missing workflow export: $source_workflow" >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! docker inspect "$container_name" >/dev/null 2>&1; then
|
||||
echo "Existing n8n container not found: $container_name" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
callback_token="$(sed -n 's/^MOBILITYOPS_CALLBACK_TOKEN=//p' .env | tail -n 1)"
|
||||
if [ -z "$callback_token" ]; then
|
||||
echo "MOBILITYOPS_CALLBACK_TOKEN is empty" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
temporary_workflow="$(mktemp /tmp/mobilityops-n8n-workflow.XXXXXX.json)"
|
||||
container_workflow="/tmp/mobilityops-return-processing.json"
|
||||
cleanup() {
|
||||
rm -f "$temporary_workflow"
|
||||
docker exec "$container_name" rm -f "$container_workflow" >/dev/null 2>&1 || true
|
||||
}
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
jq --arg callback_url "$callback_url" --arg callback_token "$callback_token" '
|
||||
(.nodes[] | select(.id == "callback-node") | .parameters.url) = $callback_url |
|
||||
(.nodes[] | select(.id == "callback-node") | .parameters.headerParameters.parameters[] |
|
||||
select(.name == "X-Service-Token") | .value) = $callback_token
|
||||
' "$source_workflow" > "$temporary_workflow"
|
||||
|
||||
docker cp "$temporary_workflow" "$container_name:$container_workflow" >/dev/null
|
||||
docker exec "$container_name" n8n import:workflow --input="$container_workflow"
|
||||
docker exec "$container_name" n8n publish:workflow --id=mobilityops-return-processing
|
||||
docker restart "$container_name" >/dev/null
|
||||
|
||||
echo "Published MobilityOps return workflow to existing container ${container_name}"
|
||||
Reference in New Issue
Block a user