自动在系统重启时启动forever(node)

199

我正在使用Node的forever模块来保持我的Node服务器运行。但是,当系统重新启动时,Forever会终止。有没有办法可以在系统重新启动时自动启动Node服务器(带有forever)?


1
这个服务器在云端吗?您有它的任何引导脚本吗? - Jorge Aranda
7
请查看PM2!它还支持启动脚本生成(systemd,systemv...)。http://pm2.keymetrics.io/docs/usage/startup/ - Unitech
16个回答

349

我建议使用crontab。它很容易使用。

如何使用

  1. 为了开始编辑,请运行以下命令,并将“testuser”替换为您要为节点进程选择的运行时用户。如果您选择的用户不是您自己,请使用sudo运行此命令。

$ crontab -u testuser -e
  • 如果您以前从未进行过此操作,则会询问您希望使用哪个编辑器进行编辑。我喜欢vim,但出于易用性考虑,我建议使用nano。

  • 进入编辑器后,请添加以下行:

  • @reboot /usr/local/bin/forever start /your/path/to/your/app.js
    
  • 保存文件。你应该得到一些反馈,表示cron已安装。

  • 为了进一步确认cron是否已安装,请执行以下命令(再次将“testuser”替换为目标用户名)以列出当前已安装的cron:

  • $ crontab -u testuser -l 
    
    注意,我认为在cron中执行二进制文件时应始终使用完整路径。另外,如果您的forever脚本路径不正确,请运行which forever以获取完整路径。 考虑到forever调用node,您可能还想提供node的完整路径:
    @reboot /usr/local/bin/forever start -c /usr/local/bin/node /your/path/to/your/app.js
    

    进一步阅读


    6
    你怎么会这么想呢? http://en.wikipedia.org/wiki/Cron#Predefined_scheduling_definitions 解释了@reboot cron会在cron守护进程启动时运行。此外,我从未遇到过任何情况表明我设置为@reboot的cron在系统启动时不会运行。关机的方式对此无关紧要。 - Julian Lannigan
    16
    看起来 /home 还没有挂载,所以如果你的代码位于 /home 中,这将无法运行。 - chovy
    6
    我发现上述方法对我无效,因为当 cron 尝试运行 forever 时,node 不在路径中,即使加上 -c 选项也不行。然而,事实证明,只要将 PATH= 语句直接添加到 crontab 中并确保它位于计划语句之上,就可以使 @reboot 语句像梦幻一样运作了。 - YorkshireKev
    2
    感谢您的评论@chovy,非常有帮助。对于那些使用bashrc中的环境变量的人,请注意他的评论。由于/home没有挂载,所以它不起作用。在crontab命令中设置变量,如@reboot varname=value ... - lsborg
    2
    应用程序使用express.js创建,使用bin/www启动服务,而bin/www使用#!/usr/bin/env node语法来要求node.js进行处理。不幸的是,/usr/local/bin不在引导路径中,所以我的解决方案是将以下行放置在我的crontab文件的顶部:PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin以扩展根用户的PATH变量,这对我有效。 - Hover Ruan
    显示剩余15条评论

    128

    您可以使用forever-service来实现这一点。

    npm install -g forever-service
    forever-service install test
    

    使用forever,将当前目录中的app.js作为服务进行配置。该服务将在每次系统重启时自动重新启动。同时,在停止服务时,它将尝试进行优雅的停止。此脚本还提供了logrotate脚本。

    Github网址:https://github.com/zapty/forever-service

    注意:我是forever-service的作者。


    2
    使用“-e“PORT=80 ENV=prod FOO=bar”选项。 - arva
    4
    我不明白如何运行 forever-service。在“forever-service install test”中,“test”是什么?我的启动应用程序 forever 的命令是:“/usr/local/bin/forever start -c /usr/local/bin/node /home/alex/public/node_modules/http-server/bin/http-server -s -d false”。我需要写什么?您需要运行以下命令来将您的应用程序添加到 forever-service 中:forever-service install myapp --script /usr/local/bin/forever --scriptArgs "start -c /usr/local/bin/node /home/alex/public/node_modules/http-server/bin/http-server -s -d false"这个命令将创建一个名为“myapp”的服务,该服务将始终运行您的应用程序。在该命令中,“test”是安装服务的名称。 - Alex
    3
    这里的“test”是服务的名称。当你运行“forever-service install test”时,它会创建一个名为“test”的服务,以便将该目录中的app.js作为服务运行。我建议阅读GitHub页面上的帮助文档,如果仍无法理解,则在那里添加问题。 - arva
    6
    @Alex - 为了澄清arva的评论 - 在例子 forever-service install test 中,test 将是所安装的 服务 的名称,而不是要运行的实际程序 / node.js 文件的名称。默认情况下,它假设程序的名称为 app.js,但您可以使用 --script 标志覆盖它,如下所示:forever-service install test --script main.js。(未经测试,请在语法细节有误时纠正我)。 - Dan Nissenbaum
    3
    @DanNissenbaum 感谢您的回答。我现在正在使用 PM2,它运行得非常好。指南链接:https://www.digitalocean.com/community/tutorials/how-to-use-pm2-to-setup-a-node-js-production-environment-on-an-ubuntu-vps - Alex
    显示剩余11条评论

    34
    1. 使用NPM全局安装PM2

      npm install pm2 -g

    2. 使用pm2启动你的脚本

      pm2 start app.js

    3. 生成一个活动的启动脚本

      pm2 startup

      注意:pm2 startup用于在系统重新启动时启动PM2。一旦启动了PM2,它会重新启动系统崩溃之前正在管理的所有进程。

    如果您想禁用自动启动,只需使用pm2 unstartup

    如果您希望启动脚本在另一个用户下执行,请使用-u <username>选项和--hp <user_home>


    请不要在多个问题中发布相同的答案 - FelixSFD
    我真的很喜欢pm2的精细化处理,并且它还带有一个很棒的监控工具。希望更多人能够注意到这一点。@rv7,我相信你已经看到了,但是有一个Windows解决方案:https://www.npmjs.com/package/pm2-windows-service。不过我自己还没有尝试过。 - John Lee
    这看起来比不停地调整 forever 和 forever-service 要容易得多。 - Martin Braun

    28

    此方法仅适用于Debian。

    请将以下内容添加到/etc/rc.local文件中:

    /usr/bin/sudo -u {{user}} /usr/local/bin/forever start {{app path}}

    • {{user}}替换为您的用户名。
    • {{app path}}替换为您的应用程序路径。例如:/var/www/test/app.js

    2
    这个方法不处理优雅的关闭,但对于许多人来说,这可能不是问题。 - UpTheCreek
    6
    顺便说一句 - 我认为你应该编辑/etc/rc.local,而不是/etc/init.d/rc.local - UpTheCreek
    同意@UpTheCreek的观点,/etc/rc.local是添加此内容更合适的地方-请参见:http://unix.stackexchange.com/a/59945以获取详细解释。 - So Over It
    2
    此外,您可能需要在 app.js 中指定“当前工作目录”,以确保相对文件正确加载 - process.chdir('/your/path/to/your/app');。Node.js 参考文档在此处 - So Over It
    1
    如果你需要为你的Node.JS脚本设置环境变量(例如Express的$PORT),可以将以下行添加到/etc/rc.local中:( cd /path/to/project && /usr/bin/sudo -u {{user}} env PORT={{port number}} PATH=$PATH:/usr/local/bin sh -c "forever start app.js" )。这对我很有用。 - sffc
    使用sudo更改用户会在rc.local的错误日志中输出此错误:sudo:抱歉,您必须拥有tty才能运行sudo。 - woj.sierak

    13

    这个答案和这篇博客文章启发,提供了一种备选的crontab方法。

    1. 创建一个bash脚本文件(将bob更改为所需用户)。

    vi /home/bob/node_server_init.sh
    

    2. 将以下内容复制并粘贴到您刚创建的文件中。

    #!/bin/sh
    
    export NODE_ENV=production
    export PATH=/usr/local/bin:$PATH
    forever start /node/server/path/server.js > /dev/null
    

    请确保根据您的配置编辑上面的路径!

    3. 确保可以执行bash脚本。

    chmod 700 /home/bob/node_server_init.sh
    

    4. 测试bash脚本。

    sh /home/bob/node_server_init.sh
    

    5. 用节点的运行时用户替换 "bob"。

    crontab -u bob -e
    

    6. 复制并粘贴(将bob更改为所需的用户)。

    @reboot /bin/sh /home/bob/node_server_init.sh
    

    保存 crontab。

    你已经完成了,你的奖励是重启(以进行测试):)


    这种方法对我来说效果最好。当我将完整路径放入server.js文件时,Forever总是会退出。如果我在同一目录中运行它,Forever就能正常工作。失败的原因是server.js文件包含其他文件,但路径混乱了。使用这种方法,我可以在我的.sh脚本中CD到该目录,然后相对于那里运行所有内容。 - BeardedGeek

    9

    从附加的问题中复制答案。

    您可以使用PM2, 它是一个用于Node.js应用程序的生产流程管理器,带有内置负载均衡器。

    安装PM2。

    $ npm install pm2 -g
    

    开始一个应用程序

    $ pm2 start app.js
    

    如果您正在使用Express,则可以按以下方式启动您的应用程序:
    pm2 start ./bin/www --name="app"
    

    列出所有正在运行的进程:
    $ pm2 list
    

    它将列出所有进程。然后,您可以使用应用程序的ID或名称使用以下命令停止/重新启动服务。
    $ pm2 stop all                  
    $ pm2 stop 0                    
    $ pm2 restart all               
    

    显示日志
    $ pm2 logs ['all'|app_name|app_id]
    

    它如何在系统启动时自动启动?您只需复制/粘贴CLI手动输入。 - Green
    @Green, 运行, $pm2 startup 之后,你会看到pm2要求手动运行一个命令,复制并运行它。 然后, $pm2 save 现在你的app.js将在系统重启后继续运行。 - yajnesh

    7
    您需要在 /etc/init.d 文件夹中创建一个shell脚本。如果你从未这样做过,这可能有点复杂,但是网络上有很多关于init.d脚本的信息。
    以下是我创建的用于使用forever运行CoffeeScript站点的示例脚本:
    #!/bin/bash
    #
    # initd-example      Node init.d 
    #
    # chkconfig: 345 
    # description: Script to start a coffee script application through forever
    # processname: forever/coffeescript/node
    # pidfile: /var/run/forever-initd-hectorcorrea.pid 
    # logfile: /var/run/forever-initd-hectorcorrea.log
    #
    # Based on a script posted by https://gist.github.com/jinze at https://gist.github.com/3748766
    #
    
    
    # Source function library.
    . /lib/lsb/init-functions
    
    
    pidFile=/var/run/forever-initd-hectorcorrea.pid 
    logFile=/var/run/forever-initd-hectorcorrea.log 
    
    sourceDir=/home/hectorlinux/website
    coffeeFile=app.coffee
    scriptId=$sourceDir/$coffeeFile
    
    
    start() {
        echo "Starting $scriptId"
    
        # This is found in the library referenced at the top of the script
        start_daemon
    
        # Start our CoffeeScript app through forever
        # Notice that we change the PATH because on reboot
        # the PATH does not include the path to node.
        # Launching forever or coffee with a full path
        # does not work unless we set the PATH.
        cd $sourceDir
        PATH=/usr/local/bin:$PATH
        NODE_ENV=production PORT=80 forever start --pidFile $pidFile -l $logFile -a -d --sourceDir $sourceDir/ -c coffee $coffeeFile
    
        RETVAL=$?
    }
    
    restart() {
        echo -n "Restarting $scriptId"
        /usr/local/bin/forever restart $scriptId
        RETVAL=$?
    }
    
    stop() {
        echo -n "Shutting down $scriptId"
        /usr/local/bin/forever stop $scriptId
        RETVAL=$?
    }
    
    status() {
        echo -n "Status $scriptId"
        /usr/local/bin/forever list
        RETVAL=$?
    }
    
    
    case "$1" in
        start)
            start
            ;;
        stop)
            stop
            ;;
        status)
            status
            ;;
        restart)
            restart
            ;;
        *)
            echo "Usage:  {start|stop|status|restart}"
            exit 1
            ;;
    esac
    exit $RETVAL
    

    由于init.d脚本是以root身份运行的,因此我必须确保文件夹和路径已经显式设置或对root用户可用。


    2
    如果您有任何依赖项也是使用init.d启动的,那么可能会出现加载顺序问题。 - UpTheCreek
    @alexandru.topliceanu 我已经修复了链接。 - Hector Correa

    6
    使用PM2来运行服务器生产环境是最佳选择。
    通过这种方式运行应用程序的优点有哪些?
    • 如果应用程序崩溃,PM2会自动重新启动它。

    • PM2将记录未处理的异常 - 在这种情况下,记录在/home/safeuser/.pm2/logs/app-err.log文件中。

    • 使用一个命令,PM2可以确保它管理的任何应用程序在服务器重新启动时重新启动。基本上,你的Node应用程序将作为服务启动。

    参考:https://www.digitalocean.com/community/tutorials/how-to-use-pm2-to-setup-a-node-js-production-environment-on-an-ubuntu-vps

    5

    crontab在我使用的CentOS x86 6.5上无法正常工作,@reboot似乎也不起作用。

    最终我找到了这个解决方案:

    编辑:/etc/rc.local

    sudo vi /etc/rc.local
    

    请在文件末尾添加此行。将USER_NAMEPATH_TO_PROJECT更改为您自己的信息。NODE_ENV=production表示应用程序以生产模式运行。如果需要运行多个node.js应用程序,则可以添加更多行。

    su - USER_NAME -c "NODE_ENV=production /usr/local/bin/forever start /PATH_TO_PROJECT/app.js"
    

    不要将NODE_ENV设置在单独的一行,否则您的应用程序仍将以开发模式运行,因为forever无法获取NODE_ENV
    # WRONG!
    su - USER_NAME -c "export NODE_ENV=production"
    

    保存并退出 vi(按下 ESC : w q return)。您可以尝试重新启动服务器。在您的服务器重新启动后,即使您不通过 ssh 远程登录任何帐户,您的 node.js 应用程序也应该自动运行。

    您最好在 shell 中设置 NODE_ENV 环境变量。当您的帐户 USER_NAME 登录时,NODE_ENV 将自动设置。

    echo export NODE_ENV=production >> ~/.bash_profile
    

    因此,您可以通过ssh运行像forever stop/start /PATH_TO_PROJECT/app.js这样的命令,而无需再次设置NODE_ENV


    在Debian 7.6上我遇到了同样的问题。这个方法对我有用。非常感谢。 - Daniele Vrut
    如果你不想使用“forever”,你可以将该行更改为“su - USER_NAME -c“NODE_ENV = production node /PATH_TO_PROJECT/bin/www””。 - yaobin

    5

    Forever并不是用来将Node应用程序作为服务运行的。正确的方法是创建一个/etc/inittab条目(旧的Linux系统)或一个Upstart(较新的Linux系统)。

    以下是如何设置Upstart的一些文档: https://github.com/cvee/node-upstart


    Upstart在CentOS上让我失望了,而且我读到它将会消失。创建init.d条目并不是最用户友好的方式,但毕竟这是Linux :) - Jorre

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接