From d155f2f1f6fc4a08413daf731602c26fa5adb575 Mon Sep 17 00:00:00 2001 From: Vincent Vu <172068404+rubixvi@users.noreply.github.com> Date: Sun, 26 Oct 2025 11:32:26 +1100 Subject: [PATCH] feat(blueprints): n8n + worker/runner + redis/postgres + ollama & fix(blueprints): twentycrm (#364) * feat(n8n): add n8n runner with Postgres and Ollama configuration * feat(meta): update n8n runner version to nightly and enhance description * feat(docker): update PostgreSQL image to 17-alpine and enhance healthcheck command * feat(n8n): update environment variables and enhance configuration for Redis and Ollama integration * feat(n8n): replace hardcoded N8N_PROXY_HOPS with environment variable and fix encryption key variable name * feat(n8n): comment out SMTP environment variables in docker-compose.yml * feat(n8n): set default value for N8N_PROXY_HOPS environment variable * Update blueprints/n8n-runner-postgres-ollama/docker-compose.yml * Update blueprints/n8n-runner-postgres-ollama/docker-compose.yml * Update blueprints/n8n-runner-postgres-ollama/docker-compose.yml * Update blueprints/n8n-runner-postgres-ollama/docker-compose.yml * Update blueprints/n8n-runner-postgres-ollama/docker-compose.yml * feat(twenty): update HTTP protocol handling in environment variables and enhance healthcheck configuration * refactor(docker-compose): remove container names for n8n services --------- Co-authored-by: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> --- .../docker-compose.yml | 146 ++++++++++++++++++ blueprints/n8n-runner-postgres-ollama/n8n.png | Bin 0 -> 6592 bytes .../n8n-runner-postgres-ollama/template.toml | 35 +++++ blueprints/twenty/docker-compose.yml | 31 ++-- blueprints/twenty/template.toml | 2 + meta.json | 20 +++ 6 files changed, 219 insertions(+), 15 deletions(-) create mode 100644 blueprints/n8n-runner-postgres-ollama/docker-compose.yml create mode 100644 blueprints/n8n-runner-postgres-ollama/n8n.png create mode 100644 blueprints/n8n-runner-postgres-ollama/template.toml diff --git a/blueprints/n8n-runner-postgres-ollama/docker-compose.yml b/blueprints/n8n-runner-postgres-ollama/docker-compose.yml new file mode 100644 index 00000000..5fde3224 --- /dev/null +++ b/blueprints/n8n-runner-postgres-ollama/docker-compose.yml @@ -0,0 +1,146 @@ +services: + n8n: + image: n8nio/n8n:latest + restart: unless-stopped + environment: + - NODE_ENV=production + - N8N_HOST=${N8N_HOST} + - N8N_PORT=${N8N_PORT} + - N8N_PROTOCOL=https + # Database + - DB_TYPE=postgresdb + - DB_POSTGRESDB_HOST=postgres + - DB_POSTGRESDB_USER=${POSTGRES_USER} + - DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD} + # Configuration + - N8N_DIAGNOSTICS_ENABLED=false + - N8N_PERSONALIZATION_ENABLED=true + - N8N_ENCRYPTION_KEY=${ENCRYPTION_KEY} + - N8N_USER_MANAGEMENT_JWT_SECRET + - N8N_SECURE_COOKIE=true + - N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true + - N8N_BLOCK_ENV_ACCESS_IN_NODE=true + - N8N_PROXY_HOPS=${PROXY_HOPS:-1} + - WEBHOOK_URL=https://${N8N_HOST}/ + - GENERIC_TIMEZONE=${GENERIC_TIMEZONE} + - N8N_TEMPLATES_ENABLED=true + - N8N_HIRING_BANNER_ENABLED=false + - OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS=true + # Ollama + - OLLAMA_HOST=${OLLAMA_HOST:-ollama:11434} + # Runners + - N8N_RUNNERS_ENABLED=true + - N8N_RUNNERS_MODE=external + - N8N_RUNNERS_BROKER_LISTEN_ADDRESS=0.0.0.0 + - N8N_RUNNERS_AUTH_TOKEN=${N8N_RUNNERS_SECRET} + - N8N_NATIVE_PYTHON_RUNNER=true + - N8N_RUNNERS_MAX_CONCURRENCY=50 + # Logging + - EXECUTIONS_DATA_PRUNE=true + - EXECUTIONS_DATA_MAX_AGE=7 + # Redis + - EXECUTIONS_MODE=queue + - QUEUE_BULL_REDIS_HOST=redis + - QUEUE_BULL_REDIS_PORT=6379 + # Emails + # - N8N_SMTP_HOST=${SMTP_HOST} + # - N8N_SMTP_PORT=${SMTP_PORT} + # - N8N_SMTP_USER=${SMTP_USER} + # - N8N_SMTP_PASS=${SMTP_PASS} + volumes: + - n8n_data:/home/node/.n8n + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + + n8n-worker: + image: docker.n8n.io/n8nio/n8n:latest + restart: always + command: worker + environment: + - NODE_ENV=production + - N8N_HOST=${N8N_HOST} + - N8N_PORT=${N8N_PORT} + - N8N_PROTOCOL=https + - EXECUTIONS_MODE=queue + - DB_TYPE=postgresdb + - DB_POSTGRESDB_HOST=postgres + - DB_POSTGRESDB_USER=${POSTGRES_USER} + - DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD} + - N8N_ENCRYPTION_KEY=${ENCRYPTION_KEY} + - N8N_SECURE_COOKIE=true + - N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true + - N8N_BLOCK_ENV_ACCESS_IN_NODE=true + - N8N_PROXY_HOPS=${PROXY_HOPS} + - WEBHOOK_URL=https://${N8N_HOST}/ + - GENERIC_TIMEZONE=${GENERIC_TIMEZONE} + - QUEUE_BULL_REDIS_HOST=redis + - QUEUE_BULL_REDIS_PORT=6379 + depends_on: + - n8n + - redis + + n8n-runner: + image: n8nio/runners:nightly + restart: always + environment: + - N8N_RUNNERS_TASK_BROKER_URI=http://n8n:5679 + - N8N_RUNNERS_AUTH_TOKEN=${N8N_RUNNERS_SECRET} + - N8N_ENCRYPTION_KEY=${ENCRYPTION_KEY} + - GENERIC_TIMEZONE=${GENERIC_TIMEZONE} + - N8N_RUNNERS_MAX_CONCURRENCY=50 + depends_on: + - n8n + + ollama: + image: ollama/ollama:latest + restart: unless-stopped + volumes: + - ollama_storage:/home/node/.ollama + + init-ollama: + image: ollama/ollama:latest + volumes: + - ollama_storage:/home/node/.ollama + entrypoint: /bin/sh + environment: + - OLLAMA_HOST=ollama:11434 + command: + - "-c" + - "sleep 3; ollama pull llama3.2:latest; ollama pull gemma3:latest" + + redis: + image: redis:7-alpine + restart: unless-stopped + command: redis-server --appendonly yes + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 5s + retries: 5 + volumes: + - redis_storage:/data + + postgres: + image: postgres:17-alpine + hostname: postgres + restart: unless-stopped + environment: + - POSTGRES_USER=${POSTGRES_USER} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} + - POSTGRES_DB=${POSTGRES_DB} + volumes: + - postgres_storage:/var/lib/postgresql/data + healthcheck: + test: ['CMD-SHELL', 'pg_isready -h localhost -U ${POSTGRES_USER} -d ${POSTGRES_DB}'] + interval: 5s + timeout: 5s + retries: 10 + +volumes: + n8n_data: + postgres_storage: + ollama_storage: + redis_storage: diff --git a/blueprints/n8n-runner-postgres-ollama/n8n.png b/blueprints/n8n-runner-postgres-ollama/n8n.png new file mode 100644 index 0000000000000000000000000000000000000000..0e9a607e2494055b97bfd12878f496a6aa6e749f GIT binary patch literal 6592 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 ZQeyfU3uE)l$Tu?-nyPxQYF@mF{C_OaY>@x} literal 0 HcmV?d00001 diff --git a/blueprints/n8n-runner-postgres-ollama/template.toml b/blueprints/n8n-runner-postgres-ollama/template.toml new file mode 100644 index 00000000..867ccbc9 --- /dev/null +++ b/blueprints/n8n-runner-postgres-ollama/template.toml @@ -0,0 +1,35 @@ +[variables] +main_domain = "${domain}" +postgres_user = "${username}" +postgres_password = "${password:24}" +postgres_db = "n8n" +n8n_encryption_key = "${base64:64}" +n8n_runner_secret = "${base64:64}" + +[config] +mounts = [] + +[[config.domains]] +serviceName = "n8n" +port = 5_678 +host = "${main_domain}" + +[config.env] +N8N_HOST = "${main_domain}" +N8N_PORT = "5678" +N8N_RUNNERS_SECRET = "${n8n_runner_secret}" + +PROXY_HOPS = "0" +ENCRYPTION_KEY = "${n8n_encryption_key}" +GENERIC_TIMEZONE = "Europe/Berlin" + +POSTGRES_DB = "${postgres_db}" +POSTGRES_USER = "${postgres_user}" +POSTGRES_PASSWORD = "${postgres_password}" + +OLLAMA_HOST = "http://ollama:11434" + +SMTP_HOST = "" +SMTP_PORT = "587" +SMTP_USER = "" +SMTP_PASS = "" \ No newline at end of file diff --git a/blueprints/twenty/docker-compose.yml b/blueprints/twenty/docker-compose.yml index 800e9a72..ee69ee8f 100644 --- a/blueprints/twenty/docker-compose.yml +++ b/blueprints/twenty/docker-compose.yml @@ -1,5 +1,3 @@ -version: "3.9" - services: twenty-change-vol-ownership: image: ubuntu @@ -21,13 +19,19 @@ services: - twenty-docker-data:/app/docker-data environment: PORT: 3000 + SERVER_URL: ${HTTP_PROTOCOL}://${TWENTY_HOST} + FRONT_BASE_URL: ${HTTP_PROTOCOL}://${TWENTY_HOST} + PG_DATABASE_URL: postgres://${DB_USER}:${DB_PASSWORD}@twenty-postgres:5432/twenty - SERVER_URL: https://${TWENTY_HOST} - FRONT_BASE_URL: https://${TWENTY_HOST} - REDIS_URL: redis://twenty-redis:6379 ENABLE_DB_MIGRATIONS: "true" - SIGN_IN_PREFILLED: "true" + + REDIS_URL: redis://twenty-redis:6379 + IS_SIGN_UP_DISABLED: ${IS_SIGN_UP_DISABLED:-false} + SIGN_IN_PREFILLED: "false" + + IS_CONFIG_VARIABLES_IN_DB_ENABLED: "true" STORAGE_TYPE: local + APP_SECRET: ${APP_SECRET} depends_on: twenty-change-vol-ownership: @@ -35,10 +39,11 @@ services: twenty-postgres: condition: service_healthy healthcheck: - test: curl --fail http://localhost:3000/healthz + test: ["CMD", "curl", "-f", "http://127.0.0.1:3000/healthz"] interval: 5s timeout: 5s - retries: 10 + retries: 30 + start_period: 30s restart: always twenty-worker: @@ -47,8 +52,8 @@ services: command: ["yarn", "worker:prod"] environment: PG_DATABASE_URL: postgres://${DB_USER}:${DB_PASSWORD}@twenty-postgres:5432/twenty - SERVER_URL: https://${TWENTY_HOST} - FRONT_BASE_URL: https://${TWENTY_HOST} + SERVER_URL: ${HTTP_PROTOCOL}://${TWENTY_HOST} + FRONT_BASE_URL: ${HTTP_PROTOCOL}://${TWENTY_HOST} REDIS_URL: redis://twenty-redis:6379 ENABLE_DB_MIGRATIONS: "false" STORAGE_TYPE: local @@ -61,7 +66,7 @@ services: restart: always twenty-postgres: - image: postgres:16-alpine + image: postgres:17-alpine volumes: - twenty-postgres-data:/var/lib/postgresql/data @@ -88,10 +93,6 @@ services: retries: 10 restart: always -networks: - dokploy-network: - external: true - volumes: twenty-docker-data: twenty-postgres-data: diff --git a/blueprints/twenty/template.toml b/blueprints/twenty/template.toml index cac39a54..9ebd7f8f 100644 --- a/blueprints/twenty/template.toml +++ b/blueprints/twenty/template.toml @@ -13,7 +13,9 @@ port = 3_000 host = "${main_domain}" [config.env] +HTTP_PROTOCOL = "http" TWENTY_HOST = "${main_domain}" DB_USER = "${db_user}" DB_PASSWORD = "${db_password}" APP_SECRET = "${app_secret}" +IS_SIGN_UP_DISABLED = "false" diff --git a/meta.json b/meta.json index eecff1b6..882243a0 100644 --- a/meta.json +++ b/meta.json @@ -3582,6 +3582,26 @@ "automation" ] }, + { + "id": "n8n-runner-postgres-ollama", + "name": "n8n + Worker + Runner with Redis/Postgres and Ollama", + "version": "latest", + "description": "n8n is an open source low-code platform for automating workflows and integrations with PostgreSQL database and Ollama AI model.", + "logo": "n8n.png", + "links": { + "github": "https://github.com/n8n-io/n8n", + "website": "https://n8n.io/", + "docs": "https://docs.n8n.io/" + }, + "tags": [ + "ai", + "automation", + "workflow", + "low-code", + "postgres", + "ollama" + ] + }, { "id": "n8n-with-postgres", "name": "n8n with Postgres",