Skip to main content

N8N AI Common Shared Configuration Module

The N8N AI Common module defines the n8n workflow automation platform with an integrated AI stack (Qdrant vector database and Ollama LLM provider) for the RAD Modules ecosystem. It creates GCP resources (two Secret Manager secrets) and produces a config output consumed by platform-specific wrapper modules (N8N AI CloudRun and N8N AI GKE).

1. Overview

Purpose: To centralize all n8n-specific configuration — including the AI sidecar services (Qdrant, Ollama), Redis queue backend, GCS-backed workflow data storage, SMTP credentials, and an encryption key secret — in a single module shared by both Cloud Run and GKE deployments.

Architecture:

Layer 3: Application Wrappers
├── N8N_AI_CloudRun ──┐
└── N8N_AI_GKE ──┤── instantiate N8N_AI_Common

N8N_AI_Common (this module)
Creates: 2 Secret Manager secrets (SMTP password, encryption key)
Produces: config, storage_buckets, secret_values,
smtp_password_secret_id, encryption_key_secret_id, path

Layer 2: Platform Modules
├── App_CloudRun (serverless deployment)
└── App_GKE (Kubernetes deployment)

Layer 1: App_Common (networking, database, storage, secrets, IAM)

Key characteristics:

  • The only *_Common module that defines additional sidecar services (additional_services) — Qdrant and Ollama run alongside n8n as companion containers/services, each with their own image, port, probes, and volume mounts.
  • Uses a GCS Fuse volume (/home/node/.n8n) as the primary n8n data store, mounted with UID/GID 1000 (node user). A second GCS volume (/mnt/gcs) is shared between n8n, Qdrant, and Ollama.
  • Redis is enabled by default (enable_redis = true) for queue-mode operation; supports $(NFS_SERVER_IP) placeholder resolution at runtime for NFS-hosted Redis.
  • Supports an optional container_resources override object to replace cpu_limit/memory_limit individually — the Ollama sidecar inherits the same CPU/memory limits as the main container.

2. GCP Resources Created

Secret IDContentPurpose
<wrapper_prefix>-smtp-password16-char random alphanumericn8n outbound SMTP password
<wrapper_prefix>-encryption-key32-char random (with special chars)n8n N8N_ENCRYPTION_KEY — encrypts stored credentials in the database

Both secrets use automatic global replication. A 30-second time_sleep is applied after both secret versions are written before the secret ID outputs are resolved.


3. Outputs

config

The application configuration object passed to the platform module via application_config.

FieldValue / Description
app_namefrom application_name (default: "n8nai")
display_namefrom application_display_name (default: "N8N AI Starter Kit")
container_image"n8nio/n8n" (public image used as build base)
image_source"custom" — a custom wrapper image is built
enable_image_mirroringtrue (configurable variable — default: true)
container_build_configdockerfile_path = "Dockerfile", context_path = ".", no build args
container_port5678
database_type"POSTGRES_15"
db_nameDatabase name (default: "n8n_db")
db_userDatabase user (default: "n8n_user")
enable_cloudsql_volumeWhether to mount Cloud SQL Auth Proxy sidecar (default: true)
cloudsql_volume_mount_path"/cloudsql"
gcs_volumesMerged list: caller's gcs_volumes + a fixed n8n-data volume at /mnt/gcs
container_resourcesFrom var.container_resources if set, else cpu_limit/memory_limit
min_instance_count0 (scale-to-zero)
max_instance_count3
environment_variablesMerged map — see §4
enable_postgres_extensionsfalse
postgres_extensions[]
initialization_jobsDefault db-init job or custom override — see §6
startup_probeHTTP GET /, 120s initial delay, 3s timeout, 10s period, 3 failure threshold
liveness_probeHTTP GET /, 30s initial delay, 5s timeout, 30s period, 3 failure threshold
additional_servicesConditional list of Qdrant and/or Ollama sidecar services — see §5

storage_buckets

One GCS bucket for shared n8n, Qdrant, and Ollama data:

FieldValue
name<wrapper_prefix>-storage (explicit name, not just a suffix)
name_suffix"n8n-data"
locationDeployment region
storage_class"STANDARD"
versioning_enabledfalse
public_access_prevention"inherited"

smtp_password_secret_id / encryption_key_secret_id

Individual outputs exposing the Secret Manager secret IDs for each secret, with depends_on on the 30-second propagation wait. Used by wrapper modules to inject secrets into the container via Secret Manager references.

secret_values

A sensitive map of raw generated values for GKE deployments that bypass Secret Manager read-after-write:

{
N8N_SMTP_PASS = "<16-char password>"
N8N_ENCRYPTION_KEY = "<32-char key>"
}

path

Absolute path to the module directory, used by wrapper modules to locate scripts/.


4. Environment Variables

The module merges caller-provided environment_variables with a fixed set of n8n runtime configuration:

Default Variables (from var.environment_variables)

VariableDefaultPurpose
DB_TYPE"postgresdb"n8n database backend
DB_POSTGRESDB_PORT"5432"PostgreSQL port
DB_POSTGRESDB_SSL_REJECT_UNAUTHORIZED"false"Disable SSL cert verification (private IP)
N8N_USER_MANAGEMENT_DISABLED"false"Enable user management
EXECUTIONS_DATA_SAVE_ON_ERROR"all"Persist all failed execution data
EXECUTIONS_DATA_SAVE_ON_SUCCESS"all"Persist all successful execution data
GENERIC_TIMEZONE / TZ"UTC"Timezone
N8N_DEFAULT_BINARY_DATA_MODE"filesystem"Store binary data on disk (GCS Fuse)
N8N_EMAIL_MODE"smtp"Email delivery mode
N8N_SMTP_HOST""SMTP server hostname (caller must set)
N8N_SMTP_PORT"587"SMTP port
N8N_SMTP_USER""SMTP username (caller must set)
N8N_SMTP_SENDER""From address (caller must set)
N8N_SMTP_SSL"false"Use STARTTLS rather than SSL

Fixed Variables (always set by the module)

VariableValuePurpose
N8N_PORT"5678"n8n listening port
N8N_PROTOCOL"https"Public protocol
N8N_DIAGNOSTICS_ENABLED"true"Usage telemetry
N8N_METRICS"true"Prometheus metrics endpoint
N8N_SECURE_COOKIE"false"Disable secure cookie flag (Cloud Run terminates TLS)
N8N_DEFAULT_BINARY_DATA_MODE"filesystem"Override to filesystem
WEBHOOK_URLvar.service_urlPublic webhook base URL
N8N_EDITOR_BASE_URLvar.service_urlEditor base URL
DB_TYPE"postgresdb"Override to ensure PostgreSQL
ENABLE_REDIS"true" / "false"Redis queue mode flag
QUEUE_BULL_REDIS_HOSTvar.redis_host or "$(NFS_SERVER_IP)"Redis host; placeholder expanded at runtime
QUEUE_BULL_REDIS_PORTvar.redis_portRedis port (when enabled)
QUEUE_BULL_REDIS_PASSWORDvar.redis_authRedis auth (when set)

5. AI Sidecar Services (additional_services)

This is the defining feature of N8N AI Common. When enable_ai_components = true, the config.additional_services list includes one or both of the following companion services, deployed alongside n8n:

Qdrant (Vector Database)

Enabled when enable_qdrant = true (default).

FieldValue
Imageqdrant/qdrant:<qdrant_version> (default: latest)
Port6333
CPU / Memory1000m / 1Gi
Min / Max instances1 / 1 (always running)
IngressINGRESS_TRAFFIC_INTERNAL_ONLY
Output env varQDRANT_URL — injected into n8n so it can reach Qdrant
Storage pathQDRANT__STORAGE__STORAGE_PATH = "/mnt/gcs/qdrant"
Volume mountn8n-data GCS bucket at /mnt/gcs (shared with n8n)
Startup probeGET /readyz, 15s delay, 5s timeout, 10s period, 10 threshold

Ollama (Local LLM Provider)

Enabled when enable_ollama = true (default).

FieldValue
Imageollama/ollama:<ollama_version> (default: latest)
Port11434
CPU / MemoryInherits var.cpu_limit / var.memory_limit from the main container
Min / Max instances1 / 1 (always running)
IngressINGRESS_TRAFFIC_INTERNAL_ONLY
Output env varOLLAMA_HOST — injected into n8n so it can reach Ollama
Models pathOLLAMA_MODELS = "/mnt/gcs/ollama/models"
Volume mountn8n-data GCS bucket at /mnt/gcs (shared with n8n and Qdrant)
Startup probeGET /, 20s delay, 5s timeout, 10s period, 10 threshold

Both sidecars store their data on the shared n8n-data GCS Fuse volume under dedicated subdirectories (/mnt/gcs/qdrant and /mnt/gcs/ollama/models), avoiding the need for separate persistent volumes.


6. Initialization Job

One db-init job runs by default (when initialization_jobs = []):

FieldValue
Imagepostgres:15-alpine
Scriptscripts/db-init.sh
Secrets requiredROOT_PASSWORD (PostgreSQL superuser), DB_PASSWORD (app user)
execute_on_applytrue
Timeout600s, 1 retry

db-init.sh behavior:

  1. Detects Cloud SQL Auth Proxy socket: if /cloudsql directory contains a socket file, symlinks it to /tmp/.s.PGSQL.5432 and sets DB_HOST=/tmp.
  2. Resolves the target host from DB_IP, then DB_HOST, then DB_POSTGRESDB_HOST (n8n-native variable).
  3. Polls PostgreSQL using pg_isready until available.
  4. Creates (or updates the password of) the n8n application user.
  5. Grants the application user role to postgres to allow database ownership transfer.
  6. Creates the n8n database owned by the application user if it does not exist; otherwise reassigns ownership.
  7. Grants full privileges on the database and public schema to the application user.
  8. Signals Cloud SQL Proxy shutdown via wget POST http://127.0.0.1:9091/quitquitquit with up to 10 retry attempts (1 second sleep between each).

7. Scripts and Container Image

All supporting files are in scripts/. The scripts/ directory is used as the Docker build context.

Dockerfile

Builds from node:22-alpine3.22:

  • Installs system packages: python3, py3-pip, git, bash, curl, jq, tini, su-exec.
  • Installs n8n globally at the pinned version: npm install -g n8n@2.4.7.
  • Creates the node group (GID 1000) and user (UID 1000) — matches the GCS Fuse mount options uid=1000,gid=1000 so the mounted volume is immediately writable by n8n.
  • Creates /home/node/.n8n and sets ownership to node:node.
  • Copies and makes entrypoint.sh executable (as root, then switches back to node).
  • Sets N8N_USER_FOLDER=/home/node/.n8n and N8N_PORT=5678.
  • Exposes port 5678.
  • Installs tini as a system package but does not use it as the process supervisor — the ENTRYPOINT is set directly to /entrypoint.sh.

entrypoint.sh

Translates platform-standard environment variables into n8n's native variable names before starting n8n:

1. Unix socket detection: If DB_HOST starts with / AND the path is a socket file (-S test), symlinks the socket to /tmp/.s.PGSQL.5432 and resets DB_HOST=/tmp for PostgreSQL client compatibility. Paths starting with / that are not socket files are left unchanged.

2. DB variable mapping (only sets if the n8n-native variable is not already present):

Platform variablen8n variable
DB_HOSTDB_POSTGRESDB_HOST
DB_NAMEDB_POSTGRESDB_DATABASE
DB_USERDB_POSTGRESDB_USER
DB_PASSWORDDB_POSTGRESDB_PASSWORD

3. Redis host resolution: Expands the $(NFS_SERVER_IP) placeholder in QUEUE_BULL_REDIS_HOST to the runtime NFS server IP, enabling NFS-hosted Redis to be referenced without knowing the IP at Terraform plan time.

4. Start n8n: exec n8n "$@" — replaces the shell process with n8n as PID 1. Note that tini is installed in the image but is not invoked here; exec is used directly.


8. Input Variables

Project & Identity

VariableTypeDefaultDescription
project_idstringrequiredGCP project ID
wrapper_prefixstringrequiredPrefix for Secret Manager secret IDs and the storage bucket name
deployment_idstring""Unique deployment identifier
common_labelsmap(string){}Labels applied to secrets
regionstring"us-central1"Region for the storage bucket

Application

VariableTypeDefaultDescription
application_namestring"n8nai"Application name
application_display_namestring"N8N AI Starter Kit"Display name
descriptionstring"N8N AI Starter Kit - Workflow automation with Qdrant and Ollama"Description
application_versionstring"2.4.7"n8n version (pinned in both Dockerfile and config)
service_urlstring""Public service URL; set as WEBHOOK_URL and N8N_EDITOR_BASE_URL
environment_variablesmap(string)see §4Default n8n environment variables
initialization_jobslist(any)[]Custom init jobs; empty triggers default db-init
startup_probeobjectsee §3Startup health probe
liveness_probeobjectsee §3Liveness health probe

AI Components

VariableTypeDefaultDescription
enable_ai_componentsbooltrueMaster switch for AI sidecar services
enable_qdrantbooltrueEnable Qdrant vector database sidecar
qdrant_versionstring"latest"Qdrant Docker image tag
enable_ollamabooltrueEnable Ollama LLM provider sidecar
ollama_versionstring"latest"Ollama Docker image tag

Database & Resources

VariableTypeDefaultDescription
db_namestring"n8n_db"PostgreSQL database name
db_userstring"n8n_user"PostgreSQL application user
enable_cloudsql_volumebooltrueMount Cloud SQL Auth Proxy sidecar socket
enable_image_mirroringbooltrueMirror the container image to the project's Artifact Registry before deployment
gcs_volumeslist(any)n8n-data at /home/node/.n8nGCS Fuse volumes; always merged with the shared /mnt/gcs volume
container_resourcesanynullFull resource object override; if null, uses cpu_limit/memory_limit
cpu_limitstring"2000m"CPU limit (also used by Ollama sidecar)
memory_limitstring"4Gi"Memory limit (also used by Ollama sidecar)
min_instance_countnumber0Minimum instances (scale-to-zero)
max_instance_countnumber3Maximum instances

Redis

VariableTypeDefaultDescription
enable_redisbooltrueEnable Redis queue-mode operation
redis_hoststring""Redis host; if empty, uses $(NFS_SERVER_IP) placeholder
redis_portstring"6379"Redis port
redis_authstring""Redis auth password (sensitive)

9. GCS Volume Layout

The shared n8n-data GCS bucket (<wrapper_prefix>-storage) is mounted at /mnt/gcs in all three containers and at /home/node/.n8n in n8n, using the following directory structure:

<wrapper_prefix>-storage/          ← GCS bucket root
├── (n8n workflow data) ← /home/node/.n8n (n8n default data dir)
├── qdrant/ ← /mnt/gcs/qdrant (Qdrant storage)
│ └── collections/
└── ollama/
└── models/ ← /mnt/gcs/ollama/models (downloaded LLMs)

The default gcs_volumes variable mounts the bucket at /home/node/.n8n with uid=1000,gid=1000 (the node user). The module always appends a second mount at /mnt/gcs (without UID constraints) for the AI sidecar shared storage.


10. Platform-Specific Differences

AspectN8N AI CloudRunN8N AI GKE
service_urlComputed Cloud Run service URLInternal ClusterIP URL (or first custom domain when enable_custom_domain = true)
enable_cloudsql_volumetrue (Auth Proxy sidecar)true by default (Auth Proxy sidecar); can be set to false for TCP
DB_HOSTCloud SQL Auth Proxy socket pathCloud SQL Auth Proxy socket path (default) or Cloud SQL private IP when enable_cloudsql_volume = false
NFSOptional via enable_nfs (defaults to true)Optional via enable_nfs (defaults to true)
AI sidecarsQdrant and Ollama as separate Cloud Run servicesQdrant and Ollama as sidecar containers in the same pod
RedisEnabled by default; $(NFS_SERVER_IP) placeholderEnabled by default; $(NFS_SERVER_IP) placeholder
GCS volumesn8n-data + /mnt/gcs (two fixed volumes)n8n-data + /mnt/gcs (two fixed volumes)
ScalingServerless, scale-to-zero (min_instance_count = 0)Kubernetes Deployment with configurable replicas

11. Implementation Pattern

# Example: how N8N_AI_CloudRun instantiates N8N_AI_Common

module "n8n_app" {
source = "../N8N_AI_Common"

project_id = var.project_id
wrapper_prefix = local.resource_prefix
common_labels = local.labels
deployment_id = local.deployment_id
deployment_region = var.deployment_region
service_url = local.service_url
enable_ai_components = var.enable_ai_components
enable_qdrant = var.enable_qdrant
enable_ollama = var.enable_ollama
enable_redis = var.enable_redis
redis_host = var.redis_host
redis_port = var.redis_port
redis_auth = var.redis_auth
}

# config and secrets are passed to App_CloudRun
module "app_cloudrun" {
source = "../App_CloudRun"

application_config = module.n8n_app.config
module_storage_buckets = module.n8n_app.storage_buckets
module_secret_env_vars = {
N8N_SMTP_PASS = module.n8n_app.smtp_password_secret_id
N8N_ENCRYPTION_KEY = module.n8n_app.encryption_key_secret_id
}
scripts_dir = module.n8n_app.path
# ... other inputs
}