You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ubuntu 22.04下NodeJS Cronjob与日志及环境变量配置咨询

问题背景

我有一个使用morgan和morgan-daily-rotate实现日志功能的TypeScript项目,功能是从一台服务器拉取股票信息,再更新到另一台服务器。运行时会按YYYY-MM-DD格式生成日志文件夹。开发环境为Windows,部署到Linode的Ubuntu 22.04实例。

项目目录结构

build/
  ...
  index.js
logs/
  2022-10-04-20/ <- 根据运行日期时间生成
    combined.log
    error.log
    warn.log
src/
  ...
  index.ts
run.sh

项目部署在~/customerName/projectName/目录,部署时仅复制构建后的build文件夹和package.json到Linode实例以安装依赖。防火墙已开放http和https连接,ufw status显示规则正常。

在Windows开发环境及Ubuntu实例中直接从项目目录运行时,项目正常且日志正确生成在logs目录下的对应日期文件夹。但通过Cronjob执行命令*/5 * * * * cd /home/user/customerName/projectName/ && node index.js > /home/user/customerName/projectName/logs/cron.log 2>&1时,出现两个问题:

  • 日志生成到~/logs而非项目目录下的logs;
  • 日志中充斥Error: connect ECONNREFUSED ::1:80的axios错误。

morgan日志传输配置示例

const infoTransport: DailyRotateFile = new DailyRotateFile({
  level: "info",
  filename: "./logs/%DATE%/combined.log",
  datePattern: "YYYY-MM-DD-HH",
  maxSize: "20m",
  maxFiles: "14d",
});

问题解答

1. 如何让Cronjob从~/customerName/projectName/目录执行脚本?

有三种可靠方案:

  • 用绝对路径确保cd生效:Cron环境里~不一定指向用户主目录,直接写完整绝对路径:
    */5 * * * * cd /home/user/customerName/projectName/ && node index.js > /home/user/customerName/projectName/logs/cron.log 2>&1
    
  • 封装成shell脚本执行:把切换目录、执行逻辑写到run.sh,给脚本加执行权限(chmod +x run.sh),再让Cron调用脚本:
    run.sh内容:
    #!/bin/bash
    cd /home/user/customerName/projectName/
    node index.js > ./logs/cron.log 2>&1
    
    Cron命令:
    */5 * * * * /home/user/customerName/projectName/run.sh
    
  • 修改日志配置为绝对路径:把./logs/%DATE%/combined.log改成/home/user/customerName/projectName/logs/%DATE%/combined.log,彻底规避工作目录影响。

2. 手动运行正常,但Cronjob执行时为何出现Error: connect ECONNREFUSED ::1:80错误?

核心原因是Cron的环境变量和用户登录后的环境差异极大:

  • 手动运行时,你有完整的环境变量(比如项目依赖的目标服务器地址、node路径),但Cron的环境变量非常精简,甚至连PATH都只有默认几个目录;
  • 如果项目依赖.env文件存储请求地址,手动运行时npm或脚本会自动加载,但Cron直接执行node index.js时,不会自动加载.env,导致请求地址缺失,默认指向localhost:80(IPv6对应::1:80),引发连接拒绝。

解决方法:

  • 若用nvm安装node,在Cron命令或脚本里指定node绝对路径,比如/home/user/.nvm/versions/node/v18.17.0/bin/node;
  • 在Cron命令里直接指定环境变量,比如:
    */5 * * * * cd /home/user/customerName/projectName/ && TARGET_SERVER=https://xxx.xxx node index.js > /home/user/customerName/projectName/logs/cron.log 2>&1
    
  • 确保代码里加载.env时指定绝对路径:
    require('dotenv').config({ path: '/home/user/customerName/projectName/.env' });
    

3. 如何为脚本设置运行时的环境变量?

常用的几种方式:

  • Cron命令里直接定义:在node命令前加环境变量,多个用空格分隔:
    */5 * * * * cd /home/user/customerName/projectName/ && VAR1=value1 VAR2=value2 node index.js > /home/user/customerName/projectName/logs/cron.log 2>&1
    
  • 通过.env文件加载:用dotenv包并指定.env绝对路径,或在shell脚本里导出变量:
    #!/bin/bash
    cd /home/user/customerName/projectName/
    export $(cat .env | xargs)
    node index.js > ./logs/cron.log 2>&1
    
  • 在shell脚本里定义:把环境变量写在run.sh头部:
    #!/bin/bash
    export NODE_ENV=production
    export TARGET_API=https://stock-server.example.com
    cd /home/user/customerName/projectName/
    node index.js > ./logs/cron.log 2>&1
    
  • 全局配置Cron环境变量:执行crontab -e,在配置顶部添加全局环境变量,所有Cron任务都会继承:
    NODE_ENV=production
    TARGET_API=https://stock-server.example.com
    PATH=/home/user/.nvm/versions/node/v18.17.0/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    

内容的提问来源于stack exchange,提问作者HotFix

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 08:55:17