14 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
This is n8n-install, a Docker Compose-based installer that provides a comprehensive self-hosted environment for n8n workflow automation and numerous AI/automation services. The installer includes an interactive wizard, automated secret generation, and integrated HTTPS via Caddy.
Core Architecture
- Profile-based service management: Services are activated via Docker Compose profiles (e.g.,
n8n,flowise,monitoring). Profiles are stored in the.envfile'sCOMPOSE_PROFILESvariable. - No exposed ports: Services do NOT publish ports directly. All external HTTPS access is routed through Caddy reverse proxy on ports 80/443.
- Shared secrets: Core services (Postgres, Redis/Valkey, Caddy) are always included. Other services are optional and selected during installation.
- Queue-based n8n: n8n runs in
queuemode with Redis, Postgres, and dynamically scaled workers (N8N_WORKER_COUNT).
Key Files
Makefile: Common commands (install, update, logs, etc.)docker-compose.yml: Service definitions with profilesCaddyfile: Reverse proxy configuration with automatic HTTPS.env: Generated secrets and configuration (from.env.example)scripts/install.sh: Main installation orchestrator (runs numbered scripts 01-08 in sequence)scripts/utils.sh: Shared utility functions (sourced by all scripts viasource "$(dirname "$0")/utils.sh" && init_paths)scripts/01_system_preparation.sh: System updates, firewall, security hardeningscripts/02_install_docker.sh: Docker and Docker Compose installationscripts/git.sh: Git utilities (sync with origin, branch detection, configuration)scripts/03_generate_secrets.sh: Secret generation and bcrypt hashingscripts/04_wizard.sh: Interactive service selection using whiptailscripts/05_configure_services.sh: Service-specific configuration logicscripts/databases.sh: Creates isolated PostgreSQL databases for services (library)scripts/telemetry.sh: Anonymous telemetry functions (Scarf integration)scripts/06_run_services.sh: Starts Docker Compose stackscripts/07_final_report.sh: Post-install credential summaryscripts/08_fix_permissions.sh: Fixes file ownership for non-root accessscripts/generate_n8n_workers.sh: Generates dynamic worker/runner compose filescripts/update.sh: Update orchestrator (syncs with origin and updates images)scripts/update_preview.sh: Preview available updates without applying (dry-run)scripts/doctor.sh: System diagnostics (DNS, SSL, containers, disk, memory)scripts/apply_update.sh: Applies updates after git syncscripts/docker_cleanup.sh: Removes unused Docker resources (used bymake clean)scripts/download_top_workflows.sh: Downloads community n8n workflowsscripts/import_workflows.sh: Imports workflows fromn8n/backup/workflows/into n8n (used bymake import)
Project Name: All docker-compose commands use -p localai (defined in Makefile as PROJECT_NAME := localai).
Installation Flow
scripts/install.sh orchestrates the installation by running numbered scripts in sequence:
01_system_preparation.sh- System updates, firewall, security hardening02_install_docker.sh- Docker and Docker Compose installation03_generate_secrets.sh- Generate passwords, API keys, bcrypt hashes04_wizard.sh- Interactive service selection (whiptail UI)05_configure_services.sh- Service-specific configuration06_run_services.sh- Start Docker Compose stack07_final_report.sh- Display credentials and URLs08_fix_permissions.sh- Fix file ownership for non-root access
The update flow (scripts/update.sh) similarly orchestrates: git fetch + reset → service selection → apply_update.sh → restart.
Common Development Commands
Makefile Commands
make install # Full installation (runs scripts/install.sh)
make update # Update system and services
make update-preview # Preview available updates (dry-run)
make clean # Remove unused Docker resources (preserves data)
make clean-all # Remove ALL Docker resources including data (DANGEROUS)
make logs # View logs (all services)
make logs s=<service> # View logs for specific service
make status # Show container status
make monitor # Live CPU/memory monitoring (docker stats)
make restart # Restart all services
make show-restarts # Show restart count per container
make doctor # Run system diagnostics (DNS, SSL, containers, disk, memory)
make import # Import n8n workflows from backup
make import n=10 # Import first N workflows only
make switch-beta # Switch to develop branch and update
make switch-stable # Switch to main branch and update
make help # Show all available commands
Adding a New Service
Follow this workflow when adding a new optional service (refer to .claude/commands/add-new-service.md for complete details):
- docker-compose.yml: Add service with
profiles: ["myservice"],restart: unless-stopped. Do NOT expose ports. - Caddyfile: Add reverse proxy block using
{$MYSERVICE_HOSTNAME}. Consider if basic auth is needed. - .env.example: Add
MYSERVICE_HOSTNAME=myservice.yourdomain.comand credentials if using basic auth. - scripts/03_generate_secrets.sh: Generate passwords and bcrypt hashes. Add to
VARS_TO_GENERATEmap. - scripts/04_wizard.sh: Add service to
base_services_dataarray for wizard selection. - scripts/databases.sh: If service uses PostgreSQL, add database name to
INIT_DB_DATABASESarray. - scripts/generate_welcome_page.sh: Add service to
SERVICES_ARRAYfor welcome dashboard. - welcome/app.js: Add
SERVICE_METADATAentry with name, description, icon, color, category. - scripts/07_final_report.sh: Add service URL and credentials output using
is_profile_active "myservice". - README.md: Add one-line description under "What's Included".
- CHANGELOG.md: Add entry under
## [Unreleased]→### Added.
Always ask users if the new service requires Caddy basic auth protection.
Important Service Details
n8n Configuration (v2.0+)
- n8n runs in
EXECUTIONS_MODE=queuewith Redis as the queue backend - OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS=true: All executions (including manual tests) run on workers
- Worker-Runner Sidecar Pattern: Each worker has its own dedicated task runner
- Workers and runners are generated dynamically via
scripts/generate_n8n_workers.sh - Configuration stored in
docker-compose.n8n-workers.yml(auto-generated, gitignored) - Runner connects to its worker via
network_mode: "service:n8n-worker-N"(localhost:5679) - Runner image
n8nio/runnersmust match n8n version
- Workers and runners are generated dynamically via
- Scaling: Change
N8N_WORKER_COUNTin.envand runbash scripts/generate_n8n_workers.sh - Code node libraries: Configured via
n8n/n8n-task-runners.jsonandn8n/Dockerfile.runner:- JS packages installed via
pnpm addin Dockerfile.runner - Allowlist configured in
n8n-task-runners.json(NODE_FUNCTION_ALLOW_EXTERNAL,NODE_FUNCTION_ALLOW_BUILTIN) - Default packages:
cheerio,axios,moment,lodash
- JS packages installed via
- Workflows can access the host filesystem via
/data/shared(mapped to./shared) N8N_BLOCK_ENV_ACCESS_IN_NODE=falseallows Code nodes to access environment variables
Caddy Reverse Proxy
- Automatically obtains Let's Encrypt certificates when
LETSENCRYPT_EMAILis set - Hostnames are passed via environment variables (e.g.,
N8N_HOSTNAME,FLOWISE_HOSTNAME) - Basic auth uses bcrypt hashes generated by
scripts/03_generate_secrets.shvia Caddy's hash command - Never add
ports:to services in docker-compose.yml; let Caddy handle all external access
Secret Generation
The scripts/03_generate_secrets.sh script:
- Generates random passwords, JWT secrets, API keys, and encryption keys
- Creates bcrypt password hashes using Caddy's
hash-passwordcommand - Preserves existing user-provided values in
.env - Supports different secret types via
VARS_TO_GENERATEmap:password:32,jwt,api_key,base64:64,hex:32
Utility Functions (scripts/utils.sh)
Source with: source "$(dirname "$0")/utils.sh" && init_paths
Key functions:
is_profile_active "myservice"- Check if profile is enabledread_env_var "VAR_NAME"/write_env_var "VAR_NAME" "value"- .env manipulationload_env- Source .env file to make variables availableupdate_compose_profiles "profile1,profile2"- Update COMPOSE_PROFILES in .envgen_password 32/gen_hex 64/gen_base64 64- Secret generationgenerate_bcrypt_hash "password"- Create Caddy-compatible bcrypt hash (uses Caddy binary)json_escape "string"- Escape string for JSON outputwt_input,wt_password,wt_yesno,wt_msg- Whiptail dialog wrapperswt_checklist,wt_radiolist,wt_menu- Whiptail selection dialogswt_parse_choices "$result" array_name- Parse quoted checklist output safelylog_info,log_success,log_warning,log_error- Logging functionslog_header,log_subheader,log_divider,log_box- Formatted outputprint_ok,print_error,print_warning,print_info- Doctor output helpersget_real_user/get_real_user_home- Get actual user even under sudobackup_preserved_dirs/restore_preserved_dirs- Directory preservation for git updatescleanup_legacy_n8n_workers- Remove old n8n worker containers from previous naming conventionget_n8n_workers_compose/get_supabase_compose/get_dify_compose- Get compose file path if profile active AND file existsbuild_compose_files_array- Build globalCOMPOSE_FILESarray with all active compose files (main + external)
Service Profiles
Common profiles:
n8n: n8n workflow automation (includes main app, worker, runner, and import services)flowise: Flowise AI agent buildermonitoring: Prometheus, Grafana, cAdvisor, node-exporterlangfuse: Langfuse observability (includes ClickHouse, MinIO, worker, web)cpu,gpu-nvidia,gpu-amd: Ollama hardware profiles (mutually exclusive)cloudflare-tunnel: Cloudflare Tunnel for zero-trust access (seecloudflare-instructions.md)gost: HTTP/HTTPS proxy for routing AI service outbound trafficpython-runner: Internal Python execution environment (no external access)
Architecture Patterns
Healthchecks
Services should define healthchecks for proper dependency management:
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://localhost:8080/health || exit 1"]
interval: 30s
timeout: 10s
retries: 5
Service Dependencies
Use depends_on with conditions:
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
Environment Variable Patterns
- All secrets/passwords end with
_PASSWORDor_KEY - All hostnames end with
_HOSTNAME - Password hashes end with
_PASSWORD_HASH - Use
${VAR:-default}for optional vars with defaults
Profile Activation Logic
In bash scripts, check if a profile is active:
if is_profile_active "myservice"; then
# Service-specific logic
fi
Proxy Configuration (for AI services)
Services making outbound HTTP requests to AI APIs (OpenAI, Anthropic, etc.) should use the shared proxy anchor:
x-proxy-env: &proxy-env
HTTP_PROXY: ${GOST_PROXY_URL:-}
HTTPS_PROXY: ${GOST_PROXY_URL:-}
NO_PROXY: ${GOST_NO_PROXY:-}
services:
myservice:
environment:
<<: *proxy-env # Inherit proxy settings
Important: Healthchecks must bypass proxy:
healthcheck:
test: ["CMD-SHELL", "http_proxy= https_proxy= HTTP_PROXY= HTTPS_PROXY= wget -qO- http://localhost:8080/health || exit 1"]
Welcome Page Dashboard
The welcome page (welcome/) provides a post-install dashboard showing all active services:
scripts/generate_welcome_page.sh: Generateswelcome/services.jsonwith service URLs, credentials, and metadatawelcome/app.js: ContainsSERVICE_METADATAobject defining display properties (name, description, icon, color, category)- Categories:
ai,database,monitoring,tools,infra,automation - Always use
json_escape "$VAR"when building JSON to handle special characters
Preserved Directories
Directories in PRESERVE_DIRS (defined in scripts/utils.sh) survive git updates:
python-runner/- User's custom Python code
These are backed up before git reset --hard and restored after.
Common Issues and Solutions
Service won't start after adding
- Ensure profile is added to
COMPOSE_PROFILESin.env - Check logs:
docker compose -p localai logs <service> - Verify no port conflicts (no services should publish ports)
- Ensure healthcheck is properly defined if service has dependencies
Caddy certificate issues
- DNS must be configured before installation (wildcard A record:
*.yourdomain.com) - Check Caddy logs for certificate acquisition errors
- Verify
LETSENCRYPT_EMAILis set in.env
Password hash generation fails
- Ensure Caddy container is running:
docker compose -p localai up -d caddy - Script uses:
docker exec caddy caddy hash-password --plaintext "$password"
File Locations
- Shared files accessible by n8n:
./shared(mounted as/data/sharedin n8n) - n8n storage: Docker volume
localai_n8n_storage - Service-specific volumes: Defined in
volumes:section at top ofdocker-compose.yml - Installation logs: stdout during script execution
- Service logs:
docker compose -p localai logs <service>
Testing Changes
Syntax Validation
# Docker Compose syntax
docker compose -p localai config --quiet
# Bash script syntax (validate all key scripts)
bash -n scripts/utils.sh
bash -n scripts/git.sh
bash -n scripts/databases.sh
bash -n scripts/telemetry.sh
bash -n scripts/03_generate_secrets.sh
bash -n scripts/04_wizard.sh
bash -n scripts/05_configure_services.sh
bash -n scripts/07_final_report.sh
bash -n scripts/generate_welcome_page.sh
bash -n scripts/generate_n8n_workers.sh
bash -n scripts/apply_update.sh
bash -n scripts/update.sh
bash -n scripts/install.sh
Full Testing
When modifying installer scripts:
- Test on a clean Ubuntu 24.04 LTS system (minimum 4GB RAM / 2 CPU)
- Verify all profile combinations work
- Check that
.envis properly generated - Confirm final report displays correct URLs and credentials
- Test update script preserves custom configurations