我如何运行一个node.js应用程序作为后台服务?

由于这篇文章在过去几年里受到了很多关注,所以我在文章的底部列出了每个平台的最佳解决方案。


# EYZ0:

我希望我的node.js服务器在后台运行,即:当我关闭我的终端时,我希望我的服务器继续运行。我在谷歌上搜索过这个,并提出了这个教程,但它并没有像预期的那样工作。因此,我没有使用这个守护进程脚本,而是使用了输出重定向(2>&1 >> file部分),但这也没有退出——我在终端中得到了一个空行,就像它在等待输出/错误一样。

我也尝试过把进程放在后台,但是只要我关闭终端,进程就会被杀死。

那么,当我关闭本地计算机时,如何让它继续运行呢?


# EYZ0:

  • # EYZ0 (Linux)
  • # EYZ0 (Mac)
  • # EYZ0 (Windows)
  • # EYZ0 (node . js)
756013 次浏览

这可能不是被接受的方式,但我在屏幕上这样做,特别是在开发过程中,因为我可以在必要时恢复它并愚弄它。

screen
node myserver.js
>>CTRL-A then hit D

屏幕将分离,并幸存你注销。然后你可以用screen -r把它找回来。点击屏幕手册了解更多细节。你可以给屏幕命名等等。

更新 -正如下面的一个答案所提到的,PM2有一些非常好的功能永远都没有。考虑使用它。

原来的答案

使用# EYZ0:

nohup node server.js &

我想补充一点,接受的答案才是正确的方法。我在需要保持的实例上使用forever。我喜欢写npm install -g forever,所以它在节点路径中,然后写forever start server.js

看看赋格!除了启动许多工作者之外,您还可以妖魔化您的节点进程!

http://github.com/pgte/fugue

你可以使用Forever,一个简单的CLI工具,用于确保给定的节点脚本连续运行(即永远): # EYZ0 < / p >

这个答案有点晚了,但是我发现最好的解决方案是编写一个同时使用screen -dmSnohup命令的shell脚本。

screen -dmS newScreenName nohup node myserver.js >> logfile.log

我还在末尾添加了>> logfile位,这样我就可以轻松地保存节点console.log()语句。

为什么我要使用shell脚本?我还添加了一个if语句,检查node myserver.js进程是否已经在运行。

通过这种方式,我可以创建一个命令行选项,既可以让我保持服务器运行,也可以在我进行更改时重新启动服务器,这对开发非常有帮助。

我只是使用守护进程 npm模块:

var daemon = require('daemon');


daemon.daemonize({
stdout: './log.log'
, stderr: './log.error.log'
}
, './node.pid'
, function (err, pid) {
if (err) {
console.log('Error starting daemon: \n', err);
return process.exit(-1);
}
console.log('Daemonized successfully with pid: ' + pid);


// Your Application Code goes here
});

最近我还从TJ Holowaychuk开始使用我的(1)来启动和管理简单的节点应用程序。

Node.js作为WINDOWS XP中的后台服务

安装:

  1. 通过安装程序可执行文件安装WGET http://gnuwin32.sourceforge.net/packages/wget.htm
  2. 通过安装程序可执行文件安装git# EYZ0
  3. 通过拷贝nnsm.exe到%windir%/system32文件夹安装nssm# EYZ0
  4. < p >创建c: \ \ helloworld.js节点

    // http://howtonode.org/hello-node
    var http = require('http');
    var server = http.createServer(function (request, response) {
    response.writeHead(200, {"Content-Type": "text/plain"});
    response.end("Hello World\n");
    });
    server.listen(8000);
    console.log("Server running at http://127.0.0.1:8000/");
    
  5. Open command console and type the following (setx only if Resource Kit is installed)

    C:\node> set path=%PATH%;%CD%
    C:\node> setx path "%PATH%"
    C:\node> set NODE_PATH="C:\Program Files\nodejs\node_modules"
    C:\node> git config --system http.sslcainfo /bin/curl-ca-bundle.crt
    C:\node> git clone --recursive git://github.com/isaacs/npm.git
    C:\node> cd npm
    C:\node\npm> node cli.js install npm -gf
    C:\node> cd ..
    C:\node> nssm.exe install node-helloworld "C:\Program Files\nodejs\node.exe" c:\node\helloworld.js
    C:\node> net start node-helloworld
    
  6. A nifty batch goodie is to create c:\node\ServiceMe.cmd

    @echo off
    nssm.exe install node-%~n1 "C:\Program Files\nodejs\node.exe" %~s1
    net start node-%~n1
    pause
    

Service Management:

  • The services themselves are now accessible via Start-> Run-> services.msc or via Start->Run-> MSCONFIG-> Services (and check 'Hide All Microsoft Services').
  • The script will prefix every node made via the batch script with 'node-'.
  • Likewise they can be found in the registry: "HKLM\SYSTEM\CurrentControlSet\Services\node-xxxx"

< >强2016更新: node-windows/mac/linux系列使用跨所有操作系统的通用API,因此它绝对是一个相关的解决方案。然而;Node-linux会生成systemv init文件。随着systemd越来越受欢迎,它实际上是Linux上更好的选择。如果有人想将systemd支持添加到node-linux,欢迎使用PR:-)

原始线程:

这是一个非常老的线程,但是node-windows提供了另一种在Windows上创建后台服务的方法。它松散地基于nssm概念,即在节点脚本周围使用exe包装器。然而;它使用winsw.exe代替,并提供了一个可配置的节点包装器,以更细粒度地控制进程在失败时如何启动/停止。这些进程像其他服务一样可用:

enter image description here

该模块还烘焙了一些事件日志:

enter image description here

对脚本进行后台管理是通过代码完成的。例如:

var Service = require('node-windows').Service;


// Create a new service object
var svc = new Service({
name:'Hello World',
description: 'The nodejs.org example web server.',
script: 'C:\\path\\to\\my\\node\\script.js'
});


// Listen for the "install" event, which indicates the
// process is available as a service.
svc.on('install',function(){
svc.start();
});


// Listen for the "start" event and let us know when the
// process has actually started working.
svc.on('start',function(){
console.log(svc.name+' started!\nVisit http://127.0.0.1:3000 to see it in action.');
});


// Install the script as a service.
svc.install();

该模块支持限制重启(这样糟糕的脚本就不会影响服务器)和增加重启之间的时间间隔。

由于节点窗口服务像其他服务一样运行,因此可以使用您已经使用的任何软件来管理/监视服务。

最后,没有make依赖项。换句话说,简单的npm install -g node-windows可以工作。你不需要Visual Studio、. net或node-gyp魔法来安装它。而且,它是MIT和BSD授权的。

坦白地说,我是这个模块的作者。它的设计是为了减轻OP所经历的痛苦,但与操作系统已经提供的功能更紧密地集成。我希望未来有同样问题的观众会觉得有用。

为了完善建议的各种选项,这里还有一个:GNU/Linux中的daemon命令,您可以在这里阅读:http://libslack.org/daemon/manpages/daemon.1.html。(如果上面的评论中已经提到了这一点,我深表歉意)。

更新:我更新到包括最新的pm2:

对于许多用例,使用systemd服务是管理节点进程的最简单和最合适的方法。对于那些在单个环境中运行大量节点进程或独立运行节点微服务的人来说,pm2是一个功能更全的工具。

https://github.com/unitech/pm2

< a href = " http://pm2。io noreferrer“rel = > http://pm2.io < / >

  • 它有一个非常有用的监控功能->漂亮的“gui”命令行监控多个进程pm2 monit或进程列表pm2 list
  • organized日志管理-> pm2 logs
  • <李>其他东西:
    • 行为的配置
    • 源映射支持
    • PaaS兼容
    • 看,重新加载
    • 模块系统
    • 最大内存重载
    • 集群模式
    • 热重载
    • 开发工作流程
    • 启动脚本
    • 自动完成
    • 部署工作流程
    • Keymetrics监控
    • API
    李< /引用> < / >

使用nssm为windows的最佳解决方案,只需下载nssm,打开cmd到nssm目录并键入

nssm install <service name> <node path> <app.js path>


eg: nssm install myservice "C:\Program Files\nodejs" "C:\myapp\app.js"

这将安装一个新的windows服务,它将列在services.msc,你可以启动或停止服务,这个服务将自动启动,如果它失败了,你可以配置重新启动。

如果你在linux服务器上运行nodejs,我认为这是最好的方法。

创建业务脚本,拷贝到/etc/init/nodejs.conf目录下

Start service: sudo service nodejs Start

Stop service: sudo service nodejs Stop

服务脚本

description "DManager node.js server - Last Update: 2012-08-06"
author      "Pedro Muniz - pedro.muniz@geeklab.com.br"


env USER="nodejs" #you have to create this user
env APPNAME="nodejs" #you can change the service name
env WORKDIR="/home/<project-home-dir>" #set your project home folder here
env COMMAND="/usr/bin/node <server name>" #app.js ?


# used to be: start on startup
# until we found some mounts weren't ready yet while booting:
start on started mountall
stop on shutdown


# Automatically Respawn:
respawn
respawn limit 99 5


pre-start script
sudo -u $USER echo "[`date -u +%Y-%m-%dT%T.%3NZ`] (sys) Starting" >> /var/log/$APPNAME.log
end script


script
# Not sure why $HOME is needed, but we found that it is:
export HOME="<project-home-dir>"  #set your project home folder here
export NODE_PATH="<project node_path>"


#log file, grant permission to nodejs user
exec start-stop-daemon --start --make-pidfile --pidfile /var/run/$APPNAME.pid --chuid $USER --chdir $WORKDIR --exec $COMMAND >> /var/log/$APPNAME.log 2>&1
end script


post-start script
# Optionally put a script here that will notifiy you node has (re)started
# /root/bin/hoptoad.sh "node.js has started!"
end script


pre-stop script
sudo -u $USER echo "[`date -u +%Y-%m-%dT%T.%3NZ`] (sys) Stopping" >> /var/log/$APPNAME.log
end script

如果您正在运行OSX,那么生成真正的系统进程的最简单方法是使用launchd来启动它。

建立一个像这样的plist,并把它放在/Library/LaunchDaemons中,命名为top-level-domain.your-domain.application.plist(放置它时你需要是root用户):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>top-level-domain.your-domain.application</string>


<key>WorkingDirectory</key>
<string>/your/preferred/workingdirectory</string>


<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/node</string>
<string>your-script-file</string>
</array>


<key>RunAtLoad</key>
<true/>


<key>KeepAlive</key>
<true/>


</dict>
</plist>

完成后,发出这个(作为根):

launchctl load /Library/LaunchDaemons/top-level-domain.your-domain.application.plist
launchctl start top-level-domain.your-domain.application

你在跑步。

重新启动后,您仍将运行。

对于plist中的其他选项,请查看这里的手册页:https://developer.apple.com/library/mac/documentation/Darwin/Reference/Manpages/man5/launchd.plist.5.html

我如何运行一个Node.js应用程序作为它自己的进程?复制我自己的答案

2015的答案:几乎每个Linux发行版都带有systemd,这意味着永远,monit, PM2等不再需要-你的操作系统已经处理这些任务

制作一个myapp.service文件(显然,用你的应用程序名称替换“myapp”):

[Unit]
Description=My app


[Service]
ExecStart=/var/www/myapp/app.js
Restart=always
User=nobody
# Note Debian/Ubuntu uses 'nogroup', RHEL/Fedora uses 'nobody'
Group=nogroup
Environment=PATH=/usr/bin:/usr/local/bin
Environment=NODE_ENV=production
WorkingDirectory=/var/www/myapp


[Install]
WantedBy=multi-user.target

如果你是Unix新手,请注意: /var/www/myapp/app.js应该在第一行有#!/usr/bin/env node,可执行模式为chmod +x myapp.js

复制您的服务文件到/etc/systemd/system

systemctl start myapp开始。

启用它在引导时使用systemctl enable myapp运行。

查看journalctl -u myapp的日志

这来自我们如何在Linux上部署节点应用程序,2018版,其中还包括生成AWS/DigitalOcean/Azure CloudConfig以构建Linux/node服务器的命令(包括.service文件)。

PM2是一个用于Node.js应用程序的生产进程管理器,具有内置的负载均衡器。它允许您让应用程序永远处于活动状态,在没有停机时间的情况下重新加载它们,并方便执行常见的系统管理任务。 # EYZ0 < / p >

我很惊讶居然没有人提到老板

我一直在尝试,pm2,等等。但是,当谈到可靠的控制和基于web的性能指标时,我发现老板是迄今为止最好的。另外,它也是完全开源的。

enter image description here

编辑:但是,我不确定它是否在windows上工作。我只在linux上使用过。

有人注意到“2>&1”的位置有一个小错误吗?

2>&1 >> file

应该是

>> file 2>&1

如果使用nohup -,请尝试执行该命令

nohup npm start 2>/dev/null 1>/dev/null&

你也可以使用永久来启动服务器

forever start -c "npm start" ./

PM2也支持npm start

pm2 start npm -- start

公认的答案可能是最好的生产答案,但作为一个快速开发工作的hack,我发现了这个:

nodejs scriptname.js &不起作用,因为nodejs似乎吞噬了&,所以这个东西不让我在没有scriptname.js死亡的情况下继续使用终端。

但是我把nodejs scriptname.js放在一个.sh文件中,并且 # EYZ0工作。< / p >

绝对不是一个生产的东西,但它解决了“我需要继续使用我的终端,不想启动5个不同的终端”的问题。

我在远程主机上使用tmux作为多窗口/窗格开发环境。分离并保持进程在后台运行非常简单。看看tmux

2017年6月更新:
Linux解决方案:(Red hat)。之前的评论对我不起作用。 这适用于我的亚马逊网络服务-红帽7。

A. Create the service file
sudo vi /etc/systemd/system/myapp.service
[Unit]
Description=Your app
After=network.target


[Service]
ExecStart=/home/ec2-user/meantodos/start.sh
WorkingDirectory=/home/ec2-user/meantodos/


[Install]
WantedBy=multi-user.target

B. Create a shell file
/home/ec2-root/meantodos/start.sh
#!/bin/sh -
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to 8080
npm start


then:
chmod +rx /home/ec2-root/meantodos/start.sh
(to make this file executable)

C. Execute the Following


sudo systemctl daemon-reload
sudo systemctl start myapp
sudo systemctl status myapp


(If there are no errors, execute below.  Autorun after server restarted.)
chkconfig myapp -add

如果你只是想不间断地运行脚本直到它完成,你可以使用已经在答案中提到的nohup。但是,没有一个答案提供完整的命令,也记录stdinstdout

nohup node index.js >> app.log 2>&1 &
  • >>表示追加到app.log
  • 2>&1确保错误也被发送到stdout并添加到app.log
  • 结尾的&确保您当前的终端与命令断开连接,以便您可以继续工作。

如果您想运行节点服务器(或者在服务器重新启动时重新启动的服务器),您应该使用Systemd / systemctl

对于使用新版本的守护进程 npm模块的人,你需要传递文件描述符而不是字符串:

var fs = require('fs');
var stdoutFd = fs.openSync('output.log', 'a');
var stderrFd = fs.openSync('errors.log', 'a');
require('daemon')({
stdout: stdoutFd,
stderr: stderrFd
});

由于我在提供的答案列表中缺少这个选项,我想在2020年添加一个合格的选项:码头工人或任何等效 容器平台。除了确保您的应用程序在稳定的环境中工作外,还有额外的安全性好处以及改进的可移植性。

docker支持Windows, macOS和大多数/主要的Linux发行版。在支持的平台上安装docker相当简单,并且有良好的文档记录。设置Node.js应用程序非常简单,只需将其放入容器中并运行该容器,同时确保在关闭后重新启动。

创建容器镜像

假设您的应用程序在该服务器上的/home/me/my-app中可用,在/home/me文件夹中创建一个文本文件< >强Dockerfile < / >强,内容类似于以下内容:

FROM node:lts-alpine
COPY /my-app/ /app/
RUN cd /app && npm ci
CMD ["/app/server.js"]

它正在为在Alpine Linux下运行LTS版本的Node.js创建一个映像,将应用程序的文件复制到映像中,并运行npm ci以确保依赖项与运行时上下文匹配。

在相同的文件夹中创建另一个文件.dockerignore

**/node_modules

这将防止宿主系统的现有依赖项被注入到容器中,因为它们可能在那里不起作用。在Dockerfile中给出的RUN命令将修复这个问题。

使用如下命令创建图像:

docker build -t myapp-as-a-service /home/me

-t选项正在选择“名称”;构建的集装箱形象。这将用于下面运行的容器。

最后一个参数是选择包含Dockerfile的文件夹,而不是Dockerfile本身。你可以选择一个不同的选项-f

启动容器

使用此命令启动容器:

docker run -d --restart always -p 80:3000 myapp-as-a-service

这个命令假设你的应用程序正在监听端口3000,而你想让它暴露在主机的端口80上。

当然,这是一个非常有限的例子,但它是一个很好的起点。

如果你正在使用pm2,你可以将autorestart设置为false:

$ pm2生态系统

这将生成一个示例ecosystem.config.js:

module.exports = {
apps: [
{
script: './scripts/companies.js',
autorestart: false,
},
{
script: './scripts/domains.js',
autorestart: false,
},
{
script: './scripts/technologies.js',
autorestart: false,
},
],
}

$ pm2启动ecosystem.config.js

在RHEL 8 AWS EC2实例上使用@mikemaccana的接受答案时,我收到了以下错误

这是由于使用用户/组设置为:'nobody'。

通过谷歌搜索,似乎使用用户/组作为'nobody'/'nogroup'对于unix堆栈交换上回答在这里的守护进程来说是一个坏习惯。

在我将用户/组设置为我的实际用户和组后,它工作得很好。

您可以输入whomaigroups来查看可用的修复选项。

我的服务文件为mongodb的全堆栈节点应用程序:

[Unit]
Description=myapp
After=mongod.service


[Service]
ExecStart=/home/myusername/apps/myapp/root/build/server/index.js
Restart=always
RestartSec=30
User=myusername
Group=myusername
Environment=PATH=/usr/bin:/usr/local/bin
Environment=NODE_ENV=production
WorkingDirectory=/home/myusername/apps/myapp


[Install]
WantedBy=multi-user.target

使用pm2模块。# EYZ0

如果出于本地开发的目的,你需要启动多个NodeJS应用实例(express, fastify等),那么concurrently可能是一个选项。下面是一个设置:

Prerequesites

  • 你的NodeJS应用(express, fastify等)被放置在/opt/mca/www/mca-backend/app路径下。
  • 假设您使用的是通过brew install node@16安装的v.16节点

设置

  1. 同时安装:npm install -g concurrently

  2. 创建一个~/Library/LaunchAgents/mca.backend.plist的文件

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
    <key>Label</key>
    <string>mca.backend</string>
    <key>LimitLoadToSessionType</key>
    <array>
    <string>Aqua</string>
    <string>Background</string>
    <string>LoginWindow</string>
    <string>StandardIO</string>
    <string>System</string>
    </array>
    <key>ProgramArguments</key>
    <array>
    <string>/usr/local/bin/concurrently</string>
    <string>--names</string>
    <string>dev,prd</string>
    <string>--success</string>
    <string>all</string>
    <string>--kill-others</string>
    <string>--no-color</string>
    <string>MCA_APP_STAGE=dev  node ./server.mjs</string>
    <string>MCA_APP_STAGE=prod node ./server.mjs</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>EnvironmentVariables</key>
    <dict>
    <key>PATH</key>
    <string>/usr/local/opt/node@16/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin</string>
    </dict>
    <key>WorkingDirectory</key>
    <string>/opt/mca/www/mca-backend/app</string>
    <key>StandardErrorPath</key>
    <string>/opt/mca/www/mca-backend/err.log</string>
    <key>StandardOutPath</key>
    <string>/opt/mca/www/mca-backend/out.log</string>
    </dict>
    </plist>
    
  3. 加载并运行:launchctl bootstrap gui/`id -u` $HOME/Library/LaunchAgents/mca.backend.plist

  4. 获得一个状态:launchctl print gui/`id -u`/mca.backend

  5. < p >站:# EYZ0

  6. < p >启动/重新启动:# EYZ0

  7. 如果不再需要卸载:launchctl bootout gui/`id -u`/mca.backend

重要的:一旦你用launchctl bootstrap加载服务,你在文件中所做的任何更改 ~/Library/LaunchAgents/mca.backend.plist将不会在行动,直到你卸载服务(通过使用launchctl bootout) 然后再次加载它(使用launchctl bootstrap)

故障排除

参见启动日志:/private/var/log/com.apple.xpc.launchd/launchd.log