#!/bin/bash # n8n 中文版快速启动脚本 # 作者: 小齐 # 最后更新: 2025-09-07 set -e # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # 打印带颜色的信息 print_info() { echo -e "${BLUE}[信息]${NC} $1" } print_success() { echo -e "${GREEN}[成功]${NC} $1" } print_warning() { echo -e "${YELLOW}[警告]${NC} $1" } print_error() { echo -e "${RED}[错误]${NC} $1" } # 显示启动横幅 show_banner() { echo -e "${BLUE}" echo "======================================" echo " n8n 中文版快速启动脚本" echo " 版本: n8n-1.109.2 with 中文翻译" echo " 维护者: xiaoqi" echo "======================================" echo -e "${NC}" } # 检查依赖 check_dependencies() { print_info "正在检查系统依赖..." # 检查 Node.js if ! command -v node &> /dev/null; then print_error "Node.js 未安装或未在 PATH 中" exit 1 fi # 检查 pnpm if ! command -v pnpm &> /dev/null; then print_error "pnpm 未安装或未在 PATH 中" print_info "请先安装 pnpm: npm install -g pnpm" exit 1 fi print_success "依赖检查通过" } # 检查端口占用 check_port() { local port=5678 if lsof -Pi :$port -sTCP:LISTEN -t >/dev/null 2>&1; then print_warning "端口 $port 已被占用" print_info "正在查看占用进程..." lsof -i :$port read -p "是否杀死占用进程?(y/N): " kill_process if [[ $kill_process =~ ^[Yy]$ ]]; then print_info "正在终止占用进程..." lsof -ti:$port | xargs kill -9 print_success "进程已终止" else print_error "无法启动 n8n,端口被占用" exit 1 fi fi } # 停止现有的 n8n 进程 stop_existing() { print_info "正在停止现有的 n8n 进程..." # 停止可能存在的 pnpm dev 进程 pkill -f "pnpm.*dev" 2>/dev/null || true pkill -f "pnpm.*start" 2>/dev/null || true pkill -f "turbo.*dev" 2>/dev/null || true pkill -f "n8n" 2>/dev/null || true sleep 2 print_success "已停止现有进程" } # 设置环境变量 setup_environment() { print_info "正在设置环境变量..." # 获取局域网IP地址 local lan_ip="" if [[ "$OSTYPE" == "darwin"* ]]; then # macOS lan_ip=$(ifconfig | grep "inet " | grep -v 127.0.0.1 | head -1 | awk '{print $2}') else # Linux lan_ip=$(hostname -I | awk '{print $1}') fi export N8N_DEFAULT_LOCALE=zh-CN export N8N_SECURE_COOKIE=false export DB_SQLITE_POOL_SIZE=5 export N8N_RUNNERS_ENABLED=true export N8N_BLOCK_ENV_ACCESS_IN_NODE=false export N8N_HOST=0.0.0.0 export N8N_PORT=5678 # 设置Webhook URL和Editor URL以支持局域网访问 if [ -n "$lan_ip" ]; then export N8N_EDITOR_BASE_URL="http://${lan_ip}:5678" export WEBHOOK_URL="http://${lan_ip}:5678" export N8N_PROTOCOL=http fi # Session和Cookie配置 export N8N_SESSION_COOKIE_SAME_SITE=none export N8N_SESSION_COOKIE_SECURE=false print_success "环境变量已设置" echo " - N8N_DEFAULT_LOCALE=zh-CN" echo " - N8N_SECURE_COOKIE=false" echo " - N8N_HOST=0.0.0.0 (监听所有网络接口)" echo " - N8N_PORT=5678" if [ -n "$lan_ip" ]; then echo " - N8N_EDITOR_BASE_URL=http://${lan_ip}:5678" fi echo " - Session配置已优化以支持局域网访问" } # 检查构建状态 check_build() { if [ ! -d "packages/cli/dist" ] || [ ! -d "packages/core/dist" ]; then print_warning "检测到项目需要构建" read -p "是否现在构建项目?这可能需要几分钟时间 (y/N): " build_project if [[ $build_project =~ ^[Yy]$ ]]; then print_info "正在构建项目..." pnpm build > build.log 2>&1 & BUILD_PID=$! # 显示构建进度 while kill -0 $BUILD_PID 2>/dev/null; do echo -n "." sleep 2 done echo if wait $BUILD_PID; then print_success "项目构建完成" else print_error "构建失败,请查看 build.log" tail -20 build.log exit 1 fi fi fi } # 启动 n8n start_n8n() { print_info "正在启动 n8n 中文版..." # 创建日志文件 local log_file="n8n-$(date +%Y%m%d-%H%M%S).log" # 启动 n8n echo -e "${GREEN}正在启动 n8n 服务...${NC}" pnpm start > "$log_file" 2>&1 & N8N_PID=$! # 等待启动 echo -n "等待 n8n 启动" for i in {1..30}; do if curl -s http://localhost:5678 >/dev/null 2>&1; then break fi echo -n "." sleep 1 done echo # 检查是否启动成功 if curl -s http://localhost:5678 >/dev/null 2>&1; then print_success "n8n 启动成功!" # 获取局域网IP地址 local lan_ip="" if [[ "$OSTYPE" == "darwin"* ]]; then # macOS lan_ip=$(ifconfig | grep "inet " | grep -v 127.0.0.1 | head -1 | awk '{print $2}') else # Linux lan_ip=$(hostname -I | awk '{print $1}') fi echo echo -e "${GREEN}========== 启动信息 ==========${NC}" echo -e "📱 本地访问: ${BLUE}http://localhost:5678${NC}" if [ -n "$lan_ip" ]; then echo -e "🌐 局域网访问: ${BLUE}http://${lan_ip}:5678${NC}" echo -e "📌 提示: 局域网访问请使用 ${BLUE}http://${lan_ip}:5678${NC} 完整地址" echo -e " 避免使用 localhost 或 127.0.0.1" fi echo -e "🌏 界面语言: ${GREEN}中文 (zh-CN)${NC}" echo -e "📋 进程 PID: ${YELLOW}$N8N_PID${NC}" echo -e "📝 日志文件: ${YELLOW}$log_file${NC}" echo -e "${GREEN}=============================${NC}" echo print_info "使用 Ctrl+C 停止服务" if [ -n "$lan_ip" ]; then echo print_warning "局域网访问注意事项:" echo " 1. 确保防火墙允许 5678 端口" echo " 2. 首次访问需要创建账户" echo " 3. 使用同一个IP地址保持登录状态" fi # 保持脚本运行并显示日志 trap 'print_info "正在停止 n8n..."; kill $N8N_PID 2>/dev/null; exit 0' INT tail -f "$log_file" else print_error "n8n 启动失败" print_info "查看日志文件: $log_file" tail -20 "$log_file" exit 1 fi } # 显示使用帮助 show_help() { echo "用法: $0 [选项]" echo echo "选项:" echo " -h, --help 显示此帮助信息" echo " -d, --dev 使用开发模式启动 (支持热重载)" echo " -b, --build 强制重新构建项目" echo " -c, --check 仅检查系统状态,不启动" echo echo "示例:" echo " $0 # 正常启动" echo " $0 -d # 开发模式启动" echo " $0 -b # 重新构建并启动" echo } # 检查并切换到正确目录 check_and_change_directory() { local current_dir="$(pwd)" local script_path="$(readlink -f "$0" 2>/dev/null || realpath "$0" 2>/dev/null || echo "$0")" local script_dir="$(dirname "$script_path")" local n8n_dir="" # 如果当前目录已经是 n8n 项目目录 if [[ -f "package.json" && -d "packages" ]]; then print_info "检测到当前已在 n8n 项目目录" return 0 fi # 如果脚本在 n8n-n8n-1.109.2 目录内,则使用脚本所在目录 if [[ "$script_dir" == *"n8n-n8n-1.109.2"* ]]; then print_info "切换到脚本所在的 n8n 项目目录: $script_dir" cd "$script_dir" || { print_error "无法切换到目录: $script_dir" exit 1 } print_success "已切换到正确的 n8n 项目目录" return 0 fi # 尝试找到 n8n-n8n-1.109.2 目录 if [ -d "./n8n-n8n-1.109.2" ]; then n8n_dir="./n8n-n8n-1.109.2" elif [ -d "../n8n-n8n-1.109.2" ]; then n8n_dir="../n8n-n8n-1.109.2" elif [ -d "../../n8n-n8n-1.109.2" ]; then n8n_dir="../../n8n-n8n-1.109.2" else print_error "未找到 n8n-n8n-1.109.2 目录" print_info "请确保在正确的项目目录下运行此脚本" exit 1 fi print_info "切换到 n8n 项目目录: $n8n_dir" cd "$n8n_dir" || { print_error "无法切换到目录: $n8n_dir" exit 1 } # 验证目录结构 if [ ! -f "package.json" ] || [ ! -d "packages" ]; then print_error "目录结构不正确,缺少 package.json 或 packages 目录" exit 1 fi print_success "已切换到正确的 n8n 项目目录" } # 主函数 main() { # 解析命令行参数 while [[ $# -gt 0 ]]; do case $1 in -h|--help) show_help exit 0 ;; -d|--dev) DEV_MODE=true shift ;; -b|--build) FORCE_BUILD=true shift ;; -c|--check) CHECK_ONLY=true shift ;; *) print_error "未知选项: $1" show_help exit 1 ;; esac done # 显示横幅 show_banner # 检查并切换到正确目录 check_and_change_directory # 检查依赖 check_dependencies # 检查端口 check_port # 停止现有进程 stop_existing # 设置环境变量 setup_environment # 仅检查模式 if [ "$CHECK_ONLY" = true ]; then print_success "系统状态检查完成,一切正常" exit 0 fi # 强制构建或检查构建状态 if [ "$FORCE_BUILD" = true ]; then print_info "强制重新构建项目..." pnpm build print_success "构建完成" else check_build fi # 开发模式 if [ "$DEV_MODE" = true ]; then print_info "正在以开发模式启动 n8n..." print_warning "开发模式启动时间较长,请耐心等待..." exec pnpm dev else # 正常启动 start_n8n fi } # 运行主函数 main "$@"