adds caddy-addon mechanism for custom certificates when let's encrypt is not available. includes setup script with interactive wizard, example configs, and documentation.
16 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 (resets to origin)
make update-preview # Preview available updates (dry-run)
make git-pull # Update for forks (merges from upstream/main)
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 setup-tls # Configure custom TLS certificates
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(new service = minor version bump).
Always ask users if the new service requires Caddy basic auth protection.
Versioning (CHANGELOG.md)
This project uses Semantic Versioning. When updating CHANGELOG.md:
Version Format: MAJOR.MINOR.PATCH
| Type | When to bump | Examples |
|---|---|---|
| MAJOR (X.0.0) | Breaking changes that require user action | n8n 2.0 migration, config format changes, removed features |
| MINOR (0.X.0) | New services or features (backward compatible) | Adding NocoDB, new wizard options, new Makefile commands |
| PATCH (0.0.X) | Bug fixes (backward compatible) | Healthcheck fixes, proxy bypass fixes, typo corrections |
Changelog Entry Format
## [Unreleased]
## [2.6.0] - 2026-01-15
### Added
- **NewService** - Brief description of what it provides
### Changed
- Description of modified behavior
### Fixed
- Description of bug fix
After Release
- Move items from
[Unreleased]to new version section - Add comparison link at bottom of file:
[2.6.0]: https://github.com/kossakovsky/n8n-install/compare/v2.5.3...v2.6.0 - Update
[Unreleased]link to compare from new version
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